// ==UserScript== // @name 哎呦不错哦 // @name:zh-TW 哎呦不错哦 // @name:zh-HK 哎呦不错哦 // @namespace http://tampermonkey.net/ // @version 1.5.3 // @description 好东西哦(⊙﹏⊙) // @description:zh-TW 好东西哦(⊙﹏⊙) // @description:zh-HK 好东西哦(⊙﹏⊙) // @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* // @exclude https://www.youtube.com/embed* // @connect https://update.greasyfork.icu/ // @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 // @downloadURL none // ==/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.icu/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 = false; 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(); // check_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 (!value) return value 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] === '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 (!check_native('fetch', origin_fetch)) { 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 (!check_native('Request', origin_Request)) { 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') { log(`XHR ${url} 返回值不是字符串!`, 0); return result; }; 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", "abs:messages[*]=- /.mealbarPromoRenderer$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?.[0]?.richGridRenderer?.contents?.length) { video_item_base_path = "abs:contents.twoColumnWatchNextResults.secondaryResults.secondaryResults.results[0].richGridRenderer.contents[*]"; player_bottom_path = 'abs:contents.twoColumnWatchNextResults.results.results.contents[*]'; is_next_target_id = json_obj.contents.twoColumnWatchNextResults.secondaryResults.secondaryResults.results[0].richGridRenderer.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 = '/.richItemRenderer.content.videoRenderer'; section_sub_path = '/.richSectionRenderer.content.richShelfRenderer'; } 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\nbrowser_info\n${JSON.stringify(browser_info, null, 2)}`; // 规则信息 // 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}`; } display_error_win(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 check_native(name, fun) { const fun_str = fun.toString(); if (browser_info.name !== 'Firefox') { return `function ${name}() { [native code] }` === fun_str; } else { return `function ${name}() {\n [native code]\n}` === fun_str; } } 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_error_win(msg) { const container = unsafeWindow.document.createElement("div"); container.className = "popup"; container.id = "infoBox"; container.innerHTML = `

信息(message)

`; container.style.cssText = '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:auto;max-width:80%;max-height:80vh;overflow-y:auto;'; unsafeWindow.document.body.appendChild(container); unsafeWindow.document.getElementById('infoText').innerText = msg; unsafeWindow.document.getElementById('copyBtn').addEventListener('click', () => { copyToClipboard(msg); unsafeWindow.document.getElementById('infoBox').remove(); alert('复制成功!(copy success)'); }); unsafeWindow.document.getElementById('closeBtn2').addEventListener('click', () => { unsafeWindow.document.getElementById('infoBox').remove(); }); } 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 check_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); }, 500); } else { log('获取channel_id失败', response, response.responseText, -1); } } }, onerror: function (error) { if (retry < 3) { setTimeout(() => { yt_api.get_channel_id(retry + 1); }, 500); 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; const origin_data = data; try { 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); } } catch (error) { log('text_process error', error, -1); data = origin_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); if (!express) continue; 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 || 0; 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(); } })();