// ==UserScript== // @name 哎呦不错哦(学会看简介 黑号好像能用了,反馈一下) // @name:zh-TW 哎呦不错哦(學會看簡介 黑号好像能用了,反馈一下) // @name:zh-HK 哎呦不错哦(學會看簡介 黑号好像能用了,反馈一下) // @namespace http://tampermonkey.net/ // @version 1.6.8 // @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://api.cobalt.tools // @grant unsafeWindow // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @grant GM_info // @grant GM_addValueChangeListener // @grant GM_removeValueChangeListener // @grant GM_setClipboard // @grant GM_listValues // @grant GM_deleteValue // @run-at document-start // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com // @license MIT // @downloadURL none // ==/UserScript== // https://api.cobalt.tools 视频解析API This is a used to download video parsing API (function () { let uuid = GM_getValue('uuid'); if (!uuid) { uuid = crypto.randomUUID().substring(0, Math.floor(Math.random() * 5) + 6).replace(/-/g, ''); GM_setValue('uuid', uuid); } if (unsafeWindow[uuid]) { console.log('重复注入!'); return; } unsafeWindow[uuid] = true; let debugger_fun_name; const disableRemovePlayerAd = false; const open_config_keyword = '2333'; const display_error_keyword = '2444'; const reset_config_keyword = '2555'; 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 element_monitor_observer; let real_language = user_data.language; let is_account_init; let fake_fetch; const inject_info = { "ytInitialPlayerResponse": false, "ytInitialData": false, "ytInitialReelWatchSequenceResponse": false, "xhr": false, "fetch": false }; const $ = unsafeWindow.document.querySelector.bind(unsafeWindow.document); const $$ = unsafeWindow.document.querySelectorAll.bind(unsafeWindow.document); 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(); if (disableRemovePlayerAd) { config_api.common_ytInitialPlayerResponse_rule = config_api.common_ytInitialPlayerResponse_rule.slice(3); } const SPLIT_TAG = '###'; let cur_watch_channle_id; const trustedScript = trustedScriptInit(); setSecurePolicy(); init(); function init() { log('初始化开始!' + href, 0); url_observer(); is_account_init = false; data_process.set_obj_filter(obj_process_filter); config_api.config_init(user_data.language); const init_hook = init_hook_collection(); init_hook.property(); init_hook.other(); init_hook.request(); unsafeWindow.document.addEventListener('DOMContentLoaded', function () { set_search_listen(); // check_update(); on_page_change(); }); isinint = true; log('初始化结束!' + href, 0); open_debugger && set_debugger(); } function setSecurePolicy() { if (!unsafeWindow.isSecureContext || !unsafeWindow.trustedTypes?.createPolicy) return; try { unsafeWindow.trustedTypes.createPolicy("default", { createScriptURL: (url) => url, createHTML: (html) => html, createScript: (script) => script }); } catch (error) { } } function trustedScriptInit() { try { let test_value; eval('test_eval = 1'); return function (str) { return str; }; } catch (error) { if (unsafeWindow.trustedTypes) { const policy = unsafeWindow.trustedTypes.createPolicy('eval', { createScript: (script) => script }); return function (str) { return policy.createScript(str); }; } else { log('trustedTypes not support', error, -1); } }; }; 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(trustedScript(`debugger_${name}`)) && (eval(trustedScript(`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(trustedScript(`debugger_${name}`)) && (eval(trustedScript(`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 = unsafeWindow.document.createElement; unsafeWindow.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.fetch = fake_fetch; contentWindow.change_history = true; return contentWindow; } }); } return node; }; unsafeWindow.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); } fake_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 = $('#filter-chip-bar > div > ytm-chip-cloud-chip-renderer.selected'); node_list = $$('#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 = $('#chips > yt-chip-cloud-chip-renderer.style-scope.ytd-feed-filter-chip-bar-renderer.iron-selected'); node_list = $$('#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_; }(); unsafeWindow.fetch = fake_fetch; unsafeWindow.fetch.toString = origin_fetch.toString.bind(origin_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() { let analyzing_download_url = false; function common() { if (page_type === 'yt_shorts') { shorts_fun.check_shorts_exist(); } } function element_monitor() { element_monitor_observer?.disconnect(); const configs = wait_configs[page_type] || []; if (configs.length === 0) return; const callback = function (mutationsList) { for (let i = configs.length - 1; i >= 0; i--) { const config = configs[i]; const selector = config.seletor; const nodes = $$(selector); for (let node of nodes) { if (node.offsetHeight > 0) { if (config.inject) { if (!node.inject_xxxx) { node.inject_xxxx = true; } else { configs.splice(i, 1); break; } } if ('count' in config) { if (config.count > 0) { config.count--; if (config.count === 0) { configs.splice(i, 1); } } } // log(`找到${selector}`, 0); const funs = Array.isArray(config.fun) ? config.fun : [config.fun]; for (let fun of funs) { fun(node); } break; } } } if (configs.length === 0) { log('monitor end', 0); element_monitor_observer.disconnect(); return; } }; element_monitor_observer = new MutationObserver(callback); element_monitor_observer.observe($('body'), { childList: true, subtree: true }); } const wait_configs = { "yt_shorts": [ { "seletor": "ytd-reel-video-renderer[is-active] video", "inject": true, "fun": [shorts_auto_scroll, set_shorts_dbclick_like, set_shorts_progress] }, { "seletor": "ytd-reel-video-renderer[is-active] #comments-button", "inject": true, "fun": [shorts_change_comment_click] }, { "seletor": "ytd-reel-video-renderer[is-active] video", "count": 30, "fun": [] }, // { // "seletor": "ytd-reel-video-renderer[is-active] div#like-button #like-button button", // "inject": true, // "fun": [set_shorts_download] // } ], // "yt_watch": [{ // "seletor": "div.YtSegmentedLikeDislikeButtonViewModelSegmentedButtonsWrapper", // "count": 30, // "fun": set_watch_download // }], // "yt_music_watch": [{ // "seletor": "#layout > ytmusic-player-bar > div.middle-controls.style-scope.ytmusic-player-bar > div.middle-controls-buttons.style-scope.ytmusic-player-bar > #like-button-renderer > yt-button-shape.dislike > button", // "inject": true, // "fun": set_music_download // }], // "mobile_yt_watch": [{ // "seletor": "div.YtSegmentedLikeDislikeButtonViewModelSegmentedButtonsWrapper", // "count": 10, // "fun": set_watch_download // }], "mobile_yt_shorts": [{ "seletor": 'div.carousel-item[aria-hidden="false"] ytm-like-button-renderer', "count": 10, "fun": [shorts_auto_scroll, set_shorts_dbclick_like, set_shorts_progress] }], }; common(); element_monitor(); function set_dbclick(node, handler) { if (node.inject_dbclick) return; node.inject_dbclick = true; let corgin_onclick = node.onclick; let timers = []; node.onclick = node.onclick_ = function (event) { if ((node.dbclick_intercept_propagation || node.click_intercept_propagation)) { event.stopPropagation(); } const timer = setTimeout(() => { if (node.dbclick_intercept_propagation && !node.click_intercept_propagation) { let parent = node.parentElement; if (parent) { let parentHandler = parent.onclick; if (typeof parentHandler === 'function') { parentHandler.call(parent, event); } parent.dispatchEvent(event); } } timers.splice(timers.indexOf(timer), 1); corgin_onclick?.call(this, event); }, 300); timers.push(timer); }; define_property_hook(node, 'onclick', { get: function () { return this.onclick_; }, set: function (fun) { corgin_onclick = fun; } }); node.addEventListener('dblclick', function (event) { if (node.dbclick_intercept_propagation) event.stopPropagation(); for (let timer of timers) { clearTimeout(timer); } timers.length = 0; handler?.call(this, event); }); } function set_download_event(dislike_node, like_node, url = href) { if (!like_node) log('like_node is null'); if (!dislike_node) log('dislike_node is null'); if (!like_node || !dislike_node) { log('set_download_event error like_node or dislike_node is null', -1); return; }; function randomColor() { var letters = '0123456789ABCDEF'; var color = '#'; for (var i = 0; i < 6; i++) { color += letters[Math.floor(Math.random() * 16)]; } return color; } function set_node_download_event(node, type = 'like') { node.style.transition = `${node.style.transition && (node.style.transition + " , ")}background-color 0.5s ease`; node.backgroundColor_ = node.style.backgroundColor; node.resolve_background_color = function () { if (this.background_color_interval_id) clearInterval(this.background_color_interval_id); this.style.backgroundColor = this.backgroundColor_; }; set_dbclick(node, () => { if (user_data.dbclick_download_video === 'off') return; const tips = type === 'like' ? flag_info.download_video_confirm_tips : flag_info.download_audio_confirm_tips; if (!confirm(`${unsafeWindow.document.title}\n\n${tips}`)) return; const result = video_download(url, type !== 'like', node); if (result) { node.background_color_interval_id = setInterval(() => { node.style.backgroundColor = randomColor(); }, 100); } }); } set_node_download_event(like_node, 'like'); set_node_download_event(dislike_node, 'dislike'); } function set_shorts_dbclick_like(video_node) { video_node = page_type === 'yt_shorts' ? video_node : $('div.carousel-item[aria-hidden="false"] div.video-wrapper'); if (!video_node) return; video_node.dbclick_intercept_propagation = true; set_dbclick(video_node, function () { if (user_data.shorts_dbclick_like === 'off') return; const like_seltor = page_type === 'yt_shorts' ? 'ytd-reel-video-renderer[is-active] #like-button > yt-button-shape > label > button' : 'div.carousel-item[aria-hidden="false"] ytm-like-button-renderer button'; $(like_seltor)?.click(); }); } function set_shorts_progress(node) { const video_node = page_type === 'yt_shorts' ? node : $('video'); if (!video_node || video_node.inject_shorts_progress) return; video_node.inject_shorts_progress = true; video_node.addEventListener('timeupdate', function () { if (user_data.shorts_add_video_progress === 'off') return; const shape_button = page_type === 'yt_shorts' ? $('ytd-reel-video-renderer[is-active] #button-shape > button') : $('div.carousel-item[aria-hidden="false"] ytm-bottom-sheet-renderer button'); if (!shape_button) return; const progress = video_node.currentTime / video_node.duration * 100; const transparency = page_type === 'yt_shorts' ? '0.05' : '0.3'; const progress_color = page_type === 'yt_shorts' ? 'rgba(0, 0, 255, 0.4)' : 'rgba(255, 255, 0, 0.4)'; shape_button.style.background = `linear-gradient(to top, ${progress_color} ${progress}%, rgba(0, 0, 0, ${transparency}) ${progress}%)`; }); } function shorts_change_comment_click(comments_node) { const comments_button = comments_node.querySelector('ytd-button-renderer > yt-button-shape > label > button'); const onclick_setter = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "onclick").set; const current_render_node = $('ytd-reel-video-renderer[is-active]'); const wrap = function (fun) { return function (event) { const expand_node = current_render_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 = current_render_node.querySelector('#visibility-button > ytd-button-renderer > yt-button-shape > button'); expand_close_node?.click(); } else { fun.call(this, event); } }; }; comments_button.onclick = comments_button.onclick_ = wrap(comments_button.onclick); define_property_hook(comments_button, 'onclick', { get: function () { return this.onclick_; }, set: function (fun) { this.onclick_ = wrap(fun); onclick_setter.call(comments_button, this.onclick_); } }); } function shorts_auto_scroll(video_node) { video_node = page_type === 'yt_shorts' ? video_node : $('video'); if (!video_node) return; if (video_node?.inject_auto_scroll) return; video_node.inject_auto_scroll = true; video_node.loop = false; define_property_hook(video_node, 'loop', { get: function () { return false; } }); video_node?.addEventListener('ended', function () { if (user_data.shorts_auto_scroll === 'on') { if (page_type === 'yt_shorts') { $('#navigation-button-down > ytd-button-renderer > yt-button-shape > button').click(); } else { simulate_swipeup(this, 500, 100); } return; } if (user_data.shorts_disable_loop_play === 'on') { return; } this.play(); }); } function set_shorts_download(like_button) { const dislike_button = $('ytd-reel-video-renderer[is-active] #dislike-button > yt-button-shape > label > button'); set_download_event(dislike_button, like_button); } function set_music_download(dislike_node) { const like_node = dislike_node.parentElement.parentElement.querySelector('#button-shape-like > button'); set_download_event(dislike_node, like_node); } function set_watch_download(wrapper_node) { const like_node = wrapper_node.querySelector('like-button-view-model button'); const dislike_node = wrapper_node.querySelector('dislike-button-view-model button'); set_download_event(dislike_node, like_node); } function set_mobile_shorts_download(wrapper_node) { const nodes = wrapper_node.querySelectorAll('button'); if (nodes.length !== 2) { log('set_mobile_shorts_download 节点数量不正确', nodes.length, -1); return; } const like_node = nodes[0]; const dislike_node = nodes[1]; dislike_node.click_intercept_propagation = true; dislike_node.dbclick_intercept_propagation = true; like_node.click_intercept_propagation = true; like_node.dbclick_intercept_propagation = true; set_download_event(dislike_node, like_node); } function video_download(url = href, isAudioOnly = false, targetNode = null) { if (page_type === 'yt_music_watch') { url = 'https://www.youtube.com/watch?' + href.split('?')[1]; } // log('下载地址', url, isAudioOnly, 0); if (analyzing_download_url) return false; analyzing_download_url = true; const xhr = new XMLHttpRequest(); xhr.open('POST', 'https://api.cobalt.tools/api/json', true); xhr.setRequestHeader('Cache-Control', 'no-cache'); xhr.setRequestHeader('Accept', 'application/json'); xhr.setRequestHeader('Content-Type', 'application/json'); const data = JSON.stringify({ url: encodeURI(url), vQuality: 'max', filenamePattern: 'basic', isAudioOnly: isAudioOnly, disableMetadata: true, }); xhr.onload = function () { if (xhr.status >= 200 && xhr.status < 300) { const response = JSON.parse(xhr.responseText); const download_url = response?.url; if (download_url) { window.open(download_url, '_blank'); analyzing_download_url = false; targetNode.resolve_background_color(); return; } } let tips; try { const json_data = JSON.parse(xhr.responseText); tips = json_data?.text; } catch (error) { tips = xhr.responseText; } alert(`download failed\nstatus: ${xhr.status}\nresponseText: ${tips}\n`); analyzing_download_url = false; targetNode.resolve_background_color(); }; xhr.onerror = function (error) { alert(`download failed\nstatus: ${xhr.status}\nerror: ${error}\n`); analyzing_download_url = false; targetNode.resolve_background_color(); }; xhr.send(data); return true; } } 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 = unsafeWindow.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": "规则信息", "del_config_confirm_tips": "你确定要删除所有配置信息?", "btn_dbclick_download_video_tips": "双击点赞下载视频,双击不喜欢下载音频", "btn_dbclick_download_video_title": "双击下载视频", "download_video_confirm_tips": "要下载这个视频?", "download_audio_confirm_tips": "要下载这个音频?", "btn_shorts_auto_scroll_title": "自动滚动", "bt_shorts_disable_loop_play_title": "禁止循环播放", "btn_shorts_dbclick_like_title": "双击视频点赞", "btn_shorts_add_video_progress_title": "添加视频进度", "shorts_recommend_split_tag": "Shorts功能配置", }, "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": "規則資訊", "del_config_confirm_tips": "你確定要刪除所有設定資訊?", "btn_dbclick_download_video_tips": "雙擊我喜歡下載影片,雙擊我不喜歡下載音檔", "btn_dbclick_download_video_title": "雙擊下載視頻", "download_video_confirm_tips": "要下載這個影片?", "download_audio_confirm_tips": "要下載這個音檔?", "btn_shorts_auto_scroll_title": "自動捲動", "bt_shorts_disable_loop_play_title": "禁止循環播放", "btn_shorts_dbclick_like_title": "雙擊影片按讚", "btn_shorts_add_video_progress_title": "添加影片進度", "shorts_recommend_split_tag": "Shorts功能配置", }, "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": "規則資訊", "del_config_confirm_tips": "你確定要刪除所有配置信息嗎?", "btn_dbclick_download_video_tips": "雙擊我喜歡下載影片,雙擊我不喜歡下載音檔", "btn_dbclick_download_video_title": "雙擊下載視頻", "download_video_confirm_tips": "要下載這個影片?", "download_audio_confirm_tips": "要下載這個音檔?", "btn_shorts_auto_scroll_title": "自動捲動", "bt_shorts_disable_loop_play_title": "禁止循環播放", "btn_shorts_dbclick_like_title": "雙擊影片按讚", "btn_shorts_add_video_progress_title": "添加影片進度", "shorts_recommend_split_tag": "Shorts功能配置", }, "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", "del_config_confirm_tips": "Are you sure you want to delete all configuration settings?", "btn_dbclick_download_video_tips": "Double click like button to download the video, double click dislike button to download the audio", "btn_dbclick_download_video_title": "DoubleClickDownloadVideo", "download_video_confirm_tips": "Do you want to download this video?", "download_audio_confirm_tips": "Do you want to download this audio?", "btn_shorts_auto_scroll_title": "AutoScroll", "bt_shorts_disable_loop_play_title": "DisableLoopPlay", "btn_shorts_dbclick_like_title": "DoubleClickLikeVideo", "btn_shorts_add_video_progress_title": "AddVideoProgress", "shorts_recommend_split_tag": "ShortsConfig", } }, common_ytInitialPlayerResponse_rule: [ "abs:playerAds=- $exist", "abs:adSlots=- $exist", "abs:adPlacements=- $exist", "abs:auxiliaryUi.messageRenderers.bkaEnforcementMessageViewModel.isVisible=json(\"true\") $exist", "abs:adBreakHeartbeatParams=- $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 } } } }; data_process.storage_obj('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 } } }; data_process.storage_obj('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=+sobj(" + (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.yt-searchbox-input'; const search_input_node = $(search_selector); if (search_input_node) { clearInterval(interval_id); if (search_input_node.set_listener) return; search_input_node.set_listener = true; const oninput = function (event) { if ([display_error_keyword, open_config_keyword, reset_config_keyword].includes(this.value)) { setTimeout(function () { if (search_input_node.value === open_config_keyword) { search_input_node.value = ''; display_config_win(); } if (search_input_node.value === reset_config_keyword) { user_data_api.reset(); return; } 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')}`; //账号信息 const str_channel_id = '' + channel_id; tips += `\n\naccount_info\nchannel_id: ${(str_channel_id === 'default' || str_channel_id.length <= 10) ? str_channel_id : (str_channel_id.slice(0, 5) + '...' + str_channel_id.slice(-5))}`; tips += `\nreal_language:${real_language}`; 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); } }; search_input_node.addEventListener('input', oninput); } else if (count > 50) { clearInterval(interval_id); log('搜索框未找到', -1); } }, 200); } function simulate_swipeup(target, start, end) { function createAndDispatchTouchEvent(type, target, clientY) { const touches = type !== 'touchend' && [new Touch({ identifier: 0, target: target, clientY: clientY })] || []; let touchEvent = new TouchEvent(type, { touches: touches, bubbles: true, cancelable: true }); target.dispatchEvent(touchEvent); } createAndDispatchTouchEvent('touchstart', target, start); createAndDispatchTouchEvent('touchmove', target, end); createAndDispatchTouchEvent('touchend', target); } 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 = unsafeWindow.document.createElement("textarea"); // textarea.value = text; // unsafeWindow.document.body.appendChild(textarea); // textarea.select(); // unsafeWindow.document.execCommand('copy'); // unsafeWindow.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() { while (!debugger_fun_name) { let tmp = crypto.randomUUID().substring(0, Math.floor(Math.random() * 4) + 3).replace(/-/g, ''); tmp = tmp.match('[a-z].+')?.[0]; if (tmp && !unsafeWindow[tmp]) { debugger_fun_name = tmp; } } log(`debugger_fun_name: ${debugger_fun_name}`, 0); 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_fun_name] = 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(trustedScript(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_fun_name](keys[action]); } else if (action >= keys.length) { keys.forEach(function (key) { unsafeWindow[debugger_fun_name](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 ([-1, 0, 999].includes(flag) || 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 = `