「新しい日本語を作る会」コメントシステムの改良

「新しい日本語を作る会」の コメントシステムを 改良します。

当前为 2025-02-26 提交的版本,查看 最新版本

// ==UserScript==
// @name         「新しい日本語を作る会」コメントシステムの改良
// @namespace    http://lit.link/toracatman
// @version      2025-02-26
// @description  「新しい日本語を作る会」の コメントシステムを 改良します。
// @author       トラネコマン
// @match        http://www.tackns.net/*
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        none
// @license      MIT
// ==/UserScript==

var cat = false; //猫機能

var css = `.mute .cs_name,.mute .cs_name+.cs_text,.mute input[type="button"]+input[type="button"],.mute input[type="submit"],.mute .cs_contents {
    display: none;
}
.open * {
    display: initial !important;
}
.cs_contents {
    white-space: pre-line;
}
blockquote {
    border-left: 4px solid #ccc;
    padding: 1em 0 1em 1em;
    color: #666;
}
.code-color {
    display: inline-block;
    width: 0.8em;
    height: 0.8em;
    border: 1px solid rgba(128, 128, 128, 0.5);
    margin-left: 0.1em;
}
.note {
    color: #000;
    margin: 1em 0;
    padding: 1em 1em 1em 3em;
    position: relative;
}
.note:before {
    display: block;
    width: 1.5em;
    height: 1.5em;
    border-radius: 50%;
    font-weight: bold;
    text-align: center;
    line-height: 1.5em;
    color: #fff;
    position: absolute;
    top: 1em;
    left: 1em;
}
.note-info {
    background-color: #cfc;
}
.note-info:before {
    content: "✓";
    background-color: #0c0;
}
.note-warn {
    background-color: #ffc;
}
.note-warn:before {
    content: "!";
    background-color: #fc0;
}
.note-alert {
    background-color: #fcc;
}
.note-alert:before {
    content: "✕";
    background-color: #c00;
}

.mfm-center {
    text-align: center;
}
small {
    opacity: 0.7;
}
.mfm-blur {
    filter: blur(6px);
    transition: filter .3s;
}
.mfm-blur:hover {
    filter: blur(0px);
}
.mfm-flip {
    transform: scaleX(-1);
}
.mfm-flipV {
    transform: scaleY(-1);
}
.mfm-flipHV {
    transform: scale(-1, -1);
}
div[data-testid="tweetText"]:has(rtc) {
	line-height: 2.5;
}
ruby {
	position: relative;
}
rtc {
	text-indent: 0px;
	line-height: 1;
	text-emphasis: none;
}
ruby > rtc {
	display: ruby-text;
	font-size: 50%;
	text-align: center;
	width: 100%;
	position: absolute;
	top: 100%;
	left: 0;
}
.mfm-scale .mfm-scale {
    transform: scale(1) !important;
}
.mfm-x .mfm-x .mfm-x {
    font-size: 1em !important;
}
.mfm-transform {
    display: inline-block;
}
.mfm-jelly {
    animation: 1s linear 0s infinite normal both running mfm-jelly;
}
@keyframes mfm-jelly {
    0% {
        transform: scaleZ(1);
    }
    30% {
        transform: scale3d(1.25, 0.75, 1);
    }
    40% {
        transform: scale3d(0.75, 1.25, 1);
    }
    50% {
        transform: scale3d(1.15, 0.85, 1);
    }
    65% {
        transform: scale3d(0.95, 1.05, 1);
    }
    75% {
        transform: scale3d(1.05, 0.95, 1);
    }
    100% {
        transform: scaleZ(1);
    }
}
.mfm-tada {
    animation: 1s linear 0s infinite normal both running mfm-tada;
}
@keyframes mfm-tada {
    0% {
        transform: scaleZ(1);
    }
    10%, 20% {
        transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);
    }
    30%, 50%, 70%, 90% {
        transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
    }
    40%, 60%, 80% {
        transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
    }
    100% {
        transform: scaleZ(1);
    }
}
.mfm-jump {
    animation: 0.75s linear 0s infinite normal none running mfm-jump;
}
@keyframes mfm-jump {
    0% {
        transform: translateY(0);
    }
    25% {
        transform: translateY(-16px);
    }
    50% {
        transform: translateY(0);
    }
    75% {
        transform: translateY(-8px);
    }
    100% {
        transform: translateY(0);
    }
}
.mfm-bounce {
    animation: 0.75s linear 0s infinite normal none running mfm-bounce;
    transform-origin: center bottom;
}
@keyframes mfm-bounce {
    0% {
        transform: translateY(0) scale(1);
    }
    25% {
        transform: translateY(-16px) scale(1);
    }
    50% {
        transform: translateY(0) scale(1);
    }
    75% {
        transform: translateY(0) scale(1.5, 0.75);
    }
    100% {
        transform: translateY(0) scale(1);
    }
}
.mfm-spin {
    animation: 1.5s linear 0s infinite normal none running mfm-spin;
}
.mfm-spinL {
    animation: 1.5s linear 0s infinite reverse none running mfm-spin;
}
.mfm-spinA {
    animation: 1.5s linear 0s infinite alternate none running mfm-spin;
}
@keyframes mfm-spin {
    0% {
        transform: rotate(0);
    }
    100% {
        transform: rotate(360deg);
    }
}
.mfm-spinX {
    animation: 1.5s linear 0s infinite normal none running mfm-spinX;
}
.mfm-spinXL {
    animation: 1.5s linear 0s infinite reverse none running mfm-spinX;
}
.mfm-spinXA {
    animation: 1.5s linear 0s infinite alternate none running mfm-spinX;
}
@keyframes mfm-spinX {
    0% {
        transform: perspective(128px) rotateX(0);
    }
    100% {
        transform: perspective(128px) rotateX(360deg);
    }
}
.mfm-spinY {
    animation: 1.5s linear 0s infinite normal none running mfm-spinY;
}
.mfm-spinYL {
    animation: 1.5s linear 0s infinite reverse none running mfm-spinY;
}
.mfm-spinYA {
    animation: 1.5s linear 0s infinite alternate none running mfm-spinY;
}
@keyframes mfm-spinY {
    0% {
        transform: perspective(128px) rotateY(0);
    }
    100% {
        transform: perspective(128px) rotateY(360deg);
    }
}
.mfm-shake {
    animation: 0.5s ease 0s infinite normal none running mfm-shake;
}
@keyframes mfm-shake {
    0% {
        transform: translate(-3px, -1px) rotate(-8deg);
    }
    5% {
        transform: translateY(-1px) rotate(-10deg);
    }
    10% {
        transform: translate(1px, -3px) rotate(0);
    }
    15% {
        transform: translate(1px, 1px) rotate(11deg);
    }
    20% {
        transform: translate(-2px, 1px) rotate(1deg);
    }
    25% {
        transform: translate(-1px, -2px) rotate(-2deg);
    }
    30% {
        transform: translate(-1px, 2px) rotate(-3deg);
    }
    35% {
        transform: translate(2px, 1px) rotate(6deg);
    }
    40% {
        transform: translate(-2px, -3px) rotate(-9deg);
    }
    45% {
        transform: translateY(-1px) rotate(-12deg);
    }
    50% {
        transform: translate(1px, 2px) rotate(10deg);
    }
    55% {
        transform: translateY(-3px) rotate(8deg);
    }
    60% {
        transform: translate(1px, -1px) rotate(8deg);
    }
    65% {
        transform: translateY(-1px) rotate(-7deg);
    }
    70% {
        transform: translate(-1px, -3px) rotate(6deg);
    }
    75% {
        transform: translateY(-2px) rotate(4deg);
    }
    80% {
        transform: translate(-2px, -1px) rotate(3deg);
    }
    85% {
        transform: translate(1px, -3px) rotate(-10deg);
    }
    90% {
        transform: translate(1px) rotate(3deg);
    }
    95% {
        transform: translate(-2px) rotate(-3deg);
    }
    100% {
        transform: translate(2px, 1px) rotate(2deg);
    }
}
.mfm-twitch {
    animation: 0.5s ease 0s infinite normal none running mfm-twitch;
}
@keyframes mfm-twitch {
    0% {
        transform: translate(7px, -2px);
    }
    5% {
        transform: translate(-3px, -1px);
    }
    10% {
        transform: translate(-7px, -1px);
    }
    15% {
        transform: translateY(-1px);
    }
    20% {
        transform: translate(-8px, 6px);
    }
    25% {
        transform: translate(-4px, -3px);
    }
    30% {
        transform: translate(-4px, -6px);
    }
    35% {
        transform: translate(-8px, -8px);
    }
    40% {
        transform: translate(4px, 6px);
    }
    45% {
        transform: translate(-3px, 1px);
    }
    50% {
        transform: translate(2px, -10px);
    }
    55% {
        transform: translate(-7px);
    }
    60% {
        transform: translate(-2px, 4px);
    }
    65% {
        transform: translate(3px, -8px);
    }
    70% {
        transform: translate(6px, 7px);
    }
    75% {
        transform: translate(-7px, -2px);
    }
    80% {
        transform: translate(-7px, -8px);
    }
    85% {
        transform: translate(9px, 3px);
    }
    90% {
        transform: translate(-3px, -2px);
    }
    95% {
        transform: translate(-10px, 2px);
    }
    100% {
        transform: translate(-2px, -6px);
    }
}
.mfm-rainbow {
    animation: 1s linear 0s infinite normal none running mfm-rainbow;
}
@keyframes mfm-rainbow {
    0% {
        filter: hue-rotate(0deg) contrast(150%) saturate(150%);
    }
    100% {
        filter: hue-rotate(360deg) contrast(150%) saturate(150%);
    }
}
.mfm-sparkle:before,.mfm-sparkle:after {
    content: "✨";
    animation: 0.5s linear 0s infinite alternate none running mfm-sparkle;
}
@keyframes mfm-sparkle {
    0% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}`;

