feat(ambient-mode): add ambient-mode plugin

This commit is contained in:
Su-Yong
2023-10-04 20:28:14 +09:00
parent 110dbd3e18
commit 7479f2f697
6 changed files with 105 additions and 0 deletions

View File

@ -77,6 +77,7 @@ const defaultConfig = {
disableDefaultLists: [],
},
'album-color-theme': {},
'ambient-mode': {},
'audio-compressor': {},
'blur-nav-bar': {},
'bypass-age-restrictions': {},

View File

@ -20,6 +20,7 @@ import { APP_PROTOCOL, handleProtocol, setupProtocolHandler } from './providers/
import adblocker from './plugins/adblocker/back';
import albumColorTheme from './plugins/album-color-theme/back';
import ambientMode from './plugins/ambient-mode/back';
import blurNavigationBar from './plugins/blur-nav-bar/back';
import captionsSelector from './plugins/captions-selector/back';
import crossfade from './plugins/crossfade/back';
@ -103,6 +104,7 @@ function onClosed() {
const mainPlugins = {
'adblocker': adblocker,
'album-color-theme': albumColorTheme,
'ambient-mode': ambientMode,
'blur-nav-bar': blurNavigationBar,
'captions-selector': captionsSelector,
'crossfade': crossfade,

View File

@ -0,0 +1,10 @@
import { BrowserWindow } from 'electron';
import style from './style.css';
import { injectCSS } from '../utils';
export default (win: BrowserWindow) => {
injectCSS(win.webContents, style);
};

View File

@ -0,0 +1,83 @@
import { ConfigType } from '../../config/dynamic';
export default (_: ConfigType<'ambient-mode'>) => {
let unregister: (() => void) | null = null;
const injectBlurVideo = (): (() => void) | null => {
const songVideo = document.querySelector<HTMLDivElement>('#song-video');
const video = document.querySelector<HTMLVideoElement>('#song-video .html5-video-container > video');
const wrapper = document.querySelector('#song-video > .player-wrapper');
if (!songVideo) return null;
if (!video) return null;
if (!wrapper) return null;
const blurCanvas = document.createElement('canvas');
blurCanvas.classList.add('html5-blur-canvas');
const context = blurCanvas.getContext('2d');
const applyVideoAttributes = () => {
const rect = video.getBoundingClientRect();
blurCanvas.width = video.width || rect.width;
blurCanvas.height = video.height || rect.height;
};
const onSync = () => {
requestAnimationFrame(() => {
context?.drawImage(video, 0, 0, blurCanvas.width, blurCanvas.height);
});
};
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'attributes') {
applyVideoAttributes();
}
});
});
const resizeObserver = new ResizeObserver(() => {
applyVideoAttributes();
});
/* hooking */
video.addEventListener('timeupdate', onSync);
applyVideoAttributes();
observer.observe(songVideo, { attributes: true });
resizeObserver.observe(songVideo);
/* injecting */
wrapper.prepend(blurCanvas);
/* cleanup */
return () => {
video.removeEventListener('timeupdate', onSync);
observer.disconnect();
resizeObserver.disconnect();
wrapper.removeChild(blurCanvas);
};
};
const playerPage = document.querySelector<HTMLElement>('#player-page');
const ytmusicAppLayout = document.querySelector<HTMLElement>('#layout');
const observer = new MutationObserver((mutationsList) => {
for (const mutation of mutationsList) {
if (mutation.type === 'attributes') {
const isPageOpen = ytmusicAppLayout?.hasAttribute('player-page-open');
if (isPageOpen) {
unregister?.();
unregister = injectBlurVideo() ?? null;
}
}
}
});
if (playerPage) {
observer.observe(playerPage, { attributes: true });
}
};

View File

@ -0,0 +1,7 @@
#song-video canvas.html5-blur-canvas{
position: absolute;
left: 0;
top: 0;
filter: blur(100px);
}

View File

@ -7,6 +7,7 @@ import { setupSongControls } from './providers/song-controls-front';
import { startingPages } from './providers/extracted-data';
import albumColorThemeRenderer from './plugins/album-color-theme/front';
import ambientModeRenderer from './plugins/ambient-mode/front';
import audioCompressorRenderer from './plugins/audio-compressor/front';
import bypassAgeRestrictionsRenderer from './plugins/bypass-age-restrictions/front';
import captionsSelectorRenderer from './plugins/captions-selector/front';
@ -43,6 +44,7 @@ type PluginMapper<Type extends 'renderer' | 'preload' | 'backend'> = {
const rendererPlugins: PluginMapper<'renderer'> = {
'album-color-theme': albumColorThemeRenderer,
'ambient-mode': ambientModeRenderer,
'audio-compressor': audioCompressorRenderer,
'bypass-age-restrictions': bypassAgeRestrictionsRenderer,
'captions-selector': captionsSelectorRenderer,