- // ==UserScript==
- // @name YouTube EXPERIMENT_FLAGS Tamer (Basic)
- // @namespace UserScripts
- // @match https://www.youtube.com/*
- // @version 0.4.8.104
- // @license MIT
- // @author CY Fung
- // @icon https://raw.githubusercontent.com/cyfung1031/userscript-supports/main/icons/yt-engine.png
- // @description Adjust EXPERIMENT_FLAGS
- // @grant none
- // @unwrap
- // @run-at document-start
- // @allFrames true
- // @inject-into page
- // ==/UserScript==
-
- ((__CONTEXT__) => {
-
- // Purpose 1: Remove Obsolete Flags
- // Purpose 2: Remove Flags bring no visual difference
- // Purpose 3: Enable Flags bring performance boost
-
- const DISABLE_CINEMATICS = false; // standard design
- const NO_SerializedExperiment = false;
- const KEEP_PLAYER_QUALITY_STICKY = true; // see https://gf.qytechs.cn/scripts/471033/
- const DISABLE_serializedExperimentIds = true;
- const DISABLE_serializedExperimentFlags = true;
-
-
- // const ALLOW_FLAGS_202404_flags11 = new Set([
- // // 'use_core_sm',
- // // 'use_new_cml',
- // // 'web_api_url',
- // ]);
-
- const ENABLE_EXPERIMENT_FLAGS_MAINTAIN_STABLE_LIST = {
- defaultValue: true, // performance boost
- useExternal: () => typeof localStorage.EXPERIMENT_FLAGS_MAINTAIN_STABLE_LIST !== 'undefined',
- externalValue: () => (+localStorage.EXPERIMENT_FLAGS_MAINTAIN_STABLE_LIST ? true : false)
- };
- const ENABLE_EXPERIMENT_FLAGS_MAINTAIN_REUSE_COMPONENTS = {
- defaultValue: true, // not sure
- useExternal: () => typeof localStorage.EXPERIMENT_FLAGS_MAINTAIN_REUSE_COMPONENTS !== 'undefined',
- externalValue: () => (+localStorage.EXPERIMENT_FLAGS_MAINTAIN_REUSE_COMPONENTS ? true : false)
- };
- const ENABLE_EXPERIMENT_FLAGS_DEFER_DETACH = {
- defaultValue: true, // not sure
- useExternal: () => typeof localStorage.ENABLE_EXPERIMENT_FLAGS_DEFER_DETACH !== 'undefined',
- externalValue: () => (+localStorage.ENABLE_EXPERIMENT_FLAGS_DEFER_DETACH ? true : false)
- };
-
- const ALLOW_ALL_LIVE_CHATS_FLAGS = true;
-
-
-
- // TBC
- // kevlar_tuner_should_always_use_device_pixel_ratio
- // kevlar_tuner_should_clamp_device_pixel_ratio
- // kevlar_tuner_clamp_device_pixel_ratio
- // kevlar_tuner_should_use_thumbnail_factor
- // kevlar_tuner_thumbnail_factor
- // kevlar_tuner_min_thumbnail_quality
- // kevlar_tuner_max_thumbnail_quality
-
- // kevlar_tuner_should_test_visibility_time_between_jobs
- // kevlar_tuner_visibility_time_between_jobs_ms
-
- // kevlar_tuner_default_comments_delay
- // kevlar_tuner_run_default_comments_delay
-
- let settled = null;
- // cinematic feature is no longer an experimential feature.
- // It has been officially implemented.
- // To disable cinematics, the user shall use other userscripts or just turn off the option in the video options.
-
- const getSettingValue = (fm) => fm.useExternal() ? fm.externalValue() : fm.defaultValue;
-
- const win = this instanceof Window ? this : window;
-
- // Create a unique key for the script and check if it is already running
- const hkey_script = 'jmimcvowrlzl';
- if (win[hkey_script]) throw new Error('Duplicated Userscript Calling'); // avoid duplicated scripting
- win[hkey_script] = true;
-
- /** @type {globalThis.PromiseConstructor} */
- const Promise = ((async () => { })()).constructor;
-
- let isMainWindow = false;
- let mzFlagDetected = new Set();
- let zPlayerKevlar = false;
- try {
- isMainWindow = window.document === window.top.document
- } catch (e) { }
-
- function fixSerializedExperiment(conf) {
-
- if (DISABLE_serializedExperimentIds && typeof conf.serializedExperimentIds === 'string') {
- let ids = conf.serializedExperimentIds.split(',');
- let newIds = [];
- for (const id of ids) {
- let keep = false;
- if (keep) {
- newIds.push(id);
- }
- }
- conf.serializedExperimentIds = newIds.join(',');
- }
-
- if (DISABLE_serializedExperimentFlags && typeof conf.serializedExperimentFlags === 'string') {
- const fg = conf.serializedExperimentFlags;
- const rx = /(^|&)(\w+)=([^=&|\s\{\}\[\]\(\)?]*)/g;
- let res = [];
- for (let m; m = rx.exec(fg);) {
- let key = m[2];
- let value = m[3];
- let keep = false;
- if (KEEP_PLAYER_QUALITY_STICKY) {
- if (key === 'html5_exponential_memory_for_sticky' || key.startsWith('h5_expr_')) {
- keep = true;
- }
- }
- if (!DISABLE_CINEMATICS) {
- if (key === 'web_cinematic_watch_settings') {
- keep = true;
- }
- }
- if (keep) res.push(`${key}=${value}`);
- }
- conf.serializedExperimentFlags = res.join('&');
- }
-
- }
-
- const cachedSetFn=(o) => {
-
- const { use_maintain_stable_list, use_maintain_reuse_components, use_defer_detach } = o;
-
- const BY_PASS = [
-
- 'enable_profile_cards_on_comments',
-
- 'suppress_error_204_logging',
- ...(!DISABLE_CINEMATICS ? [
-
- 'kevlar_measure_ambient_mode_idle',
- 'kevlar_watch_cinematics_invisible',
- 'web_cinematic_theater_mode',
- 'web_cinematic_fullscreen',
-
- 'enable_cinematic_blur_desktop_loading',
- 'kevlar_watch_cinematics',
- 'web_cinematic_masthead',
- 'web_watch_cinematics_preferred_reduced_motion_default_disabled'
-
- ] : []),
-
- 'live_chat_web_enable_command_handler',
- 'live_chat_channel_activity',
- 'live_chat_web_input_update',
-
-
- ...(ALLOW_ALL_LIVE_CHATS_FLAGS ? [
-
- 'live_chat_banner_expansion_fix',
- 'live_chat_enable_mod_view',
- 'live_chat_enable_qna_banner_overflow_menu_actions',
- 'live_chat_enable_qna_channel',
- 'live_chat_enable_send_button_in_slow_mode',
- 'live_chat_filter_emoji_suggestions',
- 'live_chat_increased_min_height',
- 'live_chat_over_playlist',
- 'live_chat_web_use_emoji_manager_singleton',
- 'live_chat_whole_message_clickable',
-
- 'live_chat_emoji_picker_toggle_state',
- 'live_chat_enable_command_handler_resolver_map',
- 'live_chat_enable_controller_extraction',
- 'live_chat_enable_rta_manager',
- 'live_chat_require_space_for_autocomplete_emoji',
- 'live_chat_unclickable_message',
-
- ]:[]),
-
- 'kevlar_rendererstamper_event_listener', // https://github.com/cyfung1031/userscript-supports/issues/11
-
- // kevlar_enable_up_arrow - no use
- // kevlar_help_use_locale - might use
- // kevlar_refresh_gesture - might use
- // kevlar_smart_downloads - might use
- // kevlar_thumbnail_fluid
- 'kevlar_ytb_live_badges',
-
- ...(!use_maintain_stable_list ? [
- 'kevlar_tuner_should_test_maintain_stable_list',
- 'kevlar_should_maintain_stable_list',
- 'kevlar_tuner_should_maintain_stable_list', // fallback
-
-
- ] : []),
-
-
- ...(!use_maintain_reuse_components ? [
-
- 'kevlar_tuner_should_test_reuse_components',
- 'kevlar_tuner_should_reuse_components',
- 'kevlar_should_reuse_components' // fallback
-
- ] : []),
-
-
- 'kevlar_system_icons',
-
- // 'kevlar_prefetch_data_augments_network_data' continue;
-
- // home page / watch page icons
- 'kevlar_three_dot_ink',
- 'kevlar_use_wil_icons',
- 'kevlar_home_skeleton',
-
- 'kevlar_fluid_touch_scroll',
- 'kevlar_watch_color_update',
- 'kevlar_use_vimio_behavior', // home page - channel icon
-
- // collapsed meta; no teaser, use latest collapsed meta design
- 'kevlar_structured_description_content_inline',
- 'kevlar_watch_metadata_refresh',
-
- 'kevlar_watch_js_panel_height', // affect Tabview Youtube
-
- 'shorts_desktop_watch_while_p2',
- 'web_button_rework',
- 'web_darker_dark_theme_live_chat',
- 'web_darker_dark_theme', // it also affect cinemtaics
-
- // modern menu
- 'web_button_rework_with_live',
- 'web_fix_fine_scrubbing_drag',
-
- // full screen -buggy
- 'external_fullscreen',
-
- // minimize menu
- 'web_modern_buttons',
- 'web_modern_dialogs',
-
- // Tabview Youtube - multiline transcript
- 'enable_mixed_direction_formatted_strings',
-
-
- // Notification Menu
- "kevlar_service_command_check",
-
- // Live ChatRoom Visibility
- "live_chat_cow_visibility_set_up",
-
- ].concat(
- [
- ]
- )
-
- const s = new Set(BY_PASS);
-
- return s;
-
- };
- let cachedSet = null;
-
- const hLooper = ((fn) => {
-
- let nativeFnLoaded = false;
- let kc1 = 0;
-
- const setIntervalW = setInterval;
- const clearIntervalW = clearInterval;
- let microDisconnectFn = null;
- let fStopLooper = false;
- const looperFn = () => {
- if (fStopLooper) return;
-
- let config_ = null;
- let EXPERIMENT_FLAGS = null;
- try {
- config_ = yt.config_;
- EXPERIMENT_FLAGS = config_.EXPERIMENT_FLAGS
- } catch (e) { }
-
- if (EXPERIMENT_FLAGS) {
-
- fn(EXPERIMENT_FLAGS, config_);
-
- if (microDisconnectFn) {
- let isYtLoaded = false;
- try {
- isYtLoaded = typeof ytcfg.set === 'function';
- } catch (e) { }
- if (isYtLoaded) {
- microDisconnectFn();
- }
- }
-
- }
-
- let playerKevlar = null;
-
- try {
- playerKevlar = ytcfg.data_.WEB_PLAYER_CONTEXT_CONFIGS.WEB_PLAYER_CONTEXT_CONFIG_ID_KEVLAR_WATCH;
- } catch (e) { }
-
- if (playerKevlar && !zPlayerKevlar) {
- zPlayerKevlar = true;
-
- if (NO_SerializedExperiment && typeof playerKevlar.serializedExperimentFlags === 'string' && typeof playerKevlar.serializedExperimentIds === 'string') {
- fixSerializedExperiment(playerKevlar);
- }
-
-
- }
-
-
-
- };
-
- const controller = {
- start() {
- kc1 = setIntervalW(looperFn, 1);
- (async () => {
- while (true && !nativeFnLoaded) {
- looperFn();
- if (fStopLooper) break;
- await (new Promise(requestAnimationFrame));
- }
- })();
- looperFn();
- },
- /**
- *
- * @param {Window} __CONTEXT__
- */
- setupForCleanContext(__CONTEXT__) {
-
- const { requestAnimationFrame, setInterval, clearInterval, setTimeout, clearTimeout } = __CONTEXT__;
-
- (async () => {
- while (true) {
- looperFn();
- if (fStopLooper) break;
- await (new Promise(requestAnimationFrame));
- }
- })();
-
- let kc2 = setInterval(looperFn, 1);
-
- const marcoDisconnectFn = () => {
- if (fStopLooper) return;
- Promise.resolve().then(() => {
- if (kc1 || kc2) {
- kc1 && clearIntervalW(kc1); kc1 = 0;
- kc2 && clearInterval(kc2); kc2 = 0;
- looperFn();
- }
- fStopLooper = true;
- });
- document.removeEventListener('yt-page-data-fetched', marcoDisconnectFn, false);
- document.removeEventListener('yt-navigate-finish', marcoDisconnectFn, false);
- document.removeEventListener('spfdone', marcoDisconnectFn, false);
- };
- document.addEventListener('yt-page-data-fetched', marcoDisconnectFn, false);
- document.addEventListener('yt-navigate-finish', marcoDisconnectFn, false);
- document.addEventListener('spfdone', marcoDisconnectFn, false);
-
-
- function onReady() {
- if (!fStopLooper) {
- setTimeout(() => {
- !fStopLooper && marcoDisconnectFn();
- }, 1000);
- }
- }
-
- Promise.resolve().then(() => {
- if (document.readyState !== 'loading') {
- onReady();
- } else {
- window.addEventListener("DOMContentLoaded", onReady, false);
- }
- });
-
- nativeFnLoaded = true;
-
- microDisconnectFn = () => Promise.resolve(marcoDisconnectFn).then(setTimeout);
-
- }
- };
-
- return controller;
- })((EXPERIMENT_FLAGS, config_) => {
-
- if (!EXPERIMENT_FLAGS) return;
-
- if (!settled) {
- settled = {
- use_maintain_stable_list: getSettingValue(ENABLE_EXPERIMENT_FLAGS_MAINTAIN_STABLE_LIST),
- use_maintain_reuse_components: getSettingValue(ENABLE_EXPERIMENT_FLAGS_MAINTAIN_REUSE_COMPONENTS),
- use_defer_detach: getSettingValue(ENABLE_EXPERIMENT_FLAGS_DEFER_DETACH),
- }
- if (settled.use_maintain_stable_list) Promise.resolve().then(() => console.debug("use_maintain_stable_list"));
- if (settled.use_maintain_reuse_components) Promise.resolve().then(() => console.debug("use_maintain_reuse_components"));
- if (settled.use_defer_detach) Promise.resolve().then(() => console.debug("use_defer_detach"));
- }
- const { use_maintain_stable_list, use_maintain_reuse_components, use_defer_detach } = settled;
-
- cachedSet = cachedSet || cachedSetFn({ use_maintain_stable_list, use_maintain_reuse_components, use_defer_detach });
-
- let mps = [];
-
- setTimeout(async ()=>{
-
- if(!mps.length) return;
- let ezz = new Set();
- let e1 = 999;
- let e2 = -999;
- for(const mp of mps){
- for(const k of mp){
- ezz.add(k);
- const kl= k.length;
- if(kl<e1) e1=kl;
- if(kl>e2) e2=kl;
- }
- }
- mps.length = 0;
-
- if(!ezz.size) return;
-
- await new Promise(r => window.setTimeout(r, 1));
- let qt = Date.now();
-
- console.log('EXPERIMENT_FLAGS', [e1,e2, ezz.size]);
-
- let mf = false;
- const obj = JSON.parse(localStorage['bpghn01'] || '{}');
- for(const e of ezz){
- if(obj[e])continue;
- obj[e] = qt;
- mf= true;
- }
- if(mf){
-
- localStorage['bpghn01'] = JSON.stringify( obj);
- }
-
- // await new Promise(r => window.setTimeout(r, 1));
-
- const getEFT = function(after, offset){
-
-
- after = typeof after === 'string' ? new Date(after) : after;
- let afterValue = +after;
-
-
- let arr = Object.entries(obj).map(e=>{
- return {key: e[0], date: e[1], len:e[0].length };
- }).sort((a,b)=>{
- return a.date < b.date ? 1 : a.date>b.date ? -1 : a.len < b.len ? 1 :a.len>b.len ? -1 : `${a.key}`.localeCompare(`${b.key}`) ;
- });
-
- if (afterValue > 0) {
- arr = arr.filter(e => {
- return e.date >= afterValue + offset;
- })
- }
-
- return [arr, after, afterValue];
-
- }
-
- window.log_EXPERIMENT_FLAGS_Tamer = function(after, toString){
-
- let [arr, after_, afterValue] =getEFT(after, -86400000);
-
- const r = {
- "!log": arr,
- after: afterValue > 0 ? new Date(afterValue) : null
- };
- console.log("log_EXPERIMENT_FLAGS_Tamer", toString ? JSON.stringify(r) : r);
-
- }
-
- window.kl_EXPERIMENT_FLAGS_Tamer = function (after, kl) {
-
-
- let [arr, after_, afterValue] =getEFT(after, -86400000);
-
- arr = arr.filter(e => {
- return e.len === kl
- });
-
- return arr.map(e => e.key).join('|')
-
-
- }
-
-
- }, 800);
-
- const setFalseFn = (EXPERIMENT_FLAGS) => {
-
- let ezz = new Set();
-
- for (const [key, value] of Object.entries(EXPERIMENT_FLAGS)) {
-
-
- if (value === true) {
- // if(key.indexOf('modern')>=0 || key.indexOf('enable')>=0 || key.indexOf('theme')>=0 || key.indexOf('skip')>=0 || key.indexOf('ui')>=0 || key.indexOf('observer')>=0 || key.indexOf('polymer')>=0 )continue;
-
- if (mzFlagDetected.has(key)) continue;
- mzFlagDetected.add(key);
- const kl = key.length;
- const kl7 = kl % 7;
- const kl5 = kl % 5;
- const kl3 = kl % 3;
- const kl2 = kl % 2;
-
- if(cachedSet.has(key)) continue;
-
- ezz.add(key);
-
- // console.log(key)
- EXPERIMENT_FLAGS[key] = false;
- }
- }
- mps.push(ezz);
- ezz = null;
-
- }
-
- setFalseFn(EXPERIMENT_FLAGS);
- if (config_.EXPERIMENTS_FORCED_FLAGS) setFalseFn(config_.EXPERIMENTS_FORCED_FLAGS);
-
- EXPERIMENT_FLAGS.desktop_delay_player_resizing = false;
- EXPERIMENT_FLAGS.web_animated_like = false;
- EXPERIMENT_FLAGS.web_animated_like_lazy_load = false;
-
- if (use_maintain_stable_list) {
- EXPERIMENT_FLAGS.kevlar_tuner_should_test_maintain_stable_list = true;
- EXPERIMENT_FLAGS.kevlar_should_maintain_stable_list = true;
- EXPERIMENT_FLAGS.kevlar_tuner_should_maintain_stable_list = true; // fallback
- }
-
- if (use_maintain_reuse_components) {
- EXPERIMENT_FLAGS.kevlar_tuner_should_test_reuse_components = true;
- EXPERIMENT_FLAGS.kevlar_tuner_should_reuse_components = true;
- EXPERIMENT_FLAGS.kevlar_should_reuse_components = true; // fallback
- }
-
- if (use_defer_detach) {
- EXPERIMENT_FLAGS.kevlar_tuner_should_defer_detach = true;
- }
-
- // EXPERIMENT_FLAGS.kevlar_prefetch_data_augments_network_data = true; // TBC
- });
-
- hLooper.start();
-
-
- const cleanContext = async (win) => {
- const waitFn = requestAnimationFrame; // shall have been binded to window
- try {
- let mx = 16; // MAX TRIAL
- const frameId = 'vanillajs-iframe-v1'
- let frame = document.getElementById(frameId);
- let removeIframeFn = null;
- if (!frame) {
- frame = document.createElement('iframe');
- frame.id = 'vanillajs-iframe-v1';
- frame.sandbox = 'allow-same-origin'; // script cannot be run inside iframe but API can be obtained from iframe
- let n = document.createElement('noscript'); // wrap into NOSCRPIT to avoid reflow (layouting)
- n.appendChild(frame);
- while (!document.documentElement && mx-- > 0) await new Promise(waitFn); // requestAnimationFrame here could get modified by YouTube engine
- const root = document.documentElement;
- root.appendChild(n); // throw error if root is null due to exceeding MAX TRIAL
- removeIframeFn = (setTimeout) => {
- const removeIframeOnDocumentReady = (e) => {
- e && win.removeEventListener("DOMContentLoaded", removeIframeOnDocumentReady, false);
- win = null;
- setTimeout(() => {
- n.remove();
- n = null;
- }, 200);
- }
- if (document.readyState !== 'loading') {
- removeIframeOnDocumentReady();
- } else {
- win.addEventListener("DOMContentLoaded", removeIframeOnDocumentReady, false);
- }
- }
- }
- while (!frame.contentWindow && mx-- > 0) await new Promise(waitFn);
- const fc = frame.contentWindow;
- if (!fc) throw "window is not found."; // throw error if root is null due to exceeding MAX TRIAL
- const { requestAnimationFrame, setInterval, setTimeout, clearInterval, clearTimeout } = fc;
- const res = { requestAnimationFrame, setInterval, setTimeout, clearInterval, clearTimeout };
- for (let k in res) res[k] = res[k].bind(win); // necessary
- if (removeIframeFn) Promise.resolve(res.setTimeout).then(removeIframeFn);
- return res;
- } catch (e) {
- console.warn(e);
- return null;
- }
- };
-
- cleanContext(win).then(__CONTEXT__ => {
-
- const { requestAnimationFrame, setInterval, clearInterval, setTimeout, clearTimeout } = __CONTEXT__;
-
- hLooper.setupForCleanContext(__CONTEXT__)
-
- });
-
-
- if (isMainWindow) {
-
- console.groupCollapsed(
- "%cYouTube EXPERIMENT_FLAGS Tamer",
- "background-color: #EDE43B ; color: #000 ; font-weight: bold ; padding: 4px ;"
- );
-
- console.log("Script is loaded.");
- console.log("This might affect the new features when YouTube rolls them out to general users.");
- console.log("If you found any issue in using YouTube, please disable this script to check whether the issue is due to this script or not.");
-
- console.groupEnd();
-
- }
-
- })(null);