From b665343fd9f265210a6e5a76c7813fd0f5edd6a8 Mon Sep 17 00:00:00 2001 From: Araxeus <78568641+Araxeus@users.noreply.github.com> Date: Thu, 19 Jan 2023 18:52:40 +0200 Subject: [PATCH 1/9] make navbar draggable [in-app-menu] --- plugins/in-app-menu/style.css | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/plugins/in-app-menu/style.css b/plugins/in-app-menu/style.css index 3805e119..6d0f3006 100644 --- a/plugins/in-app-menu/style.css +++ b/plugins/in-app-menu/style.css @@ -80,3 +80,15 @@ yt-page-navigation-progress, .cet-menubar-menu-container .cet-action-item { background-color: inherit } + +#nav-bar-background { + -webkit-app-region: drag; +} + +ytmusic-nav-bar input, +ytmusic-nav-bar span, +ytmusic-nav-bar [role="button"], +ytmusic-nav-bar yt-icon, +tp-yt-iron-dropdown { + -webkit-app-region: no-drag; +} From c6bb0cfe88e76c8eb70d93cc65993df6909b125e Mon Sep 17 00:00:00 2001 From: Araxeus <78568641+Araxeus@users.noreply.github.com> Date: Thu, 19 Jan 2023 19:16:01 +0200 Subject: [PATCH 2/9] remove draggable attribute if search box is open --- plugins/in-app-menu/front.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/plugins/in-app-menu/front.js b/plugins/in-app-menu/front.js index da5841f9..e597a5e9 100644 --- a/plugins/in-app-menu/front.js +++ b/plugins/in-app-menu/front.js @@ -43,9 +43,21 @@ module.exports = (options) => { setNavbarMargin(); const playPageObserver = new MutationObserver(setNavbarMargin); playPageObserver.observe($('ytmusic-app-layout'), { attributeFilter: ['player-page-open_', 'playerPageOpen_'] }) + setupSearchOpenObserver(); }, { once: true, passive: true }) }; +function setupSearchOpenObserver() { + const searchOpenObserver = new MutationObserver(mutations => { + if (mutations[0].target.opened) { + $('#nav-bar-background').style.webkitAppRegion = 'no-drag' + } else { + $('#nav-bar-background').style.webkitAppRegion = 'drag' + } + }); + searchOpenObserver.observe($('ytmusic-search-box'), { attributeFilter: ["opened"] }) +} + function setNavbarMargin() { $('#nav-bar-background').style.right = $('ytmusic-app-layout').playerPageOpen_ ? From 333b695b16e8d714fd426281f8259159b7fafe9f Mon Sep 17 00:00:00 2001 From: Araxeus <78568641+Araxeus@users.noreply.github.com> Date: Sun, 22 Jan 2023 19:18:10 +0200 Subject: [PATCH 3/9] lint --- plugins/in-app-menu/front.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/plugins/in-app-menu/front.js b/plugins/in-app-menu/front.js index e597a5e9..17c89d4e 100644 --- a/plugins/in-app-menu/front.js +++ b/plugins/in-app-menu/front.js @@ -49,11 +49,8 @@ module.exports = (options) => { function setupSearchOpenObserver() { const searchOpenObserver = new MutationObserver(mutations => { - if (mutations[0].target.opened) { - $('#nav-bar-background').style.webkitAppRegion = 'no-drag' - } else { - $('#nav-bar-background').style.webkitAppRegion = 'drag' - } + $('#nav-bar-background').style.webkitAppRegion = + mutations[0].target.opened ? 'no-drag' : 'drag'; }); searchOpenObserver.observe($('ytmusic-search-box'), { attributeFilter: ["opened"] }) } From 8a9a3fc69dfd1ad5d7e10fb54998db50628d6e2e Mon Sep 17 00:00:00 2001 From: TC Date: Wed, 1 Feb 2023 22:25:33 +0100 Subject: [PATCH 4/9] Add option `useNativePiP` in PiP plugin to use native PiP --- plugins/picture-in-picture/front.js | 34 ++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/plugins/picture-in-picture/front.js b/plugins/picture-in-picture/front.js index 788a908e..5d0bf302 100644 --- a/plugins/picture-in-picture/front.js +++ b/plugins/picture-in-picture/front.js @@ -5,6 +5,7 @@ const { ElementFromFile, templatePath } = require("../utils"); function $(selector) { return document.querySelector(selector); } +let useNativePiP = false; let menu = null; const pipButton = ElementFromFile( templatePath(__dirname, "picture-in-picture.html") @@ -39,8 +40,24 @@ const observer = new MutationObserver(() => { menu.prepend(pipButton); }); -global.togglePictureInPicture = () => { +global.togglePictureInPicture = async () => { + if (useNativePiP) { + const isInPiP = document.pictureInPictureElement !== null; + const video = $("video"); + const togglePiP = () => + isInPiP + ? document.exitPictureInPicture.call(document) + : video.requestPictureInPicture.call(video); + + try { + await togglePiP(); + $("#icon").click(); // Close the menu + return true; + } catch {} + } + ipcRenderer.send("picture-in-picture"); + return false; }; const listenForToggle = () => { @@ -75,19 +92,24 @@ const listenForToggle = () => { } function observeMenu(options) { + useNativePiP = options.useNativePiP; document.addEventListener( "apiLoaded", () => { - listenForToggle(); + if (!useNativePiP) { + listenForToggle(); + } // remove native listeners - cloneButton(".player-minimize-button").onclick = () => { - global.togglePictureInPicture(); - setTimeout(() => $('#player').click()); + cloneButton(".player-minimize-button").onclick = async () => { + const isUsingNativePiP = await global.togglePictureInPicture(); + if (!isUsingNativePiP) { + setTimeout(() => $("#player").click()); + } }; // allows easily closing the menu by programmatically clicking outside of it $("#expanding-menu").removeAttribute("no-cancel-on-outside-click"); - // TODO: think about wether an additional button in songMenu is needed + // TODO: think about wether an additional button in songMenu is needed observer.observe($("ytmusic-popup-container"), { childList: true, subtree: true, From 0b49d57969dad31734c0552da4f4d3588eaae393 Mon Sep 17 00:00:00 2001 From: TC Date: Wed, 8 Feb 2023 23:46:24 +0100 Subject: [PATCH 5/9] Always listen for toggle --- plugins/picture-in-picture/front.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/picture-in-picture/front.js b/plugins/picture-in-picture/front.js index 5d0bf302..88cc1bfb 100644 --- a/plugins/picture-in-picture/front.js +++ b/plugins/picture-in-picture/front.js @@ -96,9 +96,7 @@ function observeMenu(options) { document.addEventListener( "apiLoaded", () => { - if (!useNativePiP) { - listenForToggle(); - } + listenForToggle(); // remove native listeners cloneButton(".player-minimize-button").onclick = async () => { const isUsingNativePiP = await global.togglePictureInPicture(); From 781a726f4bede4cbfe8768cfdedc01451aebca70 Mon Sep 17 00:00:00 2001 From: TC Date: Wed, 8 Feb 2023 23:46:43 +0100 Subject: [PATCH 6/9] Add menu option for native PiP --- plugins/picture-in-picture/menu.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/plugins/picture-in-picture/menu.js b/plugins/picture-in-picture/menu.js index bdbc1cee..61014c22 100644 --- a/plugins/picture-in-picture/menu.js +++ b/plugins/picture-in-picture/menu.js @@ -45,16 +45,24 @@ module.exports = (win, options) => [ }], ...promptOptions() }, win) - + if (output) { const { value, accelerator } = output[0]; setOptions({ [value]: accelerator }); - + item.checked = !!accelerator; } else { // Reset checkbox if prompt was canceled item.checked = !item.checked; } }, + }, + { + label: "Use native PiP", + type: "checkbox", + checked: options.useNativePiP, + click: (item) => { + setOptions({ useNativePiP: item.checked }); + }, } ]; From 97c6cad5038968b5bc165c48b7406e13e049a7eb Mon Sep 17 00:00:00 2001 From: th-ch Date: Thu, 9 Feb 2023 22:33:07 +0100 Subject: [PATCH 7/9] Avoid video pause Co-authored-by: Araxeus --- plugins/picture-in-picture/front.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/picture-in-picture/front.js b/plugins/picture-in-picture/front.js index 88cc1bfb..05f8ee57 100644 --- a/plugins/picture-in-picture/front.js +++ b/plugins/picture-in-picture/front.js @@ -100,9 +100,7 @@ function observeMenu(options) { // remove native listeners cloneButton(".player-minimize-button").onclick = async () => { const isUsingNativePiP = await global.togglePictureInPicture(); - if (!isUsingNativePiP) { - setTimeout(() => $("#player").click()); - } + setTimeout(() => $("#player").click()); }; // allows easily closing the menu by programmatically clicking outside of it From 5dd8d1a2747263a81164ce5740a25122594ab241 Mon Sep 17 00:00:00 2001 From: Araxeus <78568641+Araxeus@users.noreply.github.com> Date: Fri, 10 Feb 2023 17:49:40 +0200 Subject: [PATCH 8/9] remove titlebar from in-app-menu+PiP Results in an experience similar to the native PiP, except plugins can work (for example precise-volume) --- .../adaptors/in-app-menu.js | 37 ------------------- plugins/picture-in-picture/back.js | 13 +------ plugins/picture-in-picture/front.js | 6 ++- plugins/picture-in-picture/style.css | 23 ++++++++++-- youtube-music.css | 5 +++ 5 files changed, 31 insertions(+), 53 deletions(-) delete mode 100644 plugins/picture-in-picture/adaptors/in-app-menu.js diff --git a/plugins/picture-in-picture/adaptors/in-app-menu.js b/plugins/picture-in-picture/adaptors/in-app-menu.js deleted file mode 100644 index a96ae967..00000000 --- a/plugins/picture-in-picture/adaptors/in-app-menu.js +++ /dev/null @@ -1,37 +0,0 @@ -const { Menu, app } = require("electron"); -const { setApplicationMenu } = require("../../../menu"); - -module.exports = (win, options, setOptions, togglePip, isInPip) => { - if (isInPip) { - Menu.setApplicationMenu(Menu.buildFromTemplate([ - { - label: "App", - submenu: [ - { - label: "Exit Picture in Picture", - click: togglePip, - }, - { - label: "Always on top", - type: "checkbox", - checked: options.alwaysOnTop, - click: (item) => { - setOptions({ alwaysOnTop: item.checked }); - win.setAlwaysOnTop(item.checked); - }, - }, - { - label: "Restart", - click: () => { - app.relaunch(); - app.quit(); - }, - }, - { role: "quit" }, - ], - }, - ])); - } else { - setApplicationMenu(win); - } -}; diff --git a/plugins/picture-in-picture/back.js b/plugins/picture-in-picture/back.js index d71acd49..fd5e5511 100644 --- a/plugins/picture-in-picture/back.js +++ b/plugins/picture-in-picture/back.js @@ -3,7 +3,7 @@ const path = require("path"); const { app, ipcMain } = require("electron"); const electronLocalshortcut = require("electron-localshortcut"); -const { setOptions, isEnabled } = require("../../config/plugins"); +const { setOptions } = require("../../config/plugins"); const { injectCSS } = require("../utils"); let isInPiP = false; @@ -23,15 +23,6 @@ const setLocalOptions = (_options) => { setOptions("picture-in-picture", _options); } - -const adaptors = []; -const runAdaptors = () => adaptors.forEach(a => a()); - -if (isEnabled("in-app-menu")) { - let adaptor = require("./adaptors/in-app-menu"); - adaptors.push(() => adaptor(win, options, setLocalOptions, togglePiP, isInPiP)); -} - const togglePiP = async () => { isInPiP = !isInPiP; setLocalOptions({ isInPiP }); @@ -50,7 +41,6 @@ const togglePiP = async () => { win.setMaximizable(false); win.setFullScreenable(false); - runAdaptors(); win.webContents.send("pip-toggle", true); app.dock?.hide(); @@ -66,7 +56,6 @@ const togglePiP = async () => { win.setMaximizable(true); win.setFullScreenable(true); - runAdaptors(); win.webContents.send("pip-toggle", false); win.setVisibleOnAllWorkspaces(false); diff --git a/plugins/picture-in-picture/front.js b/plugins/picture-in-picture/front.js index 788a908e..eee48f3b 100644 --- a/plugins/picture-in-picture/front.js +++ b/plugins/picture-in-picture/front.js @@ -54,6 +54,8 @@ const listenForToggle = () => { const player = $('#player'); const onPlayerDblClick = player.onDoubleClick_; + const titlebar = $('.cet-titlebar'); + ipcRenderer.on('pip-toggle', (_, isPip) => { if (isPip) { replaceButton(".exit-fullscreen-button", originalExitButton).onclick = () => togglePictureInPicture(); @@ -64,12 +66,14 @@ const listenForToggle = () => { } fullScreenButton.click(); appLayout.classList.add("pip"); + if (titlebar) titlebar.style.display = 'none'; } else { $(".exit-fullscreen-button").replaceWith(originalExitButton); player.onDoubleClick_ = onPlayerDblClick; expandMenu.onmouseleave = undefined; originalExitButton.click(); appLayout.classList.remove("pip"); + if (titlebar) titlebar.style.display = 'flex'; } }); } @@ -80,7 +84,7 @@ function observeMenu(options) { () => { listenForToggle(); // remove native listeners - cloneButton(".player-minimize-button").onclick = () => { + cloneButton(".player-minimize-button").onclick = () => { global.togglePictureInPicture(); setTimeout(() => $('#player').click()); }; diff --git a/plugins/picture-in-picture/style.css b/plugins/picture-in-picture/style.css index 1856e01b..a7430739 100644 --- a/plugins/picture-in-picture/style.css +++ b/plugins/picture-in-picture/style.css @@ -3,9 +3,9 @@ ytmusic-app-layout.pip ytmusic-player-bar svg, ytmusic-app-layout.pip ytmusic-player-bar .time-info, ytmusic-app-layout.pip ytmusic-player-bar yt-formatted-string, ytmusic-app-layout.pip ytmusic-player-bar .yt-formatted-string { - filter: drop-shadow(2px 4px 6px black); - color: white !important; - fill: white !important; + filter: drop-shadow(2px 4px 6px black); + color: white !important; + fill: white !important; } /* improve the style of the player bar expanding menu */ @@ -20,6 +20,23 @@ ytmusic-app-layout.pip ytmusic-player-expanding-menu { top: 22px !important; } +/* make player-bar not draggable if in-app-menu is enabled */ +.cet-container ytmusic-app-layout.pip ytmusic-player-bar { + -webkit-app-region: no-drag !important; +} + +/* make player draggable if in-app-menu is enabled */ +.cet-container ytmusic-app-layout.pip #player { + -webkit-app-region: drag !important; +} + +/* remove info, thumbnail and menu from player-bar */ +ytmusic-app-layout.pip ytmusic-player-bar .content-info-wrapper, +ytmusic-app-layout.pip ytmusic-player-bar .thumbnail-image-wrapper, +ytmusic-app-layout.pip ytmusic-player-bar ytmusic-menu-renderer { + display: none !important; +} + /* disable the video-toggle button when in PiP mode */ ytmusic-app-layout.pip .video-switch-button { display: none !important; diff --git a/youtube-music.css b/youtube-music.css index 9a36c00c..ee48dc3a 100644 --- a/youtube-music.css +++ b/youtube-music.css @@ -39,3 +39,8 @@ img { ytmusic-cast-button { display: none !important; } + +/* Remove useless inaccessible button on top-right corner of the video player */ +.ytp-chrome-top-buttons { + display: none !important; +} From d9f1c589e9caee23d6aaa6065be6d61c49b9095e Mon Sep 17 00:00:00 2001 From: Araxeus <78568641+Araxeus@users.noreply.github.com> Date: Fri, 10 Feb 2023 20:14:07 +0200 Subject: [PATCH 9/9] fix PiP hotkey active in searchbox --- package.json | 2 ++ plugins/picture-in-picture/back.js | 3 --- plugins/picture-in-picture/front.js | 20 +++++++++++++++++--- yarn.lock | 4 +++- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index cb287519..a061891b 100644 --- a/package.json +++ b/package.json @@ -116,6 +116,8 @@ "filenamify": "^4.3.0", "howler": "^2.2.3", "html-to-text": "^9.0.3", + "keyboardevent-from-electron-accelerator": "^2.0.0", + "keyboardevents-areequal": "^0.2.2", "md5": "^2.3.0", "mpris-service": "^2.1.2", "node-fetch": "^2.6.8", diff --git a/plugins/picture-in-picture/back.js b/plugins/picture-in-picture/back.js index d71acd49..a364a2df 100644 --- a/plugins/picture-in-picture/back.js +++ b/plugins/picture-in-picture/back.js @@ -103,9 +103,6 @@ module.exports = (_win, _options) => { ipcMain.on("picture-in-picture", async () => { await togglePiP(); }); - if (options.hotkey) { - electronLocalshortcut.register(win, options.hotkey, togglePiP); - } }; module.exports.setOptions = setLocalOptions; diff --git a/plugins/picture-in-picture/front.js b/plugins/picture-in-picture/front.js index 788a908e..f0752d44 100644 --- a/plugins/picture-in-picture/front.js +++ b/plugins/picture-in-picture/front.js @@ -1,5 +1,8 @@ const { ipcRenderer } = require("electron"); +const { toKeyEvent } = require('keyboardevent-from-electron-accelerator'); +const keyEventAreEqual = require('keyboardevents-areequal'); + const { getSongMenu } = require("../../providers/dom-elements"); const { ElementFromFile, templatePath } = require("../utils"); @@ -74,13 +77,13 @@ const listenForToggle = () => { }); } -function observeMenu(options) { +function observeMenu() { document.addEventListener( "apiLoaded", () => { listenForToggle(); // remove native listeners - cloneButton(".player-minimize-button").onclick = () => { + cloneButton(".player-minimize-button").onclick = () => { global.togglePictureInPicture(); setTimeout(() => $('#player').click()); }; @@ -97,4 +100,15 @@ function observeMenu(options) { ); } -module.exports = observeMenu; +module.exports = (options) => { + observeMenu(); + + if (options.hotkey) { + const hotkeyEvent = toKeyEvent(options.hotkey); + window.addEventListener('keydown', (event) => { + if (keyEventAreEqual(event, hotkeyEvent) && !$('ytmusic-search-box').opened) { + togglePictureInPicture(); + } + }); + } +}; diff --git a/yarn.lock b/yarn.lock index 2d7a6028..7b1ec0a8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5518,7 +5518,7 @@ __metadata: languageName: node linkType: hard -"keyboardevents-areequal@npm:^0.2.1": +"keyboardevents-areequal@npm:^0.2.1, keyboardevents-areequal@npm:^0.2.2": version: 0.2.2 resolution: "keyboardevents-areequal@npm:0.2.2" checksum: 05d846f75170238bbb9ed45d13ca9c6cd3e68ea8ba6b7727971790fa55b44c3386ec8b9c321ae72dae0d0944678d0dc2b922148fe67d3f9720bf30a23999dd65 @@ -8979,6 +8979,8 @@ __metadata: filenamify: ^4.3.0 howler: ^2.2.3 html-to-text: ^9.0.3 + keyboardevent-from-electron-accelerator: ^2.0.0 + keyboardevents-areequal: ^0.2.2 md5: ^2.3.0 mpris-service: ^2.1.2 node-fetch: ^2.6.8