YouTube视频&音乐&儿童广告拦截
// ==UserScript==
// @name YouTube视频&音乐&儿童广告拦截
// @name:zh-CN YouTube视频&音乐&儿童广告拦截
// @name:zh-TW YouTube視頻&音樂&兒童廣告攔截
// @name:zh-HK YouTube視頻&音樂&兒童廣告攔截
// @name:en YouTubeVideo&music&kidsAdBlocking
// @namespace http://tampermonkey.net/
// @version 1.4.8
// @description 拦截所有youtube视频广告,音乐播放广告,儿童视频广告,不留白,不闪屏,无感,体验第一。已适配移动端,支持自定义拦截,添加影视频道
// @description:zh-CN 拦截所有youtube视频广告,音乐播放广告,儿童視頻廣告,不留白,不闪屏,无感,体验第一。已适配移动端,支持自定义拦截,添加影视频道
// @description:zh-TW 攔截所有YouTube視頻廣告,音樂播放廣告,兒童視頻廣告,不留白,不閃屏,無感,體驗第一。已適配移動端,支持自定義攔截,添加影視頻道
// @description:zh-HK 攔截所有YouTube視頻廣告,音樂播放廣告,兒童視頻廣告,不留白,不閃屏,無感,體驗第一。已適配移動端,支持自定義攔截,添加影視頻道
// @description:en Intercept all YouTube video ads, music playback ads, youtube kids ads, without leaving blank space, no flash screens, seamless experience, the first choice in user experience. Adapted for mobile devices, supports customizable interception, and allows the addition of video channels
// @name:fr Bloqueur de publicités YouTube Vidéos & Musique & Enfants
// @description:fr Bloque toutes les publicités des vidéos YouTube, des lectures de musique, et des vidéos pour enfants sans blancs, sans clignotements, et avec une expérience transparente. Adapté aux appareils mobiles, prend en charge le blocage personnalisé et l'ajout de chaînes vidéo
// @name:ja YouTube動画&音楽&子供広告ブロッカー
// @description:ja すべてのYouTube動画広告、音楽再生広告、子供の動画広告をブロックします。空白なし、ちらつきなし、シームレスな体験。モバイルデバイスに対応し、カスタムブロッキングとビデオチャネルの追加をサポート
// @name:ko YouTube 비디오 & 음악 & 어린이 광고 차단기
// @description:ko 모든 YouTube 비디오 광고, 음악 재생 광고 및 어린이 비디오 광고를 빈 화면 없이, 깜박임 없이, 원활하게 차단합니다. 모바일 장치에 적응되었으며, 사용자 지정 차단 및 비디오 채널 추가를 지원합니다
// @name:ru Блокировщик рекламы YouTube видео & музыка & дети
// @description:ru Блокирует всю рекламу на YouTube, в музыке и детских видео без пустых мест, без мерцания, с бесшовным опытом. Адаптировано для мобильных устройств, поддерживает пользовательскую блокировку и добавление видео каналов
// @name:es Bloqueador de anuncios de YouTube Video & Música & Niños
// @description:es Bloquea todos los anuncios de videos de YouTube, anuncios de reproducción de música y anuncios de videos infantiles sin espacios en blanco, sin parpadeos y con una experiencia sin interrupciones. Adaptado para dispositivos móviles, admite bloqueo personalizado y la adición de canales de video
// @name:mo YouTube影片&音樂&兒童廣告攔截
// @description:mo 攔截所有YouTube影片廣告,音樂播放廣告,兒童影片廣告,不留白,不閃屏,無感,體驗第一。已適配移動端,支持自定義攔截,添加影片頻道
// @author hua
// @match https://www.youtube.com/*
// @match https://m.youtube.com/*
// @match https://music.youtube.com/*
// @match https://www.youtubekids.com/*
// @exclude https://www.youtube.com/live_chat*
// @connect https://update.greasyfork.org/
// @grant unsafeWindow
// @grant GM_xmlhttpRequest
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_info
// @grant GM_addValueChangeListener
// @grant GM_removeValueChangeListener
// @grant GM_setClipboard
// @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @run-at document-start
// @license MIT
// ==/UserScript==
(function () {
if (unsafeWindow.injected_xxxxxxx) {
console.log('重复注入!');
return;
}
unsafeWindow.injected_xxxxxxx = true;
var open_config_keyword = '2333';
const display_error_keyword = '2444';
let channel_id = GM_getValue('last_channel_id', 'default');
const user_data_listener = get_user_data_listener();
const user_data_api = get_user_data_api();
let user_data = user_data_api.get();
let tmp_debugger_value;
let limit_eval = false;
let real_language = user_data.language;
let is_account_init;
const inject_info = {
"ytInitialPlayerResponse": false,
"ytInitialData": false,
"ytInitialReelWatchSequenceResponse": false,
"xhr": false,
"fetch": false
};
const origin_console = console;
const script_url = 'https://update.greasyfork.org/scripts/480192/youtube%E5%B9%BF%E5%91%8A%E6%8B%A6%E6%88%AA.user.js';
let href = location.href;
let ytInitialPlayerResponse_rule;
let ytInitialData_rule;
let ytInitialReelWatchSequenceResponse_rule;
let open_debugger = true;
let isinint = false;
let mobile_web;
let movie_channel_info;
let mobile_movie_channel_info;
let flag_info;
let debugger_ytInitialPlayerResponse;
let debugger_ytInitialData;
let debugger_ytInitialReelWatchSequenceResponse;
let debugger_music_initialData;
const error_messages = [];
let data_process = get_data_process();
let shorts_fun = get_shorts_fun();
let yt_api = get_yt_api();
const shorts_parse_delay = 500;
const browser_info = getBrowserInfo();
let page_type = get_page_type();
const config_api = get_config_api();
const SPLIT_TAG = '###';
let cur_watch_channle_id;
init();
function init() {
log('初始化开始!' + href, 0);
url_observer();
set_debugger();
is_account_init = false;
data_process.set_obj_filter(obj_process_filter);
try {
let test_eval;
eval('test_eval = 1');
limit_eval = test_eval !== 1;
} catch (error) {
limit_eval = true;
}
config_api.config_init(user_data.language);
const init_hook = init_hook_collection();
init_hook.property();
init_hook.other();
init_hook.request();
document.addEventListener('DOMContentLoaded', function () {
set_search_listen();
checke_update();
on_page_change();
});
isinint = true;
log('初始化结束!' + href, 0);
}
function init_hook_collection() {
return {
property() {
const already_inject = [];
let ytInitialPlayerResponse_value = unsafeWindow['ytInitialPlayerResponse'];
function process_property(name, value, rule, reverse = false) {
if (already_inject.includes(name)) {
log(`${name} 重复修改被拦截`, 0);
return value;
}
const start_time = Date.now();
if (typeof value === 'object') {
already_inject.push(name);
open_debugger && !limit_eval && !eval(`debugger_${name}`) && (eval(`debugger_${name} = JSON.parse(JSON.stringify(value))`));
rule && data_process.obj_process(value, rule, reverse);
}
if (typeof value === 'string') {
already_inject.push(name);
open_debugger && !limit_eval && !eval(`debugger_${name}`) && (eval(`debugger_${name} = JSON.parse(value)`));
value = data_process.text_process(value, rule, 'insert', reverse);
}
log(`${name} 时间:`, Date.now() - start_time, 'spend_time');
return value;
}
define_property_hook(unsafeWindow, 'ytInitialPlayerResponse', {
get: function () {
return ytInitialPlayerResponse_value;
},
set: function (value) {
inject_info.ytInitialPlayerResponse = true;
value = process_property('ytInitialPlayerResponse', value, config_api.common_ytInitialPlayerResponse_rule);
ytInitialPlayerResponse_value = value;
},
configurable: false
});
let ytInitialReelWatchSequenceResponse_value = unsafeWindow['ytInitialReelWatchSequenceResponse'];
define_property_hook(unsafeWindow, 'ytInitialReelWatchSequenceResponse', {
get: function () {
return ytInitialReelWatchSequenceResponse_value;
},
set: function (value) {
inject_info.ytInitialReelWatchSequenceResponse = true;
if (['yt_shorts', 'mobile_yt_shorts'].includes(page_type)) {
value = process_property('ytInitialReelWatchSequenceResponse', value,
config_api.get_rules(mobile_web ? 'yt_shorts_mobile' : 'yt_shorts').ytInitialReelWatchSequenceResponse_rule);
}
ytInitialReelWatchSequenceResponse_value = value;
},
configurable: false
});
let ytInitialData_value = unsafeWindow['ytInitialData'];
define_property_hook(unsafeWindow, 'ytInitialData', {
get: function () {
return ytInitialData_value;
},
set: function (value) {
inject_info.ytInitialData = true;
let rules = config_api.get_rules(page_type);
!['yt_watch', 'mobile_yt_watch', 'mobile_yt_watch_searching'].includes(page_type) && (rules = rules.ytInitialData_rule);
value = process_property('ytInitialData', value, rules);
ytInitialData_value = value;
},
configurable: false
});
const origin_ua = navigator.userAgent;
define_property_hook(navigator, 'userAgent', {
get: function () {
return (browser_info.isMobile || browser_info.name === 'Chrome') ? origin_ua : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36';
}
});
if (unsafeWindow.ytcfg) {
if (unsafeWindow.ytcfg.data_ && typeof (unsafeWindow.ytcfg.data_.LOGGED_IN) === 'boolean') {
account_data_init(unsafeWindow.ytcfg.data_.LOGGED_IN);
} else {
if (unsafeWindow.ytcfg.data_ && typeof unsafeWindow.ytcfg.data_ === 'object') {
define_property_hook(unsafeWindow.ytcfg.data_, 'LOGGED_IN', {
get: function () {
return unsafeWindow.ytcfg.data_.LOGGED_IN_;
},
set: function (value) {
unsafeWindow.ytcfg.data_.LOGGED_IN_ = value;
account_data_init(value);
}
});
}
}
if (!unsafeWindow.ytcfg.data_) {
if (unsafeWindow.yt?.config_) {
const config_ = unsafeWindow.yt.config_;
if (typeof (config_.LOGGED_IN) === 'boolean') {
account_data_init(config_.LOGGED_IN);
}
config_.HL && config_api.config_init(config_.HL);
}
} else {
if (unsafeWindow.ytcfg.data_?.HL) {
config_api.config_init(unsafeWindow.ytcfg.data_.HL);
} else {
if (unsafeWindow.ytcfg.msgs) {
unsafeWindow.ytcfg.msgs.__lang__ && config_api.config_init(unsafeWindow.ytcfg.msgs.__lang__);
} else {
unsafeWindow.ytcfg._msgs = unsafeWindow.ytcfg.msgs;
define_property_hook(unsafeWindow.ytcfg, 'msgs', {
get: function () {
return this._msgs;
},
set: function (newValue) {
if (newValue.__lang__) config_api.config_init(newValue.__lang__);
this._msgs = newValue;
}
});
}
}
}
} else {
define_property_hook(unsafeWindow, 'ytcfg', {
get: function () {
return this._ytcfg;
},
set: function (newValue) {
// 过滤 a = a || 1 这种
if (newValue === unsafeWindow.ytcfg) return;
if (newValue.set) {
const origin_set = newValue.set;
newValue.set = function () {
//hook ytmusic 的初始化数据 YTMUSIC_INITIAL_DATA
if (arguments?.[0].YTMUSIC_INITIAL_DATA) {
const yt_music_init_data = arguments[0].YTMUSIC_INITIAL_DATA;
if (yt_music_init_data?.length > 0) {
const browse_data = yt_music_init_data[1];
if (browse_data.path === '/browse') {
const rule = config_api.get_rules('yt_music').ytInitialData_rule;
browse_data.data = process_property('music_initialData', browse_data.data, rule);
}
}
}
origin_set.apply(this, arguments);
if (arguments[0] && typeof arguments[0].LOGGED_IN === 'boolean') {
account_data_init(arguments[0].LOGGED_IN);
}
if (arguments[0].HL) {
config_api.config_init(arguments[0].HL);
}
};
}
this._ytcfg = newValue;
}
});
}
},
other() {
const origin_createElement = document.createElement;
document.createElement = function () {
const node = origin_createElement.apply(this, arguments);
// if (arguments[0] === 'template') {
// let innerhtml_getter = Object.getOwnPropertyDescriptor(Element.prototype, "innerHTML").get;
// let innerhtml_setter = Object.getOwnPropertyDescriptor(Element.prototype, "innerHTML").set;
// define_property_hook(node, 'innerHTML', {
// get: function () {
// return innerhtml_getter.call(node);
// },
// set: function (value) {
// if (value.toString().includes('yt-mealbar-promo-renderer')) {
// log('弹窗去掉------->yt-mealbar-promo-renderer', 'node_process');
// value = '';
// }
// innerhtml_setter.call(node, value);
// }
// });
// }
if (arguments[0] === 'IFRAME') {
const contentWindow_getter = Object.getOwnPropertyDescriptor(HTMLIFrameElement.prototype, "contentWindow").get;
define_property_hook(node, 'contentWindow', {
get: function () {
const contentWindow = contentWindow_getter.call(node);
if (!contentWindow || this.src !== 'about:blank' || contentWindow.change_history) return contentWindow;
set_history_hook(contentWindow);
contentWindow.change_history = true;
return contentWindow;
}
});
}
return node;
};
document.createElement.toString = origin_createElement.toString.bind(origin_createElement);
},
request() {
async function deal_response(name, response, rule) {
if (!rule) return response;
let is_deal = false;
const responseClone = response.clone();
let result = await responseClone.text();
let origin_result = result;
if (name === 'subscribe' || name === 'unsubscribe') {
let match_list = result.match(/channelId":\"(.*?)"/);
const match_channel_id = match_list && match_list.length > 1 ? match_list[1] : '';
let channel_infos = user_data.channel_infos;
if (match_channel_id) {
if (name === 'unsubscribe') {
let index = channel_infos.ids.indexOf(match_channel_id);
if (index > -1) {
channel_infos.ids.splice(index, 1);
channel_infos.names.splice(index, 1);
}
} else {
channel_infos.ids.push(match_channel_id);
channel_infos.names.push('');
}
user_data.channel_infos = channel_infos;
user_data_api.set();
log(name, match_channel_id, 0);
}
is_deal = true;
}
if (name === 'playlist') {
let obj;
try {
obj = JSON.parse(result);
data_process.obj_process(obj.playerResponse, config_api.common_ytInitialPlayerResponse_rule, false);
data_process.obj_process(obj.response, config_api.get_rules('yt_watch', 'init'), false);
result = JSON.stringify(obj);
} catch (error) {
log('playlist 解析失败', error, -1);
result = origin_result;
}
is_deal = true;
}
if (!is_deal) {
let start_time = Date.now();
result = data_process.text_process(result, rule, 'insert', false);
log(name + ' 时间:', Date.now() - start_time, 'spend_time');
}
if (!result) {
result = origin_result;
debugger;
}
return new Response(result, response);
}
const origin_fetch = unsafeWindow.fetch;
if (origin_fetch.toString() !== 'function fetch() { [native code] }') {
log('fetch have been modified', -1);
}
unsafeWindow.fetch = function () {
const fetch_ = async function (uri, options) {
async function fetch_request(response) {
let url = response.url;
inject_info.fetch = true;
let request_body;
try {
request_body = uri.body_ ? JSON.parse(uri.body_) : null;
} catch (error) {
request_body = null;
}
if (url.includes('youtubei/v1/next')) {
const rule = config_api.get_rules(mobile_web ? 'mobile_yt_watch' : 'yt_watch', request_body?.videoId ? "init" : 'next');
return await deal_response('next', response, rule);
}
if (url.includes('youtubei/v1/player')) {
return await deal_response('player', response, config_api.common_ytInitialPlayerResponse_rule);
}
if (url.includes('youtubei/v1/reel/reel_watch_sequence')) {
const rule = config_api.get_rules(mobile_web ? 'mobile_yt_shorts' : 'yt_shorts').ytInitialReelWatchSequenceResponse_rule;
return await deal_response('reel_watch_sequence', response, rule);
}
if (url.includes('youtubei/v1/reel/reel_item_watch')) {
// shorts 内容
const rule = config_api.get_rules(mobile_web ? 'mobile_yt_shorts' : 'yt_shorts').ytInitialData_rule;
return await deal_response('reel_item_watch', response, rule);
}
if (url.includes('youtubei/v1/browse?prettyPrint=false')) {
let browse_id = request_body?.browseId;
let rule;
if (href.includes('https://music.youtube.com/')) {
rule = config_api.get_rules('yt_music', 'browse').ytInitialData_rule;
}
// 忽略音乐主页 影视主页
if (!rule && (['yt_home', 'mobile_yt_home'].includes(page_type) || browse_id === 'FEwhat_to_watch')) {
if (!browse_id) {
let node, category_text, node_list, node_index;
if (mobile_web) {
node = document.querySelector('#filter-chip-bar > div > ytm-chip-cloud-chip-renderer.selected');
node_list = document.querySelectorAll('#filter-chip-bar > div > ytm-chip-cloud-chip-renderer');
node_index = Array.from(node_list).indexOf(node);
if (node_index !== 1) return response;
} else {
node = document.querySelector('#chips > yt-chip-cloud-chip-renderer.style-scope.ytd-feed-filter-chip-bar-renderer.iron-selected');
node_list = document.querySelectorAll('#chips > yt-chip-cloud-chip-renderer.style-scope.ytd-feed-filter-chip-bar-renderer');
node_index = Array.from(node_list).indexOf(node);
if (node_index !== 0) return response;
}
}
rule = config_api.get_rules(mobile_web ? 'mobile_yt_home' : 'yt_home', request_body?.browseId ? 'init' : 'browse').ytInitialData_rule;
}
return await deal_response('browse', response, rule);
}
if (url.startsWith('https://www.youtube.com/playlist?list=')) {
return await deal_response('playlist', response, []);
}
// if (url.includes('https://m.youtube.com/youtubei/v1/guide')) {
// return response;
// }
if (url.includes('/youtubei/v1/search')) {
const rule = config_api.get_rules(mobile_web ? 'mobile_yt_search' : 'yt_search').ytInitialData_rule;
return await deal_response('search', response, rule);
}
if (url.includes('/unsubscribe?prettyPrint=false')) {
return await deal_response('unsubscribe', response, []);
}
if (url.includes('/subscribe?prettyPrint=false')) {
return await deal_response('subscribe', response, []);
}
return response;
}
return origin_fetch(uri, options).then(fetch_request);
};
return fetch_;
}();
const origin_Request = unsafeWindow.Request;
if (origin_Request.toString() !== 'function Request() { [native code] }') {
log('Request have been modified', -1);
}
unsafeWindow.Request = class extends unsafeWindow.Request {
constructor(input, options = void 0) {
super(input, options);
this.url_ = input;
if (options && 'body' in options) this['body_'] = options['body'];
}
};
unsafeWindow.XMLHttpRequest = class extends unsafeWindow.XMLHttpRequest {
open(method, url, ...opts) {
inject_info.xhr = true;
if (['mobile_yt_watch'].includes(page_type) && url.includes('m.youtube.com/watch?v')) {
log('xhr watch 返回空', 0);
return null;
}
if (['mobile_yt_home'].includes(page_type) && url.includes('m.youtube.com/?pbj')) {
log('xhr home 返回空', 0);
return null;
}
this.url_ = url;
return super.open(method, url, ...opts);
}
send(body) {
this.body_ = body;
super.send(body);
}
get xhrResponseValue() {
const xhr = this;
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
let result = super.response;
const url = xhr.responseURL;
const result_type = typeof result;
try {
if (url.includes('youtubei/v1/player')) {
// music_watch shorts
if (result_type !== 'string') throw new Error('response is not string');
result = data_process.text_process(result, config_api.common_ytInitialPlayerResponse_rule, 'insert', false);
return result;
}
if (url.includes('youtube.com/playlist')) {
debugger;
let obj;
obj = JSON.parse(result);
log(`出现 ${url} !`, 0);
data_process.obj_process(obj[2].playerResponse, ytInitialPlayerResponse_rule, false);
data_process.obj_process(obj[3].response, ytInitialData_rule, false);
tmp_debugger_value = obj;
result = JSON.stringify(obj);
return result;
}
} catch (error) {
log(`XHR ${url} 解析失败!`, error, -1);
}
}
return super.response;
}
get responseText() {
return this.xhrResponseValue;
}
get response() {
return this.xhrResponseValue;
}
};
}
};
}
function on_page_change() {
if (page_type === 'yt_shorts') {
shorts_fun.check_shorts_exist();
// 添加评论按钮关闭评论
let interval_count = 0;
const interval_id = setInterval(() => {
interval_count++;
if (interval_count > 10) {
clearInterval(interval_id);
return;
}
const video_node = document.querySelector('ytd-reel-video-renderer[is-active]');
if (!video_node) return;
if (!video_node.is_change_xx) {
clearInterval(interval_id);
video_node.is_change_xx = true;
const comments_node = video_node.querySelector('#comments-button > ytd-button-renderer > yt-button-shape > label > button');
const onclick_setter = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "onclick").set;
const wrap = function (fun) {
return function (event) {
const expand_node = video_node.querySelector('#watch-while-engagement-panel > ytd-engagement-panel-section-list-renderer:nth-child(1)');
if (expand_node?.visibility === 'ENGAGEMENT_PANEL_VISIBILITY_EXPANDED') {
const expand_close_node = video_node.querySelector('#visibility-button > ytd-button-renderer > yt-button-shape > button');
expand_close_node?.click();
} else {
fun.call(this, event);
}
};
};
comments_node.onclick = comments_node.onclick_ = wrap(comments_node.onclick);
define_property_hook(comments_node, 'onclick', {
get: function () {
return this.onclick_;
},
set: function (fun) {
this.onclick_ = wrap(fun);
onclick_setter.call(comments_node, this.onclick_);
}
});
}
}, 500);
}
}
function get_user_data_listener() {
return {
cur_channel_id: null,
listener_id: null,
set: function () {
if (channel_id === this.cur_channel_id) {
return;
};
!this.cur_channel_id && GM_removeValueChangeListener(this.listener_id);
this.cur_channel_id = channel_id;
this.listener_id = GM_addValueChangeListener(channel_id, (name, oldValue, newValue, remote) => {
if (!remote || this.cur_channel_id !== name) return;
newValue.language = user_data.language;
user_data = newValue;
config_api.config_init();
const popup_node = document.getElementById('xxx_popup');
popup_node && display_config_win();
});
}
};
}
async function account_data_init(login) {
if (is_account_init) return;
is_account_init = true;
if (login) {
yt_api.get_channel_id();
yt_api.get_subscribe_data();
} else if (channel_id !== 'default') {
channel_id = 'default';
user_data.login = false;
user_data = user_data_api.get();
}
}
function native_method_hook(method_path, handler) {
try {
let [last_path, last_key] = data_process.get_lastPath_and_key(method_path);
let last_obj = data_process.string_to_value(unsafeWindow, 'unsafeWindow.' + last_path);
let dec_obj = last_obj[last_key];
last_obj[last_key + '__'] = dec_obj;
if (typeof dec_obj !== 'function') {
log(method_path, 'have been modified', -1);
return;
}
const method_name = dec_obj.name;
if (dec_obj.toString() !== 'function ' + method_name + '() { [native code] }') {
log(method_path, 'have been modified!', -1);
}
last_obj[last_key] = handler;
} catch (error) {
log(method_path, 'hook failed!', error, -1);
}
}
function define_property_hook(obj, property, descriptor) {
const old_descriptor = Object.getOwnPropertyDescriptor(obj, property);
if (old_descriptor?.configurable === false) {
debugger;
log(property, 'is not configurable, hook error !', old_descriptor, -1);
return;
}
try {
Object.defineProperty(obj, property, descriptor);
} catch (error) {
log(property, 'hook failed!', error, -1);
}
}
function get_config_api() {
return {
flag_infos: {
"zh-CN": {
"sponsored": "赞助商广告",
"free_movie": "免费(含广告)",
"live": "直播",
"movie_channel": "影视",
"free_primetime_movie": "免费 Primetime 电影",
"Playables": "游戏大本营",
"short_buy_super_thanks": "购买超级感谢",
"think_video": "你对这个视频有何看法?|此推荐内容怎么样?",
"try": "试用",
"recommend_popular": "时下流行",
"featured": "Featured",
"category_live": "直播",
"category_game": "游戏",
"category_news": "新闻",
"btn_recommend_movie": "电影推荐",
"btn_recommend_shorts": "Shorts推荐",
"btn_recommend_liveroom": "直播推荐",
"btn_recommend_popular": "时下流行",
"btn_recommend_game": "游戏大本营推荐",
"btn_save": "保存",
"goodselect": "精选",
"music_ad_flag": "无广告打扰",
"upcoming": "即将开始",
"init": "初始化",
"ctoc": "已复制到剪贴板",
"runing_normally": "运行正常",
"err_msg": "错误信息",
"success": "成功",
"failed": "失败",
"tips": "你可以发送错误信息或者截图发给脚本开发者",
"exists_error": "存在错误信息(建议多次刷新观察是否是同样的错误信息)",
"inject": "注入",
"btn_lable_open": "开启",
"btn_lable_close": "关闭",
"btn_lable_subscribed": "仅订阅",
"recommend_subscribed_lable_tips": "只显示已订阅的推荐",
"title_add_shorts_upload_date": "Shorts添加更新时间",
"title_shorts_change_author_name": "Shorts用户名改频道名",
"config_info": "配置信息",
"page_info": "页面信息",
"rule_info": "规则信息",
},
"zh-TW": {
"sponsored": "贊助商廣告",
"free_movie": "免費 \\(含廣告\\)",
"live": "直播",
"movie_channel": "電影與電視節目",
"Playables": "遊戲角落",
"free_primetime_movie": "免費的特選電影",
"short_buy_super_thanks": "購買超級感謝",
"think_video": "你對這部影片有什麼看法?|此推荐内容怎么样?",
"try": "試用",
"recommend_popular": "發燒影片",
"featured": "Featured",
"category_live": "直播中",
"category_game": "遊戲",
"category_news": "新聞",
"btn_recommend_movie": "电影推薦",
"btn_recommend_shorts": "Shorts推薦",
"btn_recommend_liveroom": "直播推薦",
"btn_recommend_popular": "發燒影片",
"btn_recommend_game": "遊戲角落推薦",
"btn_save": "保存",
"goodselect": "精選內容",
"music_ad_flag": "零廣告",
"upcoming": "即将直播",
"init": "初始化",
"ctoc": "已複製到剪貼板",
"runing_normally": "運行正常",
"err_msg": "錯誤訊息",
"success": "成功",
"failed": "失敗",
"tips": "你可以发送錯誤訊息或截圖給腳本開發者",
"exists_error": "存在錯誤訊息(建議多次刷新觀察是否是同樣的錯誤訊息)",
"inject": "注入",
"btn_lable_open": "開啓",
"btn_lable_close": "關閉",
"btn_lable_subscribed": "僅訂閱",
"recommend_subscribed_lable_tips": "只顯示已訂閱的推薦",
"title_add_shorts_upload_date": "Shorts添加更新時間",
"title_shorts_change_author_name": "Shorts用戶名稱改頻道名",
"config_info": "設定資訊",
"page_info": "頁面資訊",
"rule_info": "規則資訊",
},
"zh-HK": {
"sponsored": "赞助",
"free_movie": "免費 \\(有廣告\\)",
"live": "直播",
"movie_channel": "電影與電視節目",
"Playables": "Playables",
"short_buy_super_thanks": "購買 Super Thanks",
"free_primetime_movie": "黃金時段電影",
"think_video": "你對此影片有何意見?|此推荐内容怎么样?",
"try": "試用",
"recommend_popular": "熱爆影片",
"featured": "Featured",
"category_live": "直播",
"category_game": "遊戲",
"category_news": "新聞",
"btn_recommend_movie": "电影推薦",
"btn_recommend_shorts": "Shorts推薦",
"btn_recommend_liveroom": "直播推薦",
"btn_recommend_popular": "熱爆影片",
"btn_recommend_game": "Playables推荐",
"btn_save": "保存",
"goodselect": "精選",
"music_ad_flag": "零廣告音樂",
"upcoming": "即將發佈",
"init": "初始化",
"ctoc": "已複製到剪貼板",
"runing_normally": "運行正常",
"err_msg": "錯誤訊息",
"success": "成功",
"failed": "失敗",
"tips": "你可以发送錯誤訊息或截圖給腳本開發者",
"exists_error": "存在錯誤訊息(建議多次刷新觀察是否是同樣的錯誤訊息)",
"inject": "注入",
"btn_lable_open": "開啓",
"btn_lable_close": "關閉",
"btn_lable_subscribed": "僅訂閱",
"recommend_subscribed_lable_tips": "只顯示已訂閱的推薦",
"title_add_shorts_upload_date": "Shorts添加更新時間",
"title_shorts_change_author_name": "Shorts用戶名稱改頻道名",
"config_info": "設定資訊",
"page_info": "頁面資訊",
"rule_info": "規則資訊",
},
"en": {
"sponsored": "Sponsored",
"free_movie": "Free with ads",
"live": "LIVE",
"movie_channel": "Movies & TV",
"Playables": "Playables",
"short_buy_super_thanks": "Buy Super Thanks",
"free_primetime_movie": "Free Primetime movies",
"think_video": "What did you think of this video?|此推荐内容怎么样?",
"try": "Try",
"recommend_popular": "Trending",
"featured": "Featured",
"category_live": "Live",
"category_game": "Gaming",
"category_news": "News",
"btn_recommend_movie": "MovieRecommend",
"btn_recommend_shorts": "ShortsRecommend",
"btn_recommend_liveroom": "LiveRecommend",
"btn_recommend_popular": "TrendingRecommend",
"btn_recommend_game": "PlayablesRecommend",
"btn_save": "Save",
"goodselect": "Featured",
"music_ad_flag": "ad-free",
"upcoming": "UPCOMING",
"init": "init",
"ctoc": "Copied to clipboard",
"runing_normally": "running normally",
"err_msg": "error message",
"success": "success",
"failed": "failed",
"tips": "You can send error message or screenshot to the developer",
"exists_error": "Error message exists (It is recommended to refresh multiple times to see if it is the same error message)",
"inject": "inject",
"btn_lable_open": "on",
"btn_lable_close": "off",
"btn_lable_subscribed": "onlySubscribed",
"recommend_subscribed_lable_tips": "only show subscribed recommend",
"title_add_shorts_upload_date": "ShortsAddUploadTime",
"title_shorts_change_author_name": "ShortsChangeToChannelName",
"config_info": "config info",
"page_info": "page info",
"rule_info": "rule info",
}
},
common_ytInitialPlayerResponse_rule: [
"abs:playerAds=- $exist",
"abs:adPlacements=- $exist",
"abs:adBreakHeartbeatParams=- $exist",
"abs:adSlots=- $exist",
"abs:streamingData.serverAbrStreamingUrl=- $exist",
],
default_language: 'en',
config_init: function (tmp_language = null) {
if (!tmp_language) {
tmp_language = unsafeWindow['ytcfg'].msgs ? unsafeWindow['ytcfg'].msgs.__lang__ : (unsafeWindow['ytcfg'].data ? unsafeWindow['ytcfg'].data.HL : undefined);
!tmp_language && (tmp_language = unsafeWindow['yt'] && unsafeWindow['yt'].config_ && unsafeWindow['yt'].config_.HL);
if (!tmp_language) {
log('语言获取错误', unsafeWindow, -1);
}
}
if (!['en', 'zh-CN', 'zh-TW', 'zh-HK'].includes(tmp_language)) {
real_language = tmp_language;
tmp_language = this.default_language;
}
if (tmp_language !== user_data.language) {
user_data.language = tmp_language;
user_data_api.set();
}
flag_info = this.flag_infos[user_data.language];
movie_channel_info = {
"guideEntryRenderer": {
"navigationEndpoint": {
"clickTrackingParams": "CBQQnOQDGAIiEwj5l8SLqPiCAxUXSEwIHbf1Dw0=",
"commandMetadata": {
"webCommandMetadata": {
"url": "/feed/storefront",
"webPageType": "WEB_PAGE_TYPE_BROWSE",
"rootVe": 6827,
"apiUrl": "/youtubei/v1/browse"
}
},
"browseEndpoint": {
"browseId": "FEstorefront"
}
},
"icon": {
"iconType": "CLAPPERBOARD"
},
"trackingParams": "CBQQnOQDGAIiEwj5l8SLqPiCAxUXSEwIHbf1Dw0=",
"formattedTitle": {
"simpleText": flag_info.movie_channel
},
"accessibility": {
"accessibilityData": {
"label": flag_info.movie_channel
}
}
}
};
unsafeWindow.movie_channel_info = movie_channel_info;
mobile_movie_channel_info = {
"navigationItemViewModel": {
"text": {
"content": flag_info.movie_channel
},
"icon": {
"sources": [
{
"clientResource": {
"imageName": "CLAPPERBOARD"
}
}
]
},
"onTap": {
"parallelCommand": {
"commands": [
{
"innertubeCommand": {
"clickTrackingParams": "CBQQnOQDGAIiEwj5l8SLqPiCAxUXSEwIHbf1Dw0=",
"hideMoreDrawerCommand": {}
}
},
{
"innertubeCommand": {
"clickTrackingParams": "CBQQnOQDGAIiEwj5l8SLqPiCAxUXSEwIHbf1Dw0=",
"commandMetadata": {
"webCommandMetadata": {
"url": "/feed/storefront",
"webPageType": "WEB_PAGE_TYPE_CHANNEL",
"rootVe": 3611,
"apiUrl": "/youtubei/v1/browse"
}
},
"browseEndpoint": {
"browseId": "FEstorefront"
}
}
}
]
}
},
"loggingDirectives": {
"trackingParams": "CBQQnOQDGAIiEwj5l8SLqPiCAxUXSEwIHbf1Dw0=",
"visibility": {
"types": "12"
},
"enableDisplayloggerExperiment": true
}
}
};
unsafeWindow.mobile_movie_channel_info = mobile_movie_channel_info;
ytInitialData_rule = null;
ytInitialReelWatchSequenceResponse_rule = null;
ytInitialPlayerResponse_rule = null;
mobile_web = page_type.startsWith('mobile');
},
get_rules: function (page_type_, type) {
page_type_ = page_type_ || page_type;
if (page_type_ === 'mobile_yt_watch_searching')
page_type_ = 'mobile_yt_watch';
else if (page_type_ === 'mobile_yt_home_searching')
page_type_ = 'mobile_yt_home';
else if (page_type_ === 'yt_music_channel')
page_type_ = 'yt_watch';
let tmp_ytInitialData_rule = null;
let tmp_ytInitialReelWatchSequenceResponse_rule = null;
let tmp_ytInitialPlayerResponse_rule = null;
const common_ytInitialData_rule = [
'adSlotRenderer.=-',
];
const return_obj = {
ytInitialData_rule: null,
ytInitialReelWatchSequenceResponse_rule: null,
ytInitialPlayerResponse_rule: null,
reverse: false,
};
if (page_type_ === 'yt_search') {
tmp_ytInitialData_rule = common_ytInitialData_rule;
return_obj.ytInitialData_rule = tmp_ytInitialData_rule;
return return_obj;
}
if (page_type_ === 'yt_music') {
return_obj.ytInitialData_rule = ["abs:overlay.mealbarPromoRenderer=- $exist"];
return return_obj;
}
if (page_type_ === 'mobile_yt_search') {
tmp_ytInitialData_rule = common_ytInitialData_rule;
return_obj.ytInitialData_rule = tmp_ytInitialData_rule;
return return_obj;
}
if (page_type_ === 'yt_kids_watch') {
tmp_ytInitialData_rule = common_ytInitialData_rule;
return_obj.ytInitialData_rule = tmp_ytInitialData_rule;
return return_obj;
}
if (page_type_ === 'yt_music_watch') {
tmp_ytInitialData_rule = common_ytInitialData_rule;
return_obj.ytInitialData_rule = tmp_ytInitialData_rule;
return return_obj;
}
if (page_type_.includes('yt_shorts')) {
const tmp_ytInitialData_rule__ = [];
// 添加时间 // 改频道名
if (user_data.add_shorts_upload_date === 'on' || user_data.shorts_change_author_name === 'on') {
let dec_path = 'overlay.reelPlayerOverlayRenderer.reelPlayerHeaderSupportedRenderers.reelPlayerHeaderRenderer.channelTitleText.runs[0].text';
let name_base_path = 'json_obj.engagementPanels[1].engagementPanelSectionListRenderer.content.structuredDescriptionContentRenderer.items[0].videoDescriptionHeaderRenderer.channel.';
let time_tag_path;
let name_tag_path;
if (mobile_web) {
user_data.add_shorts_upload_date === 'on' && (time_tag_path = '....timestampText.runs[0].text');
user_data.shorts_change_author_name === 'on' && (name_tag_path = name_base_path + 'runs[0].text');
} else {
user_data.add_shorts_upload_date === 'on' && (time_tag_path = '....timestampText.simpleText');
user_data.shorts_change_author_name === 'on' && (name_tag_path = name_base_path + 'simpleText');
}
let rule = `abs:${dec_path}={absObj(${name_tag_path ? name_tag_path : ('json_obj.' + dec_path)})\}${time_tag_path ? ('\n{pathObj(' + time_tag_path + ')\}') : ''}`;
tmp_ytInitialData_rule__.push(rule);
}
// 超级感谢
if (user_data.short_buy_super_thanks === 'off') {
// !mobile_web && tmp_ytInitialData_rule__.push('abs:overlay.reelPlayerOverlayRenderer.suggestedAction=- /.shortsSuggestedActionRenderer.text.runs[0].text=' + flag_info.short_buy_super_thanks);
!mobile_web && tmp_ytInitialData_rule__.push('abs:overlay.reelPlayerOverlayRenderer.suggestedAction=- $exist');
}
tmp_ytInitialReelWatchSequenceResponse_rule = ['abs:entries[*]=- /.command.reelWatchEndpoint.adClientParams$exist'];
tmp_ytInitialData_rule__.length && (tmp_ytInitialData_rule = tmp_ytInitialData_rule__);
return_obj.ytInitialReelWatchSequenceResponse_rule = tmp_ytInitialReelWatchSequenceResponse_rule;
return_obj.ytInitialData_rule = tmp_ytInitialData_rule;
return return_obj;
}
if (page_type_.includes('yt_watch')) {
return function (json_obj) {
/*
item_path
next 类型
移动端和桌面端
abs:onResponseReceivedActions[0].appendContinuationItemsAction.continuationItems[*]
init 类型
移动端
abs:contents.singleColumnWatchNextResults.results.results.contents[*]
桌面端
abs:contents.twoColumnWatchNextResults.secondaryResults.secondaryResults.results[1].itemSectionRenderer.contents[*]
videoRenderer_path
桌面端
/.compactVideoRenderer
移动端
/.itemSectionRenderer.contents[0].videoWithContexteRnderer
section_path
桌面端
/.reelShelfRenderer
移动端
/.itemSectionRenderer.contents[0].reelShelfRenderer
*/
if (json_obj.continuation) return [];
let video_item_base_path;
let video_sub_path;
let section_sub_path;
let player_bottom_path;
let player_bottom_section_path;
type = type || 'init';
if (type === 'next') {
if (json_obj.onResponseReceivedEndpoints?.[0]?.appendContinuationItemsAction?.continuationItems?.length) {
let target_id = json_obj.onResponseReceivedEndpoints[0].appendContinuationItemsAction.targetId;
if (target_id.startsWith('comment-replies')) return [];
// 下拉item刷新
video_item_base_path = "abs:onResponseReceivedEndpoints[0].appendContinuationItemsAction.continuationItems[*]";
video_sub_path = '/.videoWithContextRenderer';
section_sub_path = '/.reelShelfRenderer';
}
} else if (type === 'init') {
if (mobile_web) {
if (json_obj.contents?.singleColumnWatchNextResults?.results?.results?.contents?.length) {
let length = json_obj.contents.singleColumnWatchNextResults.results.results.contents.length;
video_item_base_path = `abs:contents.singleColumnWatchNextResults.results.results.contents[${length - 1}].itemSectionRenderer.contents[*]`;
length > 1 && (player_bottom_path = `abs:contents.singleColumnWatchNextResults.results.results.contents[0-${length - 2}]`);
cur_watch_channle_id = json_obj.contents.singleColumnWatchNextResults.results.results.contents?.[1]?.slimVideoMetadataSectionRenderer?.contents?.[1]?.slimOwnerRenderer?.title.runs[0].navigationEndpoint.browseEndpoint.browseId;
player_bottom_section_path = '/.itemSectionRenderer.contents[0].reelShelfRenderer';
video_sub_path = '/.videoWithContextRenderer';
section_sub_path = '/.reelShelfRenderer';
}
}
else {
let is_next_target_id;
if (json_obj.contents?.twoColumnWatchNextResults?.secondaryResults?.secondaryResults?.results?.[1]?.itemSectionRenderer?.contents?.length) {
video_item_base_path = "abs:contents.twoColumnWatchNextResults.secondaryResults.secondaryResults.results[1].itemSectionRenderer.contents[*]";
player_bottom_path = 'abs:contents.twoColumnWatchNextResults.results.results.contents[*]';
is_next_target_id = json_obj.contents.twoColumnWatchNextResults.secondaryResults.secondaryResults.results[1].itemSectionRenderer.targetId === 'watch-next-feed';
cur_watch_channle_id = json_obj.contents.twoColumnWatchNextResults.results.results.contents?.[1]?.videoSecondaryInfoRenderer?.owner?.videoOwnerRenderer?.title.runs[0].navigationEndpoint.browseEndpoint.browseId;
player_bottom_section_path = '/.itemSectionRenderer.contents[0]';
video_sub_path = '/.compactVideoRenderer';
section_sub_path = '/.reelShelfRenderer';
}
if (!is_next_target_id && json_obj.contents?.twoColumnWatchNextResults?.secondaryResults?.secondaryResults?.results?.length) {
video_item_base_path = 'abs:contents.twoColumnWatchNextResults.secondaryResults.secondaryResults.results[*]';
player_bottom_path = 'abs:contents.twoColumnWatchNextResults.results.results.contents[*]';
cur_watch_channle_id = json_obj.contents.twoColumnWatchNextResults.results.results.contents?.[1]?.videoSecondaryInfoRenderer?.owner?.videoOwnerRenderer?.title.runs[0].navigationEndpoint.browseEndpoint.browseId;
player_bottom_section_path = '/.itemSectionRenderer.contents[0]';
video_sub_path = '/.compactVideoRenderer';
section_sub_path = '/.reelShelfRenderer';
}
}
}
if (!video_item_base_path) return [];
const rules = [];
let video_item_rules = [];
let section_item_rules = [];
let player_bottom_section_rules = [];
let player_bottom_rules = [];
//赞助商广告
mobile_web && type === 'init' && player_bottom_rules.push(`${player_bottom_section_path.replace(/\.[^\.]+$/, '')}.adSlotRenderer$exist`);
video_item_rules.push(`${video_sub_path.replace(/\.[^\.]+$/, '.adSlotRenderer$exist')}`);
// youtuber商品广告 https://www.youtube.com/watch?v=dFjXK8xpurY&list=RDCLAK5uy_mijutvVbzp7bbNlWt-B5U90qb5KplCkSQ&index=3
!mobile_web && type === 'init' && player_bottom_rules.push(`/.merchandiseShelfRenderer$exist`);
//免费电影
if (user_data.open_recommend_movie === 'off' && cur_watch_channle_id !== 'UClgRkhTL3_hImCAmdLfDE4g') {
if (mobile_web) {
video_item_rules.push(`${video_sub_path}.badges[0].metadataBadgeRenderer.style=BADGE_STYLE_TYPE_YPC`);
} else {
video_item_rules.push(`${video_sub_path.replace(/\.[^\.]+$/, '.compactMovieRenderer')}$exist`);
}
}
//直播规则
if (['off', 'subscribed'].includes(user_data.open_recommend_liveroom)) {
if (mobile_web)
video_item_rules.push(`${video_sub_path}.thumbnailOverlays[0].thumbnailOverlayTimeStatusRenderer.style=LIVE|UPCOMING`);
else
video_item_rules.push(`${video_sub_path}.badges[0].metadataBadgeRenderer.style=BADGE_STYLE_TYPE_LIVE_NOW`);
}
// 添加已订阅短视频
if (user_data.open_recommend_shorts === 'subscribed' && type === 'init' && page_type !== 'mobile_yt_watch') {
rules.push(`${video_item_base_path.replace('[*]', '')}=+(arr_insert,method(shorts_fun.get_shorts_section()),0) @user_data.shorts_list.length$value>0`);
}
// 大标题栏目 短视频等
if (['off', 'subscribed'].includes(user_data.open_recommend_shorts)) {
section_item_rules.push(`${section_sub_path}.icon.iconType=YOUTUBE_SHORTS_BRAND_24`);
mobile_web && type === 'init' && player_bottom_rules.push(`${player_bottom_section_path}.icon.iconType=YOUTUBE_SHORTS_BRAND_24`);
}
// 视频下方可能会出现的推荐栏目
player_bottom_rules.length && rules.push(`${player_bottom_path}=- ${player_bottom_rules.join(data_process.condition_split_or_tag)}`);
section_item_rules.length && video_item_rules.push(...section_item_rules);
video_item_rules.length && rules.push(`${video_item_base_path}=- ${video_item_rules.join(data_process.condition_split_or_tag)}`);
return rules;
};
}
if (page_type_.includes('yt_home')) {
/*
item_path
browse 类型
移动端和桌面端
abs:onResponseReceivedActions[0].appendContinuationItemsAction.continuationItems[*]
init 类型
移动端
abs:contents.singleColumnBrowseResultsRenderer.tabs[0].tabRenderer.content.richGridRenderer.contents[*]
桌面端
singleColumnBrowseResultsRenderer ---> twoColumnBrowseResultsRenderer
videoRenderer_path
桌面端
/.richItemRenderer.content.videoRenderer
移动端
videoRenderer --> videoWithContextRenderer
richSectionRenderer_path
桌面端
/.richSectionRenderer.content.richShelfRenderer
移动端
richShelfRenderer ---> reelShelfRenderer
*/
let item_path;
let item_rules = [];
let rules = [];
type = type || 'init';
if (type === 'browse') {
item_path = "abs:onResponseReceivedActions[0].appendContinuationItemsAction.continuationItems[*]";
} else if (type === 'init') {
item_path = `abs:contents.${mobile_web ? 'singleColumnBrowseResultsRenderer' : 'twoColumnBrowseResultsRenderer'}.tabs[0].tabRenderer.content.richGridRenderer.contents[*]`;
} else {
return {};
}
const video_path = `/.richItemRenderer.content.${mobile_web ? 'videoWithContextRenderer' : 'videoRenderer'}`;
const section_path = `/.richSectionRenderer.content.${mobile_web ? 'reelShelfRenderer' : 'richShelfRenderer'}`;
//赞助商广告
item_rules.push('/.richItemRenderer.content.adSlotRenderer$exist');
//头部第一个广告
!mobile_web && type === 'init' && rules.push('abs:contents.twoColumnBrowseResultsRenderer.tabs[0].tabRenderer.content.richGridRenderer.masthead=- $exist');
// Shorts
if (['off', 'subscribed'].includes(user_data.open_recommend_shorts)) {
item_rules.push(`${section_path}.icon.iconType=YOUTUBE_SHORTS_BRAND_24`);
}
// 时下流行
if (user_data.open_recommend_popular === 'off') {
item_rules.push(`${section_path}.endpoint.browseEndpoint.browseId=FEtrending`);
}
// playables
if (user_data.open_recommend_playables === 'off') {
item_rules.push('/.richSectionRenderer.content.richShelfRenderer.endpoint.browseEndpoint.browseId=FEmini_app_destination');
}
// 添加已订阅短视频
if (user_data.open_recommend_shorts === 'subscribed' && type === 'init') {
rules.push(item_path.replace('[*]', '') + '=+(arr_insert,method(shorts_fun.get_shorts_section()),0) @user_data.shorts_list.length$value>0');
}
//直播
if (['off', 'subscribed'].includes(user_data.open_recommend_liveroom)) {
!mobile_web && item_rules.push(`${video_path}.badges[0].metadataBadgeRenderer.style=BADGE_STYLE_TYPE_LIVE_NOW`);
const tag_express = `UPCOMING${mobile_web ? data_process.value_split_or_tag + "LIVE" : ''}`;
item_rules.push(`${video_path}.thumbnailOverlays[-1].thumbnailOverlayTimeStatusRenderer.style=${tag_express}`);
}
//免费电影
if (user_data.open_recommend_movie === 'off') {
item_rules.push(`${section_path}.endpoint.browseEndpoint.browseId=FEstorefront|UClgRkhTL3_hImCAmdLfDE4g`);
item_rules.push(`${video_path}.badges[0].metadataBadgeRenderer.style=BADGE_STYLE_TYPE_YPC`);
}
//电视好物
item_rules.push('/.richSectionRenderer.content.statementBannerRenderer$exist');
// youtube调查弹窗
rules.push('abs:survey=- $exist');
//调查
item_rules.push(section_path.replace(/\.[^\.]+$/, '.inlineSurveyRenderer$exist'));
// primetime
item_rules.push(section_path.replace(/\.[^\.]+$/, '.primetimePromoRenderer$exist'));
//添加电影频道
const add_movie_channel_rule = "loadingStrategy.inlineContent.moreDrawerViewModel.content=+obj(" + (mobile_web ? "mobile_" : "") + "movie_channel_info) !~=" + flag_info.movie_channel;
rules.push(add_movie_channel_rule);
rules.push(`${item_path}=- ${item_rules.join(data_process.condition_split_or_tag)}`);
return_obj.ytInitialData_rule = rules;
return return_obj;
}
return return_obj;
}
};
}
function set_search_listen() {
let count = 0;
const interval_id = setInterval(() => {
if (!['yt_watch', 'yt_home', 'mobile_yt_home_searching', 'mobile_yt_watch_searching', 'yt_shorts'].includes(page_type)) {
clearInterval(interval_id);
return;
}
count++;
const search_selector = href.includes('https://m.youtube.com/') ? 'input.searchbox-input.title' : 'input[id="search"]';
const search_input_node = document.querySelector(search_selector);
if (search_input_node) {
clearInterval(interval_id);
if (search_input_node.set_listener) return;
search_input_node.set_listener = true;
search_input_node.oninput = function (event) {
if (open_config_keyword === this.value || this.value === display_error_keyword) {
setTimeout(function () {
if (search_input_node.value === open_config_keyword) {
search_input_node.value = '';
display_config_win();
}
if (search_input_node.value === display_error_keyword) {
search_input_node.value = '';
let tips = `script ${flag_info.init} ${isinint ? flag_info.success : flag_info.failed}`;
if (error_messages.length === 0 && isinint) tips += ' ' + flag_info.runing_normally;
for (let key of Object.keys(inject_info)) {
if (!mobile_web && key === 'ytInitialPlayerResponse') continue;
if (key === 'ytInitialReelWatchSequenceResponse' && !['yt_shorts', 'mobile_yt_shorts'].includes(page_type)) continue;
tips += `\n${key} ${flag_info.inject} ${inject_info[key] ? flag_info.success : flag_info.failed}`;
}
// 配置信息
const tmp_user_data = JSON.parse(JSON.stringify(user_data));
delete tmp_user_data.shorts_list;
delete tmp_user_data.channel_infos;
tips += `\n\n${flag_info.config_info}\n${JSON.stringify(tmp_user_data, null, 2)}\n\n${flag_info.page_info}\npage_type: ${page_type}\nhref: ${href}`;
// 规则信息
tips += `\n\n${flag_info.rule_info}\nytInitialData_rule: \n${ytInitialData_rule && ytInitialData_rule.join('\n')}\n\nytInitialPlayerResponse_rule: \n${ytInitialPlayerResponse_rule && ytInitialPlayerResponse_rule.join('\n')}
\n\nytInitialReelWatchSequenceResponse_rule: \n${ytInitialReelWatchSequenceResponse_rule && ytInitialReelWatchSequenceResponse_rule.join('\n')}`;
if (error_messages.length !== 0) {
tips += `\n\n${flag_info.exists_error}\n-----------${flag_info.err_msg}(${flag_info.ctoc})-----------------\n${error_messages.join('\n')}\n\n${flag_info.tips}`;
}
alert(tips);
copyToClipboard(tips);
}
}, 500);
}
};
} else if (count > 50) {
clearInterval(interval_id);
log('搜索框未找到', -1);
}
}, 200);
}
function getCookie(cookieName) {
const name = cookieName + "=";
let decodedCookie;
try {
decodedCookie = decodeURIComponent(document.cookie);
} catch (error) {
log('cookie decode error', error, -1);
return null;
}
const cookieArray = decodedCookie.split(';');
for (let i = 0; i < cookieArray.length; i++) {
const cookie = cookieArray[i].trim();
if (cookie.startsWith(name)) {
return cookie.substring(name.length, cookie.length);
}
}
return null;
}
function copyToClipboard(text) {
GM_setClipboard(text, "text");
// if (navigator.clipboard?.writeText) return navigator.clipboard.writeText(text);
// const textarea = document.createElement("textarea");
// textarea.value = text;
// document.body.appendChild(textarea);
// textarea.select();
// document.execCommand('copy');
// document.body.removeChild(textarea);
}
function set_history_hook(window_obj) {
const wrap = function (type) {
const origin = window_obj.history[type];
return function () {
let rv;
try {
rv = origin.apply(this, arguments);
} catch (error) {
log('history hook error', error, 0);
return;
}
let url = arguments[2] || location.href;
url.startsWith('/') && (url = location.origin + url);
!url.startsWith('http') && (url = location.origin + '/' + url);
url_change(url);
return rv;
};
};
window_obj.history.pushState = wrap('pushState');
window_obj.history.replaceState = wrap('replaceState');
}
function url_observer() {
// if (unsafeWindow.navigation) {
// unsafeWindow.navigation.addEventListener('navigate', (event) => {
// url_change(event);
// });
// return;
// }
set_history_hook(unsafeWindow);
unsafeWindow.addEventListener('popstate', function (event) {
url_change(event);
});
unsafeWindow.addEventListener('hashchange', function (event) {
url_change(event);
});
}
function url_change(event = null) {
let destination_url;
if (typeof (event) === 'object')
destination_url = event?.destination?.url || '';
else
destination_url = event;
if (destination_url.startsWith('about:blank')) return;
if (destination_url === href) return;
href = destination_url || location.href;
log('网页url改变 href -> ' + href, 0);
const tmp_page_type = get_page_type();
if (tmp_page_type !== page_type) {
page_type = tmp_page_type;
config_api.config_init();
set_search_listen();
}
on_page_change();
}
function get_page_type(url = href) {
if (!url) return 'other';
url.startsWith('/') && (url = location.origin + url);
const base_url = url.split('?')[0];
let tmp_page_type;
if (base_url.match('https://www.youtube.com/?$')) tmp_page_type = 'yt_home';
else if (base_url.match('https://m.youtube.com/?#?$')) tmp_page_type = 'mobile_yt_home';
else if (base_url.match('https://www.youtube.com/watch$')) tmp_page_type = 'yt_watch';
else if (base_url.match('https://m.youtube.com/watch$')) tmp_page_type = 'mobile_yt_watch';
else if (base_url.match('https://www.youtube.com/results$')) tmp_page_type = 'yt_search';
else if (base_url.match('https://m.youtube.com/results$')) tmp_page_type = 'mobile_yt_search';
else if (base_url.startsWith('https://www.youtube.com/shorts')) tmp_page_type = 'yt_shorts';
else if (base_url.startsWith('https://m.youtube.com/shorts')) tmp_page_type = 'mobile_yt_shorts';
else if (base_url.match('https://www.youtubekids.com/watch$')) tmp_page_type = 'yt_kids_watch';
else if (base_url.match('https://music.youtube.com/?$')) tmp_page_type = 'yt_music_home';
else if (base_url.match('https://music.youtube.com/watch$')) tmp_page_type = 'yt_music_watch';
else if (base_url.match('https://m.youtube.com/#searching$')) tmp_page_type = 'mobile_yt_home_searching';
else if (base_url.startsWith('https://www.youtube.com/playlist')) tmp_page_type = 'yt_watch_playlist';
else if (base_url.includes('channel/UC-9-kyTW8ZkZNDHQJ6FgpwQ')) tmp_page_type = 'yt_music_channel';
else tmp_page_type = 'other';
if (tmp_page_type === 'mobile_yt_watch' && href.endsWith('#searching')) tmp_page_type = 'mobile_yt_watch_searching';
return tmp_page_type;
}
function set_debugger() {
const debugger_config_info = {
'ytInitialPlayerResponse': debugger_ytInitialPlayerResponse,
'ytInitialData': debugger_ytInitialData,
'ytInitialReelWatchSequenceResponse': debugger_ytInitialReelWatchSequenceResponse,
'music_initialData': debugger_music_initialData,
'inject_info': inject_info,
'info': [
'ytInitialData_rule',
'ytInitialPlayerResponse_rule',
'is_account_init',
'user_data',
'mobile_web',
'page_type',
'tmp_debugger_value',
],
};
unsafeWindow.debugger_ = function (action = null) {
const keys = Object.keys(debugger_config_info);
if (!action && action !== 0) { debugger; return; }
if (action === 'ytInitialPlayerResponse') log('ytInitialPlayerResponse', debugger_ytInitialPlayerResponse, 0);
if (action === 'ytInitialData') log('ytInitialData', debugger_ytInitialData, 0);
if (action === 'inject_info') log('inject_info', inject_info, 0);
if (action === 'info') {
if (limit_eval) {
log('eval限制使用了', 0);
} else {
for (let key of debugger_config_info['info']) {
log(key, eval(key), 0);
}
}
return;
}
if (action === 'list') {
keys.forEach(function (key, index) {
log(index, key, 0);
});
}
if (typeof (action) === 'number') {
if (action < keys.length) {
unsafeWindow.debugger_(keys[action]);
} else if (action >= keys.length) {
keys.forEach(function (key) {
unsafeWindow.debugger_(key);
});
}
}
};
}
function log() {
const arguments_arr = [...arguments];
const flag = arguments_arr.pop();
if (flag === -1) {
error_messages.push(arguments_arr.join(' '));
}
if (flag === 999) arguments_arr.unshift('-----test---test-----');
if (flag !== 0 && flag !== 999) arguments_arr.push(getCodeLocation());
if (flag === 0 || flag === 999) {
const array_length = arguments_arr.length;
const color = flag === 0 ? 'orange' : 'blue';
const css_str = `color: ${color};font-size: 20px`;
for (let i = 0; i < array_length; i++) {
if (typeof (arguments_arr[i]) === 'string') {
arguments_arr[i] = '%c' + arguments_arr[i];
i === (array_length - 1) ? arguments_arr.push(css_str) : (arguments_arr.splice(i + 1, 0, css_str));
break;
}
}
}
if (flag === 0 || open_debugger) flag === -1 ? origin_console.error(...arguments_arr) : origin_console.log(...arguments_arr);
}
function getBrowserInfo() {
const userAgent = navigator.userAgent;
let browserName;
let browserVersion;
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);
if (userAgent.indexOf("Firefox") > -1) {
browserName = "Firefox";
browserVersion = userAgent.match(/Firefox\/([0-9.]+)/)[1];
} else if (userAgent.indexOf("OPR") > -1 || userAgent.indexOf("Opera") > -1) {
browserName = "Opera";
browserVersion = userAgent.match(/(OPR|Opera)\/([0-9.]+)/)[2];
} else if (userAgent.indexOf("Edg") > -1) {
browserName = "Edge";
browserVersion = userAgent.match(/Edg\/([0-9.]+)/)[1];
} else if (userAgent.indexOf("Chrome") > -1) {
browserName = "Chrome";
browserVersion = userAgent.match(/Chrome\/([0-9.]+)/)[1];
} else if (userAgent.indexOf("Safari") > -1) {
browserName = "Safari";
browserVersion = userAgent.match(/Version\/([0-9.]+)/)[1];
} else if (userAgent.indexOf("MSIE") > -1 || userAgent.indexOf("rv:") > -1) {
browserName = "Internet Explorer";
browserVersion = userAgent.match(/(MSIE |rv:)([0-9.]+)/)[2];
} else {
browserName = "Unknown";
browserVersion = "N/A";
}
return {
name: browserName,
version: browserVersion,
isMobile: isMobile,
};
}
function getCodeLocation() {
if (['Firefox'].includes(browser_info.name)) return "";
const callstack = new Error().stack.split("\n");
callstack.shift();
while (callstack.length && callstack[0].includes("-extension://")) {
callstack.shift();
}
if (!callstack.length) {
return "";
}
return '\n' + callstack[0].trim();
}
function display_config_win() {
const css_str = '.popup{ z-index:999999999; position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);padding:20px;background-color:#ffffff;border:1px solid #3498db;border-radius:5px;box-shadow:0 0 10px rgba(0,0,0,0.3);width:200px; max-height: 80vh;overflow-y: auto;}.btn{cursor:pointer;background-color:#3498db;color:#ffffff;border:none;padding:5px 10px;margin:0 auto;border-radius:5px;display:block;margin-top:10px;}.recommend-title{user-select: none;font-weight:bold;font-size: large;background-color:#3498db;color:#ffffff;border:none;padding:5px;padding-left:10px;border-radius:5px;width:180px;text-align:start;}.select-group{cursor:pointer;padding:5px;list-style-type:none;margin:0;padding-left:0;user-select: none;}.item-group{list-style-type:none;margin:0;padding-left:0;} .close-btn{position:absolute;top:5px;right:5px;cursor:pointer;border:none;background-color:floralwhite;} label{font-size: large;}';
const style = document.createElement("style");
style.textContent = css_str;
document.querySelector('body').appendChild(style);
let win_config;
const home_watch_config = {
"recommend_btn": [
{
"id": "open_recommend_shorts",
"title": "btn_recommend_shorts",
"items": [
{
"tag": "btn_lable_open",
"value": "on",
},
{
"tag": "btn_lable_close",
"value": "off",
},
{
"tag": "btn_lable_subscribed",
"value": "subscribed",
"tips": "recommend_subscribed_lable_tips",
"condition": {
"login_status": true
}
}
]
}, {
"id": "open_recommend_liveroom",
"title": "btn_recommend_liveroom",
"items": [
{
"tag": "btn_lable_open",
"value": "on",
},
{
"tag": "btn_lable_close",
"value": "off",
},
{
"tag": "btn_lable_subscribed",
"value": "subscribed",
"tips": "recommend_subscribed_lable_tips",
"condition": {
"login_status": true
}
}
]
}
,
{
"id": "open_recommend_movie",
"title": "btn_recommend_movie",
"items": [
{
"tag": "btn_lable_open",
"value": "on",
},
{
"tag": "btn_lable_close",
"value": "off",
},
]
},
{
"id": "open_recommend_popular",
"title": "btn_recommend_popular",
"items": [
{
"tag": "btn_lable_open",
"value": "on",
},
{
"tag": "btn_lable_close",
"value": "off",
},
]
},
{
"id": "open_recommend_playables",
"title": "btn_recommend_game",
"items": [
{
"tag": "btn_lable_open",
"value": "on",
},
{
"tag": "btn_lable_close",
"value": "off",
},
]
}
]
};
const shorts_config = {
"recommend_btn": [
{
"id": "add_shorts_upload_date",
"title": "title_add_shorts_upload_date",
"items": [
{
"tag": "btn_lable_open",
"value": "on",
},
{
"tag": "btn_lable_close",
"value": "off",
},
]
},
{
"id": "shorts_change_author_name",
"title": "title_shorts_change_author_name",
"items": [
{
"tag": "btn_lable_open",
"value": "on",
},
{
"tag": "btn_lable_close",
"value": "off",
},
]
},
{
"id": "short_buy_super_thanks",
"title": "short_buy_super_thanks",
"items": [
{
"tag": "btn_lable_open",
"value": "on",
},
{
"tag": "btn_lable_close",
"value": "off",
},
]
},
]
};
['mobile_yt_home_searching', 'mobile_yt_watch_searching'].includes(page_type) && home_watch_config.recommend_btn.push(...shorts_config.recommend_btn);
['yt_home', 'yt_watch', 'mobile_yt_watch_searching', 'mobile_yt_home_searching'].includes(page_type) && (win_config = home_watch_config);
['yt_shorts'].includes(page_type) && (win_config = shorts_config);
if (!win_config) return;
const popup_node = document.getElementById('xxx_popup');
if (popup_node) {
popup_node.remove_popup_listener('rm');
}
const popup = document.createElement('div');
popup.id = 'xxx_popup';
popup.className = 'popup';
const close_btn = document.createElement('button');
close_btn.className = 'close-btn';
close_btn.innerHTML = 'x';
close_btn.addEventListener('click', remove_popup_hander
);
popup.append(close_btn);
const item_groups = [];
const item_group = document.createElement('ul');
item_group.className = 'item-group';
win_config.recommend_btn.forEach(recommend_item_info => {
const recommend_id = recommend_item_info.id;
const recommend_title = flag_info[recommend_item_info.title];
const select_item_infos = recommend_item_info.items;
const select_items = [];
const item = document.createElement('li');
const select_group = document.createElement('ul');
select_group.className = 'select-group';
select_group.id = recommend_id;
select_item_infos.forEach(select_item_info => {
const tag = flag_info[select_item_info.tag];
const value = select_item_info.value;
const tips = flag_info[select_item_info.tips];
const condition = select_item_info.condition;
const select_item = document.createElement('li');
const input = document.createElement('input');
input.type = 'radio';
input.name = recommend_id + '_option';
input.id = recommend_id + '_' + value;
input.value = value;
if (condition && condition.login_status) {
if (condition.login_status !== user_data.login) {
input.disabled = true;
}
}
if (user_data[recommend_id] === value) {
input.checked = true;
}
input.addEventListener('click', () => {
handle_recommend_radio(input);
});
const label = document.createElement('label');
label.htmlFor = input.id;
label.innerText = tag;
tips && (label.title = tips);
select_item.append(input, label);
select_items.push(select_item);
});
const recommend_title_div = document.createElement('div');
recommend_title_div.className = 'recommend-title';
recommend_title_div.innerText = recommend_title;
select_group.append(...select_items);
item.append(recommend_title_div, select_group);
item_groups.push(item);
});
item_group.append(...item_groups);
popup.append(item_group);
document.body.append(popup);
function remove_popup_hander(event) {
if ((event.target && !popup.contains(event.target)) || event.target === close_btn || event === 'rm') {
popup.remove();
document.removeEventListener('click', remove_popup_hander);
if (['mobile_yt_watch_searching', 'mobile_yt_home_searching'].includes(page_type)) {
history.back();
}
}
}
popup.remove_popup_listener = remove_popup_hander;
document.addEventListener('click', remove_popup_hander);
// 隐藏搜索推荐元素
let count = 0;
const interval_id = setInterval(() => {
if (count = 30)
clearInterval(interval_id);
count++;
let class_name;
if (['yt_home', , 'yt_watch', 'yt_shorts'].includes(page_type)) class_name = 'gstl_50';
if (['mobile_yt_home', , 'mobile_yt_watch'].includes(page_type)) class_name = 'searchbox-dropdown';
if (class_name) {
let nodes = document.getElementsByClassName(class_name);
if (nodes.length) {
nodes = Array.from(nodes);
nodes.forEach(function (node) {
node.style.display = 'none';
});
}
}
}, 100);
}
function handle_recommend_radio(input_obj) {
user_data[input_obj.parentNode.parentNode.id] = input_obj.value;
user_data_api.set();
config_api.config_init(user_data.language);
}
function display_update_win() {
function btn_click() {
const btn = this;
if (btn.id === 'go_btn') {
location.href = script_url;
}
container.remove();
}
const css_str = "#update_tips_win { z-index:9999999999; display: flex; position: fixed; bottom: 20px; right: 20px; padding: 10px 20px; background-color: #fff; border: 1px solid #ccc; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); border-radius: 10px; } .btn { margin: 0 10px; display: inline-block; padding: 5px 10px; background-color: #3498db; color: #fff; border: none; border-radius: 5px; cursor: pointer; transition: background-color 0.3s ease; } .btn:hover { background-color: #2980b9; }";
const style = document.createElement("style");
style.innerText = css_str;
document.querySelector('body').appendChild(style);
const container = document.createElement("div");
container.id = "update_tips_win";
const span = document.createElement("span");
span.textContent = GM_info.script.name + '有更新了!!';
container.appendChild(span);
const go_btn = document.createElement("button");
go_btn.textContent = 'GO';
go_btn.id = 'go_btn';
go_btn.className = 'btn';
go_btn.onclick = btn_click;
container.appendChild(go_btn);
const no_btn = document.createElement("button");
no_btn.textContent = 'NO';
no_btn.className = 'btn';
no_btn.id = 'no_btn';
no_btn.onclick = btn_click;
container.appendChild(no_btn);
document.querySelector('body').appendChild(container);
}
function checke_update() {
const script_handler = GM_info.scriptHandler;
if (['Via'].includes(script_handler)) return;
const last_check_time = GM_getValue('last_check_time', 0);
if ((Date.now() - last_check_time) < 1000 * 60 * 60 * 24) return;
GM_xmlhttpRequest({
method: 'GET',
url: script_url,
onload: function (response) {
const onlineScript = response.responseText;
// 从线上脚本中提取版本号和元数据信息
const onlineMeta = onlineScript.match(/@version\s+([^\s]+)/i);
const onlineVersion = onlineMeta ? onlineMeta[1] : '';
if (onlineVersion > GM_info.script.version) {
display_update_win();
}
}
});
GM_setValue('last_check_time', Date.now());
}
function obj_process_filter(path_info, json_obj) {
if (!['yt_home', 'yt_watch', 'mobile_yt_home', 'mobile_yt_watch'].includes(page_type)) return false;
if (!user_data.login || user_data.channel_infos.ids.length === 0) return false;
if (user_data.open_recommend_shorts === 'subscribed' && path_info.condition_value === 'YOUTUBE_SHORTS_BRAND_24') {
if (path_info.express.includes('YOUTUBE_SHORTS_BRAND_24')) {
let video_list_path;
video_list_path = path_info.conform_value_path.split('["icon"]')[0] + (page_type === 'yt_home' ? '["contents"]' : '["items"]');
const video_list = data_process.string_to_value(json_obj, video_list_path) || [];
shorts_fun.node_parse(video_list);
}
}
if (user_data.open_recommend_liveroom === 'subscribed' && ['UPCOMING', 'LIVE', 'BADGE_STYLE_TYPE_LIVE_NOW'].includes(path_info.condition_value)) {
if (path_info.express.includes('UPCOMING')) {
try {
const match = JSON.stringify(data_process.string_to_value(json_obj, path_info.deal_path)).match(/"browseId"\:"(.*?)"/);
let id;
if (match && match.length > 1) id = match[1];
if (!id) {
log('id获取失败\n' + JSON.stringify(path_info), -1);
}
if (user_data.channel_infos.ids.includes(id)) {
const index = user_data.channel_infos.ids.indexOf(id);
const name = user_data.channel_infos.names[index];
log('不过滤 ' + name + (path_info.condition_value === 'UPCOMING' ? ' 等待发布的直播' : ' 正在进行的直播'), 'shorts');
return true;
}
let msg = `过滤 ${id} ${path_info.condition_value === 'UPCOMING' ? ' 等待发布的直播' : ' 正在进行的直播'}`;
log(msg, 'shorts');
} catch (error) {
log(error, -1);
}
}
}
return false;
}
function get_shorts_fun() {
class ShortsFun {
constructor() {
this.parsing = false;
this.shorts_list = [];
}
node_parse(video_list) {
!user_data.shorts_list && (user_data.shorts_list = []);
let video_id, title, views_lable, thumbnail_url;
let count = 0;
for (let video_info of video_list) {
count++;
if (page_type === "yt_home") {
video_id = video_info.richItemRenderer.content.reelItemRenderer.videoId;
title = video_info.richItemRenderer.content.reelItemRenderer.headline.simpleText;
views_lable = video_info.richItemRenderer.content.reelItemRenderer.viewCountText.simpleText;
thumbnail_url = video_info.richItemRenderer.content.reelItemRenderer.thumbnail.thumbnails[0].url;
}
if (page_type === "yt_watch") {
video_id = video_info.reelItemRenderer.videoId;
title = video_info.reelItemRenderer.headline.simpleText;
views_lable = video_info.reelItemRenderer.viewCountText.simpleText;
thumbnail_url = video_info.reelItemRenderer.thumbnail.thumbnails[0].url;
}
if (["mobile_yt_home", "mobile_yt_watch"].includes(page_type)) {
video_id = video_info.shortsLockupViewModel.entityId.replace('shorts-shelf-item-', '');
title = video_info.shortsLockupViewModel.overlayMetadata.primaryText.content;
views_lable = video_info.shortsLockupViewModel.overlayMetadata.secondaryText.content;
thumbnail_url = video_info.shortsLockupViewModel.thumbnail.sources[0].url;
}
this.shorts_list.push({
id: video_id,
title: title,
views_lable: views_lable,
thumbnail_url: thumbnail_url
});
if (!this.parsing) {
this.parsing = true;
setTimeout(() => {
this.parse_shorts_list();
}, shorts_parse_delay);
}
}
}
get_shorts_section() {
if (!user_data.shorts_list || !user_data.shorts_list.length) return;
let root, item_path;
const items = [];
if (page_type == 'yt_home') {
root = {
"richSectionRenderer": {
"content": {
"richShelfRenderer": {
"title": {
"runs": [
{
"text": "Shorts"
}
]
},
"contents": [],
"trackingParams": "CNMEEN-DAyITCOGA_NHuz4UDFWdqTAgdfF4E-Q==",
"menu": {
"menuRenderer": {
"trackingParams": "CNMEEN-DAyITCOGA_NHuz4UDFWdqTAgdfF4E-Q==",
"topLevelButtons": [
{
"buttonRenderer": {
"style": "STYLE_OPACITY",
"size": "SIZE_DEFAULT",
"isDisabled": false,
"serviceEndpoint": {
"clickTrackingParams": "CNYEEKqJCRgMIhMI4YD80e7PhQMVZ2pMCB18XgT5",
"commandMetadata": {
"webCommandMetadata": {
"sendPost": true,
"apiUrl": "/youtubei/v1/feedback"
}
},
"feedbackEndpoint": {
"feedbackToken": "AB9zfpIcTXNyA3lbF_28icb4umRJ5AveSSTqmF7T9gE8k-Sw7HrOTLE5wzA2TScqfTByCI-cR9nPuVMSWAgbNuuaruVBYx2-2dGAzujQTL8KGMOyCFM_wmGhkLTSdUBQzsFQRHEibpg_",
"uiActions": {
"hideEnclosingContainer": true
},
"actions": [
{
"clickTrackingParams": "CNYEEKqJCRgMIhMI4YD80e7PhQMVZ2pMCB18XgT5",
"replaceEnclosingAction": {
"item": {
"notificationMultiActionRenderer": {
"responseText": {
"runs": [
{
"text": "Shelf will be hidden for "
},
{
"text": "30"
},
{
"text": " days"
}
]
},
"buttons": [
{
"buttonRenderer": {
"style": "STYLE_BLUE_TEXT",
"text": {
"simpleText": "Undo"
},
"serviceEndpoint": {
"clickTrackingParams": "CNgEEPBbGAAiEwjhgPzR7s-FAxVnakwIHXxeBPk=",
"commandMetadata": {
"webCommandMetadata": {
"sendPost": true,
"apiUrl": "/youtubei/v1/feedback"
}
},
"undoFeedbackEndpoint": {
"undoToken": "AB9zfpLpAillN1hH9cyfSbyPRWwAhTOJo6mUTu-ony4HASc0KgCEy0ifaIrDUdJJEk4OXiPC43EMPZBEK8WGiIqeci4r97TGpabAUk84dEh7tHzF7-rsziFBGZjY92Jyk3YujrF2_wxC",
"actions": [
{
"clickTrackingParams": "CNgEEPBbGAAiEwjhgPzR7s-FAxVnakwIHXxeBPk=",
"undoFeedbackAction": {
"hack": true
}
}
]
}
},
"trackingParams": "CNgEEPBbGAAiEwjhgPzR7s-FAxVnakwIHXxeBPk="
}
}
],
"trackingParams": "CNcEEKW8ASITCOGA_NHuz4UDFWdqTAgdfF4E-Q=="
}
}
}
}
]
}
},
"icon": {
"iconType": "DISMISSAL"
},
"tooltip": "Not interested",
"trackingParams": "CNYEEKqJCRgMIhMI4YD80e7PhQMVZ2pMCB18XgT5",
"accessibilityData": {
"accessibilityData": {
"label": "Not interested"
}
}
}
}
]
}
},
"showMoreButton": {
"buttonRenderer": {
"style": "STYLE_OPACITY",
"size": "SIZE_DEFAULT",
"text": {
"runs": [
{
"text": "Show more"
}
]
},
"icon": {
"iconType": "EXPAND"
},
"accessibility": {
"label": "Show more"
},
"trackingParams": "CNUEEJnjCyITCOGA_NHuz4UDFWdqTAgdfF4E-Q=="
}
},
"isExpanded": false,
"icon": {
"iconType": "YOUTUBE_SHORTS_BRAND_24"
},
"isTopDividerHidden": false,
"isBottomDividerHidden": false,
"showLessButton": {
"buttonRenderer": {
"style": "STYLE_OPACITY",
"size": "SIZE_DEFAULT",
"text": {
"runs": [
{
"text": "Show less"
}
]
},
"icon": {
"iconType": "COLLAPSE"
},
"accessibility": {
"label": "Show less"
},
"trackingParams": "CNQEEPBbIhMI4YD80e7PhQMVZ2pMCB18XgT5"
}
}
}
},
"trackingParams": "CNIEEOOXBRgEIhMI4YD80e7PhQMVZ2pMCB18XgT5",
"fullBleed": false
}
};
item_path = 'root.richSectionRenderer.content.richShelfRenderer.contents';
}
if (['mobile_yt_watch', 'yt_watch'].includes(page_type)) {
root = {
"reelShelfRenderer": {
"title": {
"runs": [
{
"text": "Shorts"
}
]
},
"items": [],
"trackingParams": "CM4CEN-DAxgEIhMInKOvhY3QhQMVGcCXCB04HQR6",
"icon": {
"iconType": "YOUTUBE_SHORTS_BRAND_24"
}
}
};
item_path = 'root.reelShelfRenderer.items';
}
if (page_type == 'mobile_yt_home') {
root = {
"richSectionRenderer": {
"content": {
"reelShelfRenderer": {
"title": {
"runs": [
{
"text": "Shorts"
}
]
},
"button": {
"menuRenderer": {
"trackingParams": "CHYQ34MDIhMIqeqAyo7QhQMVz3lMCB2mCA0J",
"topLevelButtons": [
{
"buttonRenderer": {
"style": "STYLE_DEFAULT",
"size": "SIZE_DEFAULT",
"isDisabled": false,
"serviceEndpoint": {
"clickTrackingParams": "CLMBEKqJCRgPIhMIqeqAyo7QhQMVz3lMCB2mCA0J",
"commandMetadata": {
"webCommandMetadata": {
"sendPost": true,
"apiUrl": "/youtubei/v1/feedback"
}
},
"feedbackEndpoint": {
"feedbackToken": "AB9zfpJSnrbvskPWkpziyGduKV-4gTxm30-eNNYDobzecpLq84dL6HwCxdX_zbvm_OmxSKdlsngHEE1CF7JKYGiyDVYV_Q7p9ihGCzOYcnqKcAJfNnSp-U-njcnKLgCWu_USr-2prW3x",
"uiActions": {
"hideEnclosingContainer": true
},
"actions": [
{
"clickTrackingParams": "CLMBEKqJCRgPIhMIqeqAyo7QhQMVz3lMCB2mCA0J",
"replaceEnclosingAction": {
"item": {
"notificationMultiActionRenderer": {
"responseText": {
"runs": [
{
"text": "Shelf will be hidden for "
},
{
"text": "30"
},
{
"text": " days"
}
]
},
"buttons": [
{
"buttonRenderer": {
"style": "STYLE_MONO_TONAL",
"text": {
"runs": [
{
"text": "Undo"
}
]
},
"serviceEndpoint": {
"clickTrackingParams": "CLUBEPBbGAAiEwip6oDKjtCFAxXPeUwIHaYIDQk=",
"commandMetadata": {
"webCommandMetadata": {
"sendPost": true,
"apiUrl": "/youtubei/v1/feedback"
}
},
"undoFeedbackEndpoint": {
"undoToken": "AB9zfpK-nY3vxgYDkvJSkuFdbeBltD0r4XdLzoFqxz6OPnmJrroOAxKfUuDny8kPjB9yyWzwEerOZqe90BakCPEJXycRSrH8sZAdnlWpEs0n0lx6qOFERE6o5jkK3mgbcVCM-Al38oGV",
"actions": [
{
"clickTrackingParams": "CLUBEPBbGAAiEwip6oDKjtCFAxXPeUwIHaYIDQk=",
"undoFeedbackAction": {
"hack": true
}
}
]
}
},
"trackingParams": "CLUBEPBbGAAiEwip6oDKjtCFAxXPeUwIHaYIDQk="
}
}
],
"trackingParams": "CLQBEKW8ASITCKnqgMqO0IUDFc95TAgdpggNCQ=="
}
}
}
}
]
}
},
"icon": {
"iconType": "DISMISSAL"
},
"tooltip": "Not interested",
"trackingParams": "CLMBEKqJCRgPIhMIqeqAyo7QhQMVz3lMCB2mCA0J",
"accessibilityData": {
"accessibilityData": {
"label": "Not interested"
}
}
}
}
]
}
},
"items": [
],
"trackingParams": "CHYQ34MDIhMIqeqAyo7QhQMVz3lMCB2mCA0J",
"icon": {
"iconType": "YOUTUBE_SHORTS_BRAND_24"
}
}
},
"trackingParams": "CHUQ45cFGAEiEwip6oDKjtCFAxXPeUwIHaYIDQk=",
"fullBleed": false
}
};
item_path = 'root.richSectionRenderer.content.reelShelfRenderer.items';
}
let shorts;
while (shorts = user_data.shorts_list.pop()) {
const id = shorts['id'];
const title = shorts['title'];
const ago_str = shorts['ago_str'];
const author = shorts['author_name'];
const views_lable = shorts['views_lable'] + (author ? (' · ' + author) : '') + (ago_str ? (' · ' + ago_str) : '');
const thumbnail_url = shorts['thumbnail_url'];
let tmp_item;
if (['yt_home', 'yt_watch'].includes(page_type)) {
tmp_item = {
"reelItemRenderer": {
"videoId": id,
"headline": {
"simpleText": title
},
"thumbnail": {
"thumbnails": [
{
"url": thumbnail_url,
"width": 405,
"height": 720
}
],
"isOriginalAspectRatio": true
},
"viewCountText": {
"accessibility": {
"accessibilityData": {
"label": views_lable
}
},
"simpleText": views_lable
},
"navigationEndpoint": {
"clickTrackingParams": "COsCEIf2BBgAIhMInKOvhY3QhQMVGcCXCB04HQR6mgEFCCUQ-B0=",
"commandMetadata": {
"webCommandMetadata": {
"url": "/shorts/" + id,
"webPageType": "WEB_PAGE_TYPE_SHORTS",
"rootVe": 37414
}
},
"reelWatchEndpoint": {
"videoId": id,
"playerParams": "8AEBoAMCyAMluAQGogYVAdXZ-jvMfGWnXiNDPh0oiMSTJMUn",
"thumbnail": {
"thumbnails": [
{
"url": "https://i.ytimg.com/vi/" + id + "/frame0.jpg",
"width": 1080,
"height": 1920
}
],
"isOriginalAspectRatio": true
},
"overlay": {
"reelPlayerOverlayRenderer": {
"style": "REEL_PLAYER_OVERLAY_STYLE_SHORTS",
"trackingParams": "CO4CELC1BCITCJyjr4WN0IUDFRnAlwgdOB0Eeg==",
"reelPlayerNavigationModel": "REEL_PLAYER_NAVIGATION_MODEL_UNSPECIFIED"
}
},
"params": "CAYwAg%3D%3D",
"sequenceProvider": "REEL_WATCH_SEQUENCE_PROVIDER_RPC",
"sequenceParams": "CgtLRmRCbnpnSjJZWSoCGAZQGWgA",
"loggingContext": {
"vssLoggingContext": {
"serializedContextData": "CgIIDA%3D%3D"
},
"qoeLoggingContext": {
"serializedContextData": "CgIIDA%3D%3D"
}
},
"ustreamerConfig": "CAwSHDFIakVXUytucVRyTENNWlgzMXdDZmYwamZQQ0U="
}
},
"menu": {
"menuRenderer": {
"items": [
{
"menuServiceItemRenderer": {
"text": {
"runs": [
{
"text": "Report"
}
]
},
"icon": {
"iconType": "FLAG"
},
"serviceEndpoint": {
"clickTrackingParams": "COsCEIf2BBgAIhMInKOvhY3QhQMVGcCXCB04HQR6",
"commandMetadata": {
"webCommandMetadata": {
"sendPost": true,
"apiUrl": "/youtubei/v1/flag/get_form"
}
},
"getReportFormEndpoint": {
"params": "EgtLRmRCbnpnSjJZWUABWABwAXgB2AEA6AEA"
}
},
"trackingParams": "COsCEIf2BBgAIhMInKOvhY3QhQMVGcCXCB04HQR6"
}
},
{
"menuServiceItemRenderer": {
"text": {
"runs": [
{
"text": "Not interested"
}
]
},
"icon": {
"iconType": "NOT_INTERESTED"
},
"serviceEndpoint": {
"clickTrackingParams": "COsCEIf2BBgAIhMInKOvhY3QhQMVGcCXCB04HQR6",
"commandMetadata": {
"webCommandMetadata": {
"sendPost": true,
"apiUrl": "/youtubei/v1/feedback"
}
},
"feedbackEndpoint": {
"feedbackToken": "AB9zfpIBjY8nLioWtHjvUvMvrLXfhPMooShdpv91xgNNrZuxibAl6QyPeYMe7faEHcrSUm-TIqvLe2ThmYQpNRUy9rPbV1k3jjrvqqc5cOLBvnV8oN0Kbrq3-K9IjJXYitJPyOzJU0uy",
"actions": [
{
"clickTrackingParams": "COsCEIf2BBgAIhMInKOvhY3QhQMVGcCXCB04HQR6",
"replaceEnclosingAction": {
"item": {
"notificationMultiActionRenderer": {
"responseText": {
"runs": [
{
"text": "Video removed"
}
]
},
"buttons": [
{
"buttonRenderer": {
"style": "STYLE_BLUE_TEXT",
"text": {
"runs": [
{
"text": "Undo"
}
]
},
"serviceEndpoint": {
"clickTrackingParams": "CO0CEPBbGAAiEwico6-FjdCFAxUZwJcIHTgdBHo=",
"commandMetadata": {
"webCommandMetadata": {
"sendPost": true,
"apiUrl": "/youtubei/v1/feedback"
}
},
"undoFeedbackEndpoint": {
"undoToken": "AB9zfpK74nsMbZ4OfNgKTgA9g0w3Q8o72jdm384D3y82OAuy2KgvTUOAn-iII915ZC_7aqAxTK-XNir21X_T3WQEeAzdy4hCZ6o0f12hfdHW8xI1js1WB_CEn3EW27P9_1vu5dw2kDeW",
"actions": [
{
"clickTrackingParams": "CO0CEPBbGAAiEwico6-FjdCFAxUZwJcIHTgdBHo=",
"undoFeedbackAction": {
"hack": true
}
}
]
}
},
"trackingParams": "CO0CEPBbGAAiEwico6-FjdCFAxUZwJcIHTgdBHo="
}
}
],
"trackingParams": "COwCEKW8ASITCJyjr4WN0IUDFRnAlwgdOB0Eeg=="
}
}
}
}
]
}
},
"trackingParams": "COsCEIf2BBgAIhMInKOvhY3QhQMVGcCXCB04HQR6",
"accessibility": {
"accessibilityData": {
"label": "Not interested"
}
}
}
},
{
"menuNavigationItemRenderer": {
"text": {
"runs": [
{
"text": "Send feedback"
}
]
},
"icon": {
"iconType": "FEEDBACK"
},
"navigationEndpoint": {
"clickTrackingParams": "COsCEIf2BBgAIhMInKOvhY3QhQMVGcCXCB04HQR6",
"commandMetadata": {
"webCommandMetadata": {
"ignoreNavigation": true
}
},
"userFeedbackEndpoint": {
"additionalDatas": [
{
"userFeedbackEndpointProductSpecificValueData": {
"key": "video_id",
"value": id
}
},
{
"userFeedbackEndpointProductSpecificValueData": {
"key": "lockup",
"value": "shelf"
}
}
]
}
},
"trackingParams": "COsCEIf2BBgAIhMInKOvhY3QhQMVGcCXCB04HQR6",
"accessibility": {
"accessibilityData": {
"label": "Send feedback"
}
}
}
}
],
"trackingParams": "COsCEIf2BBgAIhMInKOvhY3QhQMVGcCXCB04HQR6",
"accessibility": {
"accessibilityData": {
"label": "More actions"
}
}
}
},
"trackingParams": "COsCEIf2BBgAIhMInKOvhY3QhQMVGcCXCB04HQR6QIazp8Dzs9CrKA==",
"accessibility": {
"accessibilityData": {
"label": title + " - play Short"
}
},
"style": "REEL_ITEM_STYLE_AVATAR_CIRCLE",
"dismissalInfo": {
"feedbackToken": "AB9zfpLIJd1aRU9JzdOjpgeJBW2QvHH79sx6dM6ZCDEzyc5qrISZBSpNRe5lerckNHwQ10BOwEQhlquLlHP-nkuA4VSSCXX0XgMJHBnKWBxlIXkQ1pLIUjd6cQKhrCUioDfix7xn5Ecj"
},
"videoType": "REEL_VIDEO_TYPE_VIDEO",
"loggingDirectives": {
"trackingParams": "COsCEIf2BBgAIhMInKOvhY3QhQMVGcCXCB04HQR6",
"visibility": {
"types": "12"
},
"enableDisplayloggerExperiment": true
}
}
};
}
if (page_type == "yt_home") {
tmp_item = {
"richItemRenderer": {
"content": tmp_item,
"trackingParams": "CJsFEJmNBRgAIhMI4YD80e7PhQMVZ2pMCB18XgT5"
}
};
}
if (["mobile_yt_home", "mobile_yt_watch"].includes(page_type)) {
tmp_item = {
"shortsLockupViewModel": {
"entityId": "shorts-shelf-item-" + id,
"accessibilityText": title + ", " + views_lable + " - play Short",
"thumbnail": {
"sources": [
{
"url": thumbnail_url,
"width": 405,
"height": 720
}
]
},
"onTap": {
"innertubeCommand": {
"clickTrackingParams": "CK8BEIf2BBgAIhMIqeqAyo7QhQMVz3lMCB2mCA0JWg9GRXdoYXRfdG9fd2F0Y2iaAQUIJBCOHg==",
"commandMetadata": {
"webCommandMetadata": {
"url": "/shorts/" + id,
"webPageType": "WEB_PAGE_TYPE_SHORTS",
"rootVe": 37414
}
},
"reelWatchEndpoint": {
"videoId": id,
"playerParams": "8AEBoAMByAMkuAQFogYVAdXZ-jveUoR0s0_R7sLGUd85_xAk",
"thumbnail": {
"thumbnails": [
{
"url": "https://i.ytimg.com/vi/" + id + "/frame0.jpg",
"width": 1080,
"height": 1920
}
],
"isOriginalAspectRatio": true
},
"overlay": {
"reelPlayerOverlayRenderer": {
"style": "REEL_PLAYER_OVERLAY_STYLE_SHORTS",
"trackingParams": "CLIBELC1BCITCKnqgMqO0IUDFc95TAgdpggNCQ==",
"reelPlayerNavigationModel": "REEL_PLAYER_NAVIGATION_MODEL_UNSPECIFIED"
}
},
"params": "CAUwAg%3D%3D",
"sequenceProvider": "REEL_WATCH_SEQUENCE_PROVIDER_RPC",
"sequenceParams": "CgtwblVoZV9PUTE2byoCGAVQGWgA",
"loggingContext": {
"vssLoggingContext": {
"serializedContextData": "CgIIDA%3D%3D"
},
"qoeLoggingContext": {
"serializedContextData": "CgIIDA%3D%3D"
}
},
"ustreamerConfig": "CAwSHDFIakVXUytucVRyTENNWlgzMXdDZmYwamZQQ0U="
}
}
},
"inlinePlayerData": {
"onVisible": {
"innertubeCommand": {
"clickTrackingParams": "CK8BEIf2BBgAIhMIqeqAyo7QhQMVz3lMCB2mCA0JMgZnLWhpZ2haD0ZFd2hhdF90b193YXRjaJoBBQgkEI4e",
"commandMetadata": {
"webCommandMetadata": {
"url": "/watch?v=" + id + "&pp=YAHIAQG6AwIYAugFAQ%3D%3D",
"webPageType": "WEB_PAGE_TYPE_WATCH",
"rootVe": 3832
}
},
"watchEndpoint": {
"videoId": id,
"playerParams": "YAHIAQG6AwIYAugFAQ%3D%3D"
}
}
}
},
"menuOnTap": {
"innertubeCommand": {
"clickTrackingParams": "CK8BEIf2BBgAIhMIqeqAyo7QhQMVz3lMCB2mCA0J",
"showSheetCommand": {
"panelLoadingStrategy": {
"inlineContent": {
"sheetViewModel": {
"content": {
"listViewModel": {
"listItems": [
{
"listItemViewModel": {
"title": {
"content": "Not interested"
},
"leadingImage": {
"sources": [
{
"clientResource": {
"imageName": "NOT_INTERESTED"
}
}
]
},
"rendererContext": {
"commandContext": {
"onTap": {
"innertubeCommand": {
"clickTrackingParams": "CK8BEIf2BBgAIhMIqeqAyo7QhQMVz3lMCB2mCA0J",
"commandMetadata": {
"webCommandMetadata": {
"sendPost": true,
"apiUrl": "/youtubei/v1/feedback"
}
},
"feedbackEndpoint": {
"feedbackToken": "AB9zfpJnMNgSEnsvYAu4UXP6IN5z0VfAt-OZOs8ypsKND9Mv5RhoELjmgb_vxVOvvYoiM2f8q9QFcdGMOEOCSk7LPYMnGshEHKcis4oeot-Z5OsgYpmOP3DbMXgFHUgQhOUAjL-FIj5y",
"actions": [
{
"clickTrackingParams": "CK8BEIf2BBgAIhMIqeqAyo7QhQMVz3lMCB2mCA0J",
"replaceEnclosingAction": {
"item": {
"notificationMultiActionRenderer": {
"responseText": {
"runs": [
{
"text": "Video removed"
}
]
},
"buttons": [
{
"buttonRenderer": {
"style": "STYLE_BLUE_TEXT",
"text": {
"runs": [
{
"text": "Undo"
}
]
},
"serviceEndpoint": {
"clickTrackingParams": "CLEBEPBbGAAiEwip6oDKjtCFAxXPeUwIHaYIDQk=",
"commandMetadata": {
"webCommandMetadata": {
"sendPost": true,
"apiUrl": "/youtubei/v1/feedback"
}
},
"undoFeedbackEndpoint": {
"undoToken": "AB9zfpI_UgAQH8eSODf7gCfkDtllqeFC5Qr38N7cNnlz8NmYZ78F2KiuX3KZNcumX2jfVXRzNfd2M0V7vud8UdS2Hz7SshgqVTn2TOJApWBlkIPTbUYWuQkX2CSbVKZw1p3wIHkjQOH7",
"actions": [
{
"clickTrackingParams": "CLEBEPBbGAAiEwip6oDKjtCFAxXPeUwIHaYIDQk=",
"undoFeedbackAction": {
"hack": true
}
}
]
}
},
"trackingParams": "CLEBEPBbGAAiEwip6oDKjtCFAxXPeUwIHaYIDQk="
}
}
],
"trackingParams": "CLABEKW8ASITCKnqgMqO0IUDFc95TAgdpggNCQ=="
}
}
}
}
]
}
}
}
}
}
}
},
{
"listItemViewModel": {
"title": {
"content": "Send feedback"
},
"leadingImage": {
"sources": [
{
"clientResource": {
"imageName": "FEEDBACK"
}
}
]
},
"rendererContext": {
"commandContext": {
"onTap": {
"innertubeCommand": {
"clickTrackingParams": "CK8BEIf2BBgAIhMIqeqAyo7QhQMVz3lMCB2mCA0J",
"commandMetadata": {
"webCommandMetadata": {
"ignoreNavigation": true
}
},
"userFeedbackEndpoint": {
"additionalDatas": [
{
"userFeedbackEndpointProductSpecificValueData": {
"key": "video_id",
"value": id
}
},
{
"userFeedbackEndpointProductSpecificValueData": {
"key": "lockup",
"value": "shelf"
}
}
]
}
}
}
}
}
}
}
]
}
}
}
}
}
}
}
},
"indexInCollection": 0,
"menuOnTapA11yLabel": "More actions",
"overlayMetadata": {
"primaryText": {
"content": title,
"styleRuns": [
{
"startIndex": 0,
"fontName": "",
"fontSize": 0,
"fontColor": 4294967295
}
]
},
"secondaryText": {
"content": views_lable,
"styleRuns": [
{
"startIndex": 0,
"fontName": "",
"fontSize": 0,
"fontColor": 4294967295
}
]
}
},
"loggingDirectives": {
"trackingParams": "CK8BEIf2BBgAIhMIqeqAyo7QhQMVz3lMCB2mCA0J",
"visibility": {
"types": "12"
},
"enableDisplayloggerExperiment": true
}
}
};
}
items.push(tmp_item);
}
if (item_path) {
eval(item_path + ' = items');
user_data_api.set();
return root;
}
return {};
}
get_shorts_info(video_id) {
return new Promise((resolve, reject) => {
let basic_url, author_id_reg, author_name_reg, upload_date_reg, ago_reg;
if (page_type.startsWith('mobile')) {
basic_url = 'https://m.youtube.com/shorts/';
author_id_reg = /"channelId":"(.*?)"/;
author_name_reg = /"ownerChannelName":"(.*?)"/;
// upload_date_reg = /"uploadDate":"(.*?)"/;
ago_reg = /timestampText.*?:\\x22(.*?)\\x22\\x7d/;
} else {
basic_url = 'https://www.youtube.com/shorts/';
author_id_reg = /"browseId":"([a-zA-Z0-9\-_]+)","canonicalBaseUrl"/;
author_name_reg = /"channel":\{"simpleText":"(.*?)"/;
// upload_date_reg = /"uploadDate":"(.*?)"/;
ago_reg = /"timestampText":{"simpleText":"(.*?)"}/;
}
const url = basic_url + video_id;
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.setRequestHeader('accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7');
let author_id = '';
let author_name = '';
// let upload_date_str = '';
let ago_str = '';
// let upload_date;
xhr.onload = function () {
if (xhr.status === 200) {
let match;
const result = xhr.responseText;
match = result.match(author_id_reg);
if (match && match.length > 1) author_id = match[1];
match = result.match(author_name_reg);
if (match && match.length > 1) author_name = match[1];
match = result.match(ago_reg);
if (match && match.length > 1) ago_str = match[1];
resolve({
id: video_id,
author_id: author_id,
author_name: author_name,
ago_str: ago_str
});
} else {
reject(xhr.responseText);
}
};
xhr.onerror = function () {
reject(new Error('XHR request failed'));
};
xhr.send();
});
}
parse_shorts_list() {
if (!this.shorts_list.length) return;
const { id, title, views_lable, thumbnail_url } = this.shorts_list.pop();
this.get_shorts_info(id).then((author_info) => {
const { author_id, author_name, ago_str } = author_info;
if (author_id && user_data.channel_infos.ids.includes(author_id)) {
if (user_data.shorts_list.some((value) => { return value.id === id; })) {
log('已存在' + author_name + '的短视频:' + title, 'shorts');
} else {
log('不过滤' + author_name + '的短视频:' + title, 'shorts');
const shorts_info = {
id: id,
title: title,
author_id: author_id,
author_name: author_name,
views_lable: views_lable,
from: page_type,
thumbnail_url: thumbnail_url,
ago_str: ago_str,
};
user_data.shorts_list.push(shorts_info);
user_data_api.set();
}
} else {
log('过滤' + author_name + '的短视频:' + title, 'shorts');
}
}
).finally(() => {
if (this.shorts_list.length > 0)
setTimeout(() => { this.parse_shorts_list(); }, shorts_parse_delay);
else
this.parsing = false;
});
}
check_shorts_exist() {
const short_id = href.split('/').pop();
for (let i = 0; i < user_data.shorts_list.length; i++) {
if (user_data.shorts_list[i].id === short_id) {
user_data.shorts_list.splice(i, 1);
user_data_api.set();
return;
}
}
}
get_interval_tag(upload_date_str) {
if (!upload_date_str) return '';
const uploadDate = new Date(upload_date_str);
const currentDate = new Date();
const timeDifference = Math.abs(currentDate - uploadDate); // Difference in milliseconds
const secondsDifference = timeDifference / 1000;
const minutesDifference = secondsDifference / 60;
const hoursDifference = minutesDifference / 60;
const daysDifference = hoursDifference / 24;
const weeksDifference = daysDifference / 7;
const monthsDifference = weeksDifference / 4.345; // Average number of weeks in a month
const yearsDifference = monthsDifference / 12;
if (secondsDifference < 60) {
return `${Math.floor(secondsDifference)} seconds ago`;
} else if (minutesDifference < 60) {
return `${Math.floor(minutesDifference)} minutes ago`;
} else if (hoursDifference < 24) {
return `${Math.floor(hoursDifference)} hours ago`;
} else if (daysDifference < 7) {
return `${Math.floor(daysDifference)} days ago`;
} else if (weeksDifference < 4.345) {
return `${Math.floor(weeksDifference)} weeks ago`;
} else if (monthsDifference < 12) {
return `${Math.floor(monthsDifference)} months ago`;
} else {
return `${Math.floor(yearsDifference)} years ago`;
}
}
};
return new ShortsFun();
}
function get_yt_api() {
return {
get_subscribe_data: function (retry = 0) {
const headers = {
"authority": "www.youtube.com",
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
};
const url = "https://www.youtube.com/feed/channels";
const requestConfig = {
method: 'GET',
headers: headers,
url: url
};
const save_this = this;
GM_xmlhttpRequest({
...requestConfig,
onload: function (response) {
const tmp_channel_names = [];
const tmp_channel_ids = [];
const regex = /var ytInitialData \= (.*?);\<\/script\>/;
try {
const match = response.responseText.match(regex);
const ytInitialData_obj = JSON.parse(match[1]);
const items = ytInitialData_obj.contents.twoColumnBrowseResultsRenderer.tabs[0].tabRenderer.content.sectionListRenderer.contents[0].itemSectionRenderer.contents[0].shelfRenderer.content.expandedShelfContentsRenderer.items;
for (let item of items) {
const channel_name = item.channelRenderer.title.simpleText;
const match_channel_id = item.channelRenderer.channelId;
tmp_channel_ids.push(match_channel_id);
tmp_channel_names.push(channel_name);
}
if (tmp_channel_ids.length > 0) {
user_data.channel_infos.ids = tmp_channel_ids;
user_data.channel_infos.names = tmp_channel_names;
user_data_api.set();
}
log('获取关注列表成功' + user_data.channel_infos.ids.length + '个', 0);
} catch (error) {
if (retry < 3) {
setTimeout(() => { save_this.get_subscribe_data(retry + 1); }, 1000);
}
log('获取关注列表失败\n', error, -1);
}
},
onerror: function (error) {
if (retry < 3) {
setTimeout(() => { save_this.get_subscribe_data(retry + 1); }, 1000);
}
log('获取关注列表失败\n', error, -1);
},
});
},
get_authorization: function () {
function Vja() {
function a() {
e[0] = 1732584193;
e[1] = 4023233417;
e[2] = 2562383102;
e[3] = 271733878;
e[4] = 3285377520;
u = q = 0;
}
function b(x) {
for (var y = l, C = 0; 64 > C; C += 4)
y[C / 4] = x[C] << 24 | x[C + 1] << 16 | x[C + 2] << 8 | x[C + 3];
for (C = 16; 80 > C; C++)
x = y[C - 3] ^ y[C - 8] ^ y[C - 14] ^ y[C - 16],
y[C] = (x << 1 | x >>> 31) & 4294967295;
x = e[0];
var E = e[1]
, H = e[2]
, R = e[3]
, T = e[4];
for (C = 0; 80 > C; C++) {
if (40 > C) {
if (20 > C) {
var X = R ^ E & (H ^ R);
var la = 1518500249;
} else
X = E ^ H ^ R,
la = 1859775393;
} else
60 > C ? (X = E & H | R & (E | H),
la = 2400959708) : (X = E ^ H ^ R,
la = 3395469782);
X = ((x << 5 | x >>> 27) & 4294967295) + X + T + la + y[C] & 4294967295;
T = R;
R = H;
H = (E << 30 | E >>> 2) & 4294967295;
E = x;
x = X;
}
e[0] = e[0] + x & 4294967295;
e[1] = e[1] + E & 4294967295;
e[2] = e[2] + H & 4294967295;
e[3] = e[3] + R & 4294967295;
e[4] = e[4] + T & 4294967295;
}
function c(x, y) {
if ("string" === typeof x) {
x = unescape(encodeURIComponent(x));
for (var C = [], E = 0, H = x.length; E < H; ++E)
C.push(x.charCodeAt(E));
x = C;
}
y || (y = x.length);
C = 0;
if (0 == q)
for (; C + 64 < y;)
b(x.slice(C, C + 64)),
C += 64,
u += 64;
for (; C < y;)
if (h[q++] = x[C++],
u++,
64 == q)
for (q = 0,
b(h); C + 64 < y;)
b(x.slice(C, C + 64)),
C += 64,
u += 64;
}
function d() {
var x = []
, y = 8 * u;
56 > q ? c(m, 56 - q) : c(m, 64 - (q - 56));
for (var C = 63; 56 <= C; C--)
h[C] = y & 255,
y >>>= 8;
b(h);
for (C = y = 0; 5 > C; C++)
for (var E = 24; 0 <= E; E -= 8)
x[y++] = e[C] >> E & 255;
return x;
}
for (var e = [], h = [], l = [], m = [128], p = 1; 64 > p; ++p)
m[p] = 0;
var q, u;
a();
return {
reset: a,
update: c,
digest: d,
digestString: function () {
for (var x = d(), y = "", C = 0; C < x.length; C++)
y += "0123456789ABCDEF".charAt(Math.floor(x[C] / 16)) + "0123456789ABCDEF".charAt(x[C] % 16);
return y;
}
};
}
const sapisid_cookie = getCookie('SAPISID') || getCookie('APISID') || getCookie('__Secure-3PAPISID');
if (sapisid_cookie) {
const timestamp = Math.floor(Date.now() / 1000);
const b = Vja();
b.update(timestamp + ' ' + sapisid_cookie + ' https://www.youtube.com');
const hash_value = b.digestString().toLowerCase();
return 'SAPISIDHASH ' + timestamp + '_' + hash_value;
}
return '';
},
get_channel_id: function (retry = 0) {
const authorization = this.get_authorization();
if (!authorization) {
log('获取authorization失败', 0);
return;
}
const url = "https://www.youtube.com/youtubei/v1/account/account_menu";
const params = {
"prettyPrint": "false"
};
const data = {
"context": {
"client": {
"clientName": "WEB",
"clientVersion": "2.20240308.00.00",
},
},
};
const jsonData = JSON.stringify(data);
const headers = {
"authorization": authorization,
"content-type": "application/json",
"origin": "https://www.youtube.com",
"referer": "https0://www.youtube.com/",
};
const requestConfig = {
method: 'POST',
headers: headers,
data: jsonData,
url: url + "?" + new URLSearchParams(params),
};
GM_xmlhttpRequest({
...requestConfig,
onload: function (response) {
const match = response.responseText.match(/"browseId"\:"(.*?)"/);
if (match && match.length > 1) {
const tmp_id = match[1];
if (tmp_id && tmp_id != channel_id) {
channel_id = tmp_id;
user_data = user_data_api.get();
GM_setValue('last_channel_id', channel_id);
}
log('获取channel_id成功' + channel_id, 0);
} else {
if (retry < 3) {
setTimeout(() => { yt_api.get_channel_id(retry + 1); }, 1000);
} else {
log('获取channel_id失败', response, response.responseText, -1);
}
}
},
onerror: function (error) {
if (retry < 3) {
setTimeout(() => { yt_api.get_channel_id(retry + 1); }, 1000);
yt_api.get_channel_id(retry + 1);
} else {
log('获取channel_id失败', error, 0);
}
},
});
}
};
}
function get_user_data_api() {
return {
get() {
const default_user_data = {
"open_recommend_shorts": 'on',
"open_recommend_movie": 'on',
"open_recommend_popular": 'on',
"open_recommend_liveroom": 'on',
"open_recommend_playables": "on",
"add_shorts_upload_date": 'on',
"shorts_change_author_name": 'on',
"short_buy_super_thanks": 'on',
"language": 'zh-CN',
"channel_infos": {
"ids": [],
"names": []
},
"shorts_list": [],
"watch_page_config": {
"shop_banner": "on"
},
"login": false,
};
let diff = false;
user_data_listener.set();
let tmp_user_data = GM_getValue(channel_id);
if (!tmp_user_data) {
tmp_user_data = default_user_data;
diff = true;
}
for (let key in default_user_data) {
if (!(key in tmp_user_data)) {
diff = true;
tmp_user_data[key] = default_user_data[key];
}
}
const tmp_login = channel_id !== 'default';
if (tmp_user_data.login !== tmp_login) {
diff = true;
tmp_user_data.login = tmp_login;
}
(diff || this.update(tmp_user_data)) && GM_setValue(channel_id, tmp_user_data);
return tmp_user_data;
},
set() {
return GM_setValue(channel_id, user_data);
},
update(tmp_user_data) {
let diff = false;
const last_version = GM_getValue('last_version', -1);
if (last_version === -1) {
tmp_user_data.open_recommend_shorts = GM_getValue("open_recommend_shorts", "off");
tmp_user_data.open_recommend_movie = GM_getValue("open_recommend_movie", "off");
tmp_user_data.open_recommend_popular = GM_getValue("open_recommend_popular", "off");
tmp_user_data.open_recommend_liveroom = GM_getValue("open_recommend_liveroom", "off");
diff = true;
}
if (typeof (tmp_user_data.open_recommend_shorts) === 'boolean') {
tmp_user_data.open_recommend_shorts = tmp_user_data.open_recommend_shorts ? 'on' : 'off';
tmp_user_data.open_recommend_movie = tmp_user_data.open_recommend_movie ? 'on' : 'off';
tmp_user_data.open_recommend_popular = tmp_user_data.open_recommend_popular ? 'on' : 'off';
tmp_user_data.open_recommend_liveroom = tmp_user_data.open_recommend_liveroom ? 'on' : 'off';
diff = true;
}
last_version !== GM_info.script.version && GM_setValue("last_version", GM_info.script.version);
return diff;
}
};
}
function get_data_process() {
class DATA_PROCESS {
constructor() {
try {
let test_eval;
eval('test_eval = 1');
this.limit_eval = test_eval !== 1;
} catch (error) {
this.limit_eval = true;
}
this.obj_filter;
this.obj_storage = {};
}
condition_split_and_tag = '&&';
condition_split_or_tag = '||';
value_split_and_tag = '&';
value_split_or_tag = '|';
storage_obj(key, obj) {
this.obj_storage[key] = obj;
}
set_obj_filter(obj_filter) {
if (typeof obj_filter !== 'function') return;
this.obj_filter = function () {
try {
obj_filter.apply(this, arguments);
} catch (error) {
log('obj_filter error', error, -1);
return false;
}
};
};
text_process(data, values, mode, traverse_all) {
if (!values) return data;
mode = mode || 'cover';
if (mode === 'reg') {
for (let value of values) {
const patten_express = value.split(SPLIT_TAG)[0];
const replace_value = value.split(SPLIT_TAG)[1];
const patten = new RegExp(patten_express, "g");
data = data.replace(patten, replace_value);
}
}
if (mode === 'cover') {
data = values[0];
}
if (mode === 'insert') {
traverse_all = traverse_all || false;
let json_data;
try {
json_data = JSON.parse(data);
} catch (error) {
log('text_process JSON parse error', -1);
return data;
}
this.obj_process(json_data, values, traverse_all);
data = JSON.stringify(json_data);
}
return data;
}
get_relative_path(basic_path, relative_path) {
if (relative_path === '/') return basic_path;
let real_path;
if (relative_path.startsWith('/.')) {
real_path = basic_path + relative_path.slice(1);
}
if (relative_path.startsWith('.')) {
const reg = /[\.\[]/g;
const positions = [];
let match;
while ((match = reg.exec(basic_path)) !== null) {
positions.push(match.index);
}
if (positions.length === 0) {
return basic_path;
}
const pointer_match = relative_path.match(/^\.+/);
const split_index = positions[positions.length - pointer_match[0].length];
const relative_attribute = relative_path.slice(pointer_match[0].length);
real_path = basic_path.slice(0, split_index) + (relative_attribute ? ((relative_attribute.startsWith('[') ? '' : '.') + relative_attribute) : '');
}
return this.convertPathToBracketNotation(real_path);
}
value_parse(parse_value, path_info = null, json_obj = null) {
const formula_match = parse_value.match(/\{.*?\}/g);
if (formula_match) {
for (let express_ of formula_match) {
const express = express_.slice(1, -1);
parse_value = parse_value.replace(express_, this.value_parse(express, path_info, json_obj));
}
}
const json_math = parse_value.match(/^json\((.*)\)$/);
if (json_math) return JSON.parse(json_math[1]);
const obj_match = parse_value.match(/^obj\((.*)\)$/);
if (obj_match) return this.string_to_value(unsafeWindow, obj_match[1]);
const number_match = parse_value.match(/^num\((.*)\)$/);
if (number_match) return Number(number_match[1]);
const method_match = parse_value.match(/^method\((.*)\)$/);
if (method_match) {
// eval 限制的时候可以使用num() obj()这些添加数字对象 方法也要放到unsafeWindow里 例:method(b("123",num(23)))
// 不限制的时候 不能使用num和obj 方法不需要放到unsafeWindow里 例:method(b("123",23))
if (this.limit_eval) {
const method_info = method_match[1].match(/(.*?)\((.*)\)$/);
const method_name = method_info[1];
const method_args_string = method_info[2];
const method_args = method_args_string.split(',');
const args = [];
for (let arg of method_args) {
args.push(this.value_parse(arg, path_info, json_obj));
}
return unsafeWindow[method_name](...args);
}
return eval(method_match[1]);
}
const deal_obj_match = parse_value.match(/^dealObj\((.*)\)$/);
if (deal_obj_match) {
const path_msg = deal_obj_match[1];
return this.string_to_value(json_obj.this.get_relative_path(path_info.deal_path, path_msg));
}
const path_obj_match = parse_value.match(/^pathObj\((.*)\)$/);
if (path_obj_match) {
const path_msg = path_obj_match[1];
return this.string_to_value(json_obj, this.get_relative_path(path_info.path, path_msg));
}
const abs_obj_match = parse_value.match(/^absObj\((.*)\)$/);
if (abs_obj_match) {
const abs_path = abs_obj_match[1];
return this.string_to_value(json_obj, abs_path);
}
const string_match = parse_value.match(/^["'](.*)["']$/);
if (string_match) return string_match[1];
if (parse_value === 'undefined') return undefined;
if (parse_value === 'null') return null;
return parse_value;
}
string_to_value(obj, path) {
try {
if (!this.limit_eval) {
return eval(path.replace('json_obj', 'obj'));
}
let tmp_obj = obj;
let matches = path.match(/\[(.*?)\]/g);
if (matches) {
matches.map((match) => {
if (match.includes('["')) {
tmp_obj = Reflect.get(tmp_obj, match.replace(/\["|"\]/g, ''));
} else {
tmp_obj = Reflect.get(tmp_obj, Number(match.replace(/\[|\]/g, '')));
}
});
return tmp_obj;
}
matches = path.split('.');
if (matches) {
matches.splice(0, 1);
matches.map((match) => {
tmp_obj = Reflect.get(tmp_obj, match);
});
return tmp_obj;
}
} catch (error) {
return null;
}
}
get_lastPath_and_key(path) {
let last_path, last_key;
let matches = path.match(/\[(.*?)\]/g);
if (matches && matches.length > 0) {
const tmp = matches[matches.length - 1];
if (tmp.includes('["')) {
last_key = tmp.replace(/\["|"\]/g, '');
} else {
last_key = Number(tmp.replace(/\[|\]/g, ''));
}
last_path = path.substring(0, path.lastIndexOf(tmp));
}
if (!matches) {
matches = path.split('.');
if (matches && matches.length > 0) {
last_key = matches[matches.length - 1];
last_path = path.replace('.' + last_key, '');
}
}
return [last_path, last_key];
}
convertPathToBracketNotation(path) {
if (!path) return '';
return path.replace(/\.[\d\w\-\_\$@]+/g, function (match) {
return '["' + match.slice(1) + '"]';
});
}
paths_sort(paths_arr, key_name = null, reverse = false) {
// 路径格式是json_obj["onResponseReceivedActions"][0]["appendContinuationItemsAction"]
// 支持数组元素是对象,根据里面的某个属性排序
// 支持数组元素是字符串,根据字符串排序
if (!Array.isArray(paths_arr)) {
throw new Error('paths_arr must be an array');
}
if (paths_arr.length === 0) return;
let tmp_paths_arr = paths_arr;
if (!key_name) {
key_name = 'path';
if (typeof paths_arr[0] !== 'string') throw new Error('paths_arr must be a string array');
tmp_paths_arr = [];
paths_arr.forEach(path => {
tmp_paths_arr.push({
path: path
});
});
}
const reverse_factor = reverse ? -1 : 1;
tmp_paths_arr.sort((a, b) => {
function get_sort_key(obj) {
if (!obj.sort_keys) {
const reg = /\["?(.*?)"?\]/g;
let matches = [];
let match;
while (match = reg.exec(obj[key_name])) {
if (!match[0].startsWith('["')) {
if (isNaN(match[1])) throw new Error('array index must be a number');
match[1] = parseInt(match[1]);
}
matches.push(match[1]);
}
obj.sort_keys = matches;
}
}
if (a[key_name] === b[key_name]) return 0;
get_sort_key(a);
get_sort_key(b);
const a_sort_keys = a.sort_keys;
const b_sort_keys = b.sort_keys;
if (a_sort_keys.length !== b_sort_keys.length) {
return (b_sort_keys.length - a_sort_keys.length) * reverse_factor;
}
for (let i = 0; i < a_sort_keys.length; i++) {
if (a_sort_keys[i] !== b_sort_keys[i]) {
return (b_sort_keys[i] > a_sort_keys[i] ? 1 : -1) * reverse_factor;
}
}
return 0;
});
if (paths_arr !== tmp_paths_arr) {
paths_arr.length = 0;
tmp_paths_arr.forEach(path_info => {
paths_arr.push(path_info.path);
});
}
}
obj_process(json_obj, express_list, traverse_all = false) {
if (typeof json_obj !== 'object') {
log('obj_process不是对象', express_list, -1);
return;
}
if (typeof express_list === 'function') {
try {
express_list = express_list(json_obj);
if (!express_list || Array.isArray(express_list) && express_list.length === 0) return;
} catch (error) {
log('obj_process express_list函数执行错误', error, -1);
return;
}
}
const data_this = this;
const abs_path_info_list = [];
const relative_path_info_list = [];
const relative_path_list = [];
const relative_short_path_list = [];
if (!json_obj || !express_list) return;
const is_array_obj = Array.isArray(json_obj);
try {
express_list.forEach(express => {
if (!express) return;
let reg;
const express_type = typeof (express);
let matches;
let conditions;
reg = /^(abs:)?(.*?)(=\-|~=|=\+|=)(\(?([^ ][\s\S]*?)\)?)?( ([\s\S]*))?$/;
if (express_type === 'string') {
matches = express.match(reg);
} else {
matches = express.value.match(reg);
conditions = express.conditions;
}
const abs = matches[1];
let path = matches[2];
const operator = matches[3];
let value = matches[4];
const condition = matches[7];
const path_extral_match = path.match(/\/\..*$|\.+$|\.\(.*$/);
let path_extral;
if (path_extral_match) {
path_extral = path_extral_match[0];
path = path.replace(path_extral, '');
}
let value_mode;
if (express_type === 'string') {
const mode_match = value?.match(/^\((.*)\)$/);
if (mode_match) {
// =('arr_insert',value,0)
const mode_info = mode_match[1].split(',');
value = mode_info[1];
const mode = mode_info[0];
mode_info.shift();
mode_info.shift();
value_mode = {
'mode': mode,
'params': mode_info
};
}
if (condition) {
// (fffddf|||ffff)&&&(ffff)
const tmp_conditions = condition ? condition.split(this.condition_split_and_tag) : [];
conditions = {};
for (let index = 0; index < tmp_conditions.length; index++) {
conditions['value' + index] = tmp_conditions[index].split(this.condition_split_or_tag);
}
}
}
matches = path.match(/\[([\*\d\-,]*)\]$/);
let array_index;
if (matches) {
path = path.replace(/\[([\*\d\-,]*)\]$/, '');
array_index = matches[1];
}
if (abs) {
add_data_to_abs_path({
"path": `json_obj${is_array_obj ? '' : '.'}` + path,
"express": express,
"relative_path": path,
"operator": operator,
"value": value,
"condition": conditions,
"array_index": array_index,
"path_extral": path_extral,
"value_mode": value_mode
});
} else {
relative_path_list.push(path);
const tmp_short_path = path.split('.').pop();
relative_short_path_list.push(tmp_short_path);
relative_path_info_list.push({
"express": express,
"path": path,
"operator": operator,
"value": value,
"value_mode": value_mode,
"conditions": conditions,
"array_index": array_index,
"path_extral": path_extral
});
}
});
if (relative_path_list.length > 0) {
const dec_list = [];
const dec_index_list = [];
obj_property_traverse(json_obj, '', {
"short_keys": relative_short_path_list,
"real_keys": relative_path_list
}, dec_list, dec_index_list, traverse_all);
for (let i = 0; i < dec_index_list.length; i++) {
const real_index = dec_index_list[i];
const real_path_info = relative_path_info_list[real_index];
const tmp_path = 'json_obj' + dec_list[i];
add_data_to_abs_path({
"path": tmp_path,
"express": real_path_info.express,
"relative_path": real_path_info.path,
"operator": real_path_info.operator,
"value": real_path_info.value,
"condition": real_path_info.conditions,
"array_index": real_path_info.array_index,
"path_extral": real_path_info.path_extral,
"value_mode": real_path_info.value_mode
});
}
}
try {
this.paths_sort(abs_path_info_list, 'deal_path');
} catch (error) {
abs_path_info_list.sort((a, b) => a < b ? 1 : -1);
}
for (let path_info of abs_path_info_list) {
if (!this.obj_conditional(path_info, json_obj)) continue;
if (this.obj_filter && this.obj_filter(path_info, json_obj)) continue;
obj_modify(json_obj, path_info);
}
} catch (error) {
log('obj_process处理失败', error, -1);
}
function add_data_to_abs_path(params) {
let { path, express, relative_path, operator, value, condition, array_index, path_extral, value_mode } = params;
let tmp;
path = data_this.convertPathToBracketNotation(path);
if (array_index === undefined) {
tmp = {};
path = path;
tmp.path = path;
tmp.relative_path = relative_path;
tmp.operator = operator;
tmp.value = value;
tmp.value_mode = value_mode;
tmp.condition = condition;
tmp.path_extral = path_extral;
tmp.express = express;
add_path(tmp);
return;
}
let array_index_list = [];
if (array_index === '*') {
let array_length;
try {
array_length = data_this.string_to_value(json_obj, path).length;
if (!array_length) return;
} catch (error) {
log('obj_process获取数组长度失败--->' + path, error, -1);
return;
}
array_index_list = Array.from({ length: array_length }, (_, i) => i);
} else if (array_index.includes(',')) {
let is_error = false;
array_index_list = array_index.split(',').map(item => {
if (is_error) return;
if (isNaN(item)) {
is_error = true;
return;
}
return Number(item);
});
if (is_error) {
return log('obj_process数组索引格式错误--->' + path, -1);
}
} else if (array_index.includes('-')) {
const index_arr = array_index.split('-');
if (index_arr.length !== 2) return log('obj_process数组索引格式错误--->' + path, -1);
const start = Number(index_arr[0]);
const end = Number(index_arr[1]);
if (isNaN(start) || isNaN(end)) {
return log('obj_process数组索引格式错误--->' + path, -1);
}
array_index_list = Array.from({ length: end - start + 1 }, (_, i) => start + i);
} else if (!isNaN(array_index)) {
array_index_list = [array_index];
} else {
return log('obj_process数组索引格式错误--->' + path, -1);
}
for (let tmp_index = array_index_list.length - 1; tmp_index >= 0; tmp_index--) {
tmp = {};
tmp.path = path + "[" + array_index_list[tmp_index] + "]";
tmp.operator = operator;
tmp.value = value;
tmp.value_mode = value_mode;
tmp.condition = condition;
tmp.path_extral = path_extral;
tmp.relative_path = relative_path;
tmp.express = express;
add_path(tmp);
}
function add_path(path_info) {
path_info.deal_path = path_extral ? data_this.get_relative_path(path, path_extral) : path_info.path;
abs_path_info_list.push(path_info);
}
}
function obj_property_traverse(obj, cur_path, dec_infos, dec_list, dec_index_list, traverse_all = false) {
if (Array.isArray(obj)) {
obj.forEach((tmp_obj, index) => {
const tmp_path = cur_path + '[' + index + ']';
if (!tmp_obj || typeof (tmp_obj) !== 'object') return;
obj_property_traverse(tmp_obj, tmp_path, dec_infos, dec_list, dec_index_list, traverse_all);
});
return;
}
Object.keys(obj).forEach((key) => {
const tmp_path = cur_path + '.' + key;
let deal = false;
for (let i = 0; i < dec_infos["short_keys"].length; i++) {
if (dec_infos["short_keys"][i] === key) {
const len = dec_infos["real_keys"][i].length;
if (tmp_path.slice(tmp_path.length - len) === dec_infos["real_keys"][i]) {
dec_list.push(tmp_path);
dec_index_list.push(i);
if (!deal && traverse_all && typeof (obj[key]) === 'object') {
obj_property_traverse(obj[key], tmp_path, dec_infos, dec_list, dec_index_list, traverse_all);
}
deal = true;
}
}
}
const value = obj[key];
if (deal || !value || typeof (value) !== 'object') return;
obj_property_traverse(value, tmp_path, dec_infos, dec_list, dec_index_list, traverse_all);
});
}
function obj_modify(json_obj, path_info) {
const path = path_info['deal_path'];
const operator = path_info['operator'];
let value = path_info['value'];
const [last_path, last_key] = data_this.get_lastPath_and_key(path);
const last_obj = data_this.string_to_value(json_obj, last_path);
if (!last_obj) {
debugger;
return log('obj_modify处理失败,找不到对象--->' + path_info, -1);
}
if (operator === '=-') {
const is_array = typeof last_key === 'number';
if (is_array)
last_obj.splice(last_key, 1);
else
delete last_obj[last_key];
log('依据:' + path_info.express, 'obj_process');
log('删除属性-->' + path, 'obj_process');
return;
}
if (operator === '=') {
value = data_this.value_parse(value, path_info, json_obj);
last_obj[last_key] = value;
log('依据:' + path_info.express, 'obj_process');
log('修改属性-->' + path, 'obj_process');
}
const dec_obj = last_obj[last_key];
if (!dec_obj) {
return log('obj_modify处理失败,找不到对象--->' + path_info, -1);
}
if (operator === '=+') {
value = data_this.value_parse(value, path_info, json_obj);
if (dec_obj === null || dec_obj === undefined) throw new Error('dec_obj is null');
let type_ = typeof dec_obj;
if (Array.isArray(dec_obj)) type_ = 'array';
if (type_ === 'array') {
const mode_info = path_info.value_mode;
if (mode_info) {
try {
mode_info.mode === 'arr_insert' && last_obj[last_key].splice(Number(mode_info.params[0]), 0, value);
} catch (error) {
log(error, -1);
}
} else {
last_obj[last_key].push(value);
}
}
if (type_ === 'string' || type_ === 'number') last_obj[last_key] = last_obj[last_key] + value;
log('依据:' + path_info.express, 'obj_process');
log('修改属性-->' + path, 'obj_process');
}
if (operator === '~=') {
const search_value = value.split(SPLIT_TAG)[0];
const replace_value = value.split(SPLIT_TAG)[1];
last_obj[last_key] = dec_obj.replace(new RegExp(search_value, 'g'), replace_value);
log('依据:' + path_info.express, 'obj_process');
log('修改属性-->' + path, 'obj_process');
}
}
}
path_process(json_obj, path) {
if (path.includes('[-')) {
const match = path.match(/\[(-\d+)\]/);
const index = parseInt(match[1]);
const dec_obj_path = path.slice(0, match.index);
const array_length = this.string_to_value(json_obj, dec_obj_path + '["length"]');
if (!array_length) return path;
const real_index = array_length + index;
path = path.replace(`[${index}`, `[${real_index}`);
return this.path_process(json_obj, path);
}
return path;
}
value_conditional(value, condition_express) {
const reg = /(\$text|\$value|\$exist|\$notexist)?((>=|<=|>|<|!~=|!=|~=|=))?(.*)/;
const match = condition_express.match(reg);
const condition_type = match[1] || '$text';
const condition_operator = match[2];
const condition_test_value = match[4];
const operator_reg = /(>=|<=|>|<|!~=|!=|~=|=)?(.*)$/;
if (condition_type === '$value') {
// $value=1|2 或 $value>=1&2
if (!['>=', '<=', '>', '<', '='].includes(condition_operator)) return false;
const split_tag = condition_test_value.includes(this.value_split_or_tag) && this.value_split_or_tag || this.value_split_and_tag;
const condition_test_value_arr = condition_test_value.split(split_tag);
let result;
for (let test_value of condition_test_value_arr) {
const operator_match = test_value.match(operator_reg);
const operator = operator_match && operator_match[1] || condition_operator;
test_value = operator_match && operator_match[2];
if (isNaN(test_value)) {
if (split_tag === this.value_split_and_tag) return false; else continue;
};
test_value = parseInt(test_value);
if (operator === '=') result = test_value === value;
if (operator === '>=') result = value >= test_value;
if (operator === '<=') result = value <= test_value;
if (operator === '>') result = value > test_value;
if (operator === '<') result = value < test_value;
if (!result) {
if (split_tag === this.value_split_and_tag) return false; else continue;
};
return true;
}
}
if (condition_type === '$exist') {
return value !== undefined && value !== null;
}
if (condition_type === '$notexist') {
return value === undefined || value === null;
}
if (condition_type === '$text') {
let split_tag;
let condition_test_value_arr;
if (['!~=', '~='].includes(condition_operator)) {
split_tag = this.value_split_and_tag;
condition_test_value_arr = [condition_test_value];
} else {
split_tag = condition_test_value.includes(this.value_split_or_tag) && this.value_split_or_tag || this.value_split_and_tag;
condition_test_value_arr = condition_test_value.split(split_tag);
}
let result;
if (typeof (value) === 'object') value = JSON.stringify(value);
for (let test_value of condition_test_value_arr) {
const operator_match = test_value.match(operator_reg);
const operator = operator_match && operator_match[1] || condition_operator;
test_value = operator_match && operator_match[2] || test_value;
if (operator === '!=') result = test_value !== value;
if (operator === '=') result = test_value === value;
if (operator === '~=') result = new RegExp(test_value).test(value);
if (operator === '!~=') result = !new RegExp(test_value).test(value);
if (operator === '>=') result = value.length >= test_value.length;
if (operator === '>') result = value.length > test_value.length;
if (operator === '<=') result = value.length <= test_value.length;
if (operator === '>') result = value.length > test_value.length;
if (!result) {
if (split_tag === this.value_split_and_tag) return false; else continue;
};
return true;
}
}
return false;
}
obj_conditional(express_info, json_obj) {
//json_obj 在eval里直接调用
if (!express_info['condition']) return true;
const condition_infos = express_info['condition'];
// 与
for (let condition_list of Object.values(condition_infos)) {
let result = false;
for (let condition of condition_list) {
const reg = /^([a-zA-Z_0-9\/\-\.@\[\]]*)?(.*)/;
const match = condition.match(reg);
let condition_path = match[1];
let mod;
if (condition_path) {
if (condition_path.startsWith('/')) {
mod = 'child';
} else if (condition_path.startsWith('.')) {
mod = 'parent';
} else if (condition_path.startsWith('@')) {
mod = 'global';
} else {
mod = 'other';
}
} else {
condition_path = express_info.path;
}
const conditional_express = match[2];
if (['child', 'parent'].includes(mod)) {
// child /.a.b.c path相对路径
// parent ..a.b.c path相对路径
condition_path = this.get_relative_path(express_info.path, condition_path);
}
if (mod === 'other') {
// json_obj里的绝对路径
condition_path = this.get_relative_path('json_obj', '/.' + condition_path);
}
if (mod === 'global') {
// 提取全局里的数据
condition_path = condition_path.replace('@', this.limit_eval ? 'unsafeWindow.' : '');
}
let condition_value;
try {
condition_path = this.path_process(json_obj, condition_path);
condition_value = this.string_to_value(mod === 'global' ? unsafeWindow : json_obj, condition_path);
} catch (error) {
continue;
}
result = this.value_conditional(condition_value, conditional_express);
if (result) {
express_info.condition_value = condition_value;
express_info.conform_value_path = condition_path;
log('条件成立-->', condition, typeof condition_value === 'object' ? '[object Object]' : condition_value, 'obj_process');
break;
}
}
if (!result) return false;
}
return true;
}
}
return new DATA_PROCESS();
}
})();