Greasy Fork is available in English.

YouTube视频&音乐&儿童广告拦截

拦截所有youtube视频广告,音乐播放广告,儿童视频广告,不留白,不闪屏,无感,体验第一。已适配移动端,支持自定义拦截,添加影视频道

< Обсуждения YouTube视频&音乐&儿童广告拦截

Вопрос/комментарий

§
Создано: 13.04.2024
Отредактировано: 13.04.2024

Code建議修正部份

Class Function的Override需要修正,見uBO的做法

這種做法才符合類繼承。避免腳本衝突 (包括與YT自身的改動的腳本衝突)

Request

Request部份應改成

    unsafeWindow.Request = class extends unsafeWindow.Request {
        constructor(input, options = void 0) {
            super(input, options);
            if (options && options['body']) this['body_'] = options['body'];
        }
    };

XMLHttpRequest

XMLHttpRequest 也需要更改

    unsafeWindow.XMLHttpRequest = class extends unsafeWindow.XMLHttpRequest {
        open(method, url, ...opts) {
            inject_info.xhr = true;
            return super.open(method, url, ...opts);
        }
        get xhrResponseValue() {
            const xhr = this;
            let result = super.response;
            if (xhr.readyState === XMLHttpRequest.DONE) {
                if (xhr.responseURL.indexOf('youtubei/v1/player') > -1) {
                    result = data_process.text_process(result, ytInitialPlayerResponse_ad_rule, 'insert', true);
                }
                if (xhr.responseURL.indexOf('youtube.com/playlist') > -1) {
                    let obj;
                    try {
                        obj = JSON.parse(result);
                    } catch (error) {
                        log('JSON解析失败', 1);
                        return result;
                    }
                    data_process.obj_process(obj[2].playerResponse, ytInitialPlayerResponse_ad_rule, true);
                    data_process.obj_process(obj[3].response, watch_page_ytInitialData_ad_rule, true);
                    tmp_debugger_value = obj;
                    result = JSON.stringify(obj);
                }
            } else {
                result = '';
            }
            return result;
        }
        get responseText() {
            return this.xhrResponseValue;
        }
        get response() {
            return this.xhrResponseValue;
        }
    };
§
Создано: 13.04.2024
Отредактировано: 13.04.2024

document.createElement.toString = origin_creatElement.toString 的部份寫錯了

現在是


let origin_creatElement = document.createElement
document.createElement.toString = origin_creatElement.toString
document.createElement = function () {
    let node = origin_creatElement.apply(this, arguments)
    // ...
}

應更正為

const origin_createElement = document.createElement;
document.createElement = function (tagName, options = void 0) {
    let node = origin_createElement.call(this, tagName, options);
    // ...
}
document.createElement.toString = origin_createElement.toString.bind(origin_createElement);

(注意錯別字 origin_creatElement )

非常感谢呀,我学习学习

§
Создано: 14.04.2024
Отредактировано: 14.04.2024
  • 以下的只是剛好發現。你可以順便改一改。不改也沒差。上面的較重要

1.3.1 新增的@match是多餘的

// @match        https://www.youtube.com/results*

已被原本的

 // @match        https://www.youtube.com/*

包含了

