【ブラウザ拡張機能】ROM専を極めるDiscord【2 1 Techno Diary #1】【コードあり】

技術系

前置き

ブンブンハロー卵のブログ!卵鯖の技術者の2 1です。今回から2 1が自由気ままで不定期な技術の日記 「2 1 Techno Diary」を始めます。(日記って何?)

記事を通して読者の皆様に技術の知見を広げてもらえたら幸いです。

あとこのブログの所有者なので執筆を通してブログのシステムが使いやすいかも見ていきたいけどどうでもいいwアーチャウチャウ

ROM専を極めたい。

みなさんは、Discordなどで ROM専 になったことはありますか? Read Only Member 、すなわち書き込みをしないで、他の人達の会話を見るだけの人です。その是非に関しては今回は置いておきましょう。私はいくつかのDiscordサーバーに参加していますが、卵鯖以外はほぼROM専です。

アメリカのUXリサーチ企業、ニールセン・ノーマン・グループによる調査ではインターネットを使う90%の人はROM専であるという結果も出ており、もしかしたら読者の皆さんの中にもどこかでROMってるわ(笑)という人もいるに違いありません。

the 90-9-1 rule for participation in an online community

Participation Inequality: The 90-9-1 Rule for Social Features
In most online communities, 90% of users are lurkers who never contribute, 9% of users contribute a little, and 1% of us...

さぁ、そこで問題になってくる(?)のが、「誤って文字を入力してしまった!」というときです。Discordをはじめとするチャットサービスには「入力中…」というインジケーターがあります。

今までに喋ってもない人が急に「入力中」となったら、それはもう会話している人たちの心境はまさにこのようになるでしょう。(※個人的な見解です。)

新しい人きたあああああああああああああああああああああああ!!!!!

どんな人か気になるなぁ、そうに決まってる。

しかしその後に何もなく入力中の表示が消えてしまったときの彼等の心境を考えれば、それはもう心が痛いを通り越して清水の舞台から飛び降りました。

WASTED.

(実際に入力中が消えて云々…って人はそんなに居ないので皆さんは飛び降りなくてもいいですからねこれねw)

さぁ、そんなことを防ぎ、ROM専を極めるべく、今回私は、

流れてくるメッセージ以外を排除する

拡張機能を開発しました!

とその前に、このコードはブラウザ版のDiscordでしか実行できません。スマホやタブレットの方、大変申し訳ありませんでした。

【本題】拡張機能のコード (※使用は自己責任)

{
    "manifest_version": 3,
    "name": "Discord Message Monitor",
    "version": "1.0",
    "description": "Customize your discord client view appearance for Message Monitor.",
    "content_scripts": [
        {
            "matches": [
                "https://discord.com/channels/*"
            ],
            "js": [
                "content.js"
            ]
        }
    ]
}
function log(message){
    console.log(
        "%c[Discord Message Monitor]%c %c[LOG]%c",
        "color:white; background-color:purple; padding:2px 4px; border-radius:4px;",
        "",
        "color: green;",
        " ",
        message
    );
}

function waiter(selector, resolve){
    let interval = setInterval(() => {
        let target = document.querySelector(selector);

        if (target != null){
            log("Target element appeared.");
            clearInterval(interval);
            resolve(target);
        }
        
    }, 500);
}

function waitUntilElementAppear(selector){
    return new Promise((resolve) => {
        waiter(selector, resolve);
    })
}

function hideElement(selector){
    let hiddenElement = document.querySelector(selector);
    
    if (hiddenElement != null){
        hiddenElement.style.display = "none";
    }

    log(`Element ${selector} is now hidden.`);
}

async function main(){
    log("Plugin works.");

    let urlParams = new URLSearchParams(window.location.search);
    if (urlParams.get("xmonitor_view") !== "1"){
        return;
    }

    log("Monitor view enabled.");

    await waitUntilElementAppear(".subtitleContainer_f75fb0");

    hideElement(".container_c8ffbb");
    hideElement(".formWithLoadedChatInput_f75fb0");
    hideElement(".subtitleContainer_f75fb0");
    hideElement(".sidebar__5e434");

    if (urlParams.get("xmonitor_disable_interaction") === "1"){
        log("Interaction Disabled.");
        document.querySelector(".content__5e434").inert = true;
    }
}

main();

さぁさぁPCの方、これらを同じフォルダに導入して拡張機能にぶちこんでもらえれば動きます。

【本題】拡張機能の使い方

拡張機能を有効にしたら、まずはDiscordを開いて、任意のチャンネルにアクセスします。

