Skip to content

Commit 0b41349

Browse files
authored
feat(ambient-mode): add config for ambient-mode plugin (#1349)
1 parent dc73561 commit 0b41349

File tree

7 files changed

+169
-15
lines changed

7 files changed

+169
-15
lines changed

src/config/defaults.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,16 @@ const defaultConfig = {
8181
disableDefaultLists: false,
8282
},
8383
'album-color-theme': {},
84-
'ambient-mode': {},
84+
'ambient-mode': {
85+
enabled: false,
86+
quality: 50,
87+
buffer: 30,
88+
interpolationTime: 1500,
89+
blur: 100,
90+
size: 100,
91+
opacity: 1,
92+
fullscreen: false,
93+
},
8594
'audio-compressor': {},
8695
'blur-nav-bar': {},
8796
'bypass-age-restrictions': {},

src/menu.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { startingPages } from './providers/extracted-data';
88
import promptOptions from './providers/prompt-options';
99

1010
import adblockerMenu from './plugins/adblocker/menu';
11+
import ambientModeMenu from './plugins/ambient-mode/menu';
1112
import captionsSelectorMenu from './plugins/captions-selector/menu';
1213
import crossfadeMenu from './plugins/crossfade/menu';
1314
import disableAutoplayMenu from './plugins/disable-autoplay/menu';
@@ -32,6 +33,7 @@ const betaPlugins = ['crossfade', 'lumiastream'];
3233

3334
const pluginMenus = {
3435
'adblocker': adblockerMenu,
36+
'ambient-mode': ambientModeMenu,
3537
'disable-autoplay': disableAutoplayMenu,
3638
'captions-selector': captionsSelectorMenu,
3739
'crossfade': crossfadeMenu,

src/plugins/ambient-mode/back.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import { BrowserWindow } from 'electron';
22

3+
import config from './config';
34
import style from './style.css';
45

56
import { injectCSS } from '../utils';
67

8+
export default (win: BrowserWindow) => {
9+
config.subscribeAll((newConfig) => {
10+
win.webContents.send('ambient-mode:config-change', newConfig);
11+
});
712

8-
export default (win: BrowserWindow) => {
913
injectCSS(win.webContents, style);
1014
};

src/plugins/ambient-mode/config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { PluginConfig } from '../../config/dynamic';
2+
3+
const config = new PluginConfig('ambient-mode');
4+
export default config;

src/plugins/ambient-mode/front.ts

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1+
import { ipcRenderer } from 'electron';
2+
13
import { ConfigType } from '../../config/dynamic';
24

3-
export default (_: ConfigType<'ambient-mode'>) => {
4-
const interpolationTime = 3000; // interpolation time (ms)
5-
const framerate = 30; // frame
6-
const qualityRatio = 50; // width size (pixel)
5+
export default (config: ConfigType<'ambient-mode'>) => {
6+
let interpolationTime = config.interpolationTime; // interpolation time (ms)
7+
let buffer = config.buffer; // frame
8+
let qualityRatio = config.quality; // width size (pixel)
9+
let sizeRatio = config.size / 100; // size ratio (percent)
10+
let blur = config.blur; // blur (pixel)
11+
let opacity = config.opacity; // opacity (percent)
12+
let isFullscreen = config.fullscreen; // fullscreen (boolean)
713

814
let unregister: (() => void) | null = null;
915

@@ -37,7 +43,7 @@ export default (_: ConfigType<'ambient-mode'>) => {
3743

3844
context.globalAlpha = 1;
3945
if (lastImageData) {
40-
const frameOffset = (1 / framerate) * (1000 / interpolationTime);
46+
const frameOffset = (1 / buffer) * (1000 / interpolationTime);
4147
context.globalAlpha = 1 - (frameOffset * 2); // because of alpha value must be < 1
4248
context.putImageData(lastImageData, 0, 0);
4349
context.globalAlpha = frameOffset;
@@ -61,8 +67,18 @@ export default (_: ConfigType<'ambient-mode'>) => {
6167

6268
blurCanvas.width = qualityRatio;
6369
blurCanvas.height = Math.floor(newHeight / newWidth * qualityRatio);
64-
blurCanvas.style.width = `${newWidth}px`;
65-
blurCanvas.style.height = `${newHeight}px`;
70+
blurCanvas.style.width = `${newWidth * sizeRatio}px`;
71+
blurCanvas.style.height = `${newHeight * sizeRatio}px`;
72+
73+
if (isFullscreen) blurCanvas.classList.add('fullscreen');
74+
else blurCanvas.classList.remove('fullscreen');
75+
76+
const leftOffset = newWidth * (sizeRatio - 1) / 2;
77+
const topOffset = newHeight * (sizeRatio - 1) / 2;
78+
blurCanvas.style.setProperty('--left', `${-1 * leftOffset}px`);
79+
blurCanvas.style.setProperty('--top', `${-1 * topOffset}px`);
80+
blurCanvas.style.setProperty('--blur', `${blur}px`);
81+
blurCanvas.style.setProperty('--opacity', `${opacity}`);
6682
};
6783

6884
const observer = new MutationObserver((mutations) => {
@@ -75,10 +91,22 @@ export default (_: ConfigType<'ambient-mode'>) => {
7591
const resizeObserver = new ResizeObserver(() => {
7692
applyVideoAttributes();
7793
});
94+
const onConfigSync = (_: Electron.IpcRendererEvent, newConfig: ConfigType<'ambient-mode'>) => {
95+
if (typeof newConfig.interpolationTime === 'number') interpolationTime = newConfig.interpolationTime;
96+
if (typeof newConfig.buffer === 'number') buffer = newConfig.buffer;
97+
if (typeof newConfig.quality === 'number') qualityRatio = newConfig.quality;
98+
if (typeof newConfig.size === 'number') sizeRatio = newConfig.size / 100;
99+
if (typeof newConfig.blur === 'number') blur = newConfig.blur;
100+
if (typeof newConfig.opacity === 'number') opacity = newConfig.opacity;
101+
if (typeof newConfig.fullscreen === 'boolean') isFullscreen = newConfig.fullscreen;
78102

103+
applyVideoAttributes();
104+
};
105+
ipcRenderer.on('ambient-mode:config-change', onConfigSync);
106+
79107
/* hooking */
80108
let canvasInterval: NodeJS.Timeout | null = null;
81-
canvasInterval = setInterval(onSync, Math.max(1, Math.ceil(1000 / framerate)));
109+
canvasInterval = setInterval(onSync, Math.max(1, Math.ceil(1000 / buffer)));
82110
applyVideoAttributes();
83111
observer.observe(songVideo, { attributes: true });
84112
resizeObserver.observe(songVideo);
@@ -90,7 +118,7 @@ export default (_: ConfigType<'ambient-mode'>) => {
90118
};
91119
const onPlay = () => {
92120
if (canvasInterval) clearInterval(canvasInterval);
93-
canvasInterval = setInterval(onSync, Math.max(1, Math.ceil(1000 / framerate)));
121+
canvasInterval = setInterval(onSync, Math.max(1, Math.ceil(1000 / buffer)));
94122
};
95123
songVideo.addEventListener('pause', onPause);
96124
songVideo.addEventListener('play', onPlay);
@@ -107,6 +135,7 @@ export default (_: ConfigType<'ambient-mode'>) => {
107135

108136
observer.disconnect();
109137
resizeObserver.disconnect();
138+
ipcRenderer.off('ambient-mode:config-change', onConfigSync);
110139
window.removeEventListener('resize', applyVideoAttributes);
111140

112141
wrapper.removeChild(blurCanvas);

src/plugins/ambient-mode/menu.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import config from './config';
2+
3+
import { MenuTemplate } from '../../menu';
4+
5+
const interpolationTimeList = [0, 500, 1000, 1500, 2000, 3000, 4000, 5000];
6+
const qualityList = [10, 25, 50, 100, 200, 500, 1000];
7+
const sizeList = [100, 110, 125, 150, 175, 200, 300];
8+
const bufferList = [1, 5, 10, 20, 30];
9+
const blurAmountList = [0, 5, 10, 25, 50, 100, 150, 200, 500];
10+
const opacityList = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1];
11+
12+
export default (): MenuTemplate => [
13+
{
14+
label: 'Smoothness transition',
15+
submenu: interpolationTimeList.map((interpolationTime) => ({
16+
label: `During ${interpolationTime / 1000}s`,
17+
type: 'radio',
18+
checked: config.get('interpolationTime') === interpolationTime,
19+
click() {
20+
config.set('interpolationTime', interpolationTime);
21+
},
22+
})),
23+
},
24+
{
25+
label: 'Quality',
26+
submenu: qualityList.map((quality) => ({
27+
label: `${quality} pixels`,
28+
type: 'radio',
29+
checked: config.get('quality') === quality,
30+
click() {
31+
config.set('quality', quality);
32+
},
33+
})),
34+
},
35+
{
36+
label: 'Size',
37+
submenu: sizeList.map((size) => ({
38+
label: `${size}%`,
39+
type: 'radio',
40+
checked: config.get('size') === size,
41+
click() {
42+
config.set('size', size);
43+
},
44+
})),
45+
},
46+
{
47+
label: 'Buffer',
48+
submenu: bufferList.map((buffer) => ({
49+
label: `${buffer}`,
50+
type: 'radio',
51+
checked: config.get('buffer') === buffer,
52+
click() {
53+
config.set('buffer', buffer);
54+
},
55+
})),
56+
},
57+
{
58+
label: 'Opacity',
59+
submenu: opacityList.map((opacity) => ({
60+
label: `${opacity * 100}%`,
61+
type: 'radio',
62+
checked: config.get('opacity') === opacity,
63+
click() {
64+
config.set('opacity', opacity);
65+
},
66+
})),
67+
},
68+
{
69+
label: 'Blur amount',
70+
submenu: blurAmountList.map((blur) => ({
71+
label: `${blur} pixels`,
72+
type: 'radio',
73+
checked: config.get('blur') === blur,
74+
click() {
75+
config.set('blur', blur);
76+
},
77+
})),
78+
},
79+
{
80+
label: 'Using fullscreen',
81+
type: 'checkbox',
82+
checked: config.get('fullscreen'),
83+
click(item) {
84+
config.set('fullscreen', item.checked);
85+
},
86+
},
87+
];

src/plugins/ambient-mode/style.css

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,26 @@
1-
#song-video canvas.html5-blur-canvas{
1+
#song-video canvas.html5-blur-canvas {
2+
filter: blur(var(--blur, 100px));
3+
opacity: var(--opacity, 1);
4+
5+
pointer-events: none;
6+
}
7+
8+
#song-video canvas.html5-blur-canvas:not(.fullscreen) {
29
position: absolute;
3-
left: 0;
4-
top: 0;
510

6-
filter: blur(100px);
11+
left: var(--left, 0px);
12+
top: var(--top, 0px);
13+
}
14+
15+
#song-video canvas.html5-blur-canvas.fullscreen {
16+
position: fixed;
17+
18+
width: 100% !important;
19+
height: 100% !important;
20+
left: 0 !important;
21+
top: 0 !important;
22+
}
23+
24+
#song-video .html5-video-container > video {
25+
top: 0 !important;
726
}

0 commit comments

Comments
 (0)