YouTubeVideo&music&kidsAdBlocking

Intercept all YouTube video ads, music playback ads, youtube kids ads, without leaving blank space, no flash screens, seamless experience, the first choice in user experience. Adapted for mobile devices, supports customizable interception, and allows the addition of video channels

< Feedback on YouTubeVideo&music&kidsAdBlocking

Question/comment

§
Posted: 2024-04-13
Edited: 2024-04-13

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;
        }
    };
§
Posted: 2024-04-13
Edited: 2024-04-13

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 )

随便啦...Author
§
Posted: 2024-04-14

非常感谢呀,我学习学习

§
Posted: 2024-04-14
Edited: 2024-04-14
  • 以下的只是剛好發現。你可以順便改一改。不改也沒差。上面的較重要

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;
随便啦...Author
§
Posted: 2024-04-15

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

§
Posted: 2024-04-24
Edited: 2024-04-24

發現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

期待你的更新~

随便啦...Author
§
Posted: 2024-04-30

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

§
Posted: 2024-05-01
Edited: 2024-05-01

另外發現使用了var的問題

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

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


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

随便啦...Author
§
Posted: 2024-05-01

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

§
Posted: 2024-05-03
Edited: 2024-05-03

如果多個分頁同時開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

随便啦...Author
§
Posted: 2024-05-04

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 一样,在我的使用场景下,代码就变得复杂了,这个我觉得还是要保留的。
大佬辛苦了,感谢大佬指点。比心,更新后,期待大佬抽空去瞧瞧

§
Posted: 2024-05-04
Edited: 2024-05-04

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":"(.*)"/

§
Posted: 2024-05-04
Edited: 2024-05-04

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;
}
随便啦...Author
§
Posted: 2024-05-04

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

随便啦...Author
§
Posted: 2024-05-04

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...)
§
Posted: 2024-05-04
Edited: 2024-05-04

關於上面的 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();也是啦)

§
Posted: 2024-05-05
Edited: 2024-05-05

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

随便啦...Author
§
Posted: 2024-05-06

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
确实该

随便啦...Author
§
Posted: 2024-05-06

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) 这里是可以自身调用的,上面那个是不在作用域里

随便啦...Author
§
Posted: 2024-05-06

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
别管这个啦,都差不多的

随便啦...Author
§
Posted: 2024-05-06

感谢大佬校正,比心

这些链接都打不开,不知道干嘛

按這個看看: https://raw.githack.com/cyfung1031/userscript-supports/main/tmp-480192.user.js

这些链接都打不开,不知道干嘛

按這個看看: https://raw.githubusercontent.com/cyfung1031/userscript-supports/main/tmp-480192.user.js

随便啦...Author
§
Posted: 2024-05-06

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

随便啦...Author
§
Posted: 2024-05-06

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好了,单独给的意义不大

随便啦...Author
§
Posted: 2024-05-06

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
这个好像也是你以前提议改的把

§
Posted: 2024-05-06
Edited: 2024-05-06

你參考一下吧

反正沒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 的寫法很隨便,變數類型也能改,很容易出錯

随便啦...Author
§
Posted: 2024-05-08

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

§
Posted: 2024-05-11
Edited: 2024-05-11
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

随便啦...Author
§
Posted: 2024-05-11

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\.\*\[\]]*) 提取,然后再用(/\/?\.+$/)进行二次提取的

§
Posted: 2024-05-11
Edited: 2024-05-11

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

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

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

随便啦...Author
§
Posted: 2024-05-11

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

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

随便啦...Author
§
Posted: 2024-05-11

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
随便啦...Author
§
Posted: 2024-05-12

1.解析失败 的話, is_deal 不應是 true
这里确实true,处理失败也是处理了,下面的逻辑是处理通用类型的。特殊的类型不适用

2.([a-zA-Z_0-9\.\*\[\]]*) 不會提取到 \/
这里确实是,只做了一种规则,另一个种没用到都没做。还得把另一种也做了

3. unsafeWindow.ytcfg._msgs = unsafeWindow.ytcfg.msgs;
啥?上面你为什么干掉了。

Post reply

Sign in to post a reply.