您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
This script (based on YouTube Patch Collection) allows you to configure YouTube features & additional ones that are on a rollout, such as the new modern tabs, rounded player, you tab & more using yt.config flags!
- // ==UserScript==
- // @name Configure YouTube features
- // @version 2023.10.26
- // @description This script (based on YouTube Patch Collection) allows you to configure YouTube features & additional ones that are on a rollout, such as the new modern tabs, rounded player, you tab & more using yt.config flags!
- // @author Alpharetzy
- // @license MIT
- // @match www.youtube.com/*
- // @icon https://www.youtube.com/favicon.ico
- // @run-at document-start
- // @grant none
- // @namespace https://greasyfork.org/users/1094802
- // ==/UserScript==
- // Attributes to remove from <html>
- const ATTRS = [
- // "system-icons",
- // "typography",
- // "typography-spacing"
- ];
- // Regular config keys.
- const CONFIGS = {
- BUTTON_REWORK: true
- };
- // Experiment flags.
- const EXPFLAGS = {
- enable_channel_page_header_profile_section: true,
- enable_header_channel_handler_ui: true,
- kevlar_unavailable_video_error_ui_client: true,
- kevlar_refresh_on_theme_change: true,
- kevlar_modern_sd_v2: true,
- kevlar_watch_cinematics: true,
- kevlar_watch_comments_panel_button: true,
- //kevlar_watch_grid: true,
- //kevlar_watch_grid_hide_chips: true,
- kevlar_watch_metadata_refresh: true,
- kevlar_watch_metadata_refresh_no_old_secondary_data: true,
- kevlar_watch_modern_metapanel: true,
- kevlar_watch_modern_panels: true,
- kevlar_watch_panel_height_matches_player: true,
- smartimation_background: true,
- web_amsterdam_playlists: true,
- web_animated_actions: true,
- kevlar_system_icons: true,
- web_animated_like: true,
- web_button_rework: true,
- web_button_rework_with_live: true,
- web_darker_dark_theme: true,
- web_enable_youtab: true,
- web_guide_ui_refresh: true,
- web_modern_ads: true,
- web_modern_buttons: true,
- web_modern_chips: true,
- web_modern_collections_v2: true,
- web_modern_dialogs: true,
- web_modern_playlists: true,
- web_modern_subscribe: true,
- web_modern_tabs: true,
- web_modern_typography: true,
- web_rounded_containers: true,
- web_rounded_thumbnails: true,
- web_searchbar_style: "default",
- web_segmented_like_dislike_button: true,
- web_sheets_ui_refresh: true,
- web_snackbar_ui_refresh: true,
- web_watch_rounded_player_large: true
- }
- // Player flags
- // !!! USE STRINGS FOR VALUES !!!
- // For example: "true" instead of true
- const PLYRFLAGS = {
- web_player_move_autonav_toggle: "true",
- web_settings_menu_icons: "true",
- web_rounded_containers: "true",
- web_rounded_thumbnails: "true"
- };
- class YTP {
- static observer = new MutationObserver(this.onNewScript);
- static _config = {};
- static isObject(item) {
- return (item && typeof item === "object" && !Array.isArray(item));
- }
- static mergeDeep(target, ...sources) {
- if (!sources.length) return target;
- const source = sources.shift();
- if (this.isObject(target) && this.isObject(source)) {
- for (const key in source) {
- if (this.isObject(source[key])) {
- if (!target[key]) Object.assign(target, { [key]: {} });
- this.mergeDeep(target[key], source[key]);
- } else {
- Object.assign(target, { [key]: source[key] });
- }
- }
- }
- return this.mergeDeep(target, ...sources);
- }
- static onNewScript(mutations) {
- for (var mut of mutations) {
- for (var node of mut.addedNodes) {
- YTP.bruteforce();
- }
- }
- }
- static start() {
- this.observer.observe(document, {childList: true, subtree: true});
- }
- static stop() {
- this.observer.disconnect();
- }
- static bruteforce() {
- if (!window.yt) return;
- if (!window.yt.config_) return;
- this.mergeDeep(window.yt.config_, this._config);
- }
- static setCfg(name, value) {
- this._config[name] = value;
- }
- static setCfgMulti(configs) {
- this.mergeDeep(this._config, configs);
- }
- static setExp(name, value) {
- if (!("EXPERIMENT_FLAGS" in this._config)) this._config.EXPERIMENT_FLAGS = {};
- this._config.EXPERIMENT_FLAGS[name] = value;
- }
- static setExpMulti(exps) {
- if (!("EXPERIMENT_FLAGS" in this._config)) this._config.EXPERIMENT_FLAGS = {};
- this.mergeDeep(this._config.EXPERIMENT_FLAGS, exps);
- }
- static decodePlyrFlags(flags) {
- var obj = {},
- dflags = flags.split("&");
- for (var i = 0; i < dflags.length; i++) {
- var dflag = dflags[i].split("=");
- obj[dflag[0]] = dflag[1];
- }
- return obj;
- }
- static encodePlyrFlags(flags) {
- var keys = Object.keys(flags),
- response = "";
- for (var i = 0; i < keys.length; i++) {
- if (i > 0) {
- response += "&";
- }
- response += keys[i] + "=" + flags[keys[i]];
- }
- return response;
- }
- static setPlyrFlags(flags) {
- if (!window.yt) return;
- if (!window.yt.config_) return;
- if (!window.yt.config_.WEB_PLAYER_CONTEXT_CONFIGS) return;
- var conCfgs = window.yt.config_.WEB_PLAYER_CONTEXT_CONFIGS;
- if (!("WEB_PLAYER_CONTEXT_CONFIGS" in this._config)) this._config.WEB_PLAYER_CONTEXT_CONFIGS = {};
- for (var cfg in conCfgs) {
- var dflags = this.decodePlyrFlags(conCfgs[cfg].serializedExperimentFlags);
- this.mergeDeep(dflags, flags);
- this._config.WEB_PLAYER_CONTEXT_CONFIGS[cfg] = {
- serializedExperimentFlags: this.encodePlyrFlags(dflags)
- }
- }
- }
- }
- window.addEventListener("yt-page-data-updated", function tmp() {
- YTP.stop();
- for (i = 0; i < ATTRS.length; i++) {
- document.getElementsByTagName("html")[0].removeAttribute(ATTRS[i]);
- }
- window.removeEventListener("yt-page-date-updated", tmp);
- });
- YTP.start();
- YTP.setCfgMulti(CONFIGS);
- YTP.setExpMulti(EXPFLAGS);
- YTP.setPlyrFlags(PLYRFLAGS);