From 768ec7bda73505c307b50d7bb3519d8433eb00fe Mon Sep 17 00:00:00 2001 From: Araxeus <78568641+Araxeus@users.noreply.github.com> Date: Sun, 10 Apr 2022 19:19:20 +0300 Subject: [PATCH] v2 --- index.js | 16 ++++-- plugins/picture-in-picture/back.js | 78 +++++++++++++++++++++-------- plugins/picture-in-picture/front.js | 17 ++++++- plugins/picture-in-picture/menu.js | 20 ++++++++ plugins/quality-changer/front.js | 3 +- 5 files changed, 106 insertions(+), 28 deletions(-) create mode 100644 plugins/picture-in-picture/menu.js diff --git a/index.js b/index.js index 96de5491..0b4566fb 100644 --- a/index.js +++ b/index.js @@ -175,6 +175,8 @@ function createMainWindow() { win.webContents.loadURL(urlToLoad); win.on("closed", onClosed); + const setPiPOptions = (key, value) => config.plugins.setOptions("picture-in-picture", { [key]: value }); + win.on("move", () => { if (win.isMaximized()) return; let position = win.getPosition(); @@ -183,6 +185,8 @@ function createMainWindow() { config.plugins.getOptions("picture-in-picture")["isInPiP"]; if (!isPiPEnabled) { lateSave("window-position", { x: position[0], y: position[1] }); + } else if(config.plugins.getOptions("picture-in-picture")["savePosition"]) { + lateSave("pip-position", position, setPiPOptions); } }); @@ -196,25 +200,29 @@ function createMainWindow() { winWasMaximized = isMaximized; config.set("window-maximized", isMaximized); } + if (isMaximized) return; + const isPiPEnabled = config.plugins.isEnabled("picture-in-picture") && config.plugins.getOptions("picture-in-picture")["isInPiP"]; - if (!isMaximized && !isPiPEnabled) { + if (!isPiPEnabled) { lateSave("window-size", { width: windowSize[0], height: windowSize[1], }); + } else if(config.plugins.getOptions("picture-in-picture")["saveSize"]) { + lateSave("pip-size", windowSize, setPiPOptions); } }); let savedTimeouts = {}; - function lateSave(key, value) { + function lateSave(key, value, fn = config.set) { if (savedTimeouts[key]) clearTimeout(savedTimeouts[key]); savedTimeouts[key] = setTimeout(() => { - config.set(key, value); + fn(key, value); savedTimeouts[key] = undefined; - }, 1000) + }, 600); } win.webContents.on("render-process-gone", (event, webContents, details) => { diff --git a/plugins/picture-in-picture/back.js b/plugins/picture-in-picture/back.js index 7cda241f..c4a0bb40 100644 --- a/plugins/picture-in-picture/back.js +++ b/plugins/picture-in-picture/back.js @@ -5,18 +5,33 @@ const { app, ipcMain } = require("electron"); const { setOptions } = require("../../config/plugins"); const { injectCSS } = require("../utils"); -let isInPiPMode = false; +let isInPiP = false; let originalPosition; let originalSize; +let originalFullScreen; +let originalMaximized; -const pipPosition = [10, 10]; -const pipSize = [450, 275]; +let win; +let options; -const togglePiP = async (win) => { - isInPiPMode = !isInPiPMode; - setOptions("picture-in-picture", { isInPiP: isInPiPMode }); +const pipPosition = () => (options.savePosition && options["pip-position"]) || [10, 10]; +const pipSize = () => (options.saveSize && options["pip-size"]) || [450, 275]; - if (isInPiPMode) { +const setLocalOptions = (_options) => { + options = { ...options, ..._options }; + setOptions("picture-in-picture", _options); +} + +const togglePiP = async () => { + isInPiP = !isInPiP; + setLocalOptions({ isInPiP }); + + if (isInPiP) { + originalFullScreen = win.isFullScreen(); + if (originalFullScreen) win.setFullScreen(false); + originalMaximized = win.isMaximized(); + if (originalMaximized) win.unmaximize(); + originalPosition = win.getPosition(); originalSize = win.getSize(); @@ -26,6 +41,13 @@ const togglePiP = async (win) => { await win.webContents.executeJavaScript( // Go fullscreen ` + var exitButton = document.querySelector(".exit-fullscreen-button"); + exitButton.replaceWith(exitButton.cloneNode(true)); + document.querySelector(".exit-fullscreen-button").onclick = () => togglePictureInPicture(); + + var onPlayerDblClick = document.querySelector('#player').onDoubleClick_ + document.querySelector('#player').onDoubleClick_ = () => {}; + document.querySelector('#expanding-menu').onmouseleave = () => document.querySelector('.middle-controls').click(); if (!document.querySelector("ytmusic-player-page").playerPageOpen_) { document.querySelector(".toggle-player-page-button").click(); } @@ -47,6 +69,9 @@ const togglePiP = async (win) => { await win.webContents.executeJavaScript( // Exit fullscreen ` + document.querySelector('#player').onDoubleClick_ = onPlayerDblClick; + document.querySelector('#expanding-menu').onmouseleave = undefined; + document.querySelector(".exit-fullscreen-button").replaceWith(exitButton); document.querySelector(".exit-fullscreen-button").click(); document.querySelector("ytmusic-player-bar").classList.remove("pip"); ` @@ -54,26 +79,39 @@ const togglePiP = async (win) => { win.setVisibleOnAllWorkspaces(false); win.setAlwaysOnTop(false); + + if (originalFullScreen) win.setFullScreen(true); + if (originalMaximized) win.maximize(); } - const [x, y] = isInPiPMode ? pipPosition : originalPosition; - const [w, h] = isInPiPMode ? pipSize : originalSize; + const [x, y] = isInPiP ? pipPosition() : originalPosition; + const [w, h] = isInPiP ? pipSize() : originalSize; win.setPosition(x, y); win.setSize(w, h); - win.setWindowButtonVisibility?.(!isInPiPMode); -}; - -module.exports = (win) => { - injectCSS(win.webContents, path.join(__dirname, "style.css")); - ipcMain.on("picture-in-picture", async () => { - await togglePiP(win); - }); + win.setWindowButtonVisibility?.(!isInPiP); }; const blockShortcutsInPiP = (event, input) => { - const blockedShortcuts = ["f", "escape"]; - if (blockedShortcuts.includes(input.key.toLowerCase())) { + const key = input.key.toLowerCase(); + + if (key === "f") { event.preventDefault(); - } + } else if (key === 'escape') { + togglePiP(); + event.preventDefault(); + }; }; + +module.exports = (_win, _options) => { + options ??= _options; + win ??= _win; + setLocalOptions({ isInPiP }); + injectCSS(win.webContents, path.join(__dirname, "style.css")); + ipcMain.on("picture-in-picture", async () => { + await togglePiP(); + }); +}; + +module.exports.setOptions = setLocalOptions; + diff --git a/plugins/picture-in-picture/front.js b/plugins/picture-in-picture/front.js index 637c7fb6..ea03cedd 100644 --- a/plugins/picture-in-picture/front.js +++ b/plugins/picture-in-picture/front.js @@ -3,6 +3,8 @@ const { ipcRenderer } = require("electron"); const { getSongMenu } = require("../../providers/dom-elements"); const { ElementFromFile, templatePath } = require("../utils"); +function $(selector) { return document.querySelector(selector); } + let menu = null; const pipButton = ElementFromFile( templatePath(__dirname, "picture-in-picture.html") @@ -14,7 +16,7 @@ const observer = new MutationObserver(() => { if (!menu) return; } if (menu.contains(pipButton)) return; - const menuUrl = document.querySelector( + const menuUrl = $( 'tp-yt-paper-listbox [tabindex="0"] #navigation-endpoint' )?.href; if (menuUrl && !menuUrl.includes("watch?")) return; @@ -30,7 +32,18 @@ function observeMenu(options) { document.addEventListener( "apiLoaded", () => { - observer.observe(document.querySelector("ytmusic-popup-container"), { + const minButton = $(".player-minimize-button"); + // remove native listeners + minButton.replaceWith(minButton.cloneNode(true)); + $(".player-minimize-button").onclick = () => { + 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 + observer.observe($("ytmusic-popup-container"), { childList: true, subtree: true, }); diff --git a/plugins/picture-in-picture/menu.js b/plugins/picture-in-picture/menu.js new file mode 100644 index 00000000..f996a57f --- /dev/null +++ b/plugins/picture-in-picture/menu.js @@ -0,0 +1,20 @@ +const { setOptions } = require("./back.js"); + +module.exports = (_win, options) => [ + { + label: "Save window position", + type: "checkbox", + checked: options.savePosition, + click: (item) => { + setOptions({ savePosition: item.checked }); + }, + }, + { + label: "Save window size", + type: "checkbox", + checked: options.saveSize, + click: (item) => { + setOptions({ saveSize: item.checked }); + }, + } +]; diff --git a/plugins/quality-changer/front.js b/plugins/quality-changer/front.js index 669d39ba..4c553a9f 100644 --- a/plugins/quality-changer/front.js +++ b/plugins/quality-changer/front.js @@ -18,8 +18,7 @@ function setup(event) { $('.top-row-buttons.ytmusic-player').prepend(qualitySettingsButton); qualitySettingsButton.onclick = function chooseQuality() { - if (api.getPlayerState() === 2) api.playVideo(); - else if (api.getPlayerState() === 1) api.pauseVideo(); + setTimeout(() => $('#player').click()); const currentIndex = api.getAvailableQualityLevels().indexOf(api.getPlaybackQuality())