コピペレス検出用ブックマークレット20251223
■ なにこれ
配信スレでどのくらい既存レスのコピペがあるのか可視化したくて生成AIが作った
検出漏れや誤検出があるけど面倒なので未修正改良できるならして
完全一致コピペレスを赤色で強調表示する
部分一致コピペレスをオレンジで強調表示する
ログでも動く
引用なんて滅多にないし読み上げなくていいと思う
ツールのプラグインに流用して検出したレスを読み上げないようにもできたけどツール側のウィンドウで強調表示のルールを再現できなかったので詳しい人に任せる
■ 引用も対象バージョン(配信スレ向け)
javascript:(()=>{if(window.__cpRunning)return;window.__cpRunning=1;const mk=p=>{const t=document.querySelector(".thre");if(!t)return;const b=document.createElement("div");b.textContent="🔍 コピペ監視中";Object.assign(b.style,{position:"absolute",padding:"4px 8px",fontSize:"12px",background:"rgba(0,0,0,0.7)",color:"#fff",borderRadius:"6px",zIndex:9999,pointerEvents:"none",...(p=="tr"?{top:"6px",right:"6px"}:{bottom:"6px",left:"6px"})});t.style.position="relative";t.appendChild(b)};mk("tr");mk("bl");const seen={};const IGN=/^キタ━━━━━━\(゚∀゚\)━━━━━━\s*!!!!!$/;const norm=s=>s.replace(/<[^>]+>/g,"").replace(/\s+/g," ").trim();const getLines=r=>{const b=r.querySelector("blockquote");if(!b)return[];return b.innerHTML.split(/
/i).map(norm).filter(t=>t&&!IGN.test(t))};const mark=(r,t)=>{r.style.background=t=="full"?"rgba(255,0,0,0.2)":"rgba(255,165,0,0.25)";r.style.border=t=="full"?"2px solid red":"2px solid orange"};const proc=r=>{if(r.dataset.cp)return;r.dataset.cp=1;const lines=getLines(r);let full=false,part=false;lines.forEach(l=>{if(seen[l])full=true});if(!full){lines.forEach(l=>{if(l.length>=10){for(const k in seen)if(k.length>=10&&l.includes(k)){part=true;break}}})}if(full)mark(r,"full");else if(part)mark(r,"part");lines.forEach(l=>{if(l.length>=10)seen[l]=1})};document.querySelectorAll(".rtd").forEach(proc);const t=document.querySelector(".thre");t&&new MutationObserver(m=>{m.forEach(x=>x.addedNodes.forEach(n=>{if(n.nodeType==1){n.matches?.(".rtd")&&proc(n);n.querySelectorAll?.(".rtd").forEach(proc)}}))}).observe(t,{childList:true,subtree:true});console.log("copipe watcher started")})();
■ 引用無視バージョン(一応通常スレにもいたので)
javascript:(()=>{if(window.__cpRunning)return;window.__cpRunning=1;const mk=p=>{const t=document.querySelector(".thre");if(!t)return;const b=document.createElement("div");b.textContent="🔍 コピペ監視中";Object.assign(b.style,{position:"absolute",padding:"4px 8px",fontSize:"12px",background:"rgba(0,0,0,0.7)",color:"#fff",borderRadius:"6px",zIndex:9999,pointerEvents:"none",...(p=="tr"?{top:"6px",right:"6px"}:{bottom:"6px",left:"6px"})});t.style.position="relative";t.appendChild(b)};mk("tr");mk("bl");const seen={};const IGN=/^(キタ━━━━━━\(゚∀゚\)━━━━━━\s*!!!!!|スレッドを立てた人によって削除されました|削除依頼によって隔離されました)$/;const isQuote=t=>/^\s*(?:>|>|>)+/.test(t);const norm=s=>s.replace(/<[^>]+>/g,"").replace(/>/g,">").replace(/\s+/g," ").trim();const getLines=r=>{const b=r.querySelector("blockquote");if(!b)return[];return b.innerHTML.split(/
/i).map(norm).filter(t=>t&&!isQuote(t)&&!IGN.test(t))};const mark=(r,t)=>{r.style.background=t=="full"?"rgba(255,0,0,0.2)":"rgba(255,165,0,0.25)";r.style.border=t=="full"?"2px solid red":"2px solid orange"};const proc=r=>{if(r.dataset.cp)return;r.dataset.cp=1;const lines=getLines(r);let full=false,part=false;lines.forEach(l=>{if(seen[l])full=true});if(!full){lines.forEach(l=>{if(l.length>=10){for(const k in seen)if(k.length>=10&&l.includes(k)){part=true;break}}})}if(full)mark(r,"full");else if(part)mark(r,"part");lines.forEach(l=>{if(l.length>=10)seen[l]=1})};document.querySelectorAll(".rtd").forEach(proc);const t=document.querySelector(".thre");t&&new MutationObserver(m=>{m.forEach(x=>x.addedNodes.forEach(n=>{if(n.nodeType==1){n.matches?.(".rtd")&&proc(n);n.querySelectorAll?.(".rtd").forEach(proc)}}))}).observe(t,{childList:true,subtree:true});console.log("copipe watcher started (strict no-quote)")})();
■ 使い方
適当なブックマークを編集→URLに「javascript:」から行末までの1行をコピペして保存→スレを表示した状態でブックマークアイコンをクリック
PC用ブラウザ推奨
最近のモバイル用ブラウザでは動かない可能性が高い
以下引用も対象バージョン(配信スレ向け)の仕様(AIが書いた)
■ 対象範囲
各レス要素(.rtd)を対象とする
初回読み込み時および追加読み込みされたレスの両方に適用する(常駐監視)
■ 行の取得・正規化
各レスの
内を対象とする
区切りで行単位に分割する HTMLタグはすべて除去する 連続する空白は1つに正規化する 行頭・行末の空白を除去する ■ 対象外とする行(完全除外) 空行 以下の固定文言に完全一致する行 スレッドを立てた人によって削除されました 削除依頼によって隔離されました キタ━━━━━━(゚∀゚)━━━━━━ !!!!! ■ 判定に使う行の条件 10文字以上の行のみを判定対象とする 10文字未満の行は 完全一致判定に使わない 部分一致判定にも使わない 履歴(seen)にも登録しない ■ 完全一致判定(赤強調) 過去に出現した行と完全一致する行が 同一レス内に1行でも含まれていれば そのレス全体を「完全一致」と判定する 完全一致が成立したレスは赤色で強調表示する ■ 部分一致判定(オレンジ強調) 完全一致が成立していないレスのみを対象とする 以下の条件をすべて満たす場合に部分一致と判定する 現在の行の文字数が10文字以上 過去に出現した別の行(10文字以上)が存在する その過去行が現在の行に文字列として完全に含まれている 部分一致が成立したレスはオレンジ色で強調表示する ■ 判定の優先順位 完全一致(赤)を最優先とする 完全一致がある場合に部分一致判定は行わない ■ 行の記録(seen管理) 判定終了後に10文字以上の行のみを履歴として保存する 保存は正規化後の文字列をキーとして行う ■ レス単位の挙動 1レス内に複数行が存在する場合でも 1行でも条件を満たせばレス全体を強調表示する 1度処理したレスは再処理しない ■ 見た目の挙動 強調はレス全体(.rtd)に適用する 完全一致:背景 赤(薄)+赤枠 部分一致:背景 オレンジ(薄)+オレンジ枠 ■ 非要件(やらないこと) > 行の判定除外(配信スレで使われることはほぼないためこの版では不要) 時間制限(30秒・60秒ルール等)は設けない 自動del送信は行わない