忘却まとめ

Blenderの中級者・上級者向けの踏み込んだ情報や、アドオン・3DCGに関する情報を記事にします

【ユーザースクリプト】コメントを正規表現でブロック・フォントサイズを変更【ニコニコ動画】

その他

更新日:

リンク

ニコニコ動画のコメントを正規表現でNGするユーザースクリプト - AdC用にとりあえず用意したブログ

ソースコード - GitHub

上記のスクリプトを使用して、正規表現によってより詳細に不快なコメントをブロックする。
ユーザースクリプトは、Tampermonkeyのような拡張機能を使用することで追加できる。

コード

上記のコードを、自分用に使いやすいように編集した。

  • ショートカットをCtrl + Bに変更。
  • フォントサイズを0.8倍に変更。
  • 文字色を無色に強制。
// ==UserScript==
// @name         nicovideo_regexp_comment_ng
// @version      0.1
// @description  ニコニコ動画のコメントを正規表現でNGするスクリプト。EscキーでNGパターンを変更して保存できます。
// @match        https://www.nicovideo.jp/watch/*
// @match        https://www.nicovideo.jp/watch_tmp/*
// ==/UserScript==

(function() {
    'use strict';

    const storageKey = 'regexp_comment_ng';
    const patDefault = 'うぽつ|荒らし|NG|んん~|にょ、';

    let image_to_is_safe;
    let patCurrent = null;
    let regexp;
    const updatePat = (pat) => {
        if (pat !== patCurrent) {
            try {
                regexp = new RegExp(pat, 'i');
                patCurrent = pat;
                image_to_is_safe = new WeakMap();
                localStorage.setItem(storageKey, pat);
                console.log('NGパターンが更新された');
            } catch(e) {
                return false;
            }
        }
        return true;
    };
    updatePat(localStorage.getItem(storageKey) ?? patDefault);

    document.addEventListener('keyup', e => {
        if (e.ctrlKey && e.code === 'KeyB') {
            let pat = localStorage.getItem(storageKey);
            while (true) {
                pat = prompt('NGパターン設定', pat);
                if (!pat || updatePat(pat)) {
                    break;
                }
            }
        }
    });

    // createElementで生成されたcanvasのfillTextを監視
    const canvas_to_text = new WeakMap();
    const createElement = document.createElement;
    document.createElement = function(tagName, ...args) {
        const elem = createElement.call(this, tagName, ...args);
        if (tagName === 'canvas') {
            const ctx = elem.getContext('2d');
            const fillText = ctx.fillText;
            ctx.fillText = function(text, ...args) {
                canvas_to_text.set(elem, text);
                return fillText.call(this, text, ...args);
            };



            // サイズ調整用の設定
            const scaleFactor = 0.8; // ★縮小倍率(0.8倍、20%縮小)
            const targetFillColor = "#e8e8e8"; // ★文字色(例:白)
            const targetStrokeColor = "#414141"; // ★輪郭色(例:黒)

            // サイズ調整を行う共通処理
            const applyScaling = (context) => {
                const originalFont = context.font;
                const originalLineWidth = context.lineWidth;

                // フォントサイズの調整(小数点も考慮)
                context.font = originalFont.replace(/(\d+(\.\d+)?)px/, (match, size) => {
                    const newSize = parseFloat(size) * scaleFactor;
                    return newSize + "px";
                });


                // 色の調整
                context.fillStyle = targetFillColor;
                context.strokeStyle = targetStrokeColor;

                // 輪郭の太さの調整(デフォルトは1px)
                // lineWidthが設定されている場合のみ縮小
                if (originalLineWidth > 0) {
                    context.lineWidth = originalLineWidth * scaleFactor;
                }

                return { originalFont, originalLineWidth };
            };

            const originalFillText = ctx.fillText;
            const originalStrokeText = ctx.strokeText;

            // 1. fillText(塗りつぶし)のフック
            ctx.fillText = function(text, x, y, maxWidth) {
                const originals = applyScaling(this);

                canvas_to_text.set(elem, text); // NG判定用にテキストを保持
                const result = originalFillText.call(this, text, x, y, maxWidth);

                // 元の状態に戻す
                this.font = originals.originalFont;
                this.lineWidth = originals.originalLineWidth;
                return result;
            };

            // 2. strokeText(輪郭)のフック(修正点)
            ctx.strokeText = function(text, x, y, maxWidth) {
                const originals = applyScaling(this);

                // ここではテキスト保持は不要(fillTextで行っているため)
                const result = originalStrokeText.call(this, text, x, y, maxWidth);

                // 元の状態に戻す
                this.font = originals.originalFont;
                this.lineWidth = originals.originalLineWidth;
                return result;
            };
        }
        return elem;
    };


    // コメント描画canvasのdrawImageを監視
    const modifyCommentCanvas = () => {
        const commentCanvas = document.querySelector('.CommentRenderer > canvas') || document.querySelector('[data-name=comment]>canvas');
        console.log('cvs', commentCanvas);
        if (!commentCanvas) {
            setTimeout(modifyCommentCanvas, 100);
            return;
        }
        const commentCtx = commentCanvas.getContext('2d');
        const drawImage = commentCtx.drawImage;
        commentCtx.drawImage = function(image, ...args) {
            let is_safe = image_to_is_safe.get(image);
            if (is_safe === undefined) {
                const text = canvas_to_text.get(image);
                if (text === undefined) {
                    is_safe = true;
                } else {
                    const m = text.match(regexp);
                    if (m) {
                        console.log('NG', m[0]);
                        is_safe = false;
                    } else {
                        is_safe = true;
                    }
                }
                image_to_is_safe.set(image, is_safe);
            }
            if (is_safe) {
                drawImage.call(this, image, ...args);
            }
        };
        console.log('コメント描画のCanvasを書き換えた');
    };
    modifyCommentCanvas();


    // 3. ページの変更を監視して、新しいCanvasが現れたら即座にパッチを当てる
    const observer = new MutationObserver(() => {
        // ニコニコのプレイヤー構成に合わせてセレクタを指定
        const canvas = document.querySelector('.CommentRenderer > canvas') ||
              document.querySelector('[data-name=comment] > canvas');
        if (canvas) {
            modifyCommentCanvas(canvas);
        }
    });

    // 監視開始(body全体を監視してCanvasの登場を待つ)
    observer.observe(document.body, { childList: true, subtree: true });


})();