URLが
https://discord.com/channels/サーバーのID/チャンネルのID
のようになっているので、末尾に
?xmonitor_view=1
を追加します。また、画面をクリックしても何も起こらないようにする(インタラクションの無効化)場合、
?xmonitor_view=1&xmonitor_disable_interaction=1
を末尾に追加します。URLが
https://discord.com/channels/サーバーのID/チャンネルのID?xmonitor_view=1
または、
https://discord.com/channels/サーバーのID/チャンネルのID?xmonitor_view=1&xmonitor_disable_interaction=1
となっていればOKです。

そのままEnterを押すと、画面が次のようになるはずです。

なんということでしょう!まるで動物園の動物を見ているかのように、相手が自分をわざわざ気にかけることもなく、メッセージを誤って打ってしまう心配もないクリーンな環境が完成したではありませんか。

あの、チャンネルぐらいは切り替えられるようにしてもらいたいんですけど…

ン?ナニカモンダイデモアリマスカ?

まぁコードは解放してあるので自由に書き換えてお使いください。私の今日の晩御飯はキムチ鍋になるでしょう。

コードの解説

まぁ何の説明もなしにコードを貼っつけるのは不審なのでここで解説をしていきます。といっても難しいことは一切書いておりません。

コードの目的

コードの目的としては、1つのチャンネルのメッセージだけに集中できるようすることです。実現のために以下の実装をしております。

  • メンバー欄(右側)の非表示
  • チャンネル、サーバー一覧の非表示
  • メッセージの入力欄の非表示

manifest.json

とくに説明することはありませんが、["content_scripts"]["matches"] (9行目あたり)には注意が必要です。要は動作するサイトをdiscord.comに制限してるので、canary.discord.comやptb.discord.comでは動きません。

content.js

こちらが中枢になります。どう説明するかもわからないのでとりあえず関数の定義ごとに節を分けてみます。

1~10行目: log()

その名の通りログを表示するものです。console.log() を使うよりもリッチに表現できるので関数にしてあります。DevToolsなどでConsoleを見てもらうと次のようにログが表示されます。(あんま目にすることないけどw)

console.log()はCSSで装飾できるので、是非何かを作る際の参考にしてください。

12~23行目: waiter()

要素が出現するのを待つ関数です。Discordは起動すると、いきなりメッセージなどが表示されるのではなく、読み込みを経てから表示されます。window.onloadイベントではまだ読み込み中で、メッセージや画像、メッセージの入力欄などが準備されているので、このイベントで取得してしまうと対象の要素がnullになり実行に失敗するので欠かせません。

25~29行目: waitUntilElementAppear()

waiter()をここでPromiseで包みました。これで非同期関数になります。正直ここでwaiter()の内容を記述しても良いと思いますが、こっちのほうがネストが深くならないので好みです。でもこれぐらいだと逆に煩雑になってるのかもしれません(笑)

そしてどうでもいいですが Promise ってゲッダンの曲名ですね。時期が時期なので一応貼っておきます。

31~39行目: hideElement()

ここで要素を隠します。要素を消去せずに非表示にする理由はAjaxの崩壊防止です。さもないと

引用: https://qiita.com/sion_neko/items/010996d402d344ca4e7c
こうなります。

41~62行目: main()

ここが一番重要かもしれません。

まずは44行目のurlParams。先述したように、この拡張機能はクエリパラメーターにより制御されます。JavaScriptはブラウザに関するAPIが豊富です(それはそう)。これも例外ではなく、WebWorkerの機能の一種になります。45行目にもあるように、URLの末尾に?xmonitor_view=1を追加することで各要素の非表示が行われます。

あとは51行目で上部のチャンネル名の表示場所である.subtitleContainer_f75fb0が出現するまで待機し、待機が終了したら右側のメンバー欄.container_c8ffbb、メッセージの入力フォーム.formWithLoadedChatInput_f75fb0、チャンネル名の表示場所、左側のチャンネル一覧とサーバー一覧.sidebar__5e434を順に非表示にします。

また、58行目からのif文は、メインのコンテナーである.content__5e434にinert属性を付与することでユーザーのインタラクトを無効にします。これはクエリパラメーターにxmonitor_disable_interaction=1を設定することで実行されます。

最後に

ということで自作の拡張機能の紹介でございました。これでみなさんもROM専を極められること間違いないでしょう!

次回はこのサイトあたりの解説でもしようかなと思っております。次回の記事もどうぞお楽しみに。

そして師走になり寒さがより一層際立ってきますので、みなさん体調には気をつけてください(7095110敗)。

ではみなさん、いい夜を。

卵のブログの課題(蛇足)

  • Clasic Editorはもう古いかもしれない。Gutenbergの襲来も近いかも…
  • コードブロックが扱いづらい。まぁClasic Editorが悪さしてますね。
  • ブログ上部がダサい。改良が必要。
  • 見出し1,2が見出し1,2っぽくない。デザイン本を読みましょうかね。
  • スクショのコピペをそのまま貼れない。まぁ不便です

コメント

タイトルとURLをコピーしました