您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Set speed, quality, subtitles and volume as default globally or specialize for each channel
当前为
- // ==UserScript==
- // @name YouTube Defaulter
- // @namespace https://greasyfork.org/ru/users/901750-gooseob
- // @version 1.10.2
- // @description Set speed, quality, subtitles and volume as default globally or specialize for each channel
- // @author GooseOb
- // @license MIT
- // @match https://www.youtube.com/*
- // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
- // ==/UserScript==
- (function(){// index.ts
- function debounce(callback, delay) {
- let timeout;
- return function(...args) {
- clearTimeout(timeout);
- timeout = window.setTimeout(() => {
- callback.apply(this, args);
- }, delay);
- };
- }
- 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)",
- 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 a usual video",
- NEW_TAB: "Open videos in a 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)",
- SAVE: "Save",
- DEFAULT: "-",
- EXPORT: "Export",
- IMPORT: "Import",
- ...translations[document.documentElement.lang]
- };
- var cfgLocalStorage = localStorage["YTDefaulter"];
- var cfg = cfgLocalStorage ? JSON.parse(cfgLocalStorage) : {
- _v: 4,
- global: {},
- channels: {},
- flags: {
- shortsToUsual: false,
- newTab: false,
- copySubs: false,
- standardMusicSpeed: false,
- enhancedBitrate: false
- }
- };
- var isDescendantOrTheSame = (child, parents) => {
- while (child !== null) {
- if (parents.includes(child))
- return true;
- child = child.parentNode;
- }
- return false;
- };
- var saveCfg = () => {
- const cfgCopy = { ...cfg };
- const channelsCfgCopy = { ...cfg.channels };
- outer:
- for (const key in channelsCfgCopy) {
- const channelCfg = channelsCfgCopy[key];
- if (channelCfg.subtitles)
- continue;
- for (const cfgKey in channelCfg)
- if (cfgKey !== "subtitles")
- continue outer;
- delete channelsCfgCopy[key];
- }
- cfgCopy.channels = channelsCfgCopy;
- localStorage["YTDefaulter"] = JSON.stringify(cfgCopy);
- };
- 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 menuControls = {
- global: {
- ["speed"]: null,
- ["customSpeed"]: null,
- ["quality"]: null,
- ["volume"]: null,
- ["subtitles"]: null
- },
- thisChannel: {
- ["speed"]: null,
- ["customSpeed"]: null,
- ["quality"]: null,
- ["volume"]: null,
- ["subtitles"]: null
- },
- flags: {
- shortsToUsual: null,
- newTab: null,
- copySubs: null,
- standardMusicSpeed: null,
- enhancedBitrate: null
- },
- updateThisChannel() {
- updateValuesIn(this.thisChannel, channelConfig.current);
- },
- updateValues() {
- console.log(cfg.global, channelConfig.current, cfg.flags);
- console.log(this);
- updateValuesIn(this.global, cfg.global);
- this.updateThisChannel();
- for (const key in cfg.flags) {
- this.flags[key].checked = cfg.flags[key];
- }
- }
- };
- var updateCfg = () => {
- 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;
- }
- saveCfg();
- }
- return doUpdate;
- };
- updateCfg();
- var restoreFocusAfter = (cb) => {
- const el = document.activeElement;
- cb();
- el.focus();
- };
- var until = (getItem, check, msToWait = 1e4, msReqTimeout = 20) => new Promise((res, rej) => {
- const reqLimit = msToWait / msReqTimeout;
- let i = 0;
- const interval = setInterval(() => {
- if (i++ > reqLimit)
- exit(rej);
- const item = getItem();
- if (!check(item))
- return;
- exit(() => res(item));
- }, msReqTimeout);
- const exit = (cb) => {
- clearInterval(interval);
- cb();
- };
- });
- var untilAppear = (getItem, msToWait) => until(getItem, Boolean, msToWait);
- var ytSettingItems = {};
- var channelConfig = { current: null };
- var video;
- var subtitlesBtn;
- var muteBtn;
- var SPEED_NORMAL;
- var isSpeedChanged = false;
- var menu = {
- element: null,
- btn: null,
- isOpen: false,
- width: 0,
- _closeListener: {
- onClick(e) {
- const el = e.target;
- if (isDescendantOrTheSame(el, [menu.element, menu.btn]))
- return;
- menu.toggle();
- },
- onKeyUp(e) {
- if (e.code !== "Escape")
- return;
- menu._setOpen(false);
- menu.btn.focus();
- },
- add() {
- document.addEventListener("click", this.onClick);
- document.addEventListener("keyup", this.onKeyUp);
- },
- remove() {
- document.removeEventListener("click", this.onClick);
- document.removeEventListener("keyup", this.onKeyUp);
- }
- },
- firstElement: null,
- _setOpen(bool) {
- if (bool) {
- this.fixPosition();
- this.element.style.visibility = "visible";
- this._closeListener.add();
- this.firstElement.focus();
- } else {
- this.element.style.visibility = "hidden";
- this._closeListener.remove();
- }
- this.isOpen = bool;
- },
- toggle: debounce(function() {
- this._setOpen(!this.isOpen);
- }, 100),
- fixPosition() {
- const { y, height, width, left } = this.btn.getBoundingClientRect();
- this.element.style.top = y + height + 8 + "px";
- this.element.style.left = left + width - this.width + "px";
- }
- };
- var $ = (id) => document.getElementById(id);
- var getChannelUsername = (aboveTheFold) => /(?<=@|\/c\/).+?$/.exec(aboveTheFold.querySelector(".ytd-channel-name > a").href)?.[0];
- var getPlr = () => $("movie_player");
- var getAboveTheFold = () => $("above-the-fold");
- var getActionsBar = () => $("actions")?.querySelector("ytd-menu-renderer");
- var iconD = {
- ["quality"]: "M15,17h6v1h-6V17z M11,17H3v1h8v2h1v-2v-1v-2h-1V17z M14,8h1V6V5V3h-1v2H3v1h11V8z M18,5v1h3V5H18z M6,14h1v-2v-1V9H6v2H3v1 h3V14z M10,12h11v-1H10V12z",
- ["speed"]: "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"
- };
- var getYtElementFinder = (elems) => (name) => findInNodeList(elems, (el) => !!el.querySelector(`path[d="${iconD[name]}"]`));
- var untilChannelUsernameAppear = (aboveTheFold) => untilAppear(() => getChannelUsername(aboveTheFold)).catch(() => "");
- var isMusicChannel = (aboveTheFold) => !!aboveTheFold.querySelector(".badge-style-type-verified-artist");
- var findInNodeList = (list, callback) => {
- for (const item of list)
- if (callback(item))
- return item;
- };
- var ytMenu = {
- async updatePlayer(plr) {
- this.element = plr.querySelector(".ytp-settings-menu");
- this._btn = plr.querySelector(".ytp-settings-button");
- const clickBtn = this._btn.click.bind(this._btn);
- restoreFocusAfter(clickBtn);
- await delay(50);
- restoreFocusAfter(clickBtn);
- },
- element: null,
- _btn: null,
- isOpen() {
- return this.element.style.display !== "none";
- },
- setOpen(bool) {
- if (bool !== this.isOpen())
- this._btn.click();
- },
- openItem(item) {
- this.setOpen(true);
- item.click();
- return this.element.querySelectorAll(".ytp-panel-animate-forward .ytp-menuitem-label");
- },
- findInItem(item, callback) {
- return findInNodeList(this.openItem(item), callback);
- }
- };
- var validateVolume = (value) => {
- const num = +value;
- return num < 0 || num > 100 ? "out of range" : isNaN(num) ? "not a number" : false;
- };
- var getElCreator = (tag) => (props) => Object.assign(document.createElement(tag), props);
- var comparators = {
- ["quality"]: (target, current) => +target >= parseInt(current) && (cfg.flags.enhancedBitrate || !current.toLowerCase().includes("premium")),
- ["speed"]: (target, current) => target === current
- };
- var logger = {
- prefix: "[YT-Defaulter]",
- err(...msgs) {
- console.error(this.prefix, ...msgs);
- },
- outOfRange(what) {
- this.err(what, "value is out of range");
- }
- };
- var valueSetters = {
- _ytSettingItem(value, settingName) {
- const isOpen = ytMenu.isOpen();
- const compare = comparators[settingName];
- ytMenu.findInItem(ytSettingItems[settingName], (btn) => compare(value, btn.textContent))?.click();
- ytMenu.setOpen(isOpen);
- },
- speed(value) {
- this._ytSettingItem(isSpeedChanged ? SPEED_NORMAL : value, "speed");
- isSpeedChanged = !isSpeedChanged;
- },
- customSpeed(value) {
- try {
- video.playbackRate = isSpeedChanged ? 1 : +value;
- } catch {
- logger.outOfRange("Custom speed");
- return;
- }
- isSpeedChanged = !isSpeedChanged;
- },
- subtitles(value) {
- if (subtitlesBtn.ariaPressed !== value.toString())
- subtitlesBtn.click();
- },
- volume(value) {
- const num = +value;
- muteBtn ||= document.querySelector(".ytp-mute-button");
- const isMuted = muteBtn.dataset.titleNoTooltip !== "Mute";
- if (num === 0) {
- if (!isMuted)
- muteBtn.click();
- return;
- }
- if (isMuted)
- muteBtn.click();
- try {
- video.volume = num / 100;
- } catch {
- logger.outOfRange("Volume");
- }
- },
- quality(value) {
- this._ytSettingItem(value, "quality");
- }
- };
- 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 = (text2, props) => _button({
- textContent: text2,
- className: `${btnClass} ${btnClass}--tonal ${btnClass}--mono ${btnClass}--size-m`,
- onfocus() {
- this.classList.add(btnClassFocused);
- },
- onblur() {
- this.classList.remove(btnClassFocused);
- },
- ...props
- });
- class Hint {
- constructor(prefix, props) {
- this.element = div(props);
- this.element.className ||= "YTDef-setting-hint";
- this.prefix = prefix;
- this.hide();
- }
- hide() {
- this.element.style.display = "none";
- }
- show(msg) {
- this.element.style.display = "block";
- if (msg)
- this.element.textContent = this.prefix + msg;
- }
- prefix;
- element;
- }
- var delay = (ms) => new Promise((res) => setTimeout(res, ms));
- var onPageChange = async () => {
- if (location.pathname !== "/watch")
- return;
- const aboveTheFold = await untilAppear(getAboveTheFold);
- const channelUsername = await untilChannelUsernameAppear(aboveTheFold);
- channelConfig.current = cfg.channels[channelUsername] ||= {};
- const plr = await untilAppear(getPlr);
- await delay(1000);
- const getAd = () => plr.querySelector(".ytp-ad-player-overlay");
- if (getAd())
- await until(getAd, (ad) => !ad, 200000);
- await ytMenu.updatePlayer(plr);
- const getMenuItems = () => ytMenu.element.querySelectorAll('.ytp-menuitem[role="menuitem"]');
- const getYtElement = getYtElementFinder(await until(getMenuItems, (arr) => !!arr.length));
- Object.assign(ytSettingItems, {
- quality: getYtElement("quality"),
- speed: getYtElement("speed")
- });
- if (!SPEED_NORMAL)
- restoreFocusAfter(() => {
- const btn = ytMenu.findInItem(ytSettingItems.speed, (btn2) => !+btn2.textContent);
- if (btn)
- SPEED_NORMAL = btn.textContent;
- });
- const doNotChangeSpeed = cfg.flags.standardMusicSpeed && isMusicChannel(aboveTheFold);
- const settings = {
- ...cfg.global,
- ...channelConfig.current
- };
- const isChannelSpeed = "speed" in channelConfig.current;
- const isChannelCustomSpeed = "customSpeed" in channelConfig.current;
- if (doNotChangeSpeed && !isChannelCustomSpeed || isChannelSpeed)
- delete settings.customSpeed;
- if (doNotChangeSpeed && !isChannelSpeed)
- settings.speed = SPEED_NORMAL;
- if (doNotChangeSpeed) {
- settings.speed = SPEED_NORMAL;
- delete settings.customSpeed;
- }
- const { customSpeed } = settings;
- delete settings.customSpeed;
- isSpeedChanged = false;
- video ||= plr.querySelector(".html5-main-video");
- subtitlesBtn ||= plr.querySelector(".ytp-subtitles-button");
- restoreFocusAfter(() => {
- for (const setting in settings)
- valueSetters[setting](settings[setting]);
- if (!isNaN(+customSpeed)) {
- isSpeedChanged = false;
- valueSetters.customSpeed(customSpeed);
- }
- ytMenu.setOpen(false);
- });
- if (menu.element) {
- menuControls.updateThisChannel();
- return;
- }
- menu.element = div({
- id: "YTDef-menu"
- });
- menu.btn = button("", {
- id: "YTDef-btn",
- ariaLabel: text.OPEN_SETTINGS,
- tabIndex: 0,
- onclick() {
- menu.toggle();
- }
- });
- const toOptions = (values, getText) => [
- option({
- value: text.DEFAULT,
- textContent: text.DEFAULT
- })
- ].concat(values.map((value) => option({
- value,
- textContent: getText(value)
- })));
- const speedValues = [
- "2",
- "1.75",
- "1.5",
- "1.25",
- SPEED_NORMAL,
- "0.75",
- "0.5",
- "0.25"
- ];
- const qualityValues = [
- "144",
- "240",
- "360",
- "480",
- "720",
- "1080",
- "1440",
- "2160",
- "4320"
- ];
- const createSection = (sectionId, title, sectionCfg) => {
- const section = div({ role: "group" });
- section.setAttribute("aria-labelledby", sectionId);
- const getLocalId = (name) => "YTDef-" + name + "-" + sectionId;
- const addItem = (name, innerHTML, elem) => {
- const item = div();
- const id = getLocalId(name);
- const label = labelEl(id, { innerHTML });
- const valueProp = elem.type === "checkbox" ? "checked" : "value";
- Object.assign(elem, {
- id,
- name,
- onchange() {
- const value = this[valueProp];
- if (value === "" || value === text.DEFAULT)
- delete sectionCfg[name];
- else
- sectionCfg[name] = value;
- }
- });
- const cfgValue = sectionCfg[name];
- if (cfgValue)
- setTimeout(() => {
- elem[valueProp] = cfgValue;
- });
- item.append(label, elem);
- section.append(item);
- menuControls[sectionId][name] = elem;
- if (elem.hint)
- section.append(elem.hint.element);
- return { elem };
- };
- const addSelectItem = (name, label, options, getText) => {
- const { elem } = addItem(name, label, selectEl({ value: text.DEFAULT }));
- elem.append(...toOptions(options, getText));
- return elem;
- };
- section.append(getElCreator("span")({ textContent: title, id: sectionId }));
- const firstElement = addSelectItem("speed", text.SPEED, speedValues, (val) => val);
- if (sectionId === "global")
- menu.firstElement = firstElement;
- addItem("customSpeed", text.CUSTOM_SPEED, input({
- type: "number",
- onfocus() {
- this.hint.show();
- },
- onblur() {
- this.hint.hide();
- },
- hint: new Hint("", { textContent: text.CUSTOM_SPEED_HINT })
- }));
- addSelectItem("quality", text.QUALITY, qualityValues, (val) => val + "p");
- addItem("volume", text.VOLUME, input({
- type: "number",
- min: "0",
- max: "100",
- oninput() {
- settings.volume = this.value;
- const warning = validateVolume(this.value);
- if (warning) {
- this.hint.show(warning);
- } else {
- this.hint.hide();
- }
- },
- hint: new Hint("Warning: ")
- }));
- addItem("subtitles", text.SUBTITLES, checkbox());
- return section;
- };
- const sections = div({ className: "YTDef-" + "sections" });
- sections.append(createSection("global", text.GLOBAL, cfg.global), createSection("thisChannel", text.LOCAL, channelConfig.current));
- const checkboxDiv = (id, prop, text2) => {
- const cont = div({ className: "check-cont" });
- id = "YTDef-" + id;
- const elem = checkbox({
- id,
- checked: cfg.flags[prop],
- onclick() {
- cfg.flags[prop] = this.checked;
- }
- });
- menuControls.flags[prop] = elem;
- cont.append(labelEl(id, { textContent: text2 }), elem);
- return cont;
- };
- const controlStatus = div();
- const updateControlStatus = (content) => {
- controlStatus.textContent = `[${new Date().toLocaleTimeString()}] ${content}`;
- };
- const controlDiv = div({ className: "control-cont" });
- controlDiv.append(button(text.SAVE, {
- onclick() {
- saveCfg();
- updateControlStatus(text.SAVE);
- }
- }), button(text.EXPORT, {
- onclick: () => {
- navigator.clipboard.writeText(localStorage["YTDefaulter"]).then(() => {
- updateControlStatus(text.EXPORT);
- });
- }
- }), button(text.IMPORT, {
- onclick: async () => {
- try {
- const raw = await navigator.clipboard.readText();
- const newCfg = JSON.parse(raw);
- if (typeof newCfg !== "object" || !newCfg._v) {
- throw new Error("Import: Invalid data");
- }
- if (!updateCfg()) {
- localStorage["YTDefaulter"] = raw;
- cfg = newCfg;
- }
- channelConfig.current = cfg.channels[channelUsername] ||= {};
- } catch (e) {
- updateControlStatus(e.message);
- return;
- }
- updateControlStatus(text.IMPORT);
- menuControls.updateValues();
- }
- }));
- menu.element.append(sections, checkboxDiv("shorts", "shortsToUsual", text.SHORTS), checkboxDiv("new-tab", "newTab", text.NEW_TAB), checkboxDiv("copy-subs", "copySubs", text.COPY_SUBS), checkboxDiv("standard-music-speed", "standardMusicSpeed", text.STANDARD_MUSIC_SPEED), checkboxDiv("enhanced-bitrate", "enhancedBitrate", text.ENHANCED_BITRATE), controlDiv, controlStatus);
- menu.element.addEventListener("keyup", (e) => {
- const el = e.target;
- if (e.code === "Enter" && el.type === "checkbox")
- el.checked = !el.checked;
- });
- const settingsIcon = document.createElementNS("http://www.w3.org/2000/svg", "svg");
- const iconStyle = {
- viewBox: "0 0 24 24",
- width: "24",
- height: "24",
- fill: "var(--yt-spec-text-primary)"
- };
- for (const key in iconStyle)
- settingsIcon.setAttribute(key, iconStyle[key]);
- settingsIcon.append($("settings"));
- menu.btn.setAttribute("aria-controls", "YTDef-menu");
- menu.btn.classList.add(btnClass + "--icon-button");
- menu.btn.append(settingsIcon);
- const actionsBar = await untilAppear(getActionsBar);
- actionsBar.insertBefore(menu.btn, actionsBar.lastChild);
- document.querySelector("ytd-popup-container").append(menu.element);
- menu.width = menu.element.getBoundingClientRect().width;
- sections.style.maxWidth = sections.offsetWidth + "px";
- };
- var lastHref;
- setInterval(() => {
- if (lastHref === location.href)
- return;
- lastHref = location.href;
- setTimeout(onPageChange, 1000);
- }, 1000);
- var onClick = (e) => {
- const { shortsToUsual, newTab } = cfg.flags;
- if (!shortsToUsual && !newTab)
- return;
- let el = e.target;
- if (el.tagName !== "A") {
- el = el.closest("a");
- if (!el)
- return;
- }
- if (!/shorts\/|watch\?v=/.test(el.href))
- return;
- if (shortsToUsual)
- el.href = el.href.replace("shorts/", "watch?v=");
- if (newTab) {
- el.target = "_blank";
- e.stopPropagation();
- }
- };
- document.addEventListener("click", onClick, { capture: true });
- document.addEventListener("keyup", (e) => {
- if (e.code === "Enter")
- return onClick(e);
- if (!e.ctrlKey || e.shiftKey)
- return;
- if (cfg.flags.copySubs && e.code === "KeyC") {
- const plr = document.querySelector(".html5-video-player");
- if (!plr?.classList.contains("ytp-fullscreen"))
- return;
- const text2 = Array.from(plr.querySelectorAll(".captions-text > span"), (line) => line.textContent).join(" ");
- navigator.clipboard.writeText(text2);
- return;
- }
- if (e.code !== "Space")
- return;
- e.stopPropagation();
- e.preventDefault();
- const customSpeedValue = channelConfig.current ? channelConfig.current.customSpeed || !channelConfig.current.speed && cfg.global.customSpeed : cfg.global.customSpeed;
- if (customSpeedValue)
- return valueSetters.customSpeed(customSpeedValue);
- restoreFocusAfter(() => {
- valueSetters["speed"]((channelConfig.current || cfg.global)["speed"]);
- });
- }, { capture: true });
- var listener = () => {
- if (menu.isOpen)
- menu.fixPosition();
- };
- window.addEventListener("scroll", listener);
- window.addEventListener("resize", listener);
- 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);";
- document.head.append(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}`
- }));
- })()