您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Set default speed, quality, subtitles and volume globally or per channel
- // ==UserScript==
- // @name YouTube Defaulter
- // @namespace https://greasyfork.org/ru/users/901750-gooseob
- // @version 1.12.8
- // @description Set default speed, quality, subtitles and volume globally or per channel
- // @author GooseOb
- // @license MIT
- // @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) => {
- let isUpdated = true;
- switch (cfg._v) {
- case 4:
- if ("shortsToUsual" in cfg.flags) {
- cfg.flags.shortsToRegular = cfg.flags.shortsToUsual;
- delete cfg.flags.shortsToUsual;
- } else {
- isUpdated = false;
- }
- break;
- 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 isUpdated;
- };
- // 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/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/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, timeout = 1e4, interval = 20) => new Promise((res, rej) => {
- let item = getItem();
- if (check(item))
- return res(item);
- const limit = timeout / interval;
- let i = 0;
- const id = setInterval(() => {
- item = getItem();
- if (check(item)) {
- clearInterval(id);
- res(item);
- } else if (++i > limit) {
- clearInterval(id);
- rej(new Error(`Timeout: item ${getItem.name} wasn't found`));
- }
- }, interval);
- });
- 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/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 = (d) => findInNodeList(items, (el) => !!el.querySelector(`path[d="${d}"]`));
- 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) => untilAppear(() => settingItems[name]).then((item) => (predicate) => {
- const oldSubItems = new Set(menuSubItems(element));
- return findInNodeList(openItem(item), (subItem) => !oldSubItems.has(subItem) && predicate(subItem));
- });
- // 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)
- findInItem("speed").then((findInSpeed) => {
- restoreFocusAfter(() => {
- speedNormal = findInSpeed((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 >= Number.parseInt(current) && (value.flags.enhancedBitrate || !current.toLowerCase().includes("premium")),
- speed: (target, current) => target === current
- };
- var setYT = (settingName) => async (value3) => {
- const isOpen2 = isOpen();
- const compare = comparators[settingName];
- const btn2 = (await 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 text = Array.from(videoPlrCaptions(plr3), (line) => line.textContent).join(" ");
- navigator.clipboard.writeText(text);
- }
- } 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/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/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) {
- const flag = flags[key];
- if (flag) {
- flag.elem.checked = cfg.flags[key];
- } else {
- err("Unknown flag:", 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/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/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" : Number.isNaN(num) ? "not a number" : null;
- };
- // 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/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/index.ts
- Object.assign(text, translations[document.documentElement.lang]);
- if (update(value)) {
- saveLS(value);
- }
- window.addEventListener("yt-navigate-finish", ({ detail: { pageType } }) => {
- if (pageType === "watch" || pageType === "live") {
- setTimeout(onVideoPage, 1000);
- }
- });
- setInterval(() => {
- if (value.flags.hideShorts)
- findInNodeList(document.querySelectorAll("#title"), (el) => el.textContent === "Shorts")?.closest("ytd-rich-section-renderer")?.remove();
- }, 1000);
- document.addEventListener("click", onClick, { capture: true });
- document.addEventListener("keyup", onKeyup, { capture: true });
- document.head.append(style);
- })()