正規表現について

何個でもNGワードを登録できる

「〇〇|✕✕|△△」のように、「 | 」で単語を囲うことで、 好きなだけブロックすることができる。

注意点

|〇〇|✕✕|△△|」のように、行頭・行末にまで「 | 」を付けてしまうと、全てのコメントが非表示になってしまうので注意。

正規表現の使い方

  • (.)\1{20}
    • 20回以上同じ文字を繰り返し使用したコメントがヒットする。
    • 「いけええええ」とか「飛んだああああ」とか「wwww」とかの文字をやたら長くしている邪魔なコメを消せる。
  • ^なるほど$
    • 特定の文字列の完全一致コメのみを消す。
      標準のNG機能ではできない正規表現の強み。
    • 行頭「^」から、文字列を挟んで、行末「$」までが同じコメントだけを消す。
    • やたら「なるほど」が連投されている動画があるので、それだけを消して、「なるほど、〇〇ですね」など人間が打ってそうなコメントはNGしないようにする。
  • \(汗\)
    • 半角の記号は正規表現用の特殊なコマンドとして判定されてしまう。
    • そのため、半角の記号をそのまま文字として認識したい場合は、「\」を左に付ける。
  • その他
    • 特定|原作勢|歌詞|過去タグ|逆再生|空耳|再走|中の人|批判|伏線|死ね|成仏|見納め|ゴーウィ|パチパチw|何がまずい|なにがまずい|過去タグ|ご友人|TE勢|TE勢|アンチ|ノルマ|(意味深|(意味深|貧乳|まな板|^壁$|コロナ
    • 使い古されたコメや動画から逸れた話題を消す。

正規表現が実際に効いているかテストする

【コマンドテスト】コメントテスト用動画【練習用動画】 - ニコニコ動画

上記のようなテスト用の動画に消したいコメントを打って、正規表現がうまく効いているか試してみるとよい。
確認したら打ったコメントは消すこと。

-その他

Copyright© 忘却まとめ , 2026 All Rights Reserved Powered by STINGER.