YouTube 頻道過濾器
YouTube 頻道過濾器 — 更新記錄
v1.0.1(2026-04-10)
🐛 修正
1. 語言過濾偵測大幅改善(含泰文修正)
問題:v1.0.0 的語言偵測函式(detectLang)僅支援 5 種語言(日、韓、中、俄、阿拉伯),導致泰文(th)等語言的 BCP-47 自訂代碼完全無效——即使正確輸入代碼,過濾也不會生效。
修正:重寫 detectLang(),擴充至 20+ 種語言的 Unicode 字元集偵測:
| 新增語言 | BCP-47 |
|---|---|
| 🇹🇭 泰文 | th |
| 🇮🇳 印地文 | hi |
| 🇧🇩 孟加拉文 | bn |
| 🇲🇲 緬甸文 | my |
| 🇱🇰 僧伽羅文 | si |
| 🇮🇳 泰盧固文 | te |
| 🇮🇳 泰米爾文 | ta |
| 🇮🇳 旁遮普文 | pa |
| 🇬🇪 喬治亞文 | ka |
| 🇦🇲 亞美尼亞文 | hy |
| 🇪🇹 阿姆哈拉文 | am |
| 🇮🇱 希伯來文 | he |
| 🇩🇪 德文 | de |
| 🇫🇷 法文 | fr |
| 🇪🇸 西班牙文 | es |
| 🇮🇹 義大利文 | it |
| 🇧🇷 葡萄牙文 | pt |
| 🇵🇱 波蘭文 | pl |
| 🇨🇿 捷克/斯洛伐克文 | cs |
| 🇳🇴 北歐文 | no |
同時修正語言比對邏輯:改用精確比對(lang === code),避免 es(西班牙文)誤命中 est(愛沙尼亞文)等邊界情況。
2. 頁面重整(Reload)後版面缺失
問題:YouTube 是 SPA,在特定操作後會清空並重建整個 DOM。腳本的 root 變數仍指向已移除的舊元素,因程式碼有 if (root) return 判斷,導致面板不重建,重整後按鈕與介面完全消失。
修正(三處):
Panel.build()加入document.body.contains(root)存在性檢查,若已脫離 DOM 則自動重置重建FAB.injectHeaderBtn()重試前先重置headerBtn,確保頂欄按鈕可重新注入Obs.watchNav()回呼加入Panel.build(),確保任何頁面切換後面板正常恢復
3. 說明頁新增捐款連結
在「ℹ️ 說明」Tab 軟體資訊下方,新增「☕ 支持開發者」區塊:
本專案採用自願訂閱模式。如果您認為這個工具有價值,並且每月能輕鬆捐贈幾枚金幣,歡迎支持我持續維護與開發。您的支持是最大的動力!
捐款連結:Liberapay
注意:Liberapay 的 JavaScript widget 會被 YouTube CSP 封鎖,改用純連結,功能相同且完全相容。
4. 首頁快捷按鈕重複顯示兩排
問題:Observer 的 selector 同時選取了 ytd-rich-item-renderer(外層容器)和 yt-lockup-view-model(內層子元素)——兩者對應同一張影片卡片,導致 injectCards 對同一卡片注入兩次快捷按鈕列。
ytd-rich-item-renderer ← 被選到(外層)
└── yt-lockup-view-model ← 被選到(內層,同一張卡)
修正:injectCards 遇到 yt-lockup-view-model 時,先用 closest() 向上查找父層容器:
- 若父層已有
data-ytf-qa標記(外層已處理)→ 跳過 - 若無父層(側邊推薦的獨立卡片)→ 正常注入
首頁卡片由 ytd-rich-item-renderer 處理,側邊推薦由 yt-lockup-view-model 處理,不再重複。
v1.0.0(2026-04-09)
首次正式發布。詳見完整功能列表。
YouTube Channel Filter — Changelog
v1.0.1 (2026-04-10)
🐛 Bug Fixes
1. Language Filter Detection — Major Improvement (including Thai)
Problem: The detectLang() function in v1.0.0 only supported 5 languages (Japanese, Korean, Chinese, Russian, Arabic). Custom BCP-47 codes like th (Thai) had no effect — even when correctly entered, no videos would be filtered.
Fix: Rewrote detectLang() to detect 20+ languages via Unicode character blocks:
| Language | BCP-47 |
|---|---|
| 🇹🇭 Thai | th |
| 🇮🇳 Hindi | hi |
| 🇧🇩 Bengali | bn |
| 🇲🇲 Burmese | my |
| 🇱🇰 Sinhala | si |
| 🇮🇳 Telugu | te |
| 🇮🇳 Tamil | ta |
| 🇮🇳 Punjabi | pa |
| 🇬🇪 Georgian | ka |
| 🇦🇲 Armenian | hy |
| 🇪🇹 Amharic | am |
| 🇮🇱 Hebrew | he |
| 🇩🇪 German | de |
| 🇫🇷 French | fr |
| 🇪🇸 Spanish | es |
| 🇮🇹 Italian | it |
| 🇧🇷 Portuguese | pt |
| 🇵🇱 Polish | pl |
| 🇨🇿 Czech / Slovak | cs |
| 🇳🇴 Nordic | no |
Also fixed language matching to use exact comparison (lang === code), preventing false positives such as es (Spanish) incorrectly matching est (Estonian).
2. Panel Missing After Page Reload
Problem: YouTube is a Single Page Application that occasionally clears and rebuilds the entire DOM. The script's root variable continued pointing to the old detached element. Because of an early-return guard (if (root) return), the panel would never rebuild — the management panel and top bar button disappeared after a reload.
Fix: Three coordinated changes:
Panel.build()— Addeddocument.body.contains(root)check; auto-resets and rebuilds if the panel has been detached from the DOM.FAB.injectHeaderBtn()— ResetsheaderBtntonullbefore retrying injection so the top bar button can be re-injected after DOM reconstruction.Obs.watchNav()callback — Now explicitly callsPanel.build()after every SPA navigation event.
3. Donate Link Added to About Tab
A new "☕ Support the Developer" section has been added below the software info card in the ℹ️ About tab:
This project runs on a voluntary subscription model. If you find this tool valuable and can comfortably spare a few coins each month, please consider supporting my work. Your support means everything!
Donate via Liberapay
Note: Liberapay's JavaScript widget is blocked by YouTube's Content Security Policy. A plain hyperlink is used instead — same destination, fully CSP-compatible.
4. Quick Action Buttons Appearing Twice on Homepage
Problem: The Observer selector included both ytd-rich-item-renderer (outer container) and yt-lockup-view-model (inner child element) — both pointing to the same video card. As a result, injectCards injected the quick action button bar twice into the same card.
ytd-rich-item-renderer ← matched (outer)
└── yt-lockup-view-model ← matched (inner, same card)
Fix: When injectCards encounters a yt-lockup-view-model, it first uses closest() to check for an already-processed parent container:
- If a parent already has the
data-ytf-qamarker (outer layer handled it) → skip - If no such parent exists (standalone sidebar card) → inject normally
Homepage cards are now handled exclusively by ytd-rich-item-renderer; sidebar recommendations are handled by yt-lockup-view-model. No more duplicates.
v1.0.0 (2026-04-09)
Initial public release. See full feature list in the main description.