YouTube から興味ない動画を徹底的に消す。「Neo's YouTube Filter」を作った

以前から、YouTube 上の興味のない動画をいかに非表示にするか、ということに格闘してきた。

以前は Channel Blocker という拡張機能を使っていたのだが、コレが上手く動かなくなり、色々としびれを切らしたので自作するに至った。その名も「Neo's YouTube Filter」。

今回も例によって、Cloudflare Workers + D1 で「非表示にしたい情報」を管理している。ウェブ管理画面もあるが、本体はそこではない。


今回は youtube.com ドメイン上で自分の作ったスクリプトを動かして、見たくない動画の DOM を非表示にしつつ、そのための情報は Cloudflare Workers から取得するということが必要だったので、CORS 設定が重要になった。

/*
  Access-Control-Allow-Origin: *
{
  "assets": {
    "directory": "./build/client",
    "not_found_handling": "single-page-application",
    
    // Workers を先に動かすパス (SPA にフォールバックしないようにする)
    "run_worker_first": [
      "/api/*"
    ]
  }
import { Hono } from 'hono';
import { createHonoServer } from 'react-router-hono-server/cloudflare';  // `react-router-hono-server` というパッケージを使用

export const app = new Hono();

// CORS を許可する
app.use('*', cors({
  origin: '*',
  allowMethods: ['GET', 'POST', 'PATCH', 'PUT', 'DELETE', 'OPTIONS'],
  allowHeaders: ['Content-Type', 'Authorization']
}));

app.route('/api', api);  // ← API を別途実装…

export default await createHonoServer({ app });  // ← この書き方が重要だった・こうしないと `/api` 配下にブラウザアクセスしても到達できなかった

ということで、通常であれば別ドメインから Workers の API を直コールなんてされたくないので塞がっているワケだが、ココまでやれば開放できた。


「メインスクリプト JS ファイル」という文言が途中登場したが、コレは要するに、動画を非表示にする処理を含んだブックマークレットみたいなモノ。以下の2つの方法でこのファイルを取得し実行できる。

javascript:(async () => {
  try {
    const policy = trustedTypes.createPolicy('neos21-ytf', { createScript: code => code });  // YouTube 上で任意の JS コードを実行するためにはこの「ポリシー作成」が必要だった
    const response = await fetch('https://ytf.neos21.workers.dev/ytf.js');  // 実際の様々な処理を持つコードを Workers からダウンロードする
    const code = await response.text();
    eval(policy.createScript(code));  // `eval()` で取得した JS ファイルを実行する
  }
  catch(error) {
    console.error('スクリプト読み込みに失敗しました', error);
  }
})();
// ==UserScript==
// @name         Neo's YouTube Filter
// @namespace    https://neos21.net/
// @version      2026-09-22
// @description  Neo's YouTube Filter
// @author       Neos21
// @match        https://www.youtube.com/*
// @match        https://m.youtube.com/*
// @require      https://ytf.neos21.workers.dev/ytf.js
// @icon         https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @run-at       document-idle
// @grant        none
// @noframes
// ==/UserScript==

どちらも ytf.js という、自分が作った「メインスクリプト JS ファイル」を読み込んでいる点が重要。

PC ブラウザの場合は Tampermonkey を使うことで、自分が用意した JS ファイルを常時読み込んで起動できる。

iPhone Safari などのように Tampermonkey が使えない環境では、ブックマークレットを起動する手間は一つ増えるが、全く同じ JS ファイルを使えるので同じ機能が動く。


こうして読み込んだメインスクリプト ytf.js は何をしているかというと、「ホーム」「動画ページ」「検索結果ページ」を表示している時だけ、「見たくない動画を非表示にする」処理を動かしている。

「見たくない動画」は、

という3つのルールで封じることが出来る。つまり、

といったことが出来る。

ブロックするルールはウェブ画面から追加・編集・削除が出来るが、YouTube 閲覧中も素早くブロックができるように、動画サムネイル上に「この動画をブロック」「このチャンネルをブロック」というボタンを重ねて表示している。コレが「メインスクリプト」による機能で、ボタンを押せば Workers の API に対して POST 操作を行い、ブロックしたいルールを DB 追加できるというワケ。

ブロックするルールは LocalStorage にキャッシュを持ってるので、API コール数も節約するようにしている。


おおよそやりたいことと実現方法は自分の中で想像できていたが、YouTube のページごとの DOM 構造を調べたりするのが大変で、ココはガッツリ Codex に調査・実装させた。

以前だったら自分で CSS クラス名や DOM 構造を調べて、「どの親要素まで上がって display: none すればいいか」とかを調整するしかなかったけど、今回は全く自分で調査せずに済んだ。AI さまさまですね。

スマホで表示した時の DOM 構造の違いとかのバグ取りも Codex がやってくれた。Codex が iPhone Safari の内容を直接見たりはできないので、「このブックマークレットを実行して、ページの情報がどのように取得できたか教えてください」と言われて、Codex の吐いた調査用のブックマークレットを実行して結果をコピーして答えてあげたりしていた。いや~マジで「コレがやりたかったんよ!」っていうことをやってくれる相方が出来た感じで、Codex スゲェっすね。w