diff --git a/package.json b/package.json index d8ae823f..8bce1310 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/in-app-menu/front.js b/plugins/in-app-menu/front.js index 68f76311..7c96d3d8 100644 --- a/plugins/in-app-menu/front.js +++ b/plugins/in-app-menu/front.js @@ -44,9 +44,18 @@ 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 => { + $('#nav-bar-background').style.webkitAppRegion = + mutations[0].target.opened ? 'no-drag' : 'drag'; + }); + searchOpenObserver.observe($('ytmusic-search-box'), { attributeFilter: ["opened"] }) +} + function setNavbarMargin() { $('#nav-bar-background').style.right = $('ytmusic-app-layout').playerPageOpen_ ? diff --git a/plugins/in-app-menu/style.css b/plugins/in-app-menu/style.css index cc8554e8..a5de9cf0 100644 --- a/plugins/in-app-menu/style.css +++ b/plugins/in-app-menu/style.css @@ -46,7 +46,7 @@ yt-page-navigation-progress, top: 30px !important; } -/* Custom scrollbar */ +/* custom scrollbar */ ::-webkit-scrollbar { width: 12px; background-color: #030303; @@ -59,7 +59,7 @@ yt-page-navigation-progress, background-color: rgba(15, 15, 15, 0.699); } -/* The scrollbar 'thumb' ...that marque oval shape in a scrollbar */ +/* the scrollbar 'thumb' ...that marque oval shape in a scrollbar */ ::-webkit-scrollbar-thumb:vertical { border: 2px solid rgba(0, 0, 0, 0); @@ -70,7 +70,7 @@ yt-page-navigation-progress, -webkit-border-radius: 100px; } ::-webkit-scrollbar-thumb:vertical:active { - background: #4d4c4c; /* Some darker color when you click it */ + background: #4d4c4c; /* some darker color when you click it */ border-radius: 100px; -moz-border-radius: 100px; -webkit-border-radius: 100px; @@ -80,6 +80,7 @@ yt-page-navigation-progress, background-color: inherit } +/** hideMenu toggler **/ .cet-window-icon { -webkit-app-region: no-drag; } @@ -88,3 +89,16 @@ yt-page-navigation-progress, -webkit-user-drag: none; filter: invert(50%); } + +/** make navbar draggable **/ +#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; +} diff --git a/plugins/picture-in-picture/back.js b/plugins/picture-in-picture/back.js index d71acd49..0bfdfa36 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); @@ -103,9 +92,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..941a4333 100644 --- a/plugins/picture-in-picture/front.js +++ b/plugins/picture-in-picture/front.js @@ -1,10 +1,14 @@ 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"); function $(selector) { return document.querySelector(selector); } +let useNativePiP = false; let menu = null; const pipButton = ElementFromFile( templatePath(__dirname, "picture-in-picture.html") @@ -39,8 +43,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 = () => { @@ -54,9 +74,12 @@ const listenForToggle = () => { const player = $('#player'); const onPlayerDblClick = player.onDoubleClick_; - ipcRenderer.on('pip-toggle', (_, isPip) => { + const titlebar = $(".cet-titlebar"); + + ipcRenderer.on("pip-toggle", (_, isPip) => { if (isPip) { - replaceButton(".exit-fullscreen-button", originalExitButton).onclick = () => togglePictureInPicture(); + replaceButton(".exit-fullscreen-button", originalExitButton).onclick = + () => togglePictureInPicture(); player.onDoubleClick_ = () => {}; expandMenu.onmouseleave = () => middleControls.click(); if (!playerPage.playerPageOpen_) { @@ -64,30 +87,33 @@ 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"; } }); } function observeMenu(options) { + useNativePiP = options.useNativePiP; document.addEventListener( "apiLoaded", () => { listenForToggle(); - // remove native listeners - cloneButton(".player-minimize-button").onclick = () => { - global.togglePictureInPicture(); - setTimeout(() => $('#player').click()); + + cloneButton(".player-minimize-button").onclick = async () => { + await global.togglePictureInPicture(); + 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, @@ -97,4 +123,18 @@ function observeMenu(options) { ); } -module.exports = observeMenu; +module.exports = (options) => { + observeMenu(options); + + if (options.hotkey) { + const hotkeyEvent = toKeyEvent(options.hotkey); + window.addEventListener("keydown", (event) => { + if ( + keyEventAreEqual(event, hotkeyEvent) && + !$("ytmusic-search-box").opened + ) { + togglePictureInPicture(); + } + }); + } +}; 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 }); + }, } ]; 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/yarn.lock b/yarn.lock index f4531d39..d6d9b08f 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 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; +}