Skip to content

Commit d2265b5

Browse files
committed
Create first version of picture in picture plugin
1 parent 5cffb6f commit d2265b5

File tree

4 files changed

+158
-0
lines changed

4 files changed

+158
-0
lines changed

plugins/picture-in-picture/back.js

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
const path = require("path");
2+
3+
const { app, ipcMain } = require("electron");
4+
5+
const { injectCSS } = require("../utils");
6+
7+
let isInPiPMode = false;
8+
let originalPosition;
9+
let originalSize;
10+
11+
const pipPosition = [10, 10];
12+
const pipSize = [400, 220];
13+
14+
const togglePiP = async (win) => {
15+
isInPiPMode = !isInPiPMode;
16+
17+
if (isInPiPMode) {
18+
injectCSS(win.webContents, path.join(__dirname, "style.css"));
19+
20+
originalPosition = win.getPosition();
21+
originalSize = win.getSize();
22+
23+
win.setFullScreenable(false);
24+
await win.webContents.executeJavaScript(
25+
// Go fullscreen
26+
`document.querySelector(".fullscreen-button").click()`
27+
);
28+
29+
app.dock.hide();
30+
win.setVisibleOnAllWorkspaces(true, {
31+
visibleOnFullScreen: true,
32+
});
33+
app.dock.show();
34+
win.setAlwaysOnTop(true, "screen-saver", 1);
35+
} else {
36+
win.setFullScreenable(true);
37+
await win.webContents.executeJavaScript(
38+
// Exit fullscreen
39+
`document.querySelector(".exit-fullscreen-button").click()`
40+
);
41+
42+
win.setVisibleOnAllWorkspaces(false);
43+
win.setAlwaysOnTop(false);
44+
}
45+
46+
const [x, y] = isInPiPMode ? pipPosition : originalPosition;
47+
const [w, h] = isInPiPMode ? pipSize : originalSize;
48+
win.setPosition(x, y);
49+
win.setSize(w, h);
50+
51+
win.setWindowButtonVisibility(!isInPiPMode);
52+
};
53+
54+
module.exports = (win) => {
55+
ipcMain.on("picture-in-picture", async () => {
56+
await togglePiP(win);
57+
});
58+
};

plugins/picture-in-picture/front.js

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
const { ipcRenderer } = require("electron");
2+
3+
const { getSongMenu } = require("../../providers/dom-elements");
4+
const { ElementFromFile, templatePath } = require("../utils");
5+
6+
let menu = null;
7+
const pipButton = ElementFromFile(
8+
templatePath(__dirname, "picture-in-picture.html")
9+
);
10+
11+
const observer = new MutationObserver(() => {
12+
if (!menu) {
13+
menu = getSongMenu();
14+
if (!menu) return;
15+
}
16+
if (menu.contains(pipButton)) return;
17+
const menuUrl = document.querySelector(
18+
'tp-yt-paper-listbox [tabindex="0"] #navigation-endpoint'
19+
)?.href;
20+
if (menuUrl && !menuUrl.includes("watch?")) return;
21+
22+
menu.prepend(pipButton);
23+
});
24+
25+
global.togglePictureInPicture = () => {
26+
ipcRenderer.send("picture-in-picture");
27+
};
28+
29+
function observeMenu(options) {
30+
document.addEventListener(
31+
"apiLoaded",
32+
() => {
33+
observer.observe(document.querySelector("ytmusic-popup-container"), {
34+
childList: true,
35+
subtree: true,
36+
});
37+
},
38+
{ once: true, passive: true }
39+
);
40+
}
41+
42+
module.exports = observeMenu;

plugins/picture-in-picture/style.css

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/* Make entire window draggable */
2+
body {
3+
-webkit-app-region: drag;
4+
}
5+
button {
6+
-webkit-app-region: no-drag;
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<div
2+
class="style-scope menu-item ytmusic-menu-popup-renderer"
3+
role="option"
4+
tabindex="-1"
5+
aria-disabled="false"
6+
aria-selected="false"
7+
onclick="togglePictureInPicture()"
8+
>
9+
<div
10+
id="navigation-endpoint"
11+
class="yt-simple-endpoint style-scope ytmusic-menu-navigation-item-renderer"
12+
tabindex="-1"
13+
>
14+
<div
15+
class="icon menu-icon style-scope ytmusic-menu-navigation-item-renderer"
16+
>
17+
<svg
18+
version="1.1"
19+
id="Layer_1"
20+
xmlns="http://www.w3.org/2000/svg"
21+
xmlns:xlink="http://www.w3.org/1999/xlink"
22+
x="0px"
23+
y="0px"
24+
viewBox="0 0 512 512"
25+
style="enable-background: new 0 0 512 512"
26+
xml:space="preserve"
27+
>
28+
<style type="text/css">
29+
.st0 {
30+
fill: #aaaaaa;
31+
}
32+
</style>
33+
<g id="XMLID_6_">
34+
<path
35+
id="XMLID_11_"
36+
class="st0"
37+
d="M418.5,139.4H232.4v139.8h186.1V139.4z M464.8,46.7H46.3C20.5,46.7,0,68.1,0,93.1v325.9
38+
c0,25.8,21.4,46.3,46.3,46.3h419.4c25.8,0,46.3-20.5,46.3-46.3V93.1C512,67.2,490.6,46.7,464.8,46.7z M464.8,418.9H46.3V92.2h419.4
39+
v326.8H464.8z"
40+
/>
41+
</g>
42+
</svg>
43+
</div>
44+
<div
45+
class="text style-scope ytmusic-menu-navigation-item-renderer"
46+
id="ytmcustom-pip"
47+
>
48+
Picture in picture
49+
</div>
50+
</div>
51+
</div>

0 commit comments

Comments
 (0)