//ミュート追加
function addMute(t, w) {
    var mute = JSON.parse(localStorage.getItem("mute"));
    if (mute == null) mute = { names: [], contents: [] };

    if (t == 0) {
        if (mute.names.indexOf(w) === -1) mute.names.push(w);
    }
    else {
        if (mute.contents.indexOf(w) === -1) mute.contents.push(w);
    }

    localStorage.setItem("mute", JSON.stringify(mute));
    makeMuteWordItem(t, w);

    muteProcess();
}

//ミュート処理
function muteProcess() {
    var mute = JSON.parse(localStorage.getItem("mute"));
    if (mute == null) mute = { names: [], contents: [] };

    var a = document.querySelectorAll(".cs_comment:not(.mute) .cs_name");
    for (var i = 0; i < a.length; i++) {
        //名前
        var f = false;
        for (var j = 0; j < mute.names.length; j++) {
            if (new RegExp(mute.names[j], "u").test(a[i].textContent)) {
                applyMute(a[i], 0, mute.names[j]);
                f = true;
                break;
            }
        }
        if (f) continue;

        //本文
        for (var j = 0; j < mute.contents.length; j++) {
            if (new RegExp(mute.contents[j], "u").test(a[i].parentNode.lastElementChild.textContent)) {
                applyMute(a[i], 1, mute.contents[j]);
                break;
            }
        }
    }
}

