您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Set speed, quality, subtitles and volume as default globally or per channel
当前为
// ==UserScript== // @name YouTube Defaulter // @namespace https://greasyfork.org/ru/users/901750-gooseob // @version 1.12.3 // @description Set speed, quality, subtitles and volume as default globally or per channel // @author GooseOb // @license MIT // @grant window.onurlchange // @match https://www.youtube.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com // ==/UserScript== (function(){// src/config/update.ts var update = (cfg) => { const doUpdate = cfg._v !== 4; if (doUpdate) { switch (cfg._v) { case 2: cfg.flags.standardMusicSpeed = false; cfg._v = 3; case 3: cfg.global.quality = cfg.global.qualityMax; delete cfg.global.qualityMax; for (const key in cfg.channels) { const currCfg = cfg.channels[key]; currCfg.quality = currCfg.qualityMax; delete currCfg.qualityMax; } cfg._v = 4; } } return doUpdate; }; // src/config/value.ts var cfgLocalStorage = localStorage.YTDefaulter; var value = cfgLocalStorage ? JSON.parse(cfgLocalStorage) : { _v: 4, global: {}, channels: {}, flags: { shortsToRegular: false, newTab: false, copySubs: false, standardMusicSpeed: false, enhancedBitrate: false } }; // src/config/save.ts var saveLS = (newCfg) => { saveLSRaw(JSON.stringify(newCfg)); }; var saveLSRaw = (raw) => { localStorage.YTDefaulter = raw; }; var save = (raw) => { const newCfg = JSON.parse(raw); if (typeof newCfg !== "object" || !newCfg._v) { throw new Error("Invalid data"); } if (update(newCfg)) { saveLS(newCfg); } else { saveLSRaw(raw); } Object.assign(value, newCfg); }; // src/config/prune.ts var prune = () => { outer: for (const key in value.channels) { const channelCfg = value.channels[key]; if (channelCfg.subtitles) continue; for (const cfgKey in channelCfg) { if (cfgKey !== "subtitles") continue outer; } delete value.channels[key]; } }; // src/utils/ref.ts var ref = (val) => ({ val }); // src/config/current-channel.ts var username = ref(""); var channel = () => value.channels[username.val] ||= {}; // src/text.ts var translations = { "be-BY": { OPEN_SETTINGS: "Адкрыць дадатковыя налады", SUBTITLES: "Субтытры", SPEED: "Хуткасьць", CUSTOM_SPEED: "Свая Хуткасьць", CUSTOM_SPEED_HINT: 'Калі вызначана, будзе выкарыстоўвацца замест "Хуткасьць"', QUALITY: "Якасьць", VOLUME: "Гучнасьць, %", GLOBAL: "Глябальна", LOCAL: "Гэты Канал", SHORTS: "Адкрываць shorts як звычайныя", NEW_TAB: "Адкрываць відэа ў новай картцы", COPY_SUBS: "Капіяваць субтытры ў поўнаэкранным, Ctrl+C", STANDARD_MUSIC_SPEED: "Звычайная хуткасьць на каналах музыкаў", ENHANCED_BITRATE: "Палепшаны бітрэйт (для карыстальнікаў Premium)", HIDE_SHORTS: "Схаваць shorts на галоўнай", SAVE: "Захаваць", EXPORT: "Экспарт", IMPORT: "Імпарт" } }; var text = { OPEN_SETTINGS: "Open additional settings", SUBTITLES: "Subtitles", SPEED: "Speed", CUSTOM_SPEED: "Custom Speed", CUSTOM_SPEED_HINT: 'If defined, will be used instead of "Speed"', QUALITY: "Quality", VOLUME: "Volume, %", GLOBAL: "Global", LOCAL: "This Channel", SHORTS: "Open shorts as regular videos", NEW_TAB: "Open videos in new tab", COPY_SUBS: "Copy subtitles by Ctrl+C in fullscreen mode", STANDARD_MUSIC_SPEED: "Normal speed on artist channels", ENHANCED_BITRATE: "Quality: Enhanced bitrate (for Premium users)", HIDE_SHORTS: "Hide shorts on the Home page", SAVE: "Save", DEFAULT: "-", EXPORT: "Export", IMPORT: "Import" }; // src/utils/$.ts var $ = (id) => document.getElementById(id); // src/utils/debounce.ts var debounce = (callback, delay) => { let timeout; return (...args) => { clearTimeout(timeout); timeout = window.setTimeout(() => { callback(...args); }, delay); }; }; // src/utils/is-descendant-or-the-same.ts var isDescendantOrTheSame = (child, parents) => { while (child !== null) { if (parents.includes(child)) return true; child = child.parentNode; } return false; }; // src/utils/restore-focus-after.ts var restoreFocusAfter = (cb) => { const el = document.activeElement; cb(); el.focus(); }; // src/utils/until.ts var until = (getItem, check, msToWait = 1e4, msReqTimeout = 20) => new Promise((res, rej) => { const item = getItem(); if (check(item)) return res(item); const reqLimit = msToWait / msReqTimeout; let i = 0; const interval = setInterval(() => { const item2 = getItem(); if (check(item2)) { clearInterval(interval); res(item2); } else if (++i > reqLimit) { clearInterval(interval); rej(new Error(`Timeout: item ${getItem.name} wasn't found`)); } }, msReqTimeout); }); var untilAppear = (getItem, msToWait) => until(getItem, Boolean, msToWait); // src/utils/find-in-node-list.ts var findInNodeList = (list, predicate) => { for (const item of list) { if (predicate(item)) return item; } return null; }; // src/utils/get-el-creator.ts var getElCreator = (tag) => (props) => Object.assign(document.createElement(tag), props); // src/utils/delay.ts var delay = (ms) => new Promise((res) => setTimeout(res, ms)); // src/style.ts var m = "#" + "YTDef-menu"; var d = " div"; var i = " input"; var s = " select"; var bg = "var(--yt-spec-menu-background)"; var underline = "border-bottom: 2px solid var(--yt-spec-text-primary);"; var style = getElCreator("style")({ textContent: ` #${"YTDef-btn"} {position: relative; margin-left: 8px} ${m} { display: flex; visibility: hidden; color: var(--yt-spec-text-primary); font-size: 14px; flex-direction: column; position: fixed; background: ${bg}; border-radius: 2rem; padding: 1rem; text-align: center; box-shadow: 0px 4px 32px 0px var(--yt-spec-static-overlay-background-light); z-index: 2202 } .control-cont > button {margin: .2rem} ${m + d} {display: flex; margin-bottom: 1rem} ${m + d + d} { flex-direction: column; margin: 0 2rem } ${m + d + d + d} { flex-direction: row; margin: 1rem 0 } ${m + s}, ${m + i} { text-align: center; background: ${bg}; border: none; ${underline} color: inherit; width: 5rem; padding: 0; margin-left: auto } ${m} .${"YTDef-setting-hint"} {margin: 0; text-align: end} ${m + i} {outline: none} ${m + d + d + d}:focus-within > label, ${m} .check-cont:focus-within > label {${underline}} ${m} .check-cont {padding: 0 1rem} ${m + s} {appearance: none; outline: none} ${m} label {margin-right: 1.5rem; white-space: nowrap} ${m + i}::-webkit-outer-spin-button, ${m + i}::-webkit-inner-spin-button {-webkit-appearance: none; margin: 0} ${m + i}[type=number] {-moz-appearance: textfield} ${m + s}::-ms-expand {display: none}` }); // src/listeners/click.ts var onClick = (e) => { const { shortsToRegular, newTab } = value.flags; if (shortsToRegular || newTab) { let el = e.target; if (el.tagName !== "A") { el = el.closest("a"); } if (el) { const isShorts = el.href.includes("/shorts/"); if (shortsToRegular && isShorts) { el.href = el.href.replace("shorts/", "watch?v="); } const isNormal = el.href.includes("/watch?v="); if (newTab && (isShorts || isNormal)) { el.target = "_blank"; e.stopPropagation(); } } } }; // src/element-getters.ts var plr = () => $("movie_player"); var aboveTheFold = () => $("above-the-fold"); var actionsBar = () => $("actions")?.querySelector("ytd-menu-renderer"); var getPlrGetter = (plr2) => (selector) => () => plr2.querySelector(selector); var plrGetters = (plr2) => { const get = getPlrGetter(plr2); return { ad: get(".ytp-ad-player-overlay"), video: get(".html5-main-video"), subtitlesBtn: get(".ytp-subtitles-button"), muteBtn: get(".ytp-mute-button"), menu: { element: get(".ytp-settings-menu"), btn: get(".ytp-settings-button") } }; }; var plrMenuItemsGetter = (menu) => () => menu.querySelectorAll('.ytp-menuitem[role="menuitem"]'); var menuSubItems = (item) => item.querySelectorAll(".ytp-menuitem-label"); var channelUsernameElementGetter = (aboveTheFold2) => () => aboveTheFold2.querySelector(".ytd-channel-name > a"); var artistChannelBadge = (aboveTheFold2) => aboveTheFold2.querySelector(".badge-style-type-verified-artist"); var videoPlr = () => document.querySelector(".html5-video-player"); var videoPlrCaptions = (plr2) => plr2.querySelectorAll(".captions-text > span"); var popupContainer = () => document.querySelector("ytd-popup-container"); // src/player/menu.ts var set = (getEl) => { element ||= getEl.menu.element(); btn ||= getEl.menu.btn(); }; var element = null; var btn = null; var clickBtn = () => { btn.click(); }; var isOpen = () => { return element.style.display !== "none"; }; var setOpen = (bool) => { if (bool !== isOpen()) btn.click(); }; var openItem = (item) => { setOpen(true); item.click(); return menuSubItems(element); }; var settingItems = { speed: null, quality: null }; var setSettingItems = (items) => { const findIcon = (d2) => findInNodeList(items, (el) => !!el.querySelector(`path[d="${d2}"]`)); settingItems.speed = findIcon("M10,8v8l6-4L10,8L10,8z M6.3,5L5.7,4.2C7.2,3,9,2.2,11,2l0.1,1C9.3,3.2,7.7,3.9,6.3,5z M5,6.3L4.2,5.7C3,7.2,2.2,9,2,11 l1,.1C3.2,9.3,3.9,7.7,5,6.3z M5,17.7c-1.1-1.4-1.8-3.1-2-4.8L2,13c0.2,2,1,3.8,2.2,5.4L5,17.7z M11.1,21c-1.8-0.2-3.4-0.9-4.8-2 l-0.6,.8C7.2,21,9,21.8,11,22L11.1,21z M22,12c0-5.2-3.9-9.4-9-10l-0.1,1c4.6,.5,8.1,4.3,8.1,9s-3.5,8.5-8.1,9l0.1,1 C18.2,21.5,22,17.2,22,12z"); settingItems.quality = findIcon("M15,17h6v1h-6V17z M11,17H3v1h8v2h1v-2v-1v-2h-1V17z M14,8h1V6V5V3h-1v2H3v1h11V8z M18,5v1h3V5H18z M6,14h1v-2v-1V9H6v2H3v1 h3V14z M10,12h11v-1H10V12z"); }; var findInItem = (name, finder) => { const prevItems = new Set(menuSubItems(element)); return findInNodeList(openItem(settingItems[name]), (item) => !prevItems.has(item) && finder(item)); }; // src/player/plr.ts var setPlr = async (el) => { const getEl = plrGetters(el); await delay(1000); await until(getEl.ad, (ad) => !ad, 200000); video ||= getEl.video(); subtitlesBtn ||= getEl.subtitlesBtn(); muteBtn ||= getEl.muteBtn(); set(getEl); restoreFocusAfter(clickBtn); await delay(50); restoreFocusAfter(clickBtn); setSettingItems(await until(plrMenuItemsGetter(element), (arr) => !!arr.length)); if (!speedNormal) restoreFocusAfter(() => { speedNormal = findInItem("speed", (btn2) => !+btn2.textContent).textContent; }); }; var isSpeed = (value3) => video.playbackRate === value3; var speedNormal = ""; var video = null; var subtitlesBtn = null; var muteBtn = null; // src/logger.ts var err = (...msgs) => { console.error("[YT-Defaulter]", ...msgs); }; var outOfRange = (what) => { err(what, "value is out of range"); }; // src/player/value-setters.ts var comparators = { quality: (target, current) => +target >= parseInt(current) && (value.flags.enhancedBitrate || !current.toLowerCase().includes("premium")), speed: (target, current) => target === current }; var setYT = (settingName) => (value3) => { const isOpen2 = isOpen(); const compare = comparators[settingName]; const btn2 = findInItem(settingName, (btn3) => compare(value3, btn3.textContent)); if (btn2) { btn2.click(); } setOpen(isOpen2); }; var valueSetters = { speed: (value3) => { setYT("speed")(isSpeed(+value3) ? speedNormal : value3); }, customSpeed: (value3) => { try { video.playbackRate = isSpeed(+value3) ? 1 : +value3; } catch { outOfRange("Custom speed"); } }, subtitles: (value3) => { if (subtitlesBtn.ariaPressed !== value3.toString()) subtitlesBtn.click(); }, volume: (value3) => { const num = +value3; const isMuted = muteBtn.dataset.titleNoTooltip !== "Mute"; if (num === 0) { if (!isMuted) muteBtn.click(); } else { if (isMuted) muteBtn.click(); try { video.volume = num / 100; } catch { outOfRange("Volume"); } } }, quality: setYT("quality") }; // src/player/apply-settings.ts var applySettings = (settings) => { if (!Number.isNaN(+settings.customSpeed)) { valueSetters.customSpeed(settings.customSpeed); } delete settings.customSpeed; restoreFocusAfter(() => { for (const setting in settings) { valueSetters[setting](settings[setting]); } setOpen(false); }); }; // src/compute-settings.ts var computeSettings = (doUseNormalSpeed) => { const channel2 = channel(); const settings = { ...value.global, ...channel2 }; if (doUseNormalSpeed) { settings.speed = speedNormal; delete settings.customSpeed; } else if ("customSpeed" in channel2) { delete settings.speed; } else if ("speed" in channel2) { delete settings.customSpeed; } else if ("customSpeed" in settings) { delete settings.speed; } return settings; }; // src/listeners/keyup.ts var onKeyup = (e) => { if (e.code === "Enter") { onClick(e); } else if (e.ctrlKey && !e.shiftKey) { if (value.flags.copySubs && e.code === "KeyC") { const plr3 = videoPlr(); if (plr3?.classList.contains("ytp-fullscreen")) { const text2 = Array.from(videoPlrCaptions(plr3), (line) => line.textContent).join(" "); navigator.clipboard.writeText(text2); } } else if (e.code === "Space") { e.stopPropagation(); e.preventDefault(); const settings = computeSettings(false); if (settings.speed) { restoreFocusAfter(() => { valueSetters.speed(settings.speed); }); } else if (settings.customSpeed) { valueSetters.customSpeed(settings.customSpeed); } } } }; // src/menu/controls.ts var updateValuesIn = (controls, cfgPart) => { controls.speed.value = cfgPart.speed || text.DEFAULT; controls.customSpeed.value = cfgPart.customSpeed || ""; controls.quality.value = cfgPart.quality || text.DEFAULT; controls.volume.value = cfgPart.volume || ""; controls.subtitles.checked = cfgPart.subtitles || false; }; var channelControls = () => ({ speed: null, customSpeed: null, quality: null, volume: null, subtitles: null }); var sections = { global: channelControls(), thisChannel: channelControls() }; var flags = { shortsToRegular: { elem: null, id: "shorts", text: text.SHORTS }, newTab: { elem: null, id: "new-tab", text: text.NEW_TAB }, copySubs: { elem: null, id: "copy-subs", text: text.COPY_SUBS }, standardMusicSpeed: { elem: null, id: "standard-music-speed", text: text.STANDARD_MUSIC_SPEED }, enhancedBitrate: { elem: null, id: "enhanced-bitrate", text: text.ENHANCED_BITRATE }, hideShorts: { elem: null, id: "hide-shorts", text: text.HIDE_SHORTS } }; var updateThisChannel = () => { updateValuesIn(sections.thisChannel, channel()); }; var updateValues = (cfg) => { updateValuesIn(sections.global, cfg.global); updateThisChannel(); for (const key in cfg.flags) { flags[key].elem.checked = cfg.flags[key]; } }; // src/utils/with.ts var withHint = (hint, getItem) => [getItem(hint).item, hint.element]; var withOnClick = (elem, listener) => { elem.addEventListener("click", listener); return elem; }; var withListeners = (elem, listeners) => { for (const key in listeners) { elem.addEventListener(key, listeners[key]); } return elem; }; var controlWith = (withFn) => (obj, ...args) => { withFn(obj.elem, ...args); return obj; }; var withControlListeners = controlWith(withListeners); // src/utils/element-creators.ts var div = getElCreator("div"); var input = getElCreator("input"); var checkbox = (props) => input({ type: "checkbox", ...props }); var option = getElCreator("option"); var _label = getElCreator("label"); var labelEl = (forId, props) => { const elem = _label(props); elem.setAttribute("for", forId); return elem; }; var selectEl = getElCreator("select"); var btnClass = "yt-spec-button-shape-next"; var btnClassFocused = btnClass + "--focused"; var _button = getElCreator("button"); var button = (textContent, props) => withListeners(_button({ textContent, className: `${btnClass} ${btnClass}--tonal ${btnClass}--mono ${btnClass}--size-m`, ...props }), { focus() { this.classList.add(btnClassFocused); }, blur() { this.classList.remove(btnClassFocused); } }); // src/menu/get-controls-creators.ts var getControlCreators = (getCreator) => ({ numericInput: getCreator((props) => input({ type: "number", ...props }), (elem) => ({ get: () => elem.value, set: (value3) => { elem.value = value3; }, default: "" })), checkbox: getCreator(checkbox, (elem) => ({ get: () => elem.checked.toString(), set: (value3) => { elem.checked = value3 === "true"; }, default: text.DEFAULT })), select: getCreator(({ values, getText }) => { const elem = selectEl({ value: text.DEFAULT }); elem.append(option({ value: text.DEFAULT, textContent: text.DEFAULT }), ...values.map((value3) => option({ value: value3, textContent: getText(value3) }))); return elem; }, (elem) => ({ get: () => elem.value, set: (value3) => { elem.value = value3; }, default: "false" })) }); // src/menu/validate-volume.ts var validateVolume = (value3) => { const num = +value3; return num < 0 || num > 100 ? "out of range" : isNaN(num) ? "not a number" : null; }; // src/hint.ts class Hint { constructor(prefix) { this.element = div(); this.element.className ||= "YTDef-setting-hint"; this.prefix = prefix; this.hide(); } hide() { this.element.style.display = "none"; } show(msg) { this.element.style.display = "block"; this.element.textContent = this.prefix + msg; } prefix; element; } // src/menu/close.ts var close = () => { element2.style.visibility = "hidden"; stopListening(); }; var listenForClose = () => { document.addEventListener("click", onClick2); document.addEventListener("keyup", onKeyUp); }; var stopListening = () => { document.removeEventListener("click", onClick2); document.removeEventListener("keyup", onKeyUp); }; var onClick2 = (e) => { const el = e.target; if (!isDescendantOrTheSame(el, [element2, btn2])) close(); }; var onKeyUp = (e) => { if (e.code === "Escape") { close(); btn2.focus(); } }; // src/menu/value.ts var set2 = (el, btnEl) => { element2 = el; btn2 = btnEl; }; var element2 = null; var btn2 = null; var isOpen2 = false; var menuWidth = 0; var adjustWidth = () => { menuWidth = element2.getBoundingClientRect().width; }; var firstFocusable = ref(null); var toggle = debounce(() => { isOpen2 = !isOpen2; if (isOpen2) { fixPosition(); element2.style.visibility = "visible"; listenForClose(); firstFocusable.val.focus(); } else { close(); } }, 100); var fixPosition = () => { const { y, height, width, left } = btn2.getBoundingClientRect(); element2.style.top = y + height + 8 + "px"; element2.style.left = left + width - menuWidth + "px"; }; // src/menu/section.ts var section = (sectionId, title, sectionCfg) => { const control = getControlCreators((createElement, initVal) => (name, label, props) => { const item = div(); const id = "YTDef-" + name + "-" + sectionId; const elem = Object.assign(createElement(props), props, { id, name }); elem.addEventListener("change", () => { const value3 = val.get(); if (value3 === val.default) { delete sectionCfg[name]; } else { sectionCfg[name] = value3; } }); const val = initVal(elem); const cfgValue = sectionCfg[name]; if (cfgValue) { setTimeout(() => { val.set(cfgValue.toString()); }); } item.append(labelEl(id, { textContent: label }), elem); sections[sectionId][name] = elem; return { item, elem }; }); const speedSelect = control.select("speed", text.SPEED, { values: ["2", "1.75", "1.5", "1.25", speedNormal, "0.75", "0.5", "0.25"], getText: (val) => val }); if (sectionId === "global") firstFocusable.val = speedSelect.elem; const sectionElement = div({ role: "group" }); sectionElement.setAttribute("aria-labelledby", sectionId); sectionElement.append(getElCreator("span")({ textContent: title, id: sectionId }), speedSelect.item, ...withHint(new Hint(""), (hint) => withControlListeners(control.numericInput("customSpeed", text.CUSTOM_SPEED), { blur: () => { hint.hide(); }, focus: () => { hint.show(text.CUSTOM_SPEED_HINT); } })), control.select("quality", text.QUALITY, { values: [ "144", "240", "360", "480", "720", "1080", "1440", "2160", "4320" ], getText: (val) => val + "p" }).item, ...withHint(new Hint("Warning: "), (hint) => withControlListeners(control.numericInput("volume", text.VOLUME, { min: "0", max: "100" }), { blur() { const warning = validateVolume(this.value); if (warning) { hint.show(warning); } else { hint.hide(); } } })), control.checkbox("subtitles", text.SUBTITLES, checkbox()).item); return sectionElement; }; // src/menu/settings-icon.ts var settingsIcon = () => { const element3 = document.createElementNS("http://www.w3.org/2000/svg", "svg"); for (const [prop, value3] of [ ["viewBox", "0 0 24 24"], ["width", "24"], ["height", "24"], ["fill", "var(--yt-spec-text-primary)"] ]) { element3.setAttribute(prop, value3); } element3.append($("settings")); return element3; }; // src/menu/init.ts var init = () => { const sections2 = div({ className: "YTDef-" + "sections" }); sections2.append(section("global", text.GLOBAL, value.global), section("thisChannel", text.LOCAL, channel())); const controlStatus = div(); const updateControlStatus = (content) => { controlStatus.textContent = `[${new Date().toLocaleTimeString()}] ${content}`; }; const controlDiv = div({ className: "control-cont" }); controlDiv.append(withOnClick(button(text.SAVE), () => { prune(); saveLS(value); updateControlStatus(text.SAVE); }), withOnClick(button(text.EXPORT), () => { navigator.clipboard.writeText(localStorage.YTDefaulter).then(() => { updateControlStatus(text.EXPORT); }); }), withOnClick(button(text.IMPORT), () => { navigator.clipboard.readText().then((raw) => { save(raw); updateValues(value); return text.IMPORT; }).catch((e) => text.IMPORT + ": " + e.message).then(updateControlStatus); })); set2(div({ id: "YTDef-menu" }), withOnClick(button("", { id: "YTDef-btn", ariaLabel: text.OPEN_SETTINGS, tabIndex: 0 }), toggle)); btn2.setAttribute("aria-controls", "YTDef-menu"); btn2.classList.add(btnClass + "--icon-button"); btn2.append(settingsIcon()); element2.append(sections2, ...Object.entries(flags).map(([flagName, flag]) => { const cont = div({ className: "check-cont" }); const id = "YTDef-" + flag.id; const elem = withOnClick(checkbox({ id, checked: value.flags[flagName] }), function() { value.flags[flagName] = this.checked; }); flag.elem = elem; cont.append(labelEl(id, { textContent: flag.text }), elem); return cont; }), controlDiv, controlStatus); element2.addEventListener("keyup", (e) => { const el = e.target; if (e.code === "Enter" && el.type === "checkbox") el.checked = !el.checked; }); untilAppear(actionsBar).then((actionsBar2) => { actionsBar2.insertBefore(btn2, actionsBar2.lastChild); popupContainer().append(element2); adjustWidth(); sections2.style.maxWidth = sections2.offsetWidth + "px"; }); const listener = () => { if (isOpen2) fixPosition(); }; window.addEventListener("scroll", listener); window.addEventListener("resize", listener); }; // src/listeners/video-page.ts var onVideoPage = async () => { const aboveTheFold2 = await untilAppear(aboveTheFold); username.val = (await untilAppear(channelUsernameElementGetter(aboveTheFold2))).href || ""; untilAppear(plr).then(setPlr).then(() => { const doNotChangeSpeed = value.flags.standardMusicSpeed && !!artistChannelBadge(aboveTheFold2); applySettings(computeSettings(doNotChangeSpeed)); if (!element2) { init(); } }); if (element2) { updateThisChannel(); } }; // src/listeners/page-change.ts var lastUrl; var onPageChange = (url) => { if (lastUrl !== url) { lastUrl = url; if (location.pathname.startsWith("/live") || location.pathname === "/watch") { setTimeout(onVideoPage, 1000); } } }; // src/index.ts Object.assign(text, translations[document.documentElement.lang]); if (update(value)) { saveLS(value); } var updatePage = () => { onPageChange(location.href); }; if (window.onurlchange === null) { window.addEventListener("urlchange", ({ url }) => { onPageChange(url); }); } setInterval(() => { if (window.onurlchange !== null) updatePage(); if (value.flags.hideShorts) findInNodeList(document.querySelectorAll("#title"), (el) => el.textContent === "Shorts")?.closest("ytd-rich-section-renderer")?.remove(); }, 1000); updatePage(); document.addEventListener("click", onClick, { capture: true }); document.addEventListener("keyup", onKeyup, { capture: true }); document.head.append(style); })()