1.3.1 修漏了的部份

  • 你只對 if (upcoming_express.includes(path_info.express)) { 那裡加了 try-catch block
  • 沒有對 if (live_express.includes(path_info.express)) { 那裡加 try-catch block

錯字部份

除了 creatElement -> createElement 還有 rsponse -> response

預設語言

語言部份,應該是反過來吧 非華文的區域就預設英文才對

user_data.language = user_data.language.indexOf('en-') === 0 ? 'en' : 'zh-CN'

修改成

user_data.language = !user_data.language.includes('zh-') ? 'en' : 'zh-CN'

body_

body_ 你只需要string吧。UInt8Array的你不用浪費記憶體儲Cache

    unsafeWindow.Request = class extends unsafeWindow.Request {
        constructor(input, options = void 0) {
            super(input, options);
            if (options && typeof options['body'] === "string") this['body_'] = options['body'];
        }
    };
  • 註: YouTube中,字串body都是非空的。空的也會在JSON.parse的try-catch中排除

其他小修正

indexOf -> includes

aaaa.indexOf(bbbb) > -1

這種寫法可以改成

aaaa.includes(bbbb)

會快一點點

querySelector -> getElementById

document.querySelector('#' + key)
document.getElementById(key)

removeChild -> remove

document.querySelector('body').removeChild(container)
container.remove()

(new Date).getTime() -> Date.now()

(new Date().getTime()
Date.now()

indexOf(...) == 0 => startsWith

cookie.indexOf(name) == 0
cookie.startsWith(name)

innerText -> textContent

  • textContent 是W3C標準。比innerText快一點點
style.innerText = css_str;
style.textContent = css_str;

缺的就是大佬的指点,感谢感谢。我慢慢改好再放出来

§
Создано: 24.04.2024
Отредактировано: 24.04.2024

發現Tabview Youtube運作時,發現了以下bug。

原因是 Firefox 不支持 NavigateEvent.destination

(見 https://developer.mozilla.org/en-US/docs/Web/API/NavigateEvent/destination )

建議修改下面代碼

function url_change(event = null) {
    if (event && event.destination.url.indexOf('about:blank') === 0) return
    href = event ? event.destination.url : location.href
    log('网页url改变 href -> ' + href, 0)
    config_init()
}

改成

function url_change(event = null) {
    const destinationUrl = event?.destination?.url || '';
    if (destinationUrl.indexOf('about:blank') === 0) return;
    href = destinationUrl || location.href;
    log('网页url改变 href -> ' + href, 0);
    config_init();
}

詳細代碼: https://github.com/cyfung1031/userscript-supports/raw/main/tmp-480192.user.js

期待你的更新~

更新啦,大佬有空再瞧瞧。这脚本还没做Firefox的兼容,我知道不只这地方,还有其他地方也有挺大的问题的。以后再慢慢做。

§
Создано: 01.05.2024
Отредактировано: 01.05.2024

另外發現使用了var的問題

這個下次更新時順便修改就好

getCookie, copyToClipboard, get_authorization 中的var都應該改用let或者const


另外個人建議整個coding部份都應使用 (function(){ ... })(); 包住避免變數宣告影響外面

coding油猴会裹一层的的。get_authorization就不改了,抄的要保持原汁原味,哈哈哈

§
Создано: 03.05.2024
Отредактировано: 03.05.2024

如果多個分頁同時開YouTube,2333的設定會不一致

(Tab1和Tab2同時打開。Tab1按2333改了,Tab2按2333的話會是改動前的設定)

方法1

  • GM_addValueChangeListener 的話可以保持設定一致,不過可能會有bug (因為數值隨時改變)
  • 整個設計都要變成GM.getValue GM.setValue
  • (注意:長遠來說,GM_getValueGM_setValue 將會被廢除)

方法2 (最少改動)

簡單的話,這樣改就可以

get_user_data_api裡加新method

        getLatestValues(tmp_user_data){
            let latest_user_data = GM_getValue(channel_id);
            if (latest_user_data) {
                Object.assign(tmp_user_data, latest_user_data);
            }
        }

後面這樣改 (加 user_data_api.getLatestValues(user_data);

                    if (search_input_node.value === open_config_keyword) {
                        search_input_node.value = '';
                        user_data_api.getLatestValues(user_data);
                        display_config_win();
                    }

這個部份可以不用regexp


                    let positions = [];
                    let regex = /\]/g;
                    while ((match = regex.exec(express_info.path)) !== null) {
                        positions.push(match.index);
                    }
                let positions = [];
                let regex = /\]/g;
                let match;
                while ((match = regex.exec(path)) !== null) {
                    positions.push(match.index);
                }

改為

function getPositions(path){
let positions = [];
for (let i = 0; i < path.length; i++) {
    if (path[i] === ']') {
        positions.push(i);
    }
}
return positions;
}
/yt_shorts$/.test(page_type)
/^\[/.test(short_condition_path)

都能改為startsWith / endsWith

1.配置同步确实没有考虑过。考虑了一下最后我还是决定用GM_addValueChangeListener,这样全部数据都能实时同步,这样更全面一下。至于bug,好像还没发现,我再测试看看。
2. regexp 对于这个,以前就是想着不要用for,看着代码太长了,懒得写又不好看,看下正则能不能一步到位,最后发现js的正则没有这个,最后就抄现在写这一段,代码看着少一点
3..test 这些确实有几个改到的,这次都改啦 。
4. GM.setValue 这几个api确实没仔细看过。GM_setValue 改成GM.setValue 确实挺好的。不过GM_getValue 改成 GM.getValue 的话,还要加await,效果跟 GM_getValue 一样,在我的使用场景下,代码就变得复杂了,这个我觉得还是要保留的。
大佬辛苦了,感谢大佬指点。比心,更新后,期待大佬抽空去瞧瞧

§
Создано: 04.05.2024
Отредактировано: 04.05.2024

1.4.3 好像改得有點多。有人回報有bug了

regexp 能改 for的話,放到最外面做一個獨立function就好看得多。

部份腳本管理器不支援 GM_setValue GM_getValue; 或是不能 GM.setValue GM_getValue這樣的組合

我覺得你都用GM_setValueGM_getValue也沒所謂


盡量不使用regexp的原因

如果是簡單的東西,能不使用就不使用regexp吧。速度有差,特別是老電腦。

這種網絡資料請求的結果,盡量效能優先吧

我自己的話在這裡regexp比對之前會先試一下長度。如果長度不夠直接跳過

重覆性的.match的話,我覺得還是有必要改掉啦。for 的話不用拆字符快得多

regexp的問題部份

abs:....

reg = /^(abs:)?([a-zA-Z_0-9\.\*\[\]]*)((=\-|~=|=\+|=))([\s\S]*)?/;

這個雙重括號有什麼用。。沒看過 ((=\-|~=|=\+|=))

([\s\S]*)?這個寫法應該是有問題的吧 ? *不會同時存在

你是要

/^(abs:)?([\w\d.*\[\]]+)(=-|~=|=\+|=)([^+=-~].*)?$/

才對吧?

[\.|\[]

你肯定是 [\.|\[] 而不是 [.\[] ? 應該沒|

/^([a-zA-Z_0-9\/\.@\[\]]*)?(.*)/

原因和上面的一樣

應該是 /^([\w\d\/.@\[\]]*)(.*)$/

/channelId":\"(.*?)"/

前面的引號漏了應該是故意?

應該是 /channelId":"(.*)"/

§
Создано: 04.05.2024
Отредактировано: 04.05.2024

base_url.match



    if (base_url.match('https://www.youtube.com/?$')) tmp_page_type = 'yt_home';
    else if (base_url.match('https://m.youtube.com/?(#searching)?$')) 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';

這堆都是寫錯吧? 為什麼match裡面是string不是regexp?

建議用 new URL(location.href) 直接分析是哪個TYPE 較好

修正如下 (當然可以再簡化)


function get_page_type() {
    let tmp_page_type;
    const uo = new URL(href);
    const isDesktop = (uo.hostname === 'www.youtube.com');
    const isMobile = (uo.hostname === 'm.youtube.com');
    const isKids = (uo.hostname === 'www.youtubekids.com');
    const isMusic = (uo.hostname === 'music.youtube.com');
    if (isDesktop && uo.pathname === '/') tmp_page_type = 'yt_home';
    else if (isMobile && uo.pathname === '/') tmp_page_type = 'mobile_yt_home';
    else if (isDesktop && uo.pathname === '/watch') tmp_page_type = 'yt_watch';
    else if (isMobile && uo.pathname === '/watch') tmp_page_type = 'mobile_yt_watch';
    else if (isDesktop && uo.pathname === '/results') tmp_page_type = 'yt_search';
    else if (isMobile && uo.pathname === '/results') tmp_page_type = 'mobile_yt_search';
    else if (isDesktop && uo.pathname === '/shorts') tmp_page_type = 'yt_shorts';
    else if (isMobile && uo.pathname === '/shorts') tmp_page_type = 'mobile_yt_shorts';
    else if (isKids && uo.pathname === '/watch') tmp_page_type = 'yt_kids_watch';
    else if (isMusic && uo.pathname === '/') tmp_page_type = 'yt_music_home';
    else if (isMusic && uo.pathname === '/watch') tmp_page_type = 'yt_music_watch';
    else tmp_page_type = 'other';
    return tmp_page_type;
}

1. 部份腳本管理器不支援 GM_setValue GM_getValue; 这个还真不太了解额,只在用scriptcat和篡改猴,我就是感觉组合着用挺适合的。官方能出这两个种也是考虑到不同场景把
2. reg = /^(abs:)?([a-zA-Z_0-9\.\*\[\]]*)((=\-|~=|=\+|=))([\s\S]*)?/; 双重括号用来子匹配的 ((=\-|~=|=\+|=)) 这些都是用来提取规则里的操作符的
3. *?是非贪婪模式,就是尽可能匹配少的字符串,没?就是贪婪了
4. [\.|\[] 这个确实有问题,有时候脑抽就会写出来,哈哈哈

while ((match = reg.exec(basic_path)) !== null) {
positions.push(match.index);
} 字符串短的时候这个比for没差多少的,字符串稍微长一点的话,性能比for更好更快的。不信你试下

沒有必要做雙重吧!? matchs[3] 跟 matchs[4] 是一模一樣 (另外英文錯了,match是加es)

(a|b|c|d)

本身就會提取

比如說

"I love orange".match(/love\s+(apple|orange|banana)/)

matches[1] 會是orange

就是非贪婪模式重覆了! 有*就不用再?

比如說

author_id_reg = /"channelId":"(.*?)"/;

你做這個

if (match && match.length > 1) author_id = match[1]; 

它match的話,match.length一定是2;也不用.*?這個怪異寫法

.是萬用符,包括空白和非空白。(不包括換行)

  • .?是一個或沒有字元 (n=0,1)
  • .+ 是一個字元或以上 (n=1,2,...)
  • .* 是沒有字元或一個字元或以上 (n=0,1,2...)
§
Создано: 04.05.2024
Отредактировано: 04.05.2024

關於上面的 base_url.match

我查了, String.prototype.match(string)的話,參數的string會自動變成 new RegExp(string)

"my.home".match('my.home$')

會匹配成功

"my_home".match('my.home$')

也會匹配成功

"性能比for更好更快的。不信你试下"

我也是很好奇,所以做了一個測試

找到了也是一行的寫法

  for (let i = 0; (i = path.indexOf(']', i)) >= 0; i++) {
    positions.push(i);
  }

這個的話在舊browser會明顯較regexp快。新Firefox則是快一點

Chrome的話還是輸RegExp一點點

詳細: https://measurethat.net/Benchmarks/ListResults/30688

document.querySelector('body')

這個可以改成 document.body

limit_eval 的部份重複了

    data_process = new DATA_PROCESS();
    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;
    }

裡面的 new DATA_PROCESS(); 已經算好了 data_process.limit_eval的值,不用再算一次

(雖然不明白你為何要分開一個全域一個data_process)

    data_process = new DATA_PROCESS();
    data_process.set_obj_filter(obj_process_filter);
    limit_eval = data_process.limit_eval;

另外,limit_eval 除了存值,還有取值吧


        try {
            let test_eval;
            const test_val = 1;
            this.limit_eval = eval('test_eval = test_val') && (test_eval !== test_val);
        } catch (error) {
            this.limit_eval = true;
        }

原生函數部份應加try-catch避免問題

例如 _historyWrap 的部份

    const _historyWrap = function (type) {
        const orig = unsafeWindow.history[type];
        const e = new Event(type);
        return function () {
            const rv = orig.apply(this, arguments);
            try {
                e.arguments = arguments;
                unsafeWindow.dispatchEvent(e);
            } catch (err) { }
            return rv;
        };
    };

這樣的話就算報錯也不會影響原有的 replaceState / pushState

其他的騎劫也是同一道理 (包括 define_property_hook 的部份)

get_shorts_info

不清楚為何這裡你用xhr非fetch

xhr的話你除了比對 xhr.status === 200 外,還要檢查 xhr.readyState === XMLHttpRequest.DONE

if (xhr.status === 200 && xhr.readyState === XMLHttpRequest.DONE) {

另外,如果報錯 (reject),parseshortslist 那邊只有then和finally,抓取不了錯誤log

parse_shorts_list

parse_shorts_list 最開始應該要 if (!this.shorts_list || this.shorts_list.length === 0) return;

否則 const { id, title, views_lable, thumbnail_url } = this.shorts_list.pop(); 可能會報錯 (是有這個機會啦)

(lable是指label吧?)

check_shorts_exist

看不懂 user_data.shorts_list.pop(shorts); 這個部份。首先pop沒有參數傳入的

你用了forloop,shorts不一定是userdata.shortslist裡的第一個

有可能本來是想寫 for (let shorts of this.shorts_list) { 嗎??

get_interval_tag

upload_date_str = shorts['upload_date'] 可以是 undefined

也就是這個部份配對失敗


                        const upload_date_math = xhr.responseText.match(upload_date_reg);
                        if (upload_date_math) upload_date_str = upload_date_math[1] || '';
                        upload_date_str && !isNaN(new Date(upload_date_str)) && (upload_date = new Date(upload_date_str));

可以這樣改


            let uploadDate;
            try{
                uploadDate = new Date(upload_date_str);
            }catch(e){}
            if (!uploadDate) return "";

get_user_data_listener

user_data = newValue; 這個不建議啦 userdata應一直都是不變的物件參考 (userdataapi和userdata都是const宣告)

改用 Object.assign(user_data, newValue)

( get_channel_id 裡的 user_data = user_data_api.get();也是啦)

§
Создано: 05.05.2024
Отредактировано: 05.05.2024

1.4.3 的其他修正建議

  • deal_resposn -> deal_response
  • matchs -> matches
  • parseing -> parsing
  • orgin_ -> origin_

let -> const

user_data_api, user_data, inject_info, shorts_parse_delay, data_this, origin_console, error_messages

未使用變數

local_this 沒有使用,應刪掉

未有初始值

let page_type = ''; // let page_type;

convertPathToBracketNotation

obj_conditional 那邊也是 convertPathToBracketNotation

condition_path = express_info.path + data_this.convertPathToBracketNotation(condition_path.slice(1));
condition_path = express_info.path.slice(0, split_index) + data_this.convertPathToBracketNotation(short_condition_path);
condition_path = data_this.convertPathToBracketNotation(`json_obj${is_array_obj ? '' : '.'}` + condition_path);

getCookie

getCookie 還是加個 try catch 吧。失敗至少能返回null (decodeURIComponent失敗會報錯)

store_user_data

這是舊版本的名稱?已經沒有這個東西。直接報錯

我猜你是指 user_data_api.set();

函式的class object漏了

  • get_yt_api 裡的 get_subscribe_data

    • get_subscribe_data(retry + 1) 改為 yt_api.get_subscribe_data(retry + 1)
  • value_parse 裡的 value_parse(arg)

    • value_parse(arg) 改為 data_this.value_parse(arg)

obj_conditionalis_array_obj

obj_conditional 裡 沒有 is_array_obj

mod === 'other' 那個 json_obj${is_array_obj ? '' : '.'} 會直接報錯

改成 json_obj${Array.isArray(json_obj) ? '' : '.'}

fetch_ 裡的 return_response

  1. let / var / const
  2. 不需要return_response,直接傳response就可以了。沒有改動

value_parse 裡的 變數沒宣告

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(',');

get_shorts_infoxhr.onloadmatch 未宣告

let match = xhr.responseText.match(author_id_reg);

get_authorizationb = Vja();b 未宣告

const b = Vja();

update(tmp_user_data)last_version 未宣告

const last_version = GM_getValue('last_version', -1);

display_update_win 裡的 btn 未宣告

function btn_click() {
    const btn = this;
    if (btn.id === 'go_btn') {
        location.href = script_url;
    }
    container.remove();
}

remove_popup_hander

document.addEventListener('click', remove_popup_hander);

之前加

document.removeEventListener('click', remove_popup_hander);

避免重覆 (沒有正確呼叫 remove_popup_hander 就 再次呼叫display_config_win時)

    document.removeEventListener('click', remove_popup_hander);
    document.addEventListener('click', remove_popup_hander);

XMLHttpRequest 的部份

responseText & response 那個部份你可以直接抄修改版的代碼

DATA_PROCESS 裡的 set_obj_filter = function (obj_filter) { 是寫錯吧


    set_obj_filter = function (obj_filter) {
        this.obj_filter = typeof obj_filter === 'function' ? obj_filter : undefined;
    };

改成

    set_obj_filter (obj_filter) {
        this.obj_filter = typeof obj_filter === 'function' ? obj_filter : undefined;
    }

DATA_PROCESS 裡的 constructor

this.obj_filter;

改成

this.obj_filter = undefined;

config_init 一直log 語言錯誤

config_init 不是只有第一次init會執行

全域加

let langProblemLogged = false;

config_init 裡改成

    if (!langProblemLogged && !['zh-CN', 'zh-TW', 'zh-HK', 'en'].includes(tmp_language)) {
        langProblemLogged = true;
        log(`Does not support language ${tmp_language}, only supports zh-CN, zh-TW, zh-HK, en, and is compatible with English locations; there may be some errors.`, -1);
        tmp_language = tmp_language.startsWith('en-') ? 'en' : 'zh-CN';
    }

補充上面的 getPositions

原來是測試法問題

現在再做一個新測試

這次Firefox, Chrome, Safari, 都有一致結果: indexOf較快


把原本的

  const reg = /\]/g;
  let match;
  while ((match = reg.exec(basic_path)) !== null) {
    positions.push(match.index);
  }

換成

  for (let j = 0; (j = basic_path.indexOf(']', j)) >= 0; j++) {
    positions.push(j);
  }

就可以

我查了一下你講的 非贪婪模式

現在了解了,我之前都沒用過

感謝


obj_process

這個也看了一下。

我有留意到你在1.4.3搞了 get_relative_path和改了value_parse

但好像愈搞愈複雜,也沒有看到規則有明顯的變化,所以無視了,基於1.4.2去改

詳細代碼: https://github.com/cyfung1031/userscript-supports/raw/main/tmp-480192.user.js

期待你的更新~

主要改動

regexp

regexp 那裡有改過,之後才理解你講的那個 非贪婪模式

之前的應該也沒bug, 所以隨你改不改吧

比如說, path.match(/\[(.*?)\]/g) 改成了 path.match(/\[([^\(\)]*)\]/g) 這樣明確的寫法

當然 [abc[def] 這樣的話就會有分別

obj_process

裡面的函數宣告都抽出來了。

另外,for (const express of express_list) { 中的 matches 有可能匹對失敗

這個加了防錯log

String Concatenation

cur_path + '[' + index + ']';

這個寫法可以改成 ${cur_path}[${index}]

目前W3C比較推這種寫法,也比較直觀

add_data_to_abs_path

那些參數太多了吧。直接用一個Object再做Object.assign 就可以了吧

obj_property_traverse

裡面的參數傳來傳去會很花CPU處理

直接傳一個Object就好,裡面都是不變的Object參考

if (operator === '=')

執行次序改到前面

因為它不需要 const dec_obj = last_obj[last_key];

express_type

只判斷是否string 的部份改成boolean

path_extral_match

首先你用 [a-zA-Z_0-9\.\*\[\]]* 的話,不會有 \/

也就是 path_extral_match[0].startsWith('/') 永遠false

(或者之前的regex要改?)

然後就是用replace替代了match

relative_path_list, relative_short_path_list, relative_path_info_list

原本一拆三的relative_path改成了relative_path_map ^keyreal_keys ~keyshort_keys

但發現 ^key 是不需要加進去所以沒加了

另外加了一個防錯,防止重覆short_keys

1. 就是非贪婪模式重覆了! 有*就不用再?
有?才是非贪婪哦,你可以试下
let test_str = '"channelId":"UC_x5XG1OV2P6uZZ5FSM9Ttw"4545646"';

2.limit_eval 的部份重複了
那个类我是要用在其他脚本。所以里面的就保留了

3. 原生函數部份應加try-catch避免問題 _historyWrap
确实挺多没加捕获的,写的时候没考虑那么多把,后面看到就改一下

4. get_shorts_info xhr.status === 200 外,還要檢查 xhr.readyState === XMLHttpRequest.DONE
这个确实不知道,得加上

5.parseshortslist 那邊只有then和finally,抓取不了錯誤log
这里不捕获错误是因为没必要,youtube会跑出来的,即使捕获了我也

6.parse_shorts_list 否則 const { id, title, views_lable, thumbnail_url } = this.shorts_list.pop(); 可能會報錯 (是有這個機會啦)
按我写的逻辑是不会报错的,因为js单线程执行。不过加上确实更严谨。得加

7.看不懂 user_data.shorts_list.pop(shorts); 這個部份。首先pop沒有參數傳入的
我也看不懂,应该是脑抽了把

8. upload_date_str = shorts['upload_date'] 可以是 undefined
确实有可能,加上if (!upload_date_str) return ''; 就好了,前面字符串
准确性已经校验过了

9.uer_data = newValue; 這個不建議啦 userdata應一直都是不變的物件參考 (userdataapi和userdata都是const宣告)
我觉得uer_data不需要特地的去固定住,现在感觉没什么太大的意义

10.deal_resposn -> deal_response
matchs -> matches
parseing -> parsing
orgin_ -> origin_
这个崩不住了。。。

11. user_data_api, user_data, inject_info, shorts_parse_delay, data_this, origin_console, error_messages let -> const
确实该

1.local_this 沒有使用,應刪掉
确实忘记了

2.let page_type = ''; // let page_type;
直接改赋值好了

3.obj_conditional 那邊也是 convertPathToBracketNotation 吧
那边好像有点差异我都有点忘了,应该不单纯是这样,到时候再理一下思路统一起来

4.getCookie 還是加個 try catch 吧。失敗至少能返回null (decodeURIComponent失敗會報錯)
确实该添加

5.store_user_data
确实忘记删了。哈哈哈

6.函式的class object漏了
get_subscribe_data(retry + 1) 改為 yt_api.get_subscribe_data(retry + 1)
这这一条确实有问题,改一下
value_parse(arg) 改為 data_this.value_parse(arg)
value_parse 裡的 value_parse(arg) 这里是可以自身调用的,上面那个是不在作用域里

1. obj_conditional 裡 is_array_obj
确实是搞错了 应该改成condition_path.startsWith('[')

2.fetch_ 裡的 return_response
以前是想着统一返回的,ok,改了

3.value_parse 裡的 變數沒宣告
确实漏了好多,感谢感谢

4.get_shorts_info 裡 xhr.onload 的 match 未宣告
感谢感谢

5.get_authorization 裡 b = Vja(); 的 b 未宣告
感谢感谢

6. update(tmp_user_data) 裡 last_version 未宣告
感谢感谢

7. display_update_win 裡的 btn 未宣告
感谢感谢

8.remove_popup_hander
确实是有隐患,不过直接在前面加document.removeEventListener('click', remove_popup_hander);
是没用的,remove_popup_hander已经不是原来的对象了,所以给popup添加了个移除函数,移除的时候
调用一下就好了

9. responseText & response 那個部份你可以直接抄修改版的代碼
这些链接都打不开,不知道干嘛

10. DATA_PROCESS 裡的 set_obj_filter = function (obj_filter) { 是寫錯吧
确实不太统一,写完都忘了

11. this.obj_filter;
不需要 this.obj_filter = undefined; 这样的,它就是undefined

12.config_init 一直log 語言錯誤
确实是个问题 ,不过有可能是会切换语言的,我测试的是时候就经常切换。只报错一次也是不太合适

13. 補充上面的 getPositions
别管这个啦,都差不多的

感谢大佬校正,比心

这些链接都打不开,问题解决了
只有全局代理才能访问,我都是用局部代理的

1.regexp
比如說, path.match(/\[(.*?)\]/g) 改成了 path.match(/\[([^\(\)]*)\]/g) 這樣明確的寫法
我觉得我这种更加容易我理解,规则如果是错的话,整体抛出来就好了,只处理对的部分的话,
感觉不太好
对于里面那些复杂的正则的话,基本是没有错误的,可能写法可以优化一下。乱改的话容易考虑不全,导致错误。

2.obj_process
裡面的函數宣告都抽出來了。
里面的函数是仅对obj_process这函数有用,拿出来是不可以单独作用的。
拿的出来的都可以作用一个独立函数去处理数据。

3.這個寫法可以改成 ${cur_path}[${index}]
模板语法,确实挺好用,有什么变量少就懒得用了


4. add_data_to_abs_path
那些參數太多了吧。直接用一個Object再做Object.assign 就可以了吧
这个确实,功能加多了就变得乱七八糟了

5.obj_property_traverse
裡面的參數傳來傳去會很花CPU處理
直接傳一個Object就好,裡面都是不變的Object參考
传obj就是传一个地址而已,把数据传进去的。

6. if (operator === '=')執行次序改到前面 因為它不需要 const dec_obj = last_obj[last_key];
也行 哈哈哈

7. express_type 只判斷是否string 的部份改成boolean
那里是留了一个功能扩展的,以后类型不只string的

8. 首先你用 [a-zA-Z_0-9\.\*\[\]]* 的話,不會有 \/
这里不是匹配path_extral的 ,[\s\S]*这个才是

9.relative_path_list, relative_short_path_list, relative_path_info_list
原本一拆三的relative_path改成了relative_path_map ^key 是 real_keys ~key 是 short_keys
还没用过map,我都是把对象当map用的,确实map点,这里慢慢来

10. 另外加了一個防錯,防止重覆short_keys
整体给个try-catch好了,单独给的意义不大

1. let array_index = undefined; // don't forget it can be undefined
array_index 后面使用会判断的

2.abs_path_info_list's entries are object-type. a < b is always false. No Sorting
这里确实是,想在这写个排序的一直没写,那条命令估计是倒序了,作用是有的。
这是测试过的

3.xhr部分
参考你的思路改了下。
obj.length >= 4
我是捕获异常让他抛出来

代码行数多的话我是不太喜欢用过多else if ,看着会比较乱,所以还是选择单if

typeof result === 'string' 这个确实也需要判断一下

get responseText()
get response()
对于这两个函数还是喜欢原来这种方式更加好点,这是直接重定向到get xhrResponseValue
这个好像也是你以前提议改的把

§
Создано: 06.05.2024
Отредактировано: 06.05.2024

你參考一下吧

反正沒bug, 不會拖慢就好

應該把之前那些名字問題,變數未宣告之類的解決就好得多了

remove_popup_hander 已经不是原来的对象了

這個也是。 不想改太多的話,外面放一個變量把舊的存下來吧。 然後addEventListener前刪掉之前的

get responseText()

get response()

這兩個都只是為了抓某幾個網址的資料

像我寫的分開兩個,再進行判斷比較合適。實際操作應該只走其中一個。原本是物件就傳回物件,原本是字串就傳回字串,其他的都不管

現在這個寫法也是重定向,只是只在readyState === XMLHttpRequest.DONE的時候改 (原本也是)

其他狀態沒改變。這是跟原本 xhrResponseValue 一樣的

但原本沒分開 responseText 和 response 兩者。

            let result = super.responseText;
            if (super.readyState === XMLHttpRequest.DONE) {
                result = this.processResult(result);
            }
            return result;

避免誤判其他網絡request (像串流的)

obj.length >= 4 我是捕获异常让他抛出来

如果是這樣的話,直接寫 if(obj.length < 4) throw XXXX 這樣會比較好

否則之後你都忘掉這裡會有機會有异常

可預計的异常都先預計出來吧,就像預計 JSON.parse 會有失敗异常一樣

Javascript 的寫法很隨便,變數類型也能改,很容易出錯

更了更了,基本都有错误处理了。没有的再说哈哈哈

§
Создано: 11.05.2024
Отредактировано: 11.05.2024
args.push(value_parse(arg, path_info, json_obj));

應改為

args.push(this.value_parse(arg, path_info, json_obj));

parse_value = parse_value.replace(express_, eval(express));

你是不是沒考慮 limit_eval = true 的情況?


这里不是匹配path_extral的 ,[\s\S]*这个才是

    let value;
    reg = /^(abs:)?([a-zA-Z_0-9\.\*\[\]]*)((=\-|~=|=\+|=))([\s\S]*)?/;
    if (express_type === 'string') {
        matches = express.match(reg);
    } else {
        matches = express.value.match(reg);
        conditions = express.conditions;
    }
    let abs = matches[1];
    let path = matches[2];
    let path_extral_match = path.match(/\/?\.+$/);
    let path_extral;
    if (path_extral_match) {
        path_extral = path_extral_match[0];
        path = path.replace(path_extral, '');
    }

matchesexpressexpress.value 配對 /^(abs:)?([a-zA-Z_0-9\.\*\[\]]*)((=\-|~=|=\+|=))([\s\S]*)?/;

matches[1] 是 abs:

matches[2] 是 [a-zA-Z_0-9\.\*\[\]]*

matches[3] 是 =\-|~=|=\+|=

matches[4] 是 =\-|~=|=\+|=

matches[5] 是 [\s\S]*

所以 path_extral_match 應該是 matches[5].match(/\/?\.+$/); 而不是 path.match(/\/?\.+$/);


abs_path_info_list.sort((a, b) => a < b ? 1 : -1);

還是有這個。


其他部份有時間再匯報

init_hook_collection 裡的 property 未加 try catch

1. args.push(this.value_parse(arg, path_info, json_obj));
这里确实是漏了,改成类之后没添加。非常感谢,nice

2. parse_value = parse_value.replace(express_, eval(express));
这规则还没确定该怎么做,忘记注释掉了

3. 所以 path_extral_match 應該是 matches[5].match(/\/?\.+$/); 而不是 path.match(/\/?\.+$/);
这里我上次也说错了,path_extral_match 是先从([a-zA-Z_0-9\.\*\[\]]*) 提取,然后再用(/\/?\.+$/)进行二次提取的

§
Создано: 11.05.2024
Отредактировано: 11.05.2024

path_extral_match 是先从([a-zA-Z_0-9\.\*\[\]]*) 提取,然后再用(/\/?\.+$/)进行二次提取的

所以 ([a-zA-Z_0-9\.\*\[\]]*) 要改成 ([\/a-zA-Z_0-9\.\*\[\]]*)

還是 (/\/?\.+$/) 要改成 (/\.+$/)

1.abs_path_info_list.sort((a, b) => a < b ? 1 : -1);
在没写出正确的排序之前,这句可以让脚本以奇奇怪怪的方式正常运行,不要还不行

2. init_hook_collection 裡的 property 未加 try catch
里面的函数已经做了处理了,就不在那再做一次了

1.還是 (/\/?\.+$/) 要改成 (/\.+$/)
不能改, /和. 作为开头是两种模式来的

                    if (name === 'playlist') {
                        let obj;
                        try {
                            obj = JSON.parse(result);
                            data_process.obj_process(obj.playerResponse, ytInitialPlayerResponse_rule, true);
                            data_process.obj_process(obj.response, ytInitialData_rule, true);
                            result = JSON.stringify(obj);
                        } catch (error) {
                            log('playlist 解析失败', error, -1);
                            result = origin_result;
                        }
                        is_deal = true;
                    }

解析失败 的話, is_deal 不應是 true

可以改成

                        if (name === 'playlist') {
                            try {
                                const obj = JSON.parse(result);
                                data_process.obj_process(obj.playerResponse, ytInitialPlayerResponse_rule, true);
                                data_process.obj_process(obj.response, ytInitialData_rule, true);
                                result = JSON.stringify(obj);
                                is_deal = true;
                            } catch (error) {
                                log('playlist 解析失败', error, -1);
                            }
                        }

不能改, /和. 作为开头是两种模式来的

([a-zA-Z_0-9\.\*\[\]]*) 不會提取到 \/


if (unsafeWindow.ytcfg.msgs) {
    unsafeWindow.ytcfg.msgs.__lang__ && 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_init(newValue.__lang__);
            this._msgs = newValue;
        }
    });
}


這個應改成

unsafeWindow.ytcfg._msgs = unsafeWindow.ytcfg.msgs;
define_property_hook(unsafeWindow.ytcfg, 'msgs', {
    get: function () {
        return this._msgs;
    },
    set: function (newValue) {
        if (newValue.__lang__) config_init(newValue.__lang__);
        this._msgs = newValue;
    }
});
unsafeWindow.ytcfg.msgs = unsafeWindow.ytcfg._msgs

Ответить

Войдите, чтобы ответить.