🏠 Home 

YouTube Popup Window

Enhances YouTube with a popup window feature.

// ==UserScript==
// @name                YouTube Popup Window
// @name:zh-TW          YouTube Popup Window
// @name:ja             YouTube Popup Window
// @namespace           http://tampermonkey.net/
// @version             0.2.2
// @description         Enhances YouTube with a popup window feature.
// @description:zh-TW   透過彈出視窗功能增強YouTube。
// @description:ja      YouTubeをポップアップウィンドウ機能で強化します。
// @author              CY Fung
// @license             MIT
// @match               https://www.youtube.com/*
// @icon                https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @require             https://cdn.jsdelivr.net/npm/@violentmonkey/[email protected]
// @grant               GM_registerMenuCommand
// @allFrames           true
// ==/UserScript==
(async function () {
'use strict';
const shortcutKey = 'ctrlcmd-alt-keya';
const winName = 'x4tGg';
const styleName = 'rCbM3';
const observablePromise = (proc, timeoutPromise) => {
let promise = null;
return {
obtain() {
if (!promise) {
promise = new Promise(resolve => {
let mo = null;
const f = () => {
let t = proc();
if (t) {
mo.disconnect();
mo.takeRecords();
mo = null;
resolve(t);
}
}
mo = new MutationObserver(f);
mo.observe(document, { subtree: true, childList: true })
f();
timeoutPromise && timeoutPromise.then(() => {
resolve(null)
});
});
}
return promise
}
}
}
function getVideo() {
return document.querySelector('.video-stream.html5-main-video');
}
function registerKeyboard(o) {
const { openPopup } = o;
const { KeyboardService } = VM.shortcut;
const service = new KeyboardService();
service.setContext('activeOnInput', false);
async function updateActiveOnInput() {
const elm = document.activeElement;
service.setContext('activeOnInput', elm instanceof HTMLInputElement || elm instanceof HTMLTextAreaElement);
}
document.addEventListener('focus', (e) => {
updateActiveOnInput();
}, true);
document.addEventListener('blur', (e) => {
updateActiveOnInput();
}, true);
service.register(shortcutKey, openPopup, {
condition: '!activeOnInput',
});
service.enable();
}
if (window.name === winName && window === top) {
if (!document.head) await observablePromise(() => document.head).obtain();
let style = document.createElement('style');
style.id = styleName;
style.textContent = `
*[class][id].style-scope.ytd-watch-flexy {
min-width: unset !important;
min-height: unset !important;
}
`
document.head.appendChild(style);
} else if (window !== top && top.name === winName) {
if (!document.head) await observablePromise(() => document.head).obtain();
let style = document.createElement('style');
style.id = styleName;
style.textContent = `
* {
min-width: unset !important;
min-height: unset !important;
}
`
document.head.appendChild(style);
} else if (window === top) {
function openPopup() {
const currentUrl = window.location.href;
const ytdAppElm = document.querySelector('ytd-app');
if (!ytdAppElm) return;
const rect = ytdAppElm.getBoundingClientRect();
const w = rect.width;
const h = rect.height;
const popupOptions = `toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=${w},height=${h}`;
let video = getVideo();
if (video) {
video.pause();
}
const win = window.open(currentUrl, '', popupOptions);
win.name = winName;
const b = document.querySelector('#x4tGg');
if (b) b.remove();
}
GM_registerMenuCommand('Open Popup Window', function () {
if (document.querySelector('#x4tGg')) return;
const div = document.body.appendChild(document.createElement('div'));
div.id = 'x4tGg';
div.textContent = 'Click to Open Popup'
Object.assign(div.style, {
'position': 'fixed',
'left': '50vw',
'top': '50vh',
'padding': '28px',
'backgroundColor': 'rgb(56, 94, 131)',
'color': '#fff',
'borderRadius': '16px',
'fontSize': '18pt',
'zIndex': '9999',
'transform': 'translate(-50%, -50%)'
})
div.onclick = function () {
openPopup();
}
});
registerKeyboard({ openPopup });
}
// Your code here...
})();