//ミュート適用
function applyMute(a, t, w) {
    var comment = a.parentNode;
    comment.setAttribute("data-mutetype", t);
    comment.setAttribute("data-muteword", w);
    comment.querySelector(".cs_button").value = "ミュート解除";
    comment.classList.add("mute");
    var b = document.createElement("span");
    b.className = "cs_text";
    b.textContent = t == 0 ? "《ミュートしている投稿者によるコメントです》" : "《ミュートしている内容が含まれるコメントです》";
    a.nextElementSibling.after(b);
    var c = document.createElement("input");
    c.type = "button";
    c.value = "表示";
    c.className = "cs_button";
    c.onclick = function() { displayButton(this) };
    b.after(c);
    c.after(document.createTextNode("\n"));
}

//ミュート解除
function removeMute(t, w) {
    var mute = JSON.parse(localStorage.getItem("mute"));
    if (mute == null) return;

    if (t == 0) {
        mute.names = mute.names.filter(f => f !== w);
    }
    else {
        mute.contents = mute.contents.filter(f => f !== w);
    }

    localStorage.setItem("mute", JSON.stringify(mute));
    document.querySelector(`#mute_word_list input[data-mutetype="${t}"][data-muteword="${w}"]`).parentNode.remove();

    var a = document.querySelectorAll(`.mute[data-mutetype="${t}"][data-muteword="${w}"]`);
    for (var i = 0; i < a.length; i++) {
        a[i].removeAttribute("data-mutetype");
        a[i].removeAttribute("data-muteword");
        a[i].classList.remove("mute");
        a[i].classList.remove("open");
        a[i].querySelector(".cs_text+.cs_text").remove();
        a[i].querySelector(".cs_button").remove();
        a[i].querySelector(".cs_button").value = "ミュート";
    }
}

//ミュートした ワード一覧の 作成
function makeMuteWordList() {
    var mute = JSON.parse(localStorage.getItem("mute"));
    if (mute == null) mute = { names: [], contents: [] };

    var details = document.createElement("details");
    details.id = "mute_word_list";
    var summary = document.createElement("summary");
    summary.textContent = "ミュートしたワード一覧";
    details.appendChild(summary);

    var span;
    var ul;

    //名前
    span = document.createElement("span");
    span.textContent = "名前";
    details.appendChild(span);
    ul = document.createElement("ul");
    ul.id = "mute_word_names";
    details.appendChild(ul);

    //本文
    span = document.createElement("span");
    span.textContent = "本文";
    details.appendChild(span);
    ul = document.createElement("ul");
    ul.id = "mute_word_contents";
    details.appendChild(ul);

    document.muteform.after(details);

    for (var i = 0; i < mute.names.length; i++) {
        makeMuteWordItem(0, mute.names[i]);
    }
    for (var i = 0; i < mute.contents.length; i++) {
        makeMuteWordItem(1, mute.contents[i]);
    }
}

//項目の 作成
function makeMuteWordItem(t, w) {
    var li = document.createElement("li");
    li.textContent = w;
    var input = document.createElement("input");
    input.type = "button";
    input.value = "ミュート解除";
    input.className = "cs_button";
    input.setAttribute("data-mutetype", t);
    input.setAttribute("data-muteword", w);
    input.onclick = function() { removeMute(Number(this.getAttribute("data-mutetype")), this.getAttribute("data-muteword")); };
    li.appendChild(input);
    document.getElementById(t == 0 ? "mute_word_names" : "mute_word_contents").appendChild(li);
}

