🎉 欢迎访问GreasyFork.Org 镜像站!本镜像站由公众号【爱吃馍】搭建,用于分享脚本。联系邮箱📮

Greasy fork 爱吃馍镜像

Youtube live, Simple Chat Stylizer

Display chat window on stream screen and apply custom stylesheet

As of 2022-11-01. See the latest version.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

🚀 安装遇到问题?关注公众号获取帮助

公众号二维码

扫码关注【爱吃馍】

回复【脚本】获取最新教程和防失联地址

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

🚀 安装遇到问题?关注公众号获取帮助

公众号二维码

扫码关注【爱吃馍】

回复【脚本】获取最新教程和防失联地址

// ==UserScript==
// @name         Youtube live, Simple Chat Stylizer
// @name:ja      Youtube live, シンプルチャットスタイル
// @description  Display chat window on stream screen and apply custom stylesheet
// @description:ja チャットウィンドウを配信画面上に配置し、カスタムスタイルを適応する
// @namespace    http://tampermonkey.net/
// @version      1.5.8
// @author       You
// @match        https://www.youtube.com/*
// @grant        none
// @run-at       document-end
// @nowrap
// ==/UserScript==

(function() {
    'use strict';
    const configAreaID = "simple-chat-stylizer-config";
    const configKey = "simple-chat-stylizer";
    const SINGLE_WINDOW_PARAMS = "toolber=no,menubar=no,scrollbar=no,titlebar=no,location=no,directories=no,status=no,resizable=yes";
    const CHAT_CONNECTION_TIMEOUT = 60 * 1000; // 1 min
    const TAG_HIGHLIGHTED = "highlighted_", TAG_HIDDEN = "hidden_";

    const EMOTE_MODE = {
        disable: 0,
        fever: 1,
        hideThreeStamp: 2,
    }

    // config object
    var c = {
        backgroundColor: "#fff0",
        chatFontSize: "13",
        isEnableChatOutline: true,
        chatOutlineColor: "#036",
        isHideAuthorName: false,
        isAuthorNameRightSide: true,
        authorNameMaxWidth: "100",
        isHideThumbnail: false,
        isHideBadge: false,
        simpleMemberChat: true,
        isHideHeader: true,
        isHideFooter: false,
        isHideCommonEmotes: true,
        isMemberOnly: false,
        isCountHeavyUser: false,
        isReloadWhenChatClogged: false,
        isHideEmotes: false,
        isFeverEmotes: false,
        disableChatFlickers: false,
        superChatViewType: "history-header-message",
        isFixModerator: true,
        moderatorChatTimeout: "20",
        windowWidth: "430",
        windowHeight: "720",
        chatWindowPosition: "right-top",
        windowOpacity: "0.9",
        enableFilter: true,
        chatFilter: "",
        fullscreenMode: false,
    };
    var isEnableFiltering = false;

    window.addEventListener("load", onLoaded);
    return;

    function onLoaded() {
        if (location.host == "www.youtube.com") {
            // チャットウィンドウ
            if (location.pathname.indexOf("/live_chat") == 0) {
                if (window == window.parent || window.parent.location.host != "www.youtube.com") return;

                loadConfig();
                addLiveChatStyle();

                setTimeout(updateChatWindowHeight, 100);
                setTimeout(setupChatObservation, 100);

                window.addEventListener("focus", focusInputField);
                window.addEventListener("mouseover", fixPlayerConflict);
            }
            // iframe
            else if (location.pathname.indexOf("/embed") == 0) {
                return;
            } else {
                // チャットウィンドウからも呼び出すのでグローバルにも定義する
                window.updateChatWindowHeight = updateChatWindowHeight;
                window.toggleConfig = toggleConfig;

                loadConfig();
                addConfigArea();
                addFloatWindowStyle();

                setTimeout(updateDynamicLayout, 20);
                setTimeout(updateDynamicLayout, 3000);
                window.addEventListener("focus", focusInputField);
                window.addEventListener("yt-set-theater-mode-enabled", () => setTimeout(updateDynamicLayout, 20));
                window.addEventListener("fullscreenchange", () => setTimeout(updateDynamicLayout, 20));
                window.addEventListener("play", () => setTimeout(updateDynamicLayout, 20));
                window.addEventListener("resize", () => setTimeout(updateDynamicLayout, 20));
                window.addEventListener("yt-update-title", () => setTimeout(updateDynamicLayout, 20));
            }
        }
    }

    /** *****************
     * Config
     * ******************/
    function addConfigArea() {
        // console.log("addConfigArea()");
        if (document.querySelector(`#${configAreaID}`)) return;

        var localize = {
            ja: {
                groupLayout: "レイアウト・表示非表示",
                groupDecoration: "テキスト装飾",
                groupAdditional: "追加機能",
                groupEmotes: "絵文字",
                groupFiltering: "チャットNG",
                configHeader: "Youbute live, シンプルチャットスタイル 設定",
                fullscreenMode: "全画面表示(ページ再読み込みで適応)",
                backgroundColor: "背景色",
                fontSize: "文字サイズ",
                chatOutline: "文字枠を有効化する",
                chatOutlineColor: "文字枠の色",
                hideAuthorName: "チャット投稿者名を非表示にする",
                authorNameIsRight: "投稿者名を右側に表示する",
                autnorNameMaxWidth: "投稿者名の最大横幅(長すぎる場合は省略します)",
                hideThumbnail: "ユーザーアイコンを非表示にする",
                hideBadge: "メンバーバッヂを非表示にする",
                simpleMemberChat: "メンバーチャットを簡易表示にする",
                hideHeader: "ヘッダーを非表示にする",
                hideFooter: "フッターを非表示にする (チャットができなくなります)",
                hideCommonEmotes: "チャンネル専用絵文字以外を非表示にする",
                isHideEmotes: "絵文字のみのチャットを非表示にする",
                isFeverEmotes: "絵文字のみのチャットを背景に流す",
                memberOnly: "メンバーチャットのみ表示する",
                isCountHeavyUser: "チャット頻度を可視化する",
                reloadWhenChatClogged : "チャットが詰まったら更新する",
                disableChatFlickers: "チャットのちらつきを低減する",
                superChatViewType: "スーパーチャットの表示方法",
                superChat: {
                    all: "全て表示",
                    historyMessage: "履歴 + チャットメッセージ",
                    history: "履歴のみ",
                    headerMessage: "チャットのみ",
                    message: "チャットメッセージのみ",
                    none: "全て表示しない",
                },
                highlightModerator: "モデレーターを強調表示する(オーナーは常時)",
                highlightTimeout: "強調表示する時間 (秒)",
                windowWidth: "チャットウィンドウの横幅",
                windowHeight: "チャットウィンドウの高さ",
                chatWindowPosition: "チャットウィンドウの位置",
                position: {
                    rightTop: "右上",
                    rightBottom: "右下",
                    leftTop: "左上",
                    leftBottom: "左下",
                },
                windowOpacity: "チャットウィンドウの透明度 (0~1で指定/0は透明)",
                chatFilter: "チャットフィルタ (正規表現が使えます/一行に一項目)",
                save: "保存",
                close: "閉じる",
            },
            en: {
                groupLayout: "Layout / Visibility",
                groupDecoration: "Text Decoration",
                groupEmotes: "Emotes",
                groupAdditional: "Additional",
                groupFiltering: "Chat Filtering",
                fullscreenMode: "Screen fix to window (Apply to reload page)",
                configHeader: "Simple chat stylizer Config",
                backgroundColor: "Background color",
                fontSize: "Font size",
                chatOutline: "Enabled chat outline",
                chatOutlineColor: "Chat outline color",
                hideAuthorName: "Hide author name",
                authorNameIsRight: "Author name is display to right side",
                autnorNameMaxWidth: "Max width of author name(If too wide, omit the part)",
                hideThumbnail: "Hide user icon",
                hideBadge: "Hide member badge icon",
                simpleMemberChat: "Display simplify member chat",
                hideHeader: "Hide header panel",
                hideFooter: "Hide footer panel (you can't chat)",
                hideCommonEmotes: "Hide emotes except for the channel",
                isHideEmotes: "Hidden if chat is emotes only",
                isFeverEmotes: "Animate on background if chat is emotes only",
                memberOnly: "Display member chat only",
                isCountHeavyUser: "Display chat frequency",
                reloadWhenChatClogged : "Reload Chat window when connection clagged",
                disableChatFlickers: "Decrement chat flickers",
                superChatViewType: "View type of super chat",
                superChat: {
                    all: "All",
                    historyMessage: "History + Message only",
                    history: "History only",
                    headerMessage: "Chat only",
                    message: "Message only",
                    none: "Not display all",
                },
                highlightModerator: "Highlight moderator chat (Owner chat is always)",
                highlightTimeout: "Time period that highlight (sec)",
                windowWidth: "Width of Chat window",
                windowHeight: "Height of Chat window",
                chatWindowPosition: "Position of Chat window",
                position: {
                    rightTop: "Right Top",
                    rightBottom: "Right Bottom",
                    leftTop: "Left Top",
                    leftBottom: "Left Bottom",
                },
                windowOpacity: "Opacity of Chat window (Set value of 0 to 1 / 0 is transport)",
                chatFilter: "Chat filter (Can use regix / Input a filter each one line)",
                save: "Save",
                close: "Close",
            },
        }

        var t = localize[window.navigator.language] || localize.en;
        const config = document.querySelector("#" + configAreaID) || document.createElement("form");
        config.id = configAreaID;
        config.innerHTML = `
            <div class="group">
                <header>${t.groupLayout}</header>
<input type="checkbox" name="isHideAuthorName" id="scs-isHideAuthorName">
<label for="scs-isHideAuthorName">${t.hideAuthorName}</label><br />
<input type="checkbox" name="isAuthorNameRightSide" id="scs-isAuthorNameRightSide">
<label for="scs-isAuthorNameRightSide">${t.authorNameIsRight}</label><br />
<input type="text" name="authorNameMaxWidth" id="scs-authorNameMaxWidth">
<label for="scs-authorNameMaxWidht">${t.autnorNameMaxWidth}</label><br />
<input type="checkbox" name="isHideThumbnail" id="scs-isHideThumbnail">
<label for="scs-isHideThumbnail">${t.hideThumbnail}</label><br />
<input type="checkbox" name="isHideBadge" id="scs-isHideBadge">
<label for="scs-isHideBadge">${t.hideBadge}</label><br />
<input type="checkbox" name="simpleMemberChat" id="scs-simpleMemberChat">
<label for="scs-isHideBadge">${t.simpleMemberChat}</label><br />
<input type="checkbox" name="isHideHeader" id="scs-isHideHeader">
<label for="scs-isHideHeader">${t.hideHeader}</label><br />
<input type="checkbox" name="isHideFooter" id="scs-isHideFooter">
<label for="scs-isHideFooter">${t.hideFooter}</label><br />
<label class="dummy"></label>
<label for="scs-superChatViewType" for="scs-superChatViewType" class="for-select">${t.superChatViewType}</label>
<select type="dropdown" name="superChatViewType" id="scs-superChatViewType" value="history-header-message">
<option value="history-header-message">${t.superChat.all}</option>
<option value="history-message">${t.superChat.historyMessage}</option>
<option value="history">${t.superChat.history}</option>
<option value="header-message">${t.superChat.headerMessage}</option>
<option value="message">${t.superChat.message}</option>
<option value="none">${t.superChat.none}</option>
</select><br />
<input type="text" name="windowWidth" id="scs-windowWidth">
<label for="scs-widowWidth">${t.windowWidth}</label><br />
<input type="text" name="windowHeight" id="scs-windowHeight">
<label for="scs-windowHeight">${t.windowHeight}</label><br />
<label class="dummy"></label>
<label for="scs-chatWindowPosition" for="scs-chatWindowPosition" class="for-select">${t.chatWindowPosition}</label>
<select type="dropdown" name="chatWindowPosition" id="scs-chatWindowPosition" value="right-top">
<option value="right-top">${t.position.rightTop}</option>
<option value="right-bottom">${t.position.rightBottom}</option>
<option value="left-top">${t.position.leftTop}</option>
<option value="left-bottom">${t.position.leftBottom}</option>
</select><br />
<input type="checkbox" name="fullscreenMode" id="scs-fullscreenMode">
<label for="scs-fullscreenMode">${t.fullscreenMode}</label><br />
            </div>
            <div class="group">
                <header>${t.groupDecoration}</header>
<input type="text" name="backgroundColor" id="scs-backgroundColor">
<label for="scs-backgroundColor">${t.backgroundColor}</label><br />
<input type="text" name="chatFontSize" id="scs-chatFontSize">
<label for="scs-chatFontSize">${t.fontSize}</label><br />
<input type="checkbox" name="isEnableChatOutline" id="scs-isEnableChatOutline">
<label for="scs-isEnableChatOutline">${t.chatOutline}</label><br />
<input type="text" name="chatOutlineColor" id="scs-chatOutlineColor">
<label for="scs-chatOutlineColor">${t.chatOutlineColor}</label><br />
            <input type="text" name="windowOpacity" id="scs-windowOpacity">
            <label for="scs-windowOpacity">${t.windowOpacity}</label><br />
            </div>
            <div class="group">
                <header>${t.groupEmotes}</header>
<input type="checkbox" name="isHideEmotes" id="scs-isHideEmotes">
<label for="scs-isHideEmotes">${t.isHideEmotes}</label><br />
<input type="checkbox" name="isFeverEmotes" id="scs-isFeverEmotes">
<label for="scs-isFeverEmotes">${t.isFeverEmotes}</label><br />
<input type="checkbox" name="isHideCommonEmotes" id="scs-isHideCommonEmotes">
<label for="scs-isHideCommonEmotes">${t.hideCommonEmotes}</label><br />
            </div>
            <div class="group">
                <header>${t.groupAdditional}</header>
<input type="checkbox" name="isFixModerator" id="scs-isFixModerator">
<label for="scs-isFixModerator">${t.highlightModerator}</label><br />
<input type="text" name="moderatorChatTimeout" id="scs-moderatorChatTimeout">
<label for="scs-moderatorChatTimeout">${t.highlightTimeout}</label><br />
<input type="checkbox" name="isCountHeavyUser" id="scs-isCountHeavyUser">
<label for="scs-isCountHeavyUser">${t.isCountHeavyUser}</label><br />
<input type="checkbox" name="isReloadWhenChatClogged" id="scs-isReloadWhenChatClogged">
<label for="scs-isReloadWhenChatClogged">${t.reloadWhenChatClogged}</label><br />
            </div>
            <div class="group">
                <header>${t.groupFiltering}</header>
<input type="checkbox" name="isMemberOnly" id="scs-isMemberOnly">
<label for="scs-isMemberOnly">${t.memberOnly}</label><br />
<input type="checkbox" name="disableChatFlickers" id="scs-disableChatFlickers">
<label for="scs-disableChatFlickers">${t.disableChatFlickers}</label><br />
<input type="checkbox" name="enableFilter" id="scs-enableFilter">
<label for="scs-enableFilter">${t.chatFilter}</label><br />
<textarea name="chatFilter" value="" id="scs-chatFilter"></textarea>
            </div>

<button id="${configAreaID}-save">${t.save}</button>
<button id="${configAreaID}-close">${t.close}</button>
        `;

        // フォームの値を設定から復元する
        var $params = config.querySelectorAll(`#${configAreaID} input, #${configAreaID} select, #${configAreaID} textarea`);
        for (var i = 0; i < $params.length; i++) {
            var $p = $params[i];
            var value = c[$p.name];

            if (typeof value != "undefined") {
                if ($p.type == "checkbox") {
                    $p.checked = !!value;
                } else {
                    $p.value = value;
                }
            }
        }
        document.body.appendChild(config);

        config.querySelector("textarea").addEventListener("input", textareaOnInput);
        config.querySelector("textarea").addEventListener("focus", textareaOnInput);
        config.querySelector(`#${configAreaID}-save`).addEventListener("click", saveButtonOnClick);
        config.querySelector(`#${configAreaID}-close`).addEventListener("click", closeButtonOnClick);

        localize = t = null;
    }

    function toggleConfig() {
        document.querySelector(`#${configAreaID}`).classList.toggle("open");
    }

    // 設定を読み込む
    function loadConfig() {
        Object.assign(c, JSON.parse(localStorage[configKey] || "{}"));

        // console.log("loaded config", c);
    }

    // フォームの設定を保存する
    function updateConfigFromForm() {
        var $params = document.querySelectorAll(`#${configAreaID} input, #${configAreaID} select, #${configAreaID} textarea`);
        for (var i = 0; i < $params.length; i++) {
            var $p = $params[i];
            var value = c[$p.name];

            if ($p.type == "checkbox") {
                c[$p.name] = $p.checked;
            } else {
                c[$p.name] = $p.value;
            }
        }

        localStorage[configKey] = JSON.stringify(c);

        // console.log("updated config", c);
    }

    // チャットアニメーションを有効にするかどうか
    function isNoTranslate() {
        return isEnableFiltering || c.isFeverEmotes;
    }

    function saveButtonOnClick(ev) {
        ev.preventDefault();
        ev.stopPropagation();
        ev.stopImmediatePropagation();

        updateConfigFromForm();

        addFloatWindowStyle();
        document.querySelector("#chatframe").contentWindow.location.reload();

        return false;
    }

    function closeButtonOnClick(ev) {
        ev.preventDefault();
        ev.stopPropagation();
        ev.stopImmediatePropagation();

        document.querySelector(`#${configAreaID}`).classList.remove("open");
    }

    function textareaOnInput() {
        this.style.height = "1px";
        this.style.height = (this.scrollHeight) + "px";
    }

    /** *****************
     * Chat Filtering
     * ******************/
    // コメント監視を開始
    function setupChatObservation() {
        var lastPostedTime = new Date().getTime();
        const filterRegex = new RegExp(c.chatFilter.split(/[\r\n]+/)
                                       .map(x => (x || "").trim("\n").trim("\r").trim())
                                       .filter(x => x != "")
                                       .map(x => "(" + x + ")").join("|"), "i"),
              emotesOnlyRegex = /^[\s\n\r]*$/,
              users = {};

        var emoteCount = 0;
        const emoteCountLimit = 200;
        const undefined = void 0;

        const scroller = document.querySelector("#item-scroller.yt-live-chat-item-list-renderer");
        const observer = new MutationObserver((mutations) => {
            var chatWindowHeight;
            if (c.isFeverEmotes) {
                chatWindowHeight = scroller.offsetHeight;
            }

            mutations.forEach((mutation) => {
                if (mutation && !mutation.addedNodes) return;

                mutation.addedNodes.forEach((chat) => {
                    // console.log(chat);
                    if (chat.nodeName != "YT-LIVE-CHAT-TEXT-MESSAGE-RENDERER") return;

                    const msg = chat.querySelector("#message");
                    if (msg == undefined) return;

                    // 強調表示中のチャットが再利用された
                    if (chat.hasAttribute(TAG_HIGHLIGHTED)) {
                        unhighlightChat(chat);
                    }


                    // コメント回数を集計する
                    if (c.isCountHeavyUser) {
                        var authorName = chat.querySelector("#author-name").__shady_native_textContent;
                        var data = users[authorName];
                        if (!data) {
                            data = users[authorName] = { count: 0 };
                        }

                        if (c.isCountHeavyUser) {
                            data.count++;
                            chat.style.setProperty("--heavy-user", data.count + "%");
                        }
                    }

                    /*
                    if (Math.random() < 0.05) {
                       highlightChat(chat);
                       return;
                    }*/

                    // モデレータチャット
                    const author = chat.getAttribute("author-type");
                    if (author == "owner" || (c.isFixModerator && author == "moderator")) {
                        highlightChat(chat);
                        // フィルタリング無効
                        return;
                    }

                    // チャットフィルタ
                    if (msg.innerText.match(emotesOnlyRegex)) {
                        if (c.isHideEmotes) {
                            chat.setAttribute(TAG_HIDDEN, "");
                        } else if (c.isFeverEmotes && author != "owner" && author != "moderator") {
                            chat.setAttribute(TAG_HIDDEN, "");

                            if (emoteCount < emoteCountLimit) {
                                var emotes = msg.querySelectorAll(".emoji");
                                emotes.forEach(e => {
                                    var startY = Math.random() * chatWindowHeight * 0.25;
                                    e.style.setProperty("--fever-height", `-${chatWindowHeight - startY}px`);
                                    e.style.setProperty("--fever-width", `${40 + Math.random() * 30}px`);
                                    e.setAttribute("fever_", "");
                                    e.setAttribute(`fever${Math.floor(Math.random() * 5) + 1}_`, "");
                                    e.style.left = (5 + Math.random() * 90) + "%";
                                    e.style.bottom = startY + "px";

                                    scroller.appendChild(e);
                                });
                                emoteCount += emotes.length;

                                setTimeout(() => {
                                    emotes.forEach(e => e.remove());
                                    emoteCount -= emotes.length;
                                }, 4000);
                            }
                        }
                    } else if (isEnableFiltering && msg.innerText.match(filterRegex)) {
                        chat.setAttribute(TAG_HIDDEN, "");
                        // console.log("filtered", chat.__shady_native_textContent);
                    } else {
                        // チャット要素は使いまわされてる
                        // @see https://greasyfork.org/ja/scripts/409664-chat-filter-for-youtube-live/code
                        chat.removeAttribute(TAG_HIDDEN);
                    }
                });
                lastPostedTime = new Date().getTime();
            });
        });

        // 一定時間チャットがなければ、更新する
        setInterval(() => {
            if (!c.isReloadWhenChatClogged) return;
            var player = document.querySelector("#ytd-player");
            if ((player && player.player_ && player.player_.getPlayerState()) == 2) return;
            if (new Date().getTime() - lastPostedTime < CHAT_CONNECTION_TIMEOUT) return;

            location.reload();
        }, 30 * 1000);

        observer.observe(document.querySelector("#items.yt-live-chat-item-list-renderer"), { childList: true });
    }

    /** *****************
     * Chat
     * ******************/
    function addLiveChatStyle() {
        // console.log("addLiveChatStyle() : ", location.href);

        const localize = {
            ja: {
                toggleAutoFocus: "チャット入力欄に自動フォーカス",
                toggleLeft: "左側表示を切り替え",
                toggleBottom: "下側表示を切り替え",
                toggleFiltering: "チャットフィルタを有効",
                toggleHeader: "ヘッダーの表示を切り替え",
                toggleChat: "チャットの表示を切り替え",
                toggleFooter: "フッターを表示を切り替え",
                popup: "ポップアップ",
                reload: "更新",
                config: "設定",
                close: "閉じる",
            },
            en: {
                toggleAutoFocus: "Toggle auto focus to input field",
                toggleLeft: "Toggle left position",
                toggleBottom: "Toggle bottom position",
                toggleFiltering: "Toggle chat filtering",
                toggleHeader: "Toggle header",
                toggleChat: "Toggle chat",
                toggleFooter: "Toggle footer",
                popup: "Popup Single bordered window",
                reload: "Reload",
                config: "Configration",
                close: "Close",
            }
        };

        // toggle buttons
        const t = localize[window.navigator.language] || localize.en,
              buttons = document.querySelector("#chat-buttons-container") || document.createElement("div");
        buttons.id = "chat-buttons-container";
        buttons.innerHTML = `
<div id="chat-left-button" class="chat-toggle-button" title="${t.toggleLeft}">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" style="width: 16px; height: 16px; opacity: 1;" xml:space="preserve">
<g>
	<path d="M154.52,265.848l90.964,69.014c2.329,1.766,4.674,2.702,6.78,2.702c2.148,0,4.022-0.974,5.276-2.741
		c1.199-1.688,1.807-3.99,1.807-6.844v-26.424c0-6.952,5.656-12.608,12.607-12.608h75.036c8.705,0,15.788-7.085,15.788-15.788
		v-34.313c0-8.703-7.083-15.788-15.788-15.788h-75.036c-6.951,0-12.607-5.656-12.607-12.608v-26.425
		c0-7.065-3.659-9.584-7.082-9.584c-2.106,0-4.451,0.936-6.78,2.702l-90.964,69.014c-3.416,2.59-5.297,6.087-5.297,9.849
		C149.223,259.762,151.103,263.259,154.52,265.848z""></path>
	<path d="M256,0C114.842,0,0.002,114.84,0.002,256S114.842,512,256,512c141.158,0,255.998-114.84,255.998-256
		S397.158,0,256,0z M256,66.785c104.334,0,189.216,84.879,189.216,189.215S360.334,445.215,256,445.215S66.783,360.336,66.783,256
		S151.667,66.785,256,66.785z""></path>
</g>
</svg>
</div>
<div id="chat-bottom-button" class="chat-toggle-button" title="${t.toggleBottom}">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" style="width: 16px; height: 16px; opacity: 1;" xml:space="preserve">
<g>
	<path d="M256,0C114.842,0,0.002,114.84,0.002,256S114.842,512,256,512c141.158,0,255.998-114.84,255.998-256
		S397.158,0,256,0z M256,66.785c104.334,0,189.216,84.879,189.216,189.215S360.334,445.215,256,445.215S66.783,360.336,66.783,256
		S151.667,66.785,256,66.785z"></path>
	<path d="M246.151,357.482c2.591,3.416,6.087,5.299,9.849,5.299c3.762,0,7.257-1.883,9.848-5.295l69.014-90.97
		c2.665-3.513,3.393-6.945,2.046-9.655c-1.347-2.713-4.518-4.208-8.93-4.208h-26.424c-6.953,0-12.609-5.652-12.609-12.604v-75.035
		c0-8.707-7.082-15.792-15.788-15.792h-34.312c-8.706,0-15.788,7.084-15.788,15.792v75.035c0,6.952-5.656,12.604-12.609,12.604
		h-26.422c-4.412,0-7.586,1.495-8.93,4.208c-1.347,2.71-0.621,6.142,2.046,9.658L246.151,357.482z"></path>
</g>
</svg>
</div>
<div id="chat-filter-button" class="chat-toggle-button" title="${t.toggleFiltering}">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" style="width: 16px; height: 16px; opacity: 1;" xml:space="preserve">
<g>
	<polygon points="4.263,0 4.263,85.338 202.063,238.938 202.063,512 309.937,443.726 309.937,238.938 507.737,85.338
		507.737,0 	"></polygon>
</g>
</svg>
</div>
<div id="chat-header-button" class="chat-toggle-button" title="${t.toggleHeader}">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" style="width: 16px; height: 16px; opacity: 1;" xml:space="preserve">
<g>
	<circle cx="256" cy="55.091" r="55.091"></circle>
	<circle cx="256" cy="256" r="55.091"></circle>
	<circle cx="256" cy="456.909" r="55.091"></circle>
</g>
</svg>
</div>
<div id="chat-chat-button" class="chat-toggle-button" title="${t.toggleChat}">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" style="width: 16px; height: 16px; opacity: 1;" xml:space="preserve">
<g>
	<path d="M352.705,62.572h-193.41C71.321,62.572,0,133.893,0,221.855c0,87.986,71.321,159.307,159.295,159.307h152.17
		c22.76,0,29.872,10.569,29.872,19.22c0,12.791-6.649,24.796-22.748,36.268c-9.969,7.101-2.128,12.779,5.69,12.779
		c101.678,0,187.72-110.942,187.72-227.574C512,133.893,440.691,62.572,352.705,62.572z M135.054,252.109
		c-16.722,0-30.254-13.543-30.254-30.254s13.531-30.242,30.254-30.242c16.7,0,30.232,13.531,30.232,30.242
		S151.755,252.109,135.054,252.109z M256,252.109c-16.699,0-30.254-13.543-30.254-30.254s13.555-30.242,30.254-30.242
		c16.7,0,30.254,13.531,30.254,30.242S272.7,252.109,256,252.109z M376.946,252.109c-16.699,0-30.23-13.543-30.23-30.254
		s13.531-30.242,30.23-30.242c16.723,0,30.254,13.531,30.254,30.242S393.668,252.109,376.946,252.109z"></path>
</g>
</svg>
</div>
<div id="chat-footer-button" class="chat-toggle-button" title="${t.toggleFooter}">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="512px" height="512px" viewBox="0 0 512 512" style="width: 16px; height: 16px; opacity: 1;" xml:space="preserve">
<g>
	<path d="M498.781,74.344c-3.531-9.313-8.906-18.234-16.125-26.297c-14.797-16.5-31.359-28.594-48.813-36.484
		C416.391,3.656,398.109,0,380.031,0c-27.688,0-54.797,8.5-78.719,23.156s-44.75,35.484-59.938,60.609l-0.047,0.078L13.219,472.609
		l-0.031,0.016c-3.219,5.594-5.141,11.313-5.172,17.344c0,2.719,0.422,5.5,1.391,8.172c1.438,4.016,4.219,7.766,7.906,10.234
		c3.656,2.5,8,3.641,12.109,3.625c2.938,0,5.766-0.563,8.453-1.469c4.031-1.438,7.719-3.688,11.109-6.656s6.484-6.625,9.281-10.969
		c0.344-0.516,0.844-1.313,1.563-2.453c5.297-8.422,21.766-34.922,36.953-59.359c14.094-22.656,27.031-43.5,28.828-46.406
		c0.156-0.156,0.516-0.516,0.813-0.672l0.406-0.172c0.125-0.031,0.25-0.063,0.516-0.063c0.25,0,0.688,0.031,1.406,0.25
		s1.75,0.625,3.125,1.438l0.156,0.125l0.188,0.078c9.813,5.484,19,9.438,27.672,12.016c8.656,2.594,16.797,3.828,24.375,3.828
		c9.594,0.016,18.297-2,25.703-5.484c5.547-2.625,10.375-6.031,14.391-9.844c6.047-5.781,10.359-12.453,13.203-19.141
		c2.828-6.719,4.281-13.422,4.313-19.906c-0.031-4.453-0.656-8.828-2.703-13.281c-1.031-2.203-2.5-4.453-4.594-6.484
		c-1.844-1.781-4.266-3.281-6.938-4.188c0.219-0.641,0.703-1.219,0.938-1.391l0.094-0.063c0.047,0,0.141,0.016,0.328,0.063
		c5.109,1.453,14.141,3.922,25.281,6.031c11.156,2.109,24.422,3.859,38.281,3.875c10-0.016,20.328-0.922,30.422-3.484
		c10.063-2.531,19.953-6.781,28.641-13.531c7.906-6.156,14.219-13.281,18.641-21.125c4.422-7.828,6.906-16.469,6.891-25.219
		c0.016-5.719-1.047-11.438-3.141-16.844c-3.156-8.156-8.609-15.563-15.875-21.734c-7.266-6.203-16.328-11.266-27.078-15.109
		c-2.688-0.938-4.734-2.531-5.906-3.969c-0.594-0.719-0.953-1.406-1.141-1.859c0-0.016,0-0.016,0-0.031
		c0.438-0.219,1.172-0.484,2.281-0.734c1.328-0.297,3.156-0.516,5.516-0.5c3-0.016,6.844,0.344,11.516,1.266v-0.016
		c11.609,2.625,22.953,3.844,33.859,3.844c36.313,0,67.875-13.5,90.406-33.844c11.25-10.172,20.297-22.063,26.594-34.953
		c6.281-12.875,9.797-26.781,9.797-40.859C503.984,93.375,502.313,83.656,498.781,74.344z"></path>
</g>
</svg>
</div>
<div id="chat-popup-button" class="chat-toggle-button" on_ title="${t.popup}">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="512px" height="512px" viewBox="0 0 512 512" style="width: 16px; height: 16px; opacity: 1;" xml:space="preserve">
<g>
	<path d="M280.781,144.391l42.047,59.125c-57.813,65.688-217.281,145.766-217.281,145.766
		c161.422,12.406,285.594-40.672,285.594-40.672l42.047,68.313L512,144.391H280.781z"></path>
	<polygon points="296.453,393.547 296.453,418.984 68.297,418.984 68.297,93.031 364.75,93.031 364.75,24.734 0,24.734
		0,487.266 364.75,487.266 364.75,418.563 349.375,393.547 	"></polygon>
</g>
</svg>
</div>
<div id="chat-reload-button" class="chat-toggle-button" on_ title="${t.reload}">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" style="width: 16px; height: 16px; opacity: 1;" xml:space="preserve">
<g>
	<path d="M446.025,92.206c-40.762-42.394-97.487-69.642-160.383-72.182c-15.791-0.638-29.114,11.648-29.752,27.433
		c-0.638,15.791,11.648,29.114,27.426,29.76c47.715,1.943,90.45,22.481,121.479,54.681c30.987,32.235,49.956,75.765,49.971,124.011
		c-0.015,49.481-19.977,94.011-52.383,126.474c-32.462,32.413-76.999,52.368-126.472,52.382
		c-49.474-0.015-94.025-19.97-126.474-52.382c-32.405-32.463-52.368-76.992-52.382-126.474c0-3.483,0.106-6.938,0.302-10.364
		l34.091,16.827c3.702,1.824,8.002,1.852,11.35,0.086c3.362-1.788,5.349-5.137,5.264-8.896l-3.362-149.834
		c-0.114-4.285-2.88-8.357-7.094-10.464c-4.242-2.071-9.166-1.809-12.613,0.738L4.008,182.45c-3.05,2.221-4.498,5.831-3.86,9.577
		c0.61,3.759,3.249,7.143,6.966,8.974l35.722,17.629c-1.937,12.166-3.018,24.602-3.018,37.279
		c-0.014,65.102,26.475,124.31,69.153,166.944C151.607,465.525,210.8,492.013,275.91,492
		c65.095,0.014,124.302-26.475,166.937-69.146c42.678-42.635,69.167-101.842,69.154-166.944
		C512.014,192.446,486.844,134.565,446.025,92.206z"></path>
</g>
</svg>
</div>
<div id="chat-config-button" class="chat-toggle-button" on_ title="${t.config}">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" style="width: 16px; height: 16px; opacity: 1;" xml:space="preserve">
<g>
	<path d="M502.325,307.303l-39.006-30.805c-6.215-4.908-9.665-12.429-9.668-20.348c0-0.084,0-0.168,0-0.252
		c-0.014-7.936,3.44-15.478,9.667-20.396l39.007-30.806c8.933-7.055,12.093-19.185,7.737-29.701l-17.134-41.366
		c-4.356-10.516-15.167-16.86-26.472-15.532l-49.366,5.8c-7.881,0.926-15.656-1.966-21.258-7.586
		c-0.059-0.06-0.118-0.119-0.177-0.178c-5.597-5.602-8.476-13.36-7.552-21.225l5.799-49.363
		c1.328-11.305-5.015-22.116-15.531-26.472L337.004,1.939c-10.516-4.356-22.646-1.196-29.701,7.736l-30.805,39.005
		c-4.908,6.215-12.43,9.665-20.349,9.668c-0.084,0-0.168,0-0.252,0c-7.935,0.014-15.477-3.44-20.395-9.667L204.697,9.675
		c-7.055-8.933-19.185-12.092-29.702-7.736L133.63,19.072c-10.516,4.356-16.86,15.167-15.532,26.473l5.799,49.366
		c0.926,7.881-1.964,15.656-7.585,21.257c-0.059,0.059-0.118,0.118-0.178,0.178c-5.602,5.598-13.36,8.477-21.226,7.552
		l-49.363-5.799c-11.305-1.328-22.116,5.015-26.472,15.531L1.939,174.996c-4.356,10.516-1.196,22.646,7.736,29.701l39.006,30.805
		c6.215,4.908,9.665,12.429,9.668,20.348c0,0.084,0,0.167,0,0.251c0.014,7.935-3.44,15.477-9.667,20.395L9.675,307.303
		c-8.933,7.055-12.092,19.185-7.736,29.701l17.134,41.365c4.356,10.516,15.168,16.86,26.472,15.532l49.366-5.799
		c7.882-0.926,15.656,1.965,21.258,7.586c0.059,0.059,0.118,0.119,0.178,0.178c5.597,5.603,8.476,13.36,7.552,21.226l-5.799,49.364
		c-1.328,11.305,5.015,22.116,15.532,26.472l41.366,17.134c10.516,4.356,22.646,1.196,29.701-7.736l30.804-39.005
		c4.908-6.215,12.43-9.665,20.348-9.669c0.084,0,0.168,0,0.251,0c7.936-0.014,15.478,3.44,20.396,9.667l30.806,39.007
		c7.055,8.933,19.185,12.093,29.701,7.736l41.366-17.134c10.516-4.356,16.86-15.168,15.532-26.472l-5.8-49.366
		c-0.926-7.881,1.965-15.656,7.586-21.257c0.059-0.059,0.119-0.119,0.178-0.178c5.602-5.597,13.36-8.476,21.225-7.552l49.364,5.799
		c11.305,1.328,22.117-5.015,26.472-15.531l17.134-41.365C514.418,326.488,511.258,314.358,502.325,307.303z M281.292,329.698
		c-39.68,16.436-85.172-2.407-101.607-42.087c-16.436-39.68,2.407-85.171,42.087-101.608c39.68-16.436,85.172,2.407,101.608,42.088
		C339.815,267.771,320.972,313.262,281.292,329.698z"></path>
</g>
</svg>
</div>
<div id="chat-toggle-button" class="chat-toggle-button" on_ title="${t.close}">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" style="width: 16px; height: 16px; opacity: 1;" xml:space="preserve">
<g>
	<polygon points="512,52.535 459.467,0.002 256.002,203.462 52.538,0.002 0,52.535 203.47,256.005 0,459.465
		52.533,511.998 256.002,308.527 459.467,511.998 512,459.475 308.536,256.005 	"></polygon>
</g>
</svg>
</div>
`;
        document.querySelector("yt-live-chat-app > #contents").appendChild(buttons);

        // document.querySelector("#chat-focus-button").onclick = focusButtonOnClick;
        document.querySelector("#chat-left-button").onclick = leftButtonOnClick;
        document.querySelector("#chat-filter-button").onclick = filterButtonOnClick;
        document.querySelector("#chat-bottom-button").onclick = bottomButtonOnClick;
        document.querySelector("#chat-header-button").onclick = headerButtonOnClick;
        document.querySelector("#chat-chat-button").onclick = chatButtonOnClick;
        document.querySelector("#chat-footer-button").onclick = footerButtonOnClick;
        document.querySelector("#chat-popup-button").onclick = popupButtonOnClick;
        document.querySelector("#chat-reload-button").onclick = reloadButtonOnClick;
        document.querySelector("#chat-config-button").onclick = () => window.parent.toggleConfig();
        document.querySelector("#chat-toggle-button").onclick = toggleButtonOnClick;

        var stylesheet = "";

        // チャット
        stylesheet += `
                       yt-live-chat-renderer.yt-live-chat-app { --scrollbar-width: 0 !important; }
                       #message.yt-live-chat-text-message-renderer,
                       #message.yt-live-chat-paid-message-renderer { font-weight: bold; font-size: ${appendUnit(c.chatFontSize)}; position: relative; }
                       yt-live-chat-header-renderer, yt-live-chat-renderer, yt-live-chat-message-input-renderer, yt-live-chat-ticker-renderer {
                           background: ${c.backgroundColor};
                       }
                       yt-live-chat-server-error-message { background: #fff; }
                       #item-scroller.yt-live-chat-item-list-renderer { scrollbar-width: none; }
                       #item-scroller.yt-live-chat-item-list-renderer::-webkit-scrollbar { display: none !important; }
                       #item-scroller.yt-live-chat-item-list-renderer #items.yt-live-chat-item-list-renderer[no_translate_],
                       #item-scroller.animated.yt-live-chat-item-list-renderer #items.yt-live-chat-item-list-renderer[no_translate_]
                           { transform: translateY(0) !important; }
                       yt-live-chat-text-message-renderer { transition: height .2s linear; }
                       yt-live-chat-text-message-renderer[${TAG_HIDDEN}] { height: 0; opacity: 0; padding: 0; }
                       yt-live-chat-text-message-renderer[${TAG_HIGHLIGHTED}] {
                           position: absolute;
                           background: #fff;
                           right: 0; left: 0;
                           height: auto; z-index: 100;
                       }
`;

        // チャットちらつき低減
        if (c.disableChatFlickers) {
            stylesheet += `#items.yt-live-chat-item-list-renderer yt-live-chat-text-message-renderer:nth-last-child(-n + 3) {
height: 0; opacity: 0; padding: 0; margin: 0;
}`;
        }

        // 文字枠をつける
        if (c.isEnableChatOutline) {
            stylesheet += `
               #message.yt-live-chat-text-message-renderer {
                   color: #ffffff; letter-spacing : 3px;
                   text-shadow : 2px 2px 1px ${c.chatOutlineColor}, -2px 2px 1px ${c.chatOutlineColor},
                                 2px -2px 1px ${c.chatOutlineColor}, -2px -2px 1px ${c.chatOutlineColor},
                                 2px 0px 1px ${c.chatOutlineColor}, 0px  2px 1px ${c.chatOutlineColor},
                                 -2px  0px 1px ${c.chatOutlineColor}, 0px -2px 1px ${c.chatOutlineColor};
               }
               #message.yt-live-chat-paid-message-renderer {
                   color: #ffffff; letter-spacing : 1px; line-height: 1.1;
                   text-shadow : 1px 1px 1px ${c.chatOutlineColor}, -1px 1px 1px ${c.chatOutlineColor},
                                 1px -1px 1px ${c.chatOutlineColor}, -1px -1px 1px ${c.chatOutlineColor},
                                 1px 0px 1px ${c.chatOutlineColor}, 0px  1px 1px ${c.chatOutlineColor},
                                 -1px  0px 1px ${c.chatOutlineColor}, 0px -1px 1px ${c.chatOutlineColor};
               }`;
        }
        // ユーザー名非表示
        if (c.isHideAuthorName) {
            stylesheet += "#items.yt-live-chat-item-list-renderer #author-name.yt-live-chat-author-chip { display: none; }";
        }
        // ユーザー名右側
        else if (c.isAuthorNameRightSide) {
            stylesheet += `#content.yt-live-chat-text-message-renderer #author-name.yt-live-chat-author-chip {
                               position: absolute;
                               right: 10px; top: 0px;
                               opacity: 0.7; transform: scale(0.8); }`;
        }
        // ユーザー名通常表示
        else {
            stylesheet += `#items.yt-live-chat-item-list-renderer #author-name.yt-live-chat-author-chip {
                               max-width: ${c.authorNameMaxWidth}px;
                               white-space: nowrap;
                               overflow: hidden;
                               text-overflow: ellipsis; }`;
        }
        // ユーザーサムネ非表示
        if (c.isHideThumbnail) {
            stylesheet += `#items.yt-live-chat-item-list-renderer yt-live-chat-text-message-renderer:not([${TAG_HIGHLIGHTED}]) #author-photo { display: none !important; }`;
        }
        // メンバーバッジ非表示
        if (c.isHideBadge) {
            stylesheet += `#items.yt-live-chat-item-list-renderer yt-live-chat-text-message-renderer:not([${TAG_HIGHLIGHTED}]) #chat-badges { display: none !important; }`;
        }
        // メンバーチャットのヘッダー非表示
        if (c.simpleMemberChat) {
            stylesheet += `#items.yt-live-chat-item-list-renderer yt-live-chat-membership-item-renderer #card #header { display: none; }`;
        }
        // フッター非表示
        stylesheet += "#panel-pages[hide_] { display: none !important; }";
        if (c.isHideFooter) {
            document.querySelector("#panel-pages").setAttribute("hide_", "");
        } else {
            document.querySelector("#chat-footer-button").setAttribute("on_", "");
        }
        // ヘッダー非表示
        stylesheet += "yt-live-chat-header-renderer[hide_] { display: none !important; }";
        if (c.isHideHeader) {
            document.querySelector("yt-live-chat-header-renderer").setAttribute("hide_", "");
        } else {
            document.querySelector("#chat-header-button").setAttribute("on_", "");
        }
        // チャット非表示
        stylesheet += `#contents[hidechat_] #ticker, #contents[hidechat_] #separator, #contents[hidechat_] #chat {
                           display: none !important; height: 0; min-height: 0; }`;
        if (c.isHideChat) {
            document.querySelector("#contents").setAttribute("hidechat_", "");
        } else {
            document.querySelector("#chat-chat-button").setAttribute("on_", "");
        }
        // メンバーチャットのみ
        if (c.isMemberOnly) {
            stylesheet += `#items.yt-live-chat-item-list-renderer yt-live-chat-text-message-renderer[author-type='']:not([${TAG_HIGHLIGHTED}]) { display: none; }`;
        }
        // チャンネル用絵文字以外非表示
        if (c.isHideCommonEmotes) {
            stylesheet += "yt-emoji-picker-renderer #category-buttons { display: none !important; }";
            var emoteCategories = ["UCkszU2WH9gy1mb0dV-11UJg/CIW60IPp_dYCFcuqTgodEu4IlQ", "😀", "🐵", "🍇", "🌍", "🎃", "👓", "🏧"];
            for (var i = 0; i < emoteCategories.length; i++) {
                stylesheet += "[aria-activedescendant='" + emoteCategories[i] + "'] { display: none; }";
            }
        }

        const chat = window.parent.document.querySelector("#chat");
        // チャットウィンドウ左側
        if (c.chatWindowPosition.indexOf("left") >= 0) {
            document.querySelector("#chat-left-button").setAttribute("on_", "");
            chat && chat.setAttribute("leftside_", "");
        } else {
            document.querySelector("#chat-left-button").removeAttribute("on_");
            chat && chat.removeAttribute("leftside_", "");
        }
        // チャットウィンドウ下側
        if (c.chatWindowPosition.indexOf("bottom") >= 0) {
            document.querySelector("#chat-bottom-button").setAttribute("on_", "");
            chat && chat.setAttribute("bottomside_", "");
        } else {
            document.querySelector("#chat-bottom-button").removeAttribute("on_");
            chat && chat.removeAttribute("bottomside_");
        }
        // チャットフィルタ
        if (c.enableFilter) {
            document.querySelector("#chat-filter-button").setAttribute("on_", "");
            isEnableFiltering = true;
        }

        if (isNoTranslate()) {
            document.querySelector("#items.yt-live-chat-item-list-renderer").setAttribute("no_translate_", "");
        } else {
            document.querySelector("#items.yt-live-chat-item-list-renderer").removeAttribute("no_translate_");
        }

        if (c.isCountHeavyUser) {
            stylesheet += `
#content.yt-live-chat-text-message-renderer { position: relative; width: 100%; }
#content.yt-live-chat-text-message-renderer::after {
    display: block;
    position: absolute;
    left: 0;
    bottom: 0;
    height: 4px;
    opacity: 0.3;
    background: #dc143c;
    content: "";
    width: var(--heavy-user, 0%);
    max-width: 100%;
    z-index: -1;
}`;
        }

        // ログインユーザー名
        stylesheet += "#input-container yt-live-chat-author-chip { display: none; }";

        // スパチャ時ポップアップ
        stylesheet += "yt-live-chat-product-picker-renderer { background: var(--yt-emoji-picker-category-background-color) }";

        // チャット入力欄
        stylesheet += `#input.yt-live-chat-message-input-renderer {
                           background-color: var(--yt-emoji-picker-category-background-color);
                           color: var(--yt-emoji-picker-category-color);
                           font-weight: bold; margin-top: -4px; margin-bottom: 4px;
                       }
                       #buttons.yt-live-chat-message-input-renderer { position: absolute; right: 20px; top: 0; }
                       #message-buttons.yt-live-chat-message-input-renderer { display: none; }
                       #input-panel.yt-live-chat-renderer::after { display: none; }
                       #avatar.yt-live-chat-message-input-renderer { margin-top: -4px; }`;

        // コントロールボタン
        stylesheet += `body {
                pointer-events: all;
            }
            yt-live-chat-app #chat-buttons-container {
                position: absolute; right: 0; bottom: 0;
                opacity: 0;
                transition: opacity .2s linear;
            }
            yt-live-chat-app:hover #chat-buttons-container {
                opacity: 1;
            }
            yt-live-chat-app .chat-toggle-button {
                display: inline-block;
                color: #fff; background: #8f8f8f;
                padding: 2px;
                cursor: pointer;
                margin-left: 3px;
                z-index: 2021;
            }
            yt-live-chat-app .chat-toggle-button svg {
                vertical-align: middle;
                fill: #fff;
            }
            yt-live-chat-app .chat-toggle-button[on_] {
                background: #1E90FF;
            }
            ytp-ad-skip-button-container {
                z-index: 9999999;
            }`;

        // スーパーチャット表示
        // 履歴非表示
        if (c.superChatViewType.indexOf("history") < 0) {
            stylesheet += `#ticker.yt-live-chat-renderer { display: none; }`;
        }
        // チャットヘッダー非表示
        if (c.superChatViewType.indexOf("header") < 0) {
            stylesheet += `
                           #content.yt-live-chat-paid-message-renderer { border-radius: 2px; }
                           #header.yt-live-chat-paid-message-renderer,
                           #price-column.yt-live-chat-paid-sticker-renderer,
                           #header-subtext.yt-live-chat-membership-item-renderer { display: none; }
                           #author-photo.yt-live-chat-membership-item-renderer,
                           #author-photo.yt-live-chat-membership-item-renderer img,
                           #author-photo.yt-live-chat-paid-sticker-renderer,
                           #author-photo.yt-live-chat-paid-sticker-renderer img,
                           #sticker.yt-live-chat-paid-sticker-renderer img {
                               width: 32px; height: 32px; }
`;
        }
        // チャットメッセージ非表示
        if (c.superChatViewType.indexOf("message") < 0) {
            stylesheet += `yt-live-chat-paid-message-renderer,
                           yt-live-chat-membership-item-renderer,
                           yt-live-chat-paid-sticker-renderer { display: none; }`;
        }

        // ガイドライン非表示
        stylesheet += "yt-live-chat-viewer-engagement-message-renderer { display: none; }";

        // 絵文字フィーバー
        stylesheet += `
.emoji.yt-live-chat-text-message-renderer[fever_] {
    position: absolute;
    display: inline-block;
    bottom: 0;
    width: 32px; height: 32px;
    z-index: -1;
    opacity: 0;
    animation: emotesFeverHorizontal 1s alternate infinite ease-in-out,
               emotesFeverVertical 4s alternate 1 ease-in;
}
.emoji.yt-live-chat-text-message-renderer[fever1_] {
    animation-delay: 0s, 0s;
}
.emoji.yt-live-chat-text-message-renderer[fever2_] {
    animation-delay: -0.4s, 0s;
}
.emoji.yt-live-chat-text-message-renderer[fever3_] {
    animation-delay: -0.8s, 0s;
}
.emoji.yt-live-chat-text-message-renderer[fever4_] {
    animation-delay: -1.2s, 0s;
}
.emoji.yt-live-chat-text-message-renderer[fever5_] {
    animation-delay: -1.6s, 0s;
}
@keyframes emotesFeverHorizontal {
    100% { transform: translateX(var(--fever-width)) rotateZ(4deg); }
}
@keyframes emotesFeverVertical {
    0% { opacity: 0; }
    10% { opacity: 0.9; }
    80% { opacity: 0.6; }
    100% { opacity: 0; transform: translateY(var(--fever-height)); }
}
`;

        // スタイルを適応する
        var style = document.createElement("style");
        style.type ="text/css";
        style.innerHTML = stylesheet;
        document.querySelector("head").appendChild(style);
    }

    function focusButtonOnClick() {
        this.toggleAttribute("on_");
    }

    function filterButtonOnClick() {
        isEnableFiltering = this.toggleAttribute("on_");

        if (isNoTranslate()) {
            document.querySelector("#items.yt-live-chat-item-list-renderer").setAttribute("no_translate_", "");
        } else {
            document.querySelector("#items.yt-live-chat-item-list-renderer").removeAttribute("no_translate_");
        }
    }

    function leftButtonOnClick() {
        if (window.parent.document.querySelector("#chat").toggleAttribute("leftside_")) {
            this.setAttribute("on_", "");
        } else {
            this.removeAttribute("on_");
        }
    }

    function bottomButtonOnClick() {
        if (window.parent.document.querySelector("#chat").toggleAttribute("bottomside_")) {
            this.setAttribute("on_", "");
        } else {
            this.removeAttribute("on_");
        }
    }

    function headerButtonOnClick() {
        if (document.querySelector("yt-live-chat-header-renderer").toggleAttribute("hide_")) {
            this.removeAttribute("on_");
        } else {
            this.setAttribute("on_", "");
        }

        return false;
    }

    function chatButtonOnClick() {
        if (document.querySelector("yt-live-chat-app > #contents").toggleAttribute("hidechat_")) {
            this.removeAttribute("on_");
        } else {
            this.setAttribute("on_", "");
        }

        return false;
    }

    function footerButtonOnClick() {
        if (document.querySelector("#panel-pages").toggleAttribute("hide_")) {
            this.removeAttribute("on_");
        } else {
            this.setAttribute("on_", "");
        }

        return false;
    }

    function popupButtonOnClick() {
        popupSingleBorderWindow(window.parent.location.href);
        if (window.parent != window) {
            parent.close();
        }

        return false;
    }

    function reloadButtonOnClick() {
        location.reload();

        return false;
    }

    function toggleButtonOnClick() {
        if (window.top) {
            window.top.document.querySelector("#show-hide-button button").click();
        }

        return false;
    }

    // チャットウィンドウのみから使用する
    // 設定ポップアップとチャットウィンドウとの干渉を解決する
    var fixPlayerConflictTimer;
    function fixPlayerConflict() {
        var chat = window.parent.document.querySelector("#chatframe");
        if (!chat) return;

        var button = window.parent.document.querySelector(".ytp-settings-button");
        if (button && button.getAttribute("aria-expanded") == "true") {
            chat.style.pointerEvents = "none";
            chat.style.opacity = 0;

            // setInterval を多重起動しない
            clearTimeout(fixPlayerConflictTimer);
            fixPlayerConflictTimer = setInterval(fixPlayerConflict, 500);
        } else {
            chat.style.pointerEvents = "all";
            chat.style.opacity = c.windowOpacity;
            clearTimeout(fixPlayerConflictTimer);
        }
    }

    // 動的にレイアウトを調整する
    // ウィンドウのリサイズなどに合わせて呼び出す
    function updateDynamicLayout() {
        if (c.fullscreenMode && document.querySelector("ytd-watch-flexy:not([hidden])") && document.querySelector("ytd-watch-flexy[theater]")) {
            setFullscreenStyle();
        } else {
            removeFullscreenStyle();
        }
        updateChatWindowHeight();
        updateStickyChat();
    }

    // チャットウィンドウの高さを調整する
    function updateChatWindowHeight() {
        // チャットウィンドウ内からでも動くようにする
        if (window != window.parent) {
            window.parent.updateChatWindowHeight && window.parent.updateChatWindowHeight();
            return;
        }

        var height = 0;
        const player = document.querySelector("#player-theater-container"),
              controls = document.querySelector(".ytp-chrome-bottom");
        if (player) {
            height += player.clientHeight;
        }
        if (controls) {
            height -= controls.clientHeight;
        }

        var chatframe = document.querySelector("#chatframe");
        if (chatframe) {
            if (height == 0) {
                delete chatframe.style.maxHeight;
            } else {
                chatframe.style.maxHeight = `${height}px`;
            }
        }
        var chat = document.querySelector("#chat");
        if (chat) {
            if (height == 0) {
                delete chat.style.maxHeight;
            } else {
                chat.style.maxHeight = `${height}px`;
            }
        }
    }

    // 強調表示をやめる
    function unhighlightChat(chat) {
        // console.log("unhighlightChat()");

        chat.removeAttribute(TAG_HIDDEN);
        chat.removeAttribute(TAG_HIGHLIGHTED);
        delete chat.style.bottom;

        updateStickyChat();
    }

    // チャットを強調表示する
    function highlightChat(chat) {
        var time = new Date().getTime();
        chat.removeAttribute(TAG_HIDDEN);
        chat.setAttribute(TAG_HIGHLIGHTED, time);

        updateStickyChat();

        setTimeout(function () {
            // 終了前に要素が再利用されたら time が変わっている
            if (chat.getAttribute(TAG_HIGHLIGHTED) == time) {
                unhighlightChat(chat);

                // 要素の高さの更新が遅れることがある?再試行
                setTimeout(updateStickyChat, 100);
            }
        }, c.moderatorChatTimeout * 1000);
    }

    // 強調表示したチャットの位置を更新する
    function updateStickyChat() {
        var chats = document.querySelectorAll(`yt-live-chat-text-message-renderer[${TAG_HIGHLIGHTED}]`);
        if (!chats) return;

        var sum = 0;
        for (var i = chats.length - 1; i >= 0; i--) {
            chats[i].style.bottom = sum + "px";
            sum += chats[i].offsetHeight;
        }
    }

    /** *****************
     * Float Window
     * ******************/
    function addFloatWindowStyle() {
        // console.log("addFloatWindowStyle()", location.href);

        // #chat default selector
        // ytd-watch-flexy[flexy_][js-panel-height_] #chat.ytd-watch-flexy:not([collapsed]).ytd-watch-flexy

        var stylesheet = "";

        stylesheet += `
        .ytp-offline-slate-background { background-size: contain; }
        ytd-watch-flexy[flexy][js-panel-height_][fullscreen] #player-theater-container.ytd-watch-flexy,
        ytd-watch-flexy[flexy][js-panel-height_][theater] #player-theater-container.ytd-watch-flexy {
           /* min-height: unset; */
        }
        ytd-watch-flexy[flexy][js-panel-height_][fullscreen] #chat,
        ytd-watch-flexy[flexy][js-panel-height_][theater] #chat {
            transition: opacity .2s linear;
            min-height: unset;
        }
        ytd-watch-flexy[flexy][js-panel-height_][fullscreen] #chat.ytd-watch-flexy:not([collapsed]).ytd-watch-flexy,
        ytd-watch-flexy[flexy][js-panel-height_][theater] #chat.ytd-watch-flexy:not([collapsed]).ytd-watch-flexy {
            position: fixed;
            border: 0;
            right: 8px;
            width: ${appendUnit(c.windowWidth)};
            height: 100%;
            min-height: 0px;
            top: calc(var(--ytd-watch-flexy-masthead-height));
            z-index: 2019; /* #masthead is 2020 */
            box-sizing: border-box;
            margin: 0;
            pointer-events: none;
        }
        ytd-app[masthead-hidden] ytd-watch-flexy[flexy][js-panel-height_][fullscreen] #chat.ytd-watch-flexy:not([collapsed]).ytd-watch-flexy,
        ytd-app[masthead-hidden] ytd-watch-flexy[flexy][js-panel-height_][theater] #chat.ytd-watch-flexy:not([collapsed]).ytd-watch-flexy {
            top: 0;
        }

        ytd-watch-flexy[flexy][js-panel-height_][fullscreen] #chat.ytd-watch-flexy[leftside_]:not([collapsed]).ytd-watch-flexy,
        ytd-watch-flexy[flexy][js-panel-height_][theater] #chat.ytd-watch-flexy[leftside_]:not([collapsed]).ytd-watch-flexy {
            left: 8px;
            rignt: unset;
        }
        ytd-watch-flexy[flexy][js-panel-height_][fullscreen] #chat.ytd-watch-flexy:not([collapsed]).ytd-watch-flexy #chatframe,
        ytd-watch-flexy[flexy][js-panel-height_][theater] #chat.ytd-watch-flexy:not([collapsed]).ytd-watch-flexy #chatframe {
            position: fixed;
            top: 0;
            height: ${appendUnit(c.windowHeight)};
            width: ${appendUnit(c.windowWidth)};
            padding: 8px;
            box-sizing: border-box;
            pointer-events: all;
            opacity: ${c.windowOpacity};
        }
        ytd-watch-flexy[flexy][js-panel-height_][fullscreen] #chat.ytd-watch-flexy[bottomside_]:not([collapsed]).ytd-watch-flexy #chatframe,
        ytd-watch-flexy[flexy][js-panel-height_][theater] #chat.ytd-watch-flexy[bottomside_]:not([collapsed]).ytd-watch-flexy #chatframe {
            top: unset;
            bottom: 0;
        }
        ytd-watch-flexy[flexy][js-panel-height_][fullscreen] #chat.ytd-watch-flexy[collapsed].ytd-watch-flexy #chatframe,
        ytd-watch-flexy[flexy][js-panel-height_][theater] #chat.ytd-watch-flexy[collapsed].ytd-watch-flexy #chatframe {
            height: 0;
        }

        ytd-app[masthead-hidden] #masthead-container.ytd-app {
            z-index: -1;
        }
`;

        // show hide button
        stylesheet += `
#chat:not([collapsed]) #show-hide-button { display: none; }
#show-hide-button.ytd-live-chat-frame > ytd-toggle-button-renderer.ytd-live-chat-frame {
    background: ${c.backgroundColor}; transition: background .2s ease; }
#show-hide-button.ytd-live-chat-frame > ytd-toggle-button-renderer.ytd-live-chat-frame:hover { background: #fffc; }
`;

        // config
        stylesheet += `
#${configAreaID} {
    display: none;
    position: fixed;
    right: 8px;
    top: 8px;
    font-size: 13px;
    line-height: 1.75rem;
    border: solid 1px #808080;
    padding: 16px;
    background: #fff;
    z-index: 10000;
    transition: height .25s ease-in-out;
    max-height: 90%;
    overflow-y: auto;
}
#${configAreaID}.open { display: block; }
#${configAreaID}::after {
    position: absolute;
    font-size: 10px;
    color: #acacac;
    top: 3px;
    right: 8px;
    content: "Youtube live, Simple Chat Stylizer";
}
#${configAreaID} header {
    font-size: 16px;
    margin: 8px 0 4px 4px;
}
#${configAreaID} input {
    display: inline-block;
    width: 60px; min-height: 20px;
    text-align: center; vertical-align: middle;
    box-sizing: border-box;
    margin: 1px 8px 1px 0;
}
#${configAreaID} .dummy {
    display: inline-block;
    width: 60px; min-height: 20px;
    box-sizing: border-box;
    margin: 1px 8px 1px 0;
}
#${configAreaID} label {
    display: inline-block; min-height: 20px; vertical-align: middle; box-sizing: border-box; }
#${configAreaID} label.for-select { margin-right: 8px; }
#${configAreaID} textarea { min-height: 2rem; max-width: 1000px; min-width: 100px; width: 100%; display: block; }
#${configAreaID} button { display: inline-block; width: 200px; height: 32px; margin: 3px 0; }
#${configAreaID}-toggle { padding: 0 4px; }
#${configAreaID}-toggle::after { display: block; content: "SCS"; cursor: pointer; padding: 0 4px; line-height: var(--yt-button-icon-size, 40px); }
`;

        // single border window
        stylesheet += `ytd-app[masthead-hidden] {
            --ytd-masthead-height: 0px !important;
        }`;

        const initTimer = setInterval(() => {
            const styleID = "yt-live-chat-float-on-screen-stylesheet";
            const style = document.createElement("style");
            style.type = "text/css";
            style.id = styleID;
            style.innerHTML = stylesheet;

            const head = document.querySelector("head");
            if (head) {
                head.appendChild(style);
                clearInterval(initTimer);
            }
        }, 500);
    }

    // チャット入力欄にフォーカスする
    function focusInputField() {
        var frame = document.querySelector("#chatframe"), input;
        if (frame && frame.contentDocument.querySelector("#chat-focus-button[on_]")) {
            input = frame.querySelector("yt-live-chat-text-input-field-renderer #input[contenteditable]");
        } else if (document.querySelector("#chat-focus-button[on_]")) {
            input = document.querySelector("yt-live-chat-text-input-field-renderer #input[contenteditable]");
        }

        if (input) {
            setTimeout(() => input.focus(), 50);
        }
    }

    function appendUnit(value) {
        if (value.match(/(%|cm|mm|Q|in|pt|px|em|ex|rem|ch|lh|vm|vh|vmin|vmax)/)) {
            return value;
        } else {
            return value + "px";
        }
    }

    /** *****************
     * Single Bordered Window
     * ******************/
    var fullscreenSytleTimer = 0;
    function setFullscreenStyle() {
        // console.log("update single border style");

        fullscreenSytleTimer = clearTimeout(setFullscreenStyle);
        fullscreenSytleTimer = setTimeout(function () {
            var app = document.querySelector("ytd-app");
            app.setAttribute("masthead-hidden", "");

            var player = document.querySelector("#movie_player");
            // player.classList.add("ytd-fullscreen");
            // player.classList.add("ytd-big-mode");

            var flexy = document.querySelector("ytd-watch-flexy");
            flexy.setAttribute("fullscreen", "");
            // flexy.setAttribute("theater", "");
            // flexy.setAttribute("theater-requested_", "");
        }, 300);
    }

    function removeFullscreenStyle() {
        var app = document.querySelector("ytd-app");
        if (app.hasAttribute("masthead-hidden")) {
            app.removeAttribute("masthead-hidden");
        }

        var player = document.querySelector("#movie_player");
        // player.classList.add("ytd-fullscreen");
        // player.classList.add("ytd-big-mode");

        var flexy = document.querySelector("ytd-watch-flexy");
        if (flexy.hasAttribute("fullscreen")) {
            flexy.removeAttribute("fullscreen", "");
        }
        // flexy.setAttribute("theater", "");
        // flexy.setAttribute("theater-requested_", "");
    }

    function popupSingleBorderWindow(url) {
        url = url || location.href;
        window.open(url, url, SINGLE_WINDOW_PARAMS);
    }
})();