From 19130e32076fae907b0d284252f0b9fa2a5d2e5c Mon Sep 17 00:00:00 2001 From: ergosteur <1992147+ergosteur@users.noreply.github.com> Date: Thu, 2 Oct 2025 11:57:59 -0400 Subject: [PATCH] add current script collection --- apollocafe-image-upgrader.user.js | 33 +++ expand-tco-links.user.js | 135 ++++++++++++ lazyload-link-collector.user.js | 345 ++++++++++++++++++++++++++++++ luxweather-tweaks.user.js | 177 +++++++++++++++ yamaha-avr-webui-unlock.user.js | 49 +++++ youtube-shorts-redirect.user.js | 29 +++ 6 files changed, 768 insertions(+) create mode 100644 apollocafe-image-upgrader.user.js create mode 100644 expand-tco-links.user.js create mode 100644 lazyload-link-collector.user.js create mode 100644 luxweather-tweaks.user.js create mode 100644 yamaha-avr-webui-unlock.user.js create mode 100644 youtube-shorts-redirect.user.js diff --git a/apollocafe-image-upgrader.user.js b/apollocafe-image-upgrader.user.js new file mode 100644 index 0000000..4e13420 --- /dev/null +++ b/apollocafe-image-upgrader.user.js @@ -0,0 +1,33 @@ +// ==UserScript== +// @name Apollo Cafe Image Upgrader +// @namespace https://apollo.cafe/ +// @version 1.0 +// @description Replace all imagedelivery.net URLs ending in /2x with /4x on apollo.cafe +// @match https://apollo.cafe/* +// @match http://apollo.cafe/* +// @icon https://apollo.cafe/favicon.ico +// @grant none +// ==/UserScript== + +(function() { + 'use strict'; + + // Function to replace /2x -> /4x in all tags + function upgradeImages() { + document.querySelectorAll('img[src*="imagedelivery.net"]').forEach(img => { + img.src = img.src.replace(/\/2x$/, '/4x'); + }); + + // Also replace inline HTML / CSS background URLs if needed + document.querySelectorAll('[style*="imagedelivery.net"]').forEach(el => { + el.style.backgroundImage = el.style.backgroundImage.replace(/\/2x(['"]?\)?$)/, '/4x$1'); + }); + } + + // Run once at page load + upgradeImages(); + + // Run again whenever DOM changes (for infinite scroll, SPA, etc.) + const observer = new MutationObserver(() => upgradeImages()); + observer.observe(document.body, { childList: true, subtree: true }); +})(); diff --git a/expand-tco-links.user.js b/expand-tco-links.user.js new file mode 100644 index 0000000..4199450 --- /dev/null +++ b/expand-tco-links.user.js @@ -0,0 +1,135 @@ +// ==UserScript== +// @name Expand t.co links (live replace, Location header fixed) +// @namespace ergosteur +// @version 0.7 +// @description Expand t.co shortlinks into final URLs by parsing Location header +// @match https://twitter.com/* +// @match https://x.com/* +// @grant GM_registerMenuCommand +// @grant GM_xmlhttpRequest +// ==/UserScript== + +(function() { + 'use strict'; + + function showTextareaDialog(title, callback) { + const overlay = document.createElement("div"); + overlay.style.position = "fixed"; + overlay.style.top = 0; + overlay.style.left = 0; + overlay.style.width = "100%"; + overlay.style.height = "100%"; + overlay.style.background = "rgba(0,0,0,0.7)"; + overlay.style.zIndex = 999999; + + const box = document.createElement("div"); + box.style.position = "absolute"; + box.style.top = "50%"; + box.style.left = "50%"; + box.style.transform = "translate(-50%, -50%)"; + box.style.background = "#fff"; + box.style.padding = "20px"; + box.style.borderRadius = "8px"; + box.style.maxWidth = "600px"; + box.style.width = "80%"; + box.style.display = "flex"; + box.style.flexDirection = "column"; + + const label = document.createElement("div"); + label.textContent = title; + label.style.marginBottom = "8px"; + + const textarea = document.createElement("textarea"); + textarea.style.width = "100%"; + textarea.style.height = "300px"; + textarea.style.whiteSpace = "pre"; + + const controls = document.createElement("div"); + controls.style.marginTop = "8px"; + controls.style.display = "flex"; + controls.style.justifyContent = "space-between"; + controls.style.alignItems = "center"; + + const button = document.createElement("button"); + button.textContent = "Expand"; + + const status = document.createElement("div"); + status.textContent = "Ready."; + + controls.appendChild(button); + controls.appendChild(status); + + box.appendChild(label); + box.appendChild(textarea); + box.appendChild(controls); + overlay.appendChild(box); + document.body.appendChild(overlay); + + button.onclick = () => { + const val = textarea.value.trim(); + if (!val) { + overlay.remove(); + return; + } + callback(textarea, status); + }; + } + + function expandOne(link) { + return new Promise((resolve) => { + GM_xmlhttpRequest({ + method: "GET", // GET is safer than HEAD for t.co + url: link, + redirect: "manual", // we want the Location header + onload: (resp) => { + let out = link; + + // responseHeaders is a string in Tampermonkey + const headers = resp.responseHeaders.split(/\r?\n/); + const locLine = headers.find(h => /^location:/i.test(h)); + if (locLine) { + out = locLine.split(/:\s*/i)[1].trim(); + } + + resolve(out); + }, + onerror: () => resolve(link) + }); + }); + } + + async function expandLinks() { + showTextareaDialog("Paste t.co links (one per line):", async (textarea, status) => { + let lines = textarea.value.split(/\r?\n/); + const total = lines.length; + + for (let i = 0; i < total; i++) { + const line = lines[i].trim(); + if (!line) continue; + + status.textContent = `Expanding ${i + 1}/${total}...`; + const full = await expandOne(line); + + lines[i] = full; + textarea.value = lines.join("\n"); + + textarea.scrollTop = textarea.scrollHeight; // auto-scroll + } + + status.textContent = `Done! Expanded ${total} links.`; + + const blob = new Blob([lines.join("\n")], {type: "text/plain"}); + const url = URL.createObjectURL(blob); + + const dl = document.createElement("a"); + dl.href = url; + dl.download = "expanded_links.txt"; + dl.textContent = "⬇ Download results"; + dl.style.marginLeft = "10px"; + + status.appendChild(dl); + }); + } + + GM_registerMenuCommand("Expand t.co Links", expandLinks); +})(); \ No newline at end of file diff --git a/lazyload-link-collector.user.js b/lazyload-link-collector.user.js new file mode 100644 index 0000000..8d660df --- /dev/null +++ b/lazyload-link-collector.user.js @@ -0,0 +1,345 @@ +// ==UserScript== +// @name Extract Links (Universal, Configurable Patterns) +// @namespace ergosteur +// @version 2.9 +// @description Universal lazy-scroll link extractor with config, HUD, stop button, and Tampermonkey menu +// @match *://*/* +// @grant GM_registerMenuCommand +// ==/UserScript== + +(function () { + 'use strict'; + + const found = new Set(); + + // 🔧 Defaults + persisted settings + let hrefPattern = localStorage.hrefPattern || "https://t.co/"; + let textPattern = localStorage.textPattern || "drive.google.com"; + let useHrefPattern = localStorage.useHrefPattern !== "false"; // default true + let useTextPattern = localStorage.useTextPattern !== "false"; // default true + let maxScrolls = parseInt(localStorage.maxScrolls || "0", 10); // 0 = unlimited + let autoShowButton = localStorage.autoShowButton === "true"; // default false + + // Scrolling behavior + const STEP_FRACTION = 0.9; + const SCROLL_DELAY_MS = 700; + const SETTLE_DELAY_MS = 800; + const STALL_LIMIT = 8; + const HARD_CAP = 2000; + + // Progress HUD + let progressEl = null; + let stopFlag = false; + + function showProgress() { + if (!progressEl) { + progressEl = document.createElement("div"); + Object.assign(progressEl.style, { + position: "fixed", + top: "20px", + left: "20px", + zIndex: "1000000", + background: "rgba(0,0,0,0.7)", + color: "white", + padding: "6px 10px", + borderRadius: "4px", + fontSize: "13px", + fontFamily: "monospace", + display: "flex", + alignItems: "center", + gap: "8px" + }); + + const label = document.createElement("span"); + label.id = "progress-label"; + progressEl.appendChild(label); + + const stopBtn = document.createElement("button"); + stopBtn.innerText = "⏹ Stop"; + Object.assign(stopBtn.style, { + background: "#d9534f", + color: "white", + border: "none", + padding: "2px 6px", + borderRadius: "3px", + cursor: "pointer", + fontSize: "12px" + }); + stopBtn.onclick = () => { stopFlag = true; }; + progressEl.appendChild(stopBtn); + + document.body.appendChild(progressEl); + } + } + + function updateProgress(rounds) { + const spinner = ["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"][rounds % 10]; + const label = document.getElementById("progress-label"); + if (label) { + label.textContent = `${spinner} Rounds: ${rounds} | Links: ${found.size}`; + } + } + + function hideProgress() { + if (progressEl) { progressEl.remove(); progressEl = null; } + } + + function extractLinks() { + document.querySelectorAll("a").forEach(a => { + const href = a.href || ""; + const text = a.textContent || ""; + const hrefOk = !useHrefPattern || (hrefPattern && href.includes(hrefPattern)); + const textOk = !useTextPattern || (textPattern && text.includes(textPattern)); + if (hrefOk && textOk && href) { + if (!found.has(href)) { + found.add(href); + } + } + }); + } + + async function wait(ms) { return new Promise(r => setTimeout(r, ms)); } + + async function scrollToTopAndSettle() { + const html = document.documentElement; + const prev = html.style.scrollBehavior; + html.style.scrollBehavior = "auto"; + window.scrollTo(0, 0); + html.style.scrollBehavior = prev || ""; + const t0 = performance.now(); + while (window.scrollY !== 0 && performance.now() - t0 < 1500) { + await wait(50); + } + await wait(SETTLE_DELAY_MS); + } + + async function autoScrollAndExtract() { + found.clear(); + stopFlag = false; + + await scrollToTopAndSettle(); + showProgress(); + + const scroller = document.scrollingElement || document.documentElement; + let lastHeight = scroller.scrollHeight; + let lastFound = 0; + let rounds = 0; + let stall = 0; + + while (!stopFlag && rounds < HARD_CAP) { + rounds++; + const step = Math.max(64, Math.floor(window.innerHeight * STEP_FRACTION)); + window.scrollBy(0, step); + await wait(SCROLL_DELAY_MS); + + extractLinks(); + updateProgress(rounds); + + const newHeight = scroller.scrollHeight; + const atBottom = (scroller.scrollTop + window.innerHeight + 2) >= newHeight; + const heightGrew = newHeight > lastHeight + 2; + const foundGrew = found.size > lastFound; + + if (heightGrew || foundGrew || !atBottom) stall = 0; + else stall++; + + lastHeight = newHeight; + lastFound = found.size; + + if ((maxScrolls > 0 && rounds >= maxScrolls) || (atBottom && stall >= STALL_LIMIT)) { + break; + } + } + + hideProgress(); + showOverlay([...found], false); + } + + function showOverlay(links, configOnly = false) { + const old = document.getElementById("extract-box"); + if (old) old.remove(); + + const container = document.createElement("div"); + container.id = "extract-box"; + Object.assign(container.style, { + position: "fixed", + top: "60px", + right: "20px", + width: "480px", + zIndex: "999999", + background: "white", + border: "2px solid black", + padding: "10px", + fontSize: "12px" + }); + + // Href config + const hrefRow = document.createElement("div"); + const hrefChk = document.createElement("input"); + hrefChk.type = "checkbox"; + hrefChk.checked = useHrefPattern; + hrefChk.onchange = () => { + useHrefPattern = hrefChk.checked; + localStorage.useHrefPattern = useHrefPattern; + }; + const hrefLbl = document.createElement("label"); + hrefLbl.innerText = " Href pattern:"; + const hrefInp = document.createElement("input"); + hrefInp.type = "text"; + hrefInp.value = hrefPattern; + Object.assign(hrefInp.style, { width: "70%", marginLeft: "6px" }); + hrefInp.onchange = () => { + hrefPattern = hrefInp.value.trim(); + localStorage.hrefPattern = hrefPattern; + }; + hrefRow.append(hrefChk, hrefLbl, hrefInp); + + // Text config + const textRow = document.createElement("div"); + const textChk = document.createElement("input"); + textChk.type = "checkbox"; + textChk.checked = useTextPattern; + textChk.onchange = () => { + useTextPattern = textChk.checked; + localStorage.useTextPattern = useTextPattern; + }; + const textLbl = document.createElement("label"); + textLbl.innerText = " Text pattern:"; + const textInp = document.createElement("input"); + textInp.type = "text"; + textInp.value = textPattern; + Object.assign(textInp.style, { width: "70%", marginLeft: "6px" }); + textInp.onchange = () => { + textPattern = textInp.value.trim(); + localStorage.textPattern = textPattern; + }; + textRow.append(textChk, textLbl, textInp); + + // Max scroll config + const maxRow = document.createElement("div"); + const maxLbl = document.createElement("label"); + maxLbl.innerText = " Max scrolls (0 = unlimited):"; + const maxInp = document.createElement("input"); + maxInp.type = "number"; + maxInp.min = "0"; + maxInp.value = maxScrolls; + Object.assign(maxInp.style, { width: "60px", marginLeft: "6px" }); + maxInp.onchange = () => { + maxScrolls = parseInt(maxInp.value, 10) || 0; + localStorage.maxScrolls = maxScrolls; + }; + maxRow.append(maxLbl, maxInp); + + // Auto show button config + const autoRow = document.createElement("div"); + const autoChk = document.createElement("input"); + autoChk.type = "checkbox"; + autoChk.checked = autoShowButton; + autoChk.onchange = () => { + autoShowButton = autoChk.checked; + localStorage.autoShowButton = autoShowButton; + }; + const autoLbl = document.createElement("label"); + autoLbl.innerText = " Show floating button automatically"; + autoRow.append(autoChk, autoLbl); + + container.append(hrefRow, textRow, maxRow, autoRow); + + if (!useHrefPattern && !useTextPattern) { + const warn = document.createElement("div"); + warn.textContent = "⚠ Warning: Both filters are off. All links will be collected."; + Object.assign(warn.style, { color: "red", margin: "6px 0" }); + container.appendChild(warn); + } + + if (!configOnly) { + const box = document.createElement("textarea"); + box.value = links.join("\n"); + Object.assign(box.style, { width: "100%", height: "200px", margin: "8px 0" }); + container.appendChild(box); + + const dl = document.createElement("button"); + dl.innerText = "⬇ Download .txt"; + Object.assign(dl.style, { + background: "#1da1f2", color: "white", border: "none", + padding: "6px 10px", borderRadius: "4px", cursor: "pointer", marginRight: "8px" + }); + dl.onclick = () => { + const blob = new Blob([links.join("\n")], { type: "text/plain" }); + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; a.download = "extracted_links.txt"; + document.body.appendChild(a); a.click(); a.remove(); + URL.revokeObjectURL(url); + }; + container.appendChild(dl); + } + + // Start + Close + const start = document.createElement("button"); + start.innerText = "▶ Start"; + Object.assign(start.style, { + background: "#1da1f2", color: "white", border: "none", + padding: "6px 10px", borderRadius: "4px", cursor: "pointer", marginRight: "8px" + }); + start.onclick = () => { container.remove(); autoScrollAndExtract(); }; + + const close = document.createElement("button"); + close.innerText = "❌ Close"; + Object.assign(close.style, { + background: "#aaa", color: "white", border: "none", + padding: "6px 10px", borderRadius: "4px", cursor: "pointer" + }); + close.onclick = () => container.remove(); + + container.append(start, close); + document.body.appendChild(container); + + if (!configOnly) { + alert(`✅ Extracted ${links.length} links (href: ${useHrefPattern ? hrefPattern : "ANY"}, text: ${useTextPattern ? textPattern : "ANY"}).`); + } + } + + function addSplitButton() { + if (document.getElementById("extract-btn")) return; + + const wrap = document.createElement("div"); + wrap.id = "extract-btn"; + Object.assign(wrap.style, { + position: "fixed", top: "20px", right: "20px", zIndex: "999999", + display: "flex", borderRadius: "4px", overflow: "hidden", + boxShadow: "0 2px 4px rgba(0,0,0,0.2)" + }); + + const mainBtn = document.createElement("button"); + mainBtn.innerText = "Extract Links"; + Object.assign(mainBtn.style, { + background: "#1da1f2", color: "white", border: "none", + padding: "8px 12px", cursor: "pointer", fontSize: "14px", flex: "1" + }); + mainBtn.onclick = autoScrollAndExtract; + + const cfgBtn = document.createElement("button"); + cfgBtn.innerText = "⛭"; + Object.assign(cfgBtn.style, { + background: "#0d8ddb", color: "white", border: "none", + padding: "8px 10px", cursor: "pointer", fontSize: "14px", width: "40px" + }); + cfgBtn.onclick = () => showOverlay([], true); + + wrap.append(mainBtn, cfgBtn); + document.body.appendChild(wrap); + } + + // Tampermonkey menu items + if (typeof GM_registerMenuCommand !== "undefined") { + GM_registerMenuCommand("Show Button", addSplitButton); + GM_registerMenuCommand("Extract Links", autoScrollAndExtract); + GM_registerMenuCommand("Config", () => showOverlay([], true)); + } + + // Auto-show only if enabled + if (autoShowButton) { + setInterval(addSplitButton, 2000); + } +})(); \ No newline at end of file diff --git a/luxweather-tweaks.user.js b/luxweather-tweaks.user.js new file mode 100644 index 0000000..1a14005 --- /dev/null +++ b/luxweather-tweaks.user.js @@ -0,0 +1,177 @@ +// ==UserScript== +// @name LuxWeather Frame & Scale Toggle (Settings Integration) +// @namespace http://tampermonkey.net/ +// @version 1.8 +// @description Toggle CRT frame and scaling (Off, Default, 4:3, 16:9, Stretch) via settings panel with localStorage + keyboard shortcuts +// @match https://luxweather.com/* +// @run-at document-idle +// ==/UserScript== + +(function () { + const LS_KEY_FRAME = 'luxweather-frame-on'; + const LS_KEY_SCALE = 'luxweather-scale-mode'; + + let frameOn = localStorage.getItem(LS_KEY_FRAME) !== 'false'; + let scaleMode = parseInt(localStorage.getItem(LS_KEY_SCALE) || '0'); + + const style = document.createElement('style'); + style.innerHTML = ` + .no-frame .tv--kitty::after, + .no-frame .tv--regular::after, + .no-frame .tv--apple::after { + background-image: none !important; + } + + .scale-default .tv { + --width: 360; + --height: 270; + } + .scale-default .tv--kitty .tv-screen, + .scale-default .tv--regular .tv-screen, + .scale-default .tv--apple .tv-screen { + top: 50% !important; + left: 50% !important; + transform: translate(-50%, -50%) !important; + width: calc((360 / var(--width)) * 100%); + height: calc((270 / var(--height)) * 100%); + } + + .scale-fit .tv, + .scale-stretch .tv { + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 100vw !important; + height: 100vh !important; + margin: 0 !important; + padding: 0 !important; + background: none !important; + } + + .scale-fit .tv-screen, + .scale-stretch .tv-screen { + position: relative !important; + background: none !important; + top: unset !important; + left: unset !important; + transform: none !important; + } + + .scale-fit .tv-screen { + width: 100vw; + height: auto; + } + + .scale-4-3 .tv-screen { + aspect-ratio: 4 / 3; + max-height: 100vh; + max-width: calc(100vh * (4 / 3)); + } + + .scale-16-9 .tv-screen { + aspect-ratio: 16 / 9; + max-height: 100vh; + max-width: calc(100vh * (16 / 9)); + } + + .scale-stretch .tv-screen { + width: 100vw !important; + height: 100vh !important; + object-fit: fill !important; + } + `; + document.head.appendChild(style); + + function applyState() { + document.body.classList.toggle('no-frame', !frameOn); + + document.body.classList.remove( + 'scale-default', + 'scale-fit', + 'scale-4-3', + 'scale-16-9', + 'scale-stretch' + ); + + switch (scaleMode) { + case 1: + document.body.classList.add('scale-default'); break; + case 2: + document.body.classList.add('scale-fit', 'scale-4-3'); break; + case 3: + document.body.classList.add('scale-fit', 'scale-16-9'); break; + case 4: + document.body.classList.add('scale-stretch'); break; + } + + localStorage.setItem(LS_KEY_FRAME, frameOn); + localStorage.setItem(LS_KEY_SCALE, scaleMode); + } + + function injectSettingsToggles() { + const settings = document.getElementById('settings_menu'); + if (!settings || settings.querySelector('#toggle_frame')) return; + + const group = document.createElement('div'); + group.className = 'settings_group'; + group.innerHTML = ` +
Custom Display
+
+ +
+ +
+ `; + settings.appendChild(group); + + const frameCheckbox = document.getElementById('toggle_frame'); + const scaleSelect = document.getElementById('toggle_scale'); + + frameCheckbox.checked = frameOn; + scaleSelect.value = scaleMode; + + frameCheckbox.addEventListener('change', () => { + frameOn = frameCheckbox.checked; + applyState(); + }); + + scaleSelect.addEventListener('change', () => { + scaleMode = parseInt(scaleSelect.value); + applyState(); + }); + } + + // Keyboard shortcuts + window.addEventListener('keydown', (e) => { + if (e.altKey && e.key === 'f') { + frameOn = !frameOn; + applyState(); + } else if (e.altKey && e.key === 's') { + scaleMode = (scaleMode + 1) % 5; + applyState(); + } + }); + + applyState(); + + const observeSettings = new MutationObserver(() => { + setTimeout(injectSettingsToggles, 50); +}); + + const interval = setInterval(() => { + const settings = document.getElementById('settings_menu'); + if (settings) { + clearInterval(interval); + injectSettingsToggles(); + observeSettings.observe(document.body, { childList: true, subtree: true }); + } + }, 300); +})(); diff --git a/yamaha-avr-webui-unlock.user.js b/yamaha-avr-webui-unlock.user.js new file mode 100644 index 0000000..eb36c93 --- /dev/null +++ b/yamaha-avr-webui-unlock.user.js @@ -0,0 +1,49 @@ +// ==UserScript== +// @name Yamaha AVR Full UI Unlock +// @namespace http://tampermonkey.net/ +// @version 1.4 +// @description Unlocks the full web UI for the Yamaha RX-V573 by spoofing the model name to a high-end model. +// @match http://rx-v573.local/* +// @grant none +// @run-at document-start +// ==/UserScript== + +(function() { + 'use strict'; + + // Intercept the setter for the g_Info object to modify it as soon as it's created. + Object.defineProperty(window, 'g_Info', { + get: function() { + return window._g_Info_Original; + }, + set: function(value) { + console.log('Tampermonkey: Intercepted g_Info setter. Original modelName is:', value.modelName); + + // Set the modelName to a high-end model for any basic checks. + //value.modelName = 'RX-V3073'; + + // Override ALL model-checking functions to always return true. + // This is the most reliable way to unlock everything. + value.blnModelTypeHigh = function() { return false; }; + value.blnModelType3073 = function() { return false; }; + value.blnModelType820 = function() { return false; }; + value.blnModelType673 = function() { return false; }; + value.blnModelTypeUnder573 = function() { return true; }; + + // This is the function you found that works. Override it for good measure. + value.blnOnlyFriendlyNameAvail = function() { return false; }; + + // Also override the HDMI and Zone checks to ensure the UI displays those controls. + //value.m_blnHasHdmi = true; + //value.m_blnZone2 = true; + //value.m_blnZone3 = true; + //value.m_blnZone4 = true; + + //console.log('Tampermonkey: All model type checks have been spoofed to return true.'); + + // Store the modified object for the rest of the script to use. + window._g_Info_Original = value; + }, + configurable: true + }); +})(); \ No newline at end of file diff --git a/youtube-shorts-redirect.user.js b/youtube-shorts-redirect.user.js new file mode 100644 index 0000000..edbac14 --- /dev/null +++ b/youtube-shorts-redirect.user.js @@ -0,0 +1,29 @@ +// ==UserScript== +// @name YouTube Shorts Redirect +// @namespace http://tampermonkey.net/ +// @version 0.1 +// @description Redirects YouTube Shorts links to the standard watch page. +// @author You +// @match https://www.youtube.com/shorts/* +// @grant none +// @run-at document-start +// ==/UserScript== + +(function() { + 'use strict'; + + // Get the current URL + const currentUrl = window.location.href; + + // Check if the URL matches the Shorts pattern (e.g., https://www.youtube.com/shorts/v1de0id) + if (currentUrl.includes('youtube.com/shorts/')) { + // Extract the video ID, which is the part after the last '/' + const videoId = currentUrl.substring(currentUrl.lastIndexOf('/') + 1); + + // Construct the new URL in the standard watch format + const newUrl = 'https://www.youtube.com/watch?v=' + videoId; + + // Redirect the browser to the new URL + window.location.replace(newUrl); + } +})(); \ No newline at end of file