From 19fd0d61c648307d2a3aea6ecb708e06d88c5e99 Mon Sep 17 00:00:00 2001 From: Franz DC Date: Wed, 26 Mar 2025 18:36:42 +0800 Subject: [PATCH] feat(plugin): add unobtrusive player plugin (#3104) * feat(plugin): add unobtrusive player plugin * fix(plugin): add removeEventListener once unobtrusive-player is disabled * feat(plugin): prevent player page button animation when changing song * fix(plugin): add removeEventListener for videodatachange once unobtrusive-player is disabled --- src/i18n/resources/en.json | 4 ++ src/plugins/unobtrusive-player/index.ts | 77 ++++++++++++++++++++++++ src/plugins/unobtrusive-player/style.css | 27 +++++++++ 3 files changed, 108 insertions(+) create mode 100644 src/plugins/unobtrusive-player/index.ts create mode 100644 src/plugins/unobtrusive-player/style.css diff --git a/src/i18n/resources/en.json b/src/i18n/resources/en.json index 2b15931f..e24614d4 100644 --- a/src/i18n/resources/en.json +++ b/src/i18n/resources/en.json @@ -788,6 +788,10 @@ "description": "Integration with OBS's plugin Tuna", "name": "Tuna OBS" }, + "unobtrusive-player": { + "description": "Prevents the player from popping up when playing a song", + "name": "Unobtrusive Player" + }, "video-toggle": { "description": "Adds a button to switch between Video/Song mode. can also optionally remove the whole video tab", "menu": { diff --git a/src/plugins/unobtrusive-player/index.ts b/src/plugins/unobtrusive-player/index.ts new file mode 100644 index 00000000..276d87bf --- /dev/null +++ b/src/plugins/unobtrusive-player/index.ts @@ -0,0 +1,77 @@ +import style from './style.css?inline'; + +import { createPlugin } from '@/utils'; +import { t } from '@/i18n'; + +const handlePlay = (e: MouseEvent) => { + if (!(e.target instanceof HTMLElement)) return; + + if ( + e.target.closest('ytmusic-play-button-renderer') && + !e.target.closest('ytmusic-player-page') + ) { + document.body.classList.add('unobtrusive-player--did-play'); + } + + if ( + e.target.closest('ytmusic-player-bar') && + !document.body.classList.contains('unobtrusive-player--auto-closing') + ) { + document.body.classList.remove('unobtrusive-player--did-play'); + } +}; + +const handleVideoDataChange = () => { + const isPlayerPageOpen = + document + .querySelector('ytmusic-app-layout') + ?.attributes.getNamedItem('player-ui-state')?.value === + 'PLAYER_PAGE_OPEN'; + + if ( + document.body.classList.contains('unobtrusive-player--did-play') && + isPlayerPageOpen + ) { + document.body.classList.add('unobtrusive-player--auto-closing'); + + document + .querySelector('.toggle-player-page-button') + ?.click(); + + // prevent animation flickering + setTimeout(() => { + document.body.classList.remove('unobtrusive-player--auto-closing'); + }, 500); + } +}; + +export default createPlugin({ + name: () => t('plugins.unobtrusive-player.name'), + description: () => t('plugins.unobtrusive-player.description'), + restartNeeded: false, + config: { + enabled: false, + }, + stylesheets: [style], + renderer: { + start: () => { + document.body.classList.add('unobtrusive-player'); + document.addEventListener('click', handlePlay); + }, + onPlayerApiReady: () => { + // Close player page when video changes while + // `unobtrusive-player--did-play` className is present. + document.addEventListener('videodatachange', handleVideoDataChange); + }, + stop: () => { + document.removeEventListener('click', handlePlay); + document.removeEventListener('videodatachange', handleVideoDataChange); + + [ + 'unobtrusive-player', + 'unobtrusive-player--did-play', + 'unobtrusive-player--auto-closing', + ].forEach((className) => document.body.classList.remove(className)); + }, + }, +}); diff --git a/src/plugins/unobtrusive-player/style.css b/src/plugins/unobtrusive-player/style.css new file mode 100644 index 00000000..d4626418 --- /dev/null +++ b/src/plugins/unobtrusive-player/style.css @@ -0,0 +1,27 @@ +body.unobtrusive-player.unobtrusive-player--did-play { + overflow: visible !important; + + & ytmusic-player-page, + ytmusic-player-page * { + visibility: hidden !important; + } + + & #content { + visibility: visible !important; + } + + & + ytmusic-app-layout:not(.content-scrolled) + #nav-bar-background.ytmusic-app-layout, + ytmusic-app-layout:not(.content-scrolled) #nav-bar-divider.ytmusic-app-layout, + ytmusic-app-layout[is-bauhaus-sidenav-enabled][player-page-open]:not( + .content-scrolled + ) + #mini-guide-background.ytmusic-app-layout { + opacity: 0 !important; + } + + & .toggle-player-page-button { + transform: rotate(180deg) !important; + } +}