//表示ボタン
function displayButton(a) {
    a.parentNode.classList.add("open");
    a.value = "隠す";
    a.onclick = function() { hideButton(this) };
}

//隠すボタン
function hideButton(a) {
    a.parentNode.classList.remove("open");
    a.value = "表示";
    a.onclick = function() { displayButton(this) };
}

//特殊処理
function convertSpecial(s) {
    s = s.trim().replace(/<br>/g, "").replace(/\\\\/g, "\\").replace(/&amp;/g, "&");

    //エスケープ
    var e = s.match(/\\./gu);
    if (e != null) {
        for (var j = 0; j < e.length; j++) {
            s = s.replace(e[j], `&#${e[j].codePointAt(1)};`);
        }
    }

    //プレーン
    var plain = s.match(/&lt;plain&gt;.+?&lt;\/plain&gt;/gs);
    if (plain != null) {
        for (var j = 0; j < plain.length; j++) {
            s = s.replace(plain[j], `\x1bA[${j}]`);
        }
    }

    //画像、リンク、URL
    var g = s.match(/!\[.+?\]\(.+?\)/g);
    if (g != null) {
        for (var j = 0; j < g.length; j++) {
            s = s.replace(g[j], `\x1bI[${j}]`);
        }
    }
    var l = s.match(/\[.+?\]\(.+?\)/g);
    if (l != null) {
        for (var j = 0; j < l.length; j++) {
            s = s.replace(l[j], `\x1bL[${j}]`);
        }
    }
    var u = s.match(/https?:\/\/[\w!?\/+\-_~;.,*&@#$%()'[\]]+/g);
    if (u != null) {
        for (var j = 0; j < u.length; j++) {
            s = s.replace(u[j], `\x1bU[${j}]`);
        }
    }

    //pre記法、code記法
    var p = s.match(/```[^\n]*\n.+?\n```/gs);
    if (p != null) {
        for (var j = 0; j < p.length; j++) {
            s = s.replace(p[j], `\x1bP[${j}]`);
        }
    }
    var c = s.match(/`.+?`/gs);
    if (c != null) {
        for (var j = 0; j < c.length; j++) {
            s = s.replace(c[j], `\x1bC[${j}]`);
        }
    }

    //引用
    var q = s.match(/^((&gt;)+ .*\n)*(&gt;)+ .*/gm);
    if (q != null) {
        for (var j = 0; j < q.length; j++) {
            s = s.replace(q[j], `\x1bQ[${j}]`);
        }
    }

    //猫機能
    if (cat) s = s.replace(/な/g, "にゃ").replace(/ナ/g, "ニャ").replace(/n(?=[Aa])/g, "ny").replace(/Na/g, "Nya").replace(/NA/g, "NYA");

    //チェックボックス
    s = s.replace(/- \[x\] ?/g, '<input type="checkbox" checked>');
    s = s.replace(/- \[ \] ?/g, '<input type="checkbox">');

    //箇条書きリスト、番号付きリスト
    var ul = s.match(/^(\t*- .*\n)*\t*- .*/gm);
    if (ul != null) {
        for (var j = 0; j < ul.length; j++) {
            var ll = ul[j].split("\n");
            var lt = "";
            var n = -1;
            for (var k = 0; k < ll.length; k++) {
                var d = ll[k].indexOf("-") - n;
                if (d > 0) lt += "<ul>";
                if (d < 0) for (var m = 0; m < -d; m++) lt += "</li></ul>";
                if (d <= 0) lt += "</li>";
                n = ll[k].indexOf("-");
                lt += `<li>${ll[k].replace(/^\t*- /, "")}`;
            }
            for (var k = 0; k < n + 1; k++) lt += "</li></ul>";
            s = s.replace(ul[j], lt);
        }
    }
    s = s.replace(/(?<=<\/ul>)\n/g, "");
    var ol = s.match(/^(\t*\d+\. .*\n)*\t*\d+\. .*/gm);
    if (ol != null) {
        for (var j = 0; j < ol.length; j++) {
            var ll = ol[j].split("\n");
            var lt = "";
            var n = -1;
            for (var k = 0; k < ll.length; k++) {
                var d = ll[k].search(/\d/) - n;
                if (d > 0) lt += "<ol>";
                if (d < 0) for (var m = 0; m < -d; m++) lt += "</li></ol>";
                if (d <= 0) lt += "</li>";
                n = ll[k].search(/\d/);
                lt += `<li>${ll[k].replace(/^\t*\d+\. /, "")}`;
            }
            for (var k = 0; k < n + 1; k++) lt += "</li></ol>";
            s = s.replace(ol[j], lt);
        }
    }
    s = s.replace(/(?<=<\/ol>)\n/g, "");

    //表
    var tb = s.match(/^(\|.*\|\n){2,}\|.*\|/gm);
    if (tb != null) {
        for (var j = 0; j < tb.length; j++) {
            var tl = tb[j].split("\n");
            var al = tl[1].split("|");
            var ali = new Array(al.length - 2);
            for (var k = 0; k < ali.length; k++) {
                if (/:-+:/.test(al[k + 1])) {
                    ali[k] = ' align="center"';
                }
                else if (/:-+/.test(al[k + 1])) {
                    ali[k] = ' align="left"';
                }
                else if (/-+:/.test(al[k + 1])) {
                    ali[k] = ' align="right"';
                }
                else {
                    ali[k] = "";
                }
            }
            tl[0] = tl[0].replace(/^\|/, `<tr><th${ali[0]}>`).replace(/\|$/, "</th></tr>");
            for (var m = 1; m < ali.length; m++) {
                tl[0] = tl[0].replace(/\|/, `</th><th${ali[m]}>`);
            }
            for (var k = 2; k < tl.length; k++) {
                tl[k] = tl[k].replace(/^\|/, `<tr><td${ali[0]}>`).replace(/\|$/, "</td></tr>");
                for (var m = 1; m < ali.length; m++) {
                    tl[k] = tl[k].replace(/\|/, `</td><td${ali[m]}>`);
                }
            }
            var tt = `<table border="1">${tl[0]}`;
            for (var k = 2; k < tl.length; k++) {
                tt += `${tl[k]}`;
            }
            tt += "</table>";
            s = s.replace(tb[j], tt);
        }
    }
    s = s.replace(/(?<=<\/table>)\n/g, "");

    //見出し
    s = s.replace(/^# (.+)$/gm, "<h1>$1</h1>");
    s = s.replace(/^## (.+)$/gm, "<h2>$1</h2>");
    s = s.replace(/^### (.+)$/gm, "<h3>$1</h3>");
    s = s.replace(/^#### (.+)$/gm, "<h4>$1</h4>");
    s = s.replace(/^##### (.+)$/gm, "<h5>$1</h5>");
    s = s.replace(/^###### (.+)$/gm, "<h6>$1</h6>");
    s = s.replace(/(?<=<\/h[1-6]>)\n/g, "");

    //太字かつ斜体
    s = s.replace(/\*\*\*(.+?)\*\*\*/gs, "<b><i>$1</i></b>");

    //太字
    s = s.replace(/\*\*(.+?)\*\*/gs, "<b>$1</b>");

    //斜体
    s = s.replace(/&lt;i&gt;(.+?)&lt;\/i&gt;/gs, "<i>$1</i>");
    s = s.replace(/\*(.+?)\*/gs, "<i>$1</i>");

    //取り消し線
    s = s.replace(/~~(.+?)~~/gs, "<del>$1</del>");

    //水平線
    s = s.replace(/^---+$/gm, "<hr>");
    s = s.replace(/(?<=<hr>)\n/g, "");

    //文字色
    s = s.replace(/&lt;font color="#([\da-fa-f]{3,8})"&gt;(.+?)&lt;\/font&gt;/gs, '<span style="color: #$1;">$2</span>');

    //補足説明
    s = s.replace(/:::note( info)?\n(.+?)\n:::/gs, '<div class="note note-info">$2</div>');
    s = s.replace(/:::note warn\n(.+?)\n:::/gs, '<div class="note note-warn">$1</div>');
    s = s.replace(/:::note alert\n(.+?)\n:::/gs, '<div class="note note-alert">$1</div>');
    s = s.replace(/(?<=<\/div>)\n/g, "");

    //タグ
    s = s.replace(/&lt;(\/?)(details|summary|dl|dt|dd)&gt;/gs, '<$1$2>');
    s = s.replace(/<(\/?)(details|summary|dl|dt|dd)>\n/g, "<$1$2>");
    s = s.replace(/\n<\/(details|summary|dl|dt|dd)>/g, "</$1>");

    //中央揃え
    s = s.replace(/&lt;center&gt;(.+?)&lt;\/center&gt;/gs, '<div class="mfm-center">$1</div>');

    //Google検索
    s = s.replace(/^(.+?) \[?(検索|Search)\]?$/gm, '<div><input type="text" value="$1" placeholder="$1"><input type="button" value="検索" onclick="window.open(\'https://www.google.com/search?q=\' + this.previousElementSibling.value);"></div>');
    s = s.replace(/(<\/div>)\n/g, "$1");

    //目立たない字
    s = s.replace(/&lt;small&gt;(.+?)&lt;\/small&gt;/gs, '<small>$1</small>');

    //MFM関数
    var os = "";
    while (os != s) {
        os = s;

        //文字色・背景色
        s = s.replace(/\$\[fg\.color=([\dA-Fa-f]{3,8}) ([^\[\]]+?)\]/gs, '<span style="color: #$1;">$2</span>');
        s = s.replace(/\$\[bg\.color=([\dA-Fa-f]{3,8}) ([^\[\]]+?)\]/gs, '<span style="background-color: #$1;">$2</span>');

        //ブラー
        s = s.replace(/\$\[blur ([^\[\]]+?)\]/gs, '<span class="mfm-blur">$1</span>');

        //フォント
        s = s.replace(/\$\[font\.("[^"]+?"|[a-z]+?) ([^\[\]]+?)\]/gs, "<span style='font-family: $1;'>$2</span>");

        //反転
        s = s.replace(/\$\[flip ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-flip">$1</span>');
        s = s.replace(/\$\[flip\.v ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-flipV">$1</span>');
        s = s.replace(/\$\[flip\.h,v ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-flipHV">$1</span>');

        //角度変更
        s = s.replace(/\$\[rotate\.deg=(-?\d+|-?\d+\.\d+) ([^\[\]]+?)\]/gs, '<span class="mfm-transform" style="transform: rotate($1deg);">$2</span>');

        //位置変更
        s = s.replace(/\$\[position\.x=(-?1000|-?\d{1,3}|-?\d{1,3}\.\d+),y=(-?1000|-?\d{1,3}|-?\d{1,3}\.\d+) ([^\[\]]+?)\]/gs, '<span class="mfm-transform" style="transform: translate($1em, $2em);">$3</span>');

        //ルビ
        s = s.replace(/\$\[ruby ([^ \[\]]+?) ([^ \[\]]+?)\]/gs, '<ruby><rb>$1</rb><rp>(</rp><rt>$2</rt><rp>)</rp></ruby>');
        s = s.replace(/\$\[ruby ([^ \[\]]+?) ([^ \[\]]+?) ([^ \[\]]+?)\]/gs, '<ruby><rb>$1</rb><rp>(</rp><rt>$2</rt><rp>)</rp><rtc>$3</rtc></ruby>');
        s = s.replace(/\$\[ruby ([^ \[\]]+?)  ([^ \[\]]+?)\]/gs, '<ruby><rb>$1</rb><rtc>$2</rtc></ruby>');

        //拡大
        s = s.replace(/\$\[scale\.x=(-?[0-5]|-?[0-4]\.\d+),y=(-?[0-5]|-?[0-4]\.\d+) ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-scale" style="transform: scale($1, $2);">$3</span>');

        //シンプル拡大
        s = s.replace(/\$\[x([0-4]|[0-3]\.\d+) ([^\[\]]+?)\]/gs, '<span class="mfm-x" style="font-size: $1em;">$2</span>');

        //アニメーション(びよんびよん)
        s = s.replace(/\$\[jelly ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-jelly">$1</span>');
        s = s.replace(/\$\[jelly\.speed=(\d+|\d+\.\d+)s ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-jelly" style="animation-duration: $1s;">$2</span>');

        //アニメーション(じゃーん)
        s = s.replace(/\$\[tada ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-tada">$1</span>');
        s = s.replace(/\$\[tada\.speed=(\d+|\d+\.\d+)s ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-tada" style="animation-duration: $1s;">$2</span>');

        //アニメーション(ジャンプ)
        s = s.replace(/\$\[jump ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-jump">$1</span>');
        s = s.replace(/\$\[jump\.speed=(\d+|\d+\.\d+)s ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-jump" style="animation-duration: $1s;">$2</span>');

        //アニメーション(バウンド)
        s = s.replace(/\$\[bounce ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-bounce">$1</span>');
        s = s.replace(/\$\[bounce\.speed=(\d+|\d+\.\d+)s ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-bounce" style="animation-duration: $1s;">$2</span>');

        //アニメーション(回転)
        s = s.replace(/\$\[spin ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-spin">$1</span>');
        s = s.replace(/\$\[spin\.speed=(\d+|\d+\.\d+)s ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-spin" style="animation-duration: $1s;">$2</span>');
        s = s.replace(/\$\[spin\.left ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-spinL">$1</span>');
        s = s.replace(/\$\[spin\.left,speed=(\d+|\d+\.\d+)s ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-spinL" style="animation-duration: $1s;">$2</span>');
        s = s.replace(/\$\[spin\.alterny?ate ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-spinA">$1</span>');
        s = s.replace(/\$\[spin\.alterny?ate,speed=(\d+|\d+\.\d+)s ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-spinA" style="animation-duration: $1s;">$2</span>');
        s = s.replace(/\$\[spin\.x ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-spinX">$1</span>');
        s = s.replace(/\$\[spin\.x,speed=(\d+|\d+\.\d+)s ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-spinX" style="animation-duration: $1s;">$2</span>');
        s = s.replace(/\$\[spin\.x,left ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-spinXL">$1</span>');
        s = s.replace(/\$\[spin\.x,left,speed=(\d+|\d+\.\d+)s ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-spinXL" style="animation-duration: $1s;">$2</span>');
        s = s.replace(/\$\[spin\.x,alterny?ate ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-spinXA">$1</span>');
        s = s.replace(/\$\[spin\.x,alterny?ate,speed=(\d+|\d+\.\d+)s ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-spinXA" style="animation-duration: $1s;">$2</span>');
        s = s.replace(/\$\[spin\.y ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-spinY">$1</span>');
        s = s.replace(/\$\[spin\.y,speed=(\d+|\d+\.\d+)s ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-spinY" style="animation-duration: $1s;">$2</span>');
        s = s.replace(/\$\[spin\.y,left ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-spinYL">$1</span>');
        s = s.replace(/\$\[spin\.y,left,speed=(\d+|\d+\.\d+)s ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-spinYL" style="animation-duration: $1s;">$2</span>');
        s = s.replace(/\$\[spin\.y,alterny?ate ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-spinYA">$1</span>');
        s = s.replace(/\$\[spin\.y,alterny?ate,speed=(\d+|\d+\.\d+)s ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-spinYA" style="animation-duration: $1s;">$2</span>');

        //アニメーション(ぶるぶる)
        s = s.replace(/\$\[shake ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-shake">$1</span>');
        s = s.replace(/\$\[shake\.speed=(\d+|\d+\.\d+)s ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-shake" style="animation-duration: $1s;">$2</span>');

        //アニメーション(ブレ)
        s = s.replace(/\$\[twitch ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-twitch">$1</span>');
        s = s.replace(/\$\[twitch\.speed=(\d+|\d+\.\d+)s ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-twitch" style="animation-duration: $1s;">$2</span>');

        //レインボー装飾
        s = s.replace(/\$\[rainbow ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-rainbow">$1</span>');
        s = s.replace(/\$\[rainbow\.speed=(\d+|\d+\.\d+)s ([^\[\]]+?)\]/gs, '<span class="mfm-transform mfm-rainbow" style="animation-duration: $1s;">$2</span>');

        //キラキラ装飾
        s = s.replace(/\$\[sparkle ([^\[\]]+?)\]/gs, '<span class="mfm-sparkle">$1</span>');
    }

    //プレーン
    if (plain != null) {
        for (var j = 0; j < plain.length; j++) {
            var t = plain[j].match(/(?<=&lt;plain&gt;).+?(?=&lt;\/plain&gt;)/s);
            s = s.replace(`\x1bA[${j}]`, t);
        }
    }

    //画像、リンク、URL
    if (g != null) {
        for (var j = 0; j < g.length; j++) {
            var t = /\[(.+?)\]\((.+?)\)/.exec(g[j]);
            s = s.replace(`\x1bI[${j}]`, `<img src="${t[2]}" alt="${t[1]}">`);
        }
    }
    if (l != null) {
        for (var j = 0; j < l.length; j++) {
            var t = /\[(.+?)\]\((.+?)\)/.exec(l[j]);
            s = s.replace(`\x1bL[${j}]`, `<a href="${t[2]}">${t[1]}</a>`);
        }
    }
    if (u != null) {
        for (var j = 0; j < u.length; j++) {
            s = s.replace(`\x1bU[${j}]`, `<a href="${u[j]}">${u[j]}</a>`);
        }
    }

    //pre記法、code記法
    if (p != null) {
        for (var j = 0; j < p.length; j++) {
            var t = p[j].match(/(?<=```[^\n]*\n).+?(?=\n```)/s);
            s = s.replace(`\x1bP[${j}]`, `<pre>${t}</pre>`);
        }
    }
    if (c != null) {
        for (var j = 0; j < c.length; j++) {
            var t = c[j].match(/(?<=`).+?(?=`)/s);
            var col = "";
            if (/^(#[\dA-Fa-f]{3,8}|rgba?\([ %,.\w]+?\)|hsla?\([ %,.\w]+?\))$/.test(t)) {
                col = `<span class="code-color" style="background-color: ${t};"></span>`;
            }
            s = s.replace(`\x1bC[${j}]`, `<code>${t}${col}</code>`);
        }
    }

    //引用
    if (q != null) {
        for (var j = 0; j < q.length; j++) {
            var ql = q[j].split("\n");
            var qt = "";
            var n = -1;
            for (var k = 0; k < ql.length; k++) {
                var d = ql[k].indexOf("&gt; ") - n;
                if (d > 0) for (var m = 0; m < d / 4; m++) qt += "<blockquote>";
                if (d == 0) qt += "\n";
                if (d < 0) for (var m = 0; m < -d / 4; m++) qt += "</blockquote>";
                n = ql[k].indexOf("&gt; ");
                qt += `${ql[k].replace(/^(&gt;)+ /, "")}`;
            }
            for (var k = 0; k < n / 4 + 1; k++) qt += "</blockquote>";
            s = s.replace(`\x1bQ[${j}]`, qt);
        }
    }
    s = s.replace(/(?<=<\/blockquote>)\n/g, "");

    return s;
}

(() => {
    var style = document.createElement("style");
    style.textContent = css;
    document.head.appendChild(style);

    //ミュートフォームの 作成
    if (location.href.indexOf("comments.cgi") !== -1) {
        var d = document.createElement("div");
        d.innerHTML = `
<p>
    【ミュートについて】<br>
    見たくないコメントを非表示にするため、ミュート機能を作りました。<br>
    ミュートパターンを選択し、ミュートするワードを入力し、ミュートボタンを押してください。<br>
</p>
<p>
    【コメントにあるミュートボタンについて】<br>
    ミュートパターンが完全一致の場合、名前、本文をミュートします。<br>
    一部の場合、選択したテキストをミュートします。<br>
    正規表現の場合、ミュートするワードに選択したテキストコピーされるので、ミュートするパターンを入力したら、ミュートボタンを押してください。
</p>
<form name="muteform">
    <p>
        ミュートパターン
        <label><input type="radio" name="mutepat" value="name" checked>名前に完全一致</label>
        <label><input type="radio" name="mutepat" value="namepart">名前の一部</label>
        <label><input type="radio" name="mutepat" value="namereg">名前の正規表現</label>
        <label><input type="radio" name="mutepat" value="content">本文に完全一致</label>
        <label><input type="radio" name="mutepat" value="contentpart">本文の一部</label>
        <label><input type="radio" name="mutepat" value="contentreg">本文の正規表現</label>
    </p>
    <p>ミュートするワード<input type="text" name="muteword"><input type="button" value="ミュート" class="cs_button"></p>
</form>`;
        d.querySelector(".cs_button").onclick = () => {
            if (document.muteform.muteword.value == "") {
                alert("ミュートするワードを入力してください。");
                return;
            }
            var s = document.muteform.muteword.value.replace(/[\[\]\.\|\^\$\(\)\*\+\?\{\}\\]/g, "\\$&");
            switch (document.muteform.mutepat.value) {
                case "name":
                    addMute(0, `^${s}\$`);
                    break;
                case "namepart":
                    addMute(0, s);
                    break;
                case "namereg":
                    addMute(0, document.muteform.muteword.value);
                    break;
                case "content":
                    addMute(1, `^${s}\$`);
                    break;
                case "contentpart":
                    addMute(1, s);
                    break;
                case "contentreg":
                    addMute(1, document.muteform.muteword.value);
                    break;
            }
        };
        document.querySelector('input[name="delkey"]').after(d);

        //ミュートした ワード一覧の 作成
        makeMuteWordList();
    }

    //ミュートボタンの 作成
    var a = document.querySelectorAll(".cs_comment .cs_name");
    for (var i = 0; i < a.length; i++) {
        var b = document.createElement("input");
        b.type = "button";
        b.value = "ミュート";
        b.className = "cs_button";
        b.onclick = function() {
            if (!this.parentNode.classList.contains("mute")) {
                //ミュート
                switch (document.muteform.mutepat.value) {
                    case "name":
                        addMute(0, `^${this.parentNode.querySelector(".cs_name").textContent.replace(/[\[\]\.\|\^\$\(\)\*\+\?\{\}\\]/g, "\\$&")}\$`);
                        break;
                    case "content":
                        addMute(1, `^${this.parentNode.querySelector(".cs_contents").textContent.replace(/[\[\]\.\|\^\$\(\)\*\+\?\{\}\\]/g, "\\$&")}\$`);
                        break;
                    case "namepart":
                        var s = String(document.getSelection()).replace(/[\[\]\.\|\^\$\(\)\*\+\?\{\}\\]/g, "\\$&");
                        if (s != "") {
                            addMute(0, s);
                        }
                        else {
                            alert("ミュートするワードを選択してください。");
                        }
                        break;
                    case "contentpart":
                        var s = String(document.getSelection()).replace(/[\[\]\.\|\^\$\(\)\*\+\?\{\}\\]/g, "\\$&");
                        if (s != "") {
                            addMute(1, s);
                        }
                        else {
                            alert("ミュートするワードを選択してください。");
                        }
                        break;
                    case "namereg":
                    case "contentreg":
                        var s = String(document.getSelection()).replace(/[\[\]\.\|\^\$\(\)\*\+\?\{\}\\]/g, "\\$&");
                        console.log("aaa");
                        console.log(s);
                        if (s != "") {
                            document.muteform.muteword.value = s;
                            document.muteform.muteword.focus();
                        }
                        else {
                            alert("ミュートするワードを選択してください。");
                        }
                        break;
                }
            }
            else {
                //ミュート解除
                var comment = this.parentNode;
                removeMute(Number(comment.getAttribute("data-mutetype")), comment.getAttribute("data-muteword"));
            }
        };
        a[i].nextElementSibling.after(b);
        b.after(document.createTextNode("\n"));
    }

    //ミュート
    muteProcess();

    //バックスラッシュ、特殊文字、リンク
    a = document.getElementsByClassName("cs_contents");
    for (var i = 0; i < a.length; i++) {
        a[i].innerHTML = convertSpecial(a[i].innerHTML);
    }
    if (location.href.indexOf("comment_post.cgi") !== -1) {
        a = document.querySelector("tr:nth-child(5) td:nth-child(2)");
        a.classList.add("cs_contents");
        a.innerHTML = convertSpecial(a.innerHTML);
    }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址