superopenj @ ウィキ
スクリプト
最終更新:
superopenj
-
view
管理者のみ編集可
スクリプト(仮)
拾ったやつとかGreasyforkで公開されてるスクリプトのまとめ
作者:onjmin
| + | Open2ch アラビア文字規制避け |
// ==UserScript==
// @name Open2ch アラビア文字規制避け
// @namespace https://onjmin.glitch.me/
// @version 1.0.0
// @description アラビア文字を入力したときピンクで警告
// @author おんJ民
// @match *://*.open2ch.net/*/*
// @icon https://avatars.githubusercontent.com/u/88383494
// @grant none
// @license GNU Affero General Public License v3.0 or later
// ==/UserScript==
(function() {
'use strict';
const ngList = [
8239,
65279
];
window.document.addEventListener('paste', (e) => {
if (e.target.tagName !== 'TEXTAREA') return;
const pasteData = (e.clipboardData || window.clipboardData).getData('text');
for (const ng of ngList) {
if (pasteData.includes(String.fromCharCode(ng))) {
e.target.style.backgroundColor = 'pink';
[...document.querySelectorAll('[type="submit"]')].forEach(e => {
e.disabled = true;
});
}
}
});
})();
|
| + | Open2ch Imgur一括削除 |
// ==UserScript==
// @name Open2ch Imgur一括削除
// @namespace https://onjmin.glitch.me/
// @version 1.0.0
// @description ポチポチせず削除できる
// @author おんJ民
// @match https://hayabusa.open2ch.net/setting/imgur_history.cgi
// @icon https://avatars.githubusercontent.com/u/88383494
// @grant GM.registerMenuCommand
// @grant GM.getValue
// @grant GM.setValue
// @license GNU Affero General Public License v3.0 or later
// ==/UserScript==
(function() {
'use strict';
const key = "clientId";
GM.registerMenuCommand('Imgur APIのClient-ID登録', async () => {
const clientId = await GM.getValue(key);
const v = prompt(`Imgur APIのClient-ID入力(現在値:${clientId})`);
if (v) GM.setValue(key, v);
});
// [[deletehash, imgurID]...]
const extractDeleteList = () => [...document.querySelectorAll("a")].map(v=>v.href).flatMap(v=>v.match(/imgur_delete.+:.+:/)?.[0] ?? []).map(v => v.slice(0,-1).split(/\=|:/).slice(-2));
const onClick = async () => {
const list = extractDeleteList();
if (!list.length) {
alert('削除対象が見つかりませんでした');
return;
}
if (!confirm(`${list.length} 件を本当に削除しますか?`)) return;
const clientId = await GM.getValue(key);
if (!clientId) return alert("Imgur APIのClient-ID登録を済ませてください");
for (const [deletehash, imgurID] of list) {
try {
const res = await fetch(`https://api.imgur.com/3/image/${deletehash}`, {
method: 'DELETE',
headers: {
'Authorization': `Client-ID ${clientId}`
}
});
const json = await res.json();
json.success
? console.log(`Deleted: ${imgurID}`)
: console.warn(`Failed: ${imgurID}`, json);
} catch (err) {
console.error(`Error deleting ${imgurID}:`, err);
}
}
alert('削除処理が完了しました(詳細はコンソールを確認)');
};
const button = Object.assign(document.createElement('button'), {
textContent: 'Imgur Bulk Delete',
style: `
position: fixed;
bottom: 20px;
right: 20px;
z-index: 9999;
padding: 10px 15px;
background-color: #d9534f;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
`
});
button.addEventListener('click', onClick);
document.body.appendChild(button);
})();
|
| + | Open2ch 強制コテ化スクリプト |
// ==UserScript==
// @name Open2ch 強制コテ化スクリプト
// @namespace https://onjmin.glitch.me/
// @version 1.0.1
// @description IDをもとにアイコンを自動生成
// @author おんJ民
// @match *://*.open2ch.net/*/*
// @icon https://avatars.githubusercontent.com/u/88383494
// @grant none
// @license GNU Affero General Public License v3.0 or later
// ==/UserScript==
(async ()=> {
'use strict';
const currentKey = 'robohash';
// const currentKey = 'dicebear/big-smile';
const avatarModes = [
{
key: "robohash",
url: (hash) => `https://robohash.org/${hash}.png`,
flip: true,
},
{
key: "dicebear",
url: (hash) =>
`https://api.dicebear.com/8.x/adventurer/svg?seed=${hash}`,
flip: true,
},
{
key: "gravatar",
url: (hash) => `https://www.gravatar.com/avatar/${hash}?d=identicon`,
flip: false,
},
];
const dicebearList = [
"adventurer", // 冒険者風キャラ(RPGっぽい)
"avataaars", // Avataaarsベースのカートゥーン
"big-ears", // 大きな耳が特徴のスタイル
"big-smile", // 巨大スマイル系アバター
"bottts", // ボット風ロボットアバター
"croodles", // ラフな手描きキャラ
"identicon", // GitHub風識別子
"initials", // 名前のイニシャルを表示
"lorelei", // 魔法使いや精霊風の人物像
"miniavs", // シンプルなミニアバター
"notionists", // Notion風人物
"open-peeps", // カジュアルな人物画(肩まで)
"personas", // ややリアル寄りの人物
"pixel-art", // ドット絵スタイル
];
const dicebear = avatarModes.find(({key}) => key === "dicebear");
for (const v of dicebearList) {
avatarModes.push({
...dicebear,
key: `dicebear/${v}`,
url: (hash) => `https://api.dicebear.com/8.x/${v}/svg?seed=${hash}`,
flip: v.includes('adventurer')
});
}
// ✅ アバター要素生成
const createAvatar = (url, flip) => {
const isSVG = url.endsWith(".svg");
const img = document.createElement("img");
Object.assign(img, {
src: url,
width: 45,
height: 45,
});
Object.assign(img.style, {
padding: "3px",
background: isSVG ? "transparent" : "rgb(238, 238, 255)",
marginRight: "3px",
borderRadius: "45px",
display: "block",
transform: flip ? "scaleX(-1)" : "",
});
img.setAttribute("iconimg", "1");
img.setAttribute("align", "left");
img.classList.add("pic", "lazy", "imgur");
const a = document.createElement("a");
a.href = url;
a.target = "_blank";
a.setAttribute("data-lightbox", "i");
a.appendChild(img);
return a;
};
const extractID = (dt) => {
const span = dt.querySelector("span._id");
if (span?.getAttribute("val")) return span.getAttribute("val");
const match = [...dt.classList].find((cls) => cls.startsWith("id"));
return match?.slice(2).trim();
};
const sha256 = async text =>
Array.from(new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(text))))
.map(b => b.toString(16).padStart(2, "0"))
.join("");
const processPosts = async (nodes) => {
for (const node of nodes) {
if (!(node instanceof HTMLElement)) continue;
const dts = node.querySelectorAll?.("dt[class*='id']") ?? [];
for (const dt of dts) {
const id = extractID(dt);
if (!id) continue;
const dd = dt.nextElementSibling;
if (!dd?.matches("dd")) continue;
// 削除既存アバター
dd.querySelectorAll('img[iconimg="1"]').forEach((img) => {
const a = img.closest("a");
a && a.parentElement === dd ? a.remove() : img.remove();
});
const mode = avatarModes.find((m) => m.key === currentKey);
if (!mode) return;
let hash = '';
if (/[^0-9a-zA-Z]/.test(id)) {
const str = id.replace(/[^0-9a-zA-Z]/g, '');
if (str.length) {
hash = str;
} else {
hash = (await sha256(str)).slice(32);
}
} else {
hash = id;
}
const avatarURL = mode.url(hash);
const avatar = createAvatar(avatarURL, mode.flip);
const icon = dd.querySelector("icon");
icon
? dd.insertBefore(avatar, icon)
: dd.insertBefore(avatar, dd.firstChild);
}
}
};
const thread = document.querySelector(".thread");
if (thread) {
// 初回に既存要素も処理
await processPosts(thread.children);
// 監視設定
const observer = new MutationObserver((mutations) => {
const added = mutations.flatMap((m) => [...m.addedNodes]);
processPosts(added);
});
observer.observe(thread, { childList: true, subtree: true });
}
})();
|
作者:K9Y_onj
| + | Open2chの返信音を変える |
// ==UserScript==
// @name Open2chの返信音を変える
// @namespace http://tampermonkey.net/
// @version 1.4
// @description hayabusaの方
// @author icchi
// @match https://hayabusa.open2ch.net/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
const targetURLs = {
'https://image.open2ch.net/lib/sound/sound.mp3':
'https://raw.githubusercontent.com/Bongocat27/onj-sound-rawlink/main/%E3%83%9A%E3%82%BF%E3%83%83.mp3',
'https://image.open2ch.net/lib/sound/drum-japanese2.mp3':
'https://raw.githubusercontent.com/Bongocat27/onj-sound-rawlink/main/%E3%83%8B%E3%83%A5%E3%833.mp3'
};
const originalAudio = window.Audio;
window.Audio = function(src) {
for (const [target, custom] of Object.entries(targetURLs)) {
if (src && src.includes(target)) {
console.log(`[Tampermonkey] 音源を置き換え: ${src} → ${custom}`);
return new originalAudio(custom);
}
}
return new originalAudio(src);
};
const originalPlay = HTMLAudioElement.prototype.play;
HTMLAudioElement.prototype.play = function() {
for (const [target, custom] of Object.entries(targetURLs)) {
if (this.src.includes(target)) {
console.log(`[Tampermonkey] 音源を置き換え: ${this.src} → ${custom}`);
this.src = custom;
}
}
return originalPlay.call(this);
};
})();
|
| + | うんはらバスター |
// ==UserScript==
// @name うんはらバスター
// @namespace http://tampermonkey.net/
// @version 1.2
// @description おんjで画像を表示するか逐一確認!
// @author icchi
// @match *://hayabusa.open2ch.net/test/read.cgi/livejupiter/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
function checkImages() {
document.querySelectorAll('img').forEach(img => {
if (img.src.includes("imgur.com") && !img.dataset.checked) { // imgur画像で未処理のもの
img.dataset.checked = "true"; // 重複処理防止
img.style.display = "none"; // 画像を非表示
let btn = document.createElement("button");
btn.textContent = "画像を表示する";
btn.style.margin = "5px";
btn.onclick = function() {
img.style.display = "block"; // 画像を表示
btn.remove(); // ボタン削除
};
img.insertAdjacentElement("beforebegin", btn);
}
});
}
// 初回実行
checkImages();
// ページの変更を監視(新しく読み込まれた画像にも対応)
let observer = new MutationObserver(checkImages);
observer.observe(document.body, { childList: true, subtree: true });
})();
|
| + | うんはらバスターV2 |
// ==UserScript==
// @name うんはらバスターV2
// @namespace http://tampermonkey.net/
// @version 1.3
// @description おんjで画像を表示するか逐一確認!
// @author icchi
// @match *://hayabusa.open2ch.net/test/read.cgi/livejupiter/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
function checkImages(targetNode = document) {
targetNode.querySelectorAll('img.imgur, img[src*="imgur.com"]').forEach(img => {
if (!img.dataset.checked) { // 未処理の画像のみ対象
img.dataset.checked = "true"; // 処理済みマーク
// 画像を非表示
img.style.display = "none";
// 親の <a> タグを探してリンクを無効化
let parentLink = img.closest('a');
if (parentLink) {
parentLink.dataset.originalHref = parentLink.href; // 元のリンクを保存
parentLink.removeAttribute("href"); // 無効化
}
// ボタン作成
let btn = document.createElement("button");
btn.textContent = "画像を表示する";
btn.style.margin = "5px";
btn.onclick = function(event) {
event.preventDefault(); // サイト遷移防止
img.style.display = "block"; // 画像表示
btn.remove(); // ボタン削除
// 親の <a> タグのリンクを復元
if (parentLink && parentLink.dataset.originalHref) {
parentLink.href = parentLink.dataset.originalHref;
}
};
// ボタンを画像の前に挿入
img.insertAdjacentElement("beforebegin", btn);
}
});
}
function resetImages() {
document.querySelectorAll('img.imgur[data-checked], img[src*="imgur.com"][data-checked]').forEach(img => {
img.removeAttribute("data-checked"); // 処理リセット
});
}
// 初回実行
checkImages();
// ページの変更を監視(新しく読み込まれた画像にも対応)
let observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1) {
if (node.tagName === "IMG" && node.src.includes("imgur.com")) {
checkImages(node.parentNode); // 追加されたimgur画像を処理
} else if (node.querySelectorAll) {
checkImages(node); // 追加された要素内の画像を処理
}
}
});
});
});
observer.observe(document.body, { childList: true, subtree: true });
// 「前のレスを取得」ボタンが押されたら、新しく追加された要素を処理
document.body.addEventListener("click", (event) => {
if (event.target.closest(".prev_bt")) {
setTimeout(() => checkImages(), 1000); // レス取得後に適用
}
});
// 履歴操作を監視してスレ移動時にも対応
window.addEventListener('popstate', () => {
resetImages();
setTimeout(() => checkImages(), 500);
});
// pushState / replaceState を監視するためのフック
let originalPushState = history.pushState;
let originalReplaceState = history.replaceState;
function hookHistoryMethod(original) {
return function() {
let result = original.apply(this, arguments);
resetImages();
setTimeout(() => checkImages(), 500);
return result;
};
}
history.pushState = hookHistoryMethod(originalPushState);
history.replaceState = hookHistoryMethod(originalReplaceState);
})();
|
| + | うんはらバスターV2(モザイクON/OFF専用) |
// ==UserScript==
// @name うんはらバスターV2(モザイクON/OFF専用)
// @namespace http://tampermonkey.net/
// @version 1.5
// @description おんjで画像にモザイクをかけたり外したり!クリックで拡大されないように修正
// @author icchi
// @match *://hayabusa.open2ch.net/test/read.cgi/livejupiter/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
function checkImages(targetNode = document) {
targetNode.querySelectorAll('img.imgur, img[src*="imgur.com"]').forEach(img => {
if (!img.dataset.checked) { // 未処理の画像のみ対象
img.dataset.checked = "true"; // 処理済みマーク
// 初期状態ではモザイクをかける
img.style.filter = "blur(10px)";
img.style.transition = "filter 0.3s ease";
// モザイク切り替えボタン作成
let btn = document.createElement("button");
btn.textContent = "モザイク切り替え";
btn.style.margin = "5px";
btn.onclick = function(event) {
event.preventDefault(); // サイト遷移防止
if (img.style.filter === "none") {
img.style.filter = "blur(10px)"; // モザイクON
} else {
img.style.filter = "none"; // モザイクOFF
}
};
// ボタンを画像の前に挿入
img.insertAdjacentElement("beforebegin", btn);
// 拡大防止:画像がクリックされた際にリンクを無効化
let parentLink = img.closest('a');
if (parentLink) {
parentLink.addEventListener('click', function(event) {
event.preventDefault(); // 画像クリックで拡大しないようにする
});
}
}
});
}
function resetImages() {
document.querySelectorAll('img.imgur[data-checked], img[src*="imgur.com"][data-checked]').forEach(img => {
img.removeAttribute("data-checked"); // 処理リセット
});
}
// 初回実行
checkImages();
// ページの変更を監視(新しく読み込まれた画像にも対応)
let observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1) {
if (node.tagName === "IMG" && node.src.includes("imgur.com")) {
checkImages(node.parentNode); // 追加されたimgur画像を処理
} else if (node.querySelectorAll) {
checkImages(node); // 追加された要素内の画像を処理
}
}
});
});
});
observer.observe(document.body, { childList: true, subtree: true });
// 「前のレスを取得」ボタンが押されたら、新しく追加された要素を処理
document.body.addEventListener("click", (event) => {
if (event.target.closest(".prev_bt")) {
setTimeout(() => checkImages(), 1000); // レス取得後に適用
}
});
// 履歴操作を監視してスレ移動時にも対応
window.addEventListener('popstate', () => {
resetImages();
setTimeout(() => checkImages(), 500);
});
// pushState / replaceState を監視するためのフック
let originalPushState = history.pushState;
let originalReplaceState = history.replaceState;
function hookHistoryMethod(original) {
return function() {
let result = original.apply(this, arguments);
resetImages();
setTimeout(() => checkImages(), 500);
return result;
};
}
history.pushState = hookHistoryMethod(originalPushState);
history.replaceState = hookHistoryMethod(originalReplaceState);
})();
|
| + | うんはらバスターZ(モザイク版) |
// ==UserScript==
// @name うんはらバスターZ(モザイク版)
// @namespace うんはらバスターZ (モザイク版)
// @version 1.0
// @description おんjで画像にモザイクをかけ、解除ボタンを表示!スレ移動でもモザイクが適用されるように改善!
// @author Wai
// @match *://hayabusa.open2ch.net/test/read.cgi/livejupiter/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// 画像にモザイクをかける関数
function applyMosaic(img) {
img.style.filter = "blur(10px)"; // モザイク効果
}
// モザイクを解除する関数
function removeMosaic(img) {
img.style.filter = "none"; // モザイク解除
}
// 画像の拡張子を取得する関数
function getFileExtension(url) {
const match = url.match(/\.([0-9a-z]+)(?=[?#])|(\.[0-9a-z]+)$/i);
return match ? match[1] || match[2].substring(1) : null;
}
// 新しい画像をチェックしてモザイクを適用する関数
function checkImages(targetNode = document) {
targetNode.querySelectorAll('img').forEach(img => {
if (img.src.includes("imgur.com") && !img.dataset.checked) { // imgur画像で未処理のもの
img.dataset.checked = "true"; // 重複処理防止
applyMosaic(img); // 画像にモザイクをかける
// 画像クリックで遷移を防ぐ
img.addEventListener('click', function(event) {
event.preventDefault();
});
// モザイク解除ボタンを作成
let btn = document.createElement("button");
btn.textContent = "モザイク解除";
btn.style.margin = "5px";
btn.style.fontSize = "1.2em"; // ボタンの文字サイズを大きくする
btn.style.padding = "5px 10px"; // ボタンのパディングを追加
btn.onclick = function(event) {
event.preventDefault(); // ボタンの遷移を防止
removeMosaic(img); // モザイク解除
btn.remove(); // ボタン削除
// モザイクボタンを再度追加
let mosaicBtn = document.createElement("button");
mosaicBtn.textContent = "モザイク";
mosaicBtn.style.margin = "5px";
mosaicBtn.style.fontSize = "1.2em"; // ボタンの文字サイズを大きくする
mosaicBtn.style.padding = "5px 10px"; // ボタンのパディングを追加
mosaicBtn.onclick = function(event) {
event.preventDefault(); // ボタンの遷移を防止
applyMosaic(img); // モザイクをかける
mosaicBtn.remove(); // ボタン削除
img.insertAdjacentElement("beforebegin", btn); // モザイク解除ボタンを再度追加
};
img.insertAdjacentElement("beforebegin", mosaicBtn);
};
img.insertAdjacentElement("beforebegin", btn);
// 拡張子を表示
const ext = getFileExtension(img.src);
const extDisplay = document.createElement("span"); // spanに変更
extDisplay.style.color = "red";
extDisplay.style.fontSize = "1.2em"; // 拡張子表示を大きくする
extDisplay.style.marginLeft = "5px"; // ボタンとの間隔を調整
extDisplay.textContent = ext ? (ext.toUpperCase() === "GIF" ? "⚠️GIF" : ext) : "拡張子不明";
img.insertAdjacentElement("afterend", extDisplay); // 拡張子を画像の後に表示
// 画像URLを青文字で表示
const urlDisplay = document.createElement("div");
urlDisplay.style.color = "blue";
urlDisplay.style.wordWrap = "break-word"; // 長いURLを折り返す
urlDisplay.textContent = img.src;
img.insertAdjacentElement("afterend", urlDisplay);
}
});
}
// 初回実行
checkImages();
// 常にページを監視して、新たに追加された画像にモザイクを適用
let observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1) { // ノードが要素ノードであるか確認
if (node.tagName === "IMG") {
checkImages(node); // 新しく追加された画像をチェック
} else if (node.querySelectorAll) {
checkImages(node); // 新しく追加されたコンテンツ内に画像が含まれていればチェック
}
}
});
});
});
// 全体のDOMを監視
observer.observe(document.body, { childList: true, subtree: true });
// 履歴操作を監視してスレ移動時にも対応
window.addEventListener('popstate', () => {
checkImages(); // スレ移動後に再チェック
});
// pushState / replaceState を監視してスレ移動時にも対応
let originalPushState = history.pushState;
let originalReplaceState = history.replaceState;
function hookHistoryMethod(original) {
return function() {
let result = original.apply(this, arguments);
checkImages(); // スレ移動後に再チェック
return result;
};
}
history.pushState = hookHistoryMethod(originalPushState);
history.replaceState = hookHistoryMethod(originalReplaceState);
})();
|
| + | ×印押す押すくん |
// ==UserScript==
// @name ×印押す押すくん
// @namespace http://tampermonkey.net/
// @version 1.2
// @description ×ボタンを押しやすく
// @author icchi
// @match *://hayabusa.open2ch.net/test/read.cgi/livejupiter/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// ×ボタンを大きくするためのCSSスタイルを追加
const style = document.createElement('style');
style.innerHTML = `
.ignore {
font-size: 20px !important; /* アイコンを大きく */
padding: 0px !important; /* ボタンの余白を広げる */
display: inline-block !important; /* インラインで表示 */
text-align: center !important; /* 中央寄せ */
}
.ignore i {
font-size: inherit !important; /* アイコンもボタンのサイズに合わせる */
}
`;
document.head.appendChild(style);
})();
|
| + | Open2ch 滞在時間カウンター |
// ==UserScript==
// @name Open2ch 滞在時間カウンター
// @namespace http://tampermonkey.net/
// @version 1.0
// @description open2ch livejupiter 板での累計滞在時間を計測
// @match https://hayabusa.open2ch.net/test/read.cgi/livejupiter/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
const KEY = "open2ch_livejupiter_time";
let startTime = Date.now();
let totalTime = parseInt(localStorage.getItem(KEY) || "0", 10);
window.addEventListener("beforeunload", () => {
let now = Date.now();
let elapsed = Math.floor((now - startTime) / 1000); // 秒
totalTime += elapsed;
localStorage.setItem(KEY, totalTime.toString());
});
let counter = document.createElement("div");
counter.style.position = "fixed";
counter.style.bottom = "10px";
counter.style.right = "10px";
counter.style.padding = "5px 10px";
counter.style.background = "rgba(0,0,0,0.7)";
counter.style.color = "white";
counter.style.fontSize = "14px";
counter.style.zIndex = 9999;
document.body.appendChild(counter);
function updateDisplay() {
let now = Date.now();
let elapsed = Math.floor((now - startTime) / 1000);
let displayTime = totalTime + elapsed;
let h = Math.floor(displayTime / 3600);
let m = Math.floor((displayTime % 3600) / 60);
let s = displayTime % 60;
counter.textContent = `お前が無駄にした時間→: ${h}時間${m}分${s}秒`;
}
setInterval(updateDisplay, 1000);
})();
|
| + | おんjらくちん安価 |
// ==UserScript==
// @name おんjらくちん安価
// @namespace K9Y_onj
// @version 1.1
// @description Detect Ctrl + numbers (up to 3 digits) and insert formatted text
// @match https://hayabusa.open2ch.net/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
let buffer = "";
let timeout = null;
const WAIT_TIME = 200;
window.addEventListener('keydown', (e) => {
if (e.ctrlKey && /^[0-9]$/.test(e.key)) {
e.preventDefault();
buffer += e.key;
if (buffer.length > 3) buffer = buffer.slice(-3);
clearTimeout(timeout);
timeout = setTimeout(() => {
insertText(`>>${buffer}\n`);
buffer = "";
}, WAIT_TIME);
}
});
function insertText(text) {
const el = document.activeElement;
if (el && (el.tagName === "TEXTAREA" || (el.tagName === "INPUT" && el.type === "text" || el.isContentEditable))) {
const start = el.selectionStart;
const end = el.selectionEnd;
const value = el.value;
el.value = value.slice(0, start) + text + value.slice(end);
el.selectionStart = el.selectionEnd = start + text.length;
el.dispatchEvent(new Event("input", { bubbles: true }));
}
}
})();
|
作者:wakawakatnt
| + | おんJ広告削除 |
// ==UserScript==
// @name おんJ広告削除
// @namespace https://open2ch.net/
// @version 2.2
// @description おんJの広告を自動で削除しやす
// @license CC0-1.0
// @match *://*.open2ch.net/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
const removeAds = () => {
const targets = [
'.kokoku',
'#adspotdiv.adspot_img',
'iframe[src*="test/ad.cgi"]',
'iframe[src*="i-mobile.co.jp"]'
];
targets.forEach(sel => {
document.querySelectorAll(sel).forEach(el => {
el.remove();
});
});
document.querySelectorAll('script').forEach(script => {
const txt = script.textContent || '';
if (/i-mobile\.co\.jp|InformationIcon/.test(txt)) {
script.remove();
}
});
document.querySelectorAll('div#adspotdiv.adspot_img').forEach(el => el.remove());
};
removeAds();
const observer = new MutationObserver(removeAds);
observer.observe(document.body, { childList: true, subtree: true });
setInterval(removeAds, 5000);
})();
// さとる万歳
// こっそり使えよ
// さとるに献金もしろよ
// 分かったか?
// 40からの文消してええで
|
| + | 虹色解除 |
// ==UserScript==
// @name 虹色解除
// @namespace http://tampermonkey.net/
// @version 1.2
// @description 虹色無効化
// @author ワイ
// @match https://*.open2ch.net/test/read.cgi/*
// @license CC0-1.0
// @run-at document-start
// @grant none
// ==/UserScript==
(function() {
'use strict';
const style = document.createElement('style');
style.textContent = `
h1.rainbow_css {
background: none !important;
-webkit-background-clip: unset !important;
-webkit-text-fill-color: red !important;
animation: none !important;
}
`;
document.head.appendChild(style);
})();
|
| + | おーぷん2ch 軽量化 |
// ==UserScript==
// @name おーぷん2ch 軽量化
// @namespace http://tampermonkey.net/
// @version 4.0
// @license CC0-1.0
// @description 軽量化するぞい
// @match https://*.open2ch.net/test/read.cgi/*
// @require https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// @grant none
// ==/UserScript==
(function () {
'use strict';
$('head').append(`
<style>
.tuhobox,.headline_div,.headline_bar,.headlineMessage,
.headlineCommentSelected,.headline-search-bt,
.headlineStopBt,.headlineReplayBt,.headlineZoomBt,
.headlineSmallBt,#headline,#headline_frame,
.komediv,.kome,.kome_options,.radio,.paypay,
.kokoku,.copyright,.copyrights,
iframe[src*="ad"],iframe[src*="headline"],
.oekakiCanvas,.paintTools,.room,
.option_wrapper,.MODAL,.prev_box{display:none!important}
body{background:#eee;margin:8px;font-size:12pt}
.thread{max-width:780px;margin:auto}
dl{background:#fff;margin:8px 0;padding:12px;
border:1px solid #ddd;border-radius:4px}
dt{background:#f5f5f5;margin:-12px -12px 8px;
padding:6px;border-radius:4px 4px 0 0}
dd{line-height:1.8;word-break:break-word}
.name{color:#228811;font-weight:bold}
.id{color:#00e}
img{max-width:100%;height:auto;margin:8px 0;border-radius:3px}
.form_fix,.formset{
position:sticky;bottom:0;background:#e6e6e6;
border:1px solid #ccc;padding:10px;border-radius:4px
}
#MESSAGE{width:100%;min-height:80px;font-size:12pt}
#submit_button{width:100%;padding:10px;font-size:13pt}
</style>
`);
function purge() {
$('.komediv,.kome,#headline,.headline_div,.headline_bar').remove();
$('iframe').remove();
}
purge();
const observer = new MutationObserver(() => purge());
observer.observe(document.body, { childList: true, subtree: true });
})();
|
| + | 色々サムネイル表示 |
対応してる奴↓
i.imgur.com(mp4とかgifのみ それ以外はおんJのシステムを利用) ul.h3z.jp tadaup.jp i.ibb.co i.postimg.cc iili.io freeimage.host funakamome.com // ==UserScript==
// @name 色々サムネイル表示
// @namespace ワイ
// @version 5.2
// @license CC0-1.0
// @description 各種画像サイトのリンクをLightboxで表示。
// @match https://*.open2ch.net/*
// @grant GM_xmlhttpRequest
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// @grant GM_listValues
// ==/UserScript==
(function () {
'use strict';
let imageDatabase = new Map();
let imageCounter = 0;
let globalEscHandler = null;
// GIFの共通サイズ設定
const GIF_DISPLAY_SIZE = '300px';
function debugLog(message, data = null) {
console.log(`[Imgur GIF Debug] ${message}`, data || '');
}
class ThumbnailCache {
constructor() {
this.CACHE_DURATION = 10 * 24 * 60 * 60 * 1000; // 10日間(ミリ秒)
this.CACHE_PREFIX = 'thumb_cache_';
this.cleanupOldEntries();
}
cleanupOldEntries() {
try {
const keys = GM_listValues();
const now = Date.now();
keys.forEach(key => {
if (key.startsWith(this.CACHE_PREFIX)) {
try {
const data = JSON.parse(GM_getValue(key, '{}'));
if (!data.timestamp || (now - data.timestamp) > this.CACHE_DURATION) {
GM_deleteValue(key);
}
} catch (e) {
GM_deleteValue(key);
}
}
});
} catch (e) {
console.warn('Cache cleanup failed:', e);
}
}
generateKey(url) {
let hash = 0;
for (let i = 0; i < url.length; i++) {
const char = url.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash;
}
return this.CACHE_PREFIX + Math.abs(hash).toString(36);
}
get(url) {
try {
const key = this.generateKey(url);
const cached = GM_getValue(key, null);
if (!cached) return null;
const data = JSON.parse(cached);
if (!data.timestamp || (Date.now() - data.timestamp) > this.CACHE_DURATION) {
GM_deleteValue(key);
return null;
}
// base64データまたはURLを返す
return data.base64Data || data.imageUrl;
} catch (e) {
console.warn('Cache get failed:', e);
return null;
}
}
// 画像本体をbase64で保存
setWithBase64(url, base64Data) {
try {
if (/imgur/i.test(url)) return;
const key = this.generateKey(url);
const data = { base64Data: base64Data, timestamp: Date.now(), originalUrl: url };
GM_setValue(key, JSON.stringify(data));
} catch (e) {
console.warn('Cache set failed:', e);
}
}
set(url, imageUrl) {
try {
if (/imgur/i.test(url)) return;
const key = this.generateKey(url);
const data = { imageUrl: imageUrl, timestamp: Date.now(), originalUrl: url };
GM_setValue(key, JSON.stringify(data));
} catch (e) {
console.warn('Cache set failed:', e);
}
}
shouldCache(url) {
return /tadaup\.jp|ul\.h3z\.jp|ibb\.co|postimg\.cc|freeimage\.host|iili\.io|funakamome\.com/i.test(url) && !/imgur/i.test(url);
}
}
const thumbnailCache = new ThumbnailCache();
function closeLightbox(e) {
if (e) e.preventDefault();
const existingLightbox = document.getElementById('lightbox');
if (existingLightbox) existingLightbox.remove();
const existingOverlay = document.getElementById('lightboxOverlay');
if (existingOverlay) existingOverlay.remove();
if (globalEscHandler) {
document.removeEventListener('keydown', globalEscHandler);
globalEscHandler = null;
}
}
function generatePostLink(postNumber) {
const currentUrl = window.location.href;
const baseUrl = currentUrl.split('#')[0];
return `${baseUrl}#${postNumber}`;
}
function addCustomCSS() {
if (document.getElementById('custom-lb-styles')) return;
const style = document.createElement('style');
style.id = 'custom-lb-styles';
style.textContent = `
.lightboxOverlay { position: absolute; top: 0; left: 0; z-index: 99990; background-color: black; opacity: 0.85; display: none; }
#lightbox { position: absolute; left: 0; width: 100%; z-index: 99991; text-align: center; line-height: 0; font-family: "Lucida Grande", sans-serif; }
.gm-no-tooltip { position: relative; }
.gm-no-tooltip::before, .gm-no-tooltip::after { display: none !important; }
/* 画像表示時の白い枠を完全に消す */
.gm-media-embed-container,
.gm-media-embed-container.lp-card,
a.lp-card.gm-media-embed-container,
.gm-media-embed-container[class*="lp-"] {
background: transparent !important;
background-color: transparent !important;
border: none !important;
box-shadow: none !important;
padding: 0 !important;
margin: 0 !important;
outline: none !important;
}
/* 親要素urlタグのスタイルもリセット */
url:has(.gm-media-embed-container) {
background: transparent !important;
border: none !important;
box-shadow: none !important;
padding: 0 !important;
margin: 0 !important;
}
.gm-imgur-gif-container { display: inline-block; position: relative; }
.gm-imgur-gif-wrapper { position: relative; display: inline-block; }
.gm-thumbnail-button {
position: absolute;
bottom: 5px;
right: 5px;
width: 24px;
height: 24px;
background: rgba(0, 0, 0, 0.7);
color: white;
border: none;
border-radius: 4px;
font-size: 16px;
cursor: pointer;
transition: opacity 0.2s;
padding: 0;
line-height: 1;
z-index: 10;
}
.gm-thumbnail-button:hover {
opacity: 0.7;
background: rgba(0, 0, 0, 0.9);
}
.gm-thumbnail-button:active {
opacity: 0.5;
}
.gm-media-wrapper {
display: inline-flex;
align-items: flex-start;
gap: 10px;
vertical-align: top;
}
.gm-thumbnail-container {
display: inline-block;
margin-left: 10px;
vertical-align: middle;
}
.gm-thumbnail-img {
object-fit: contain;
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
}
/* 連続画像の横並び表示用 */
.gm-image-row {
display: flex;
flex-wrap: wrap;
gap: 15px;
align-items: flex-start;
margin: 10px 0;
}
.gm-image-row .gm-media-wrapper,
.gm-image-row .gm-media-embed-container {
display: inline-flex;
vertical-align: top;
}
/* 取得エラー表示用 */
.gm-fetch-error {
color: #cc0000;
font-size: 12px;
}
`;
document.head.appendChild(style);
}
function showLightbox(imageIndex) {
const imageData = imageDatabase.get(imageIndex);
if (!imageData) return;
const { imageUrl, postNumber, originalUrl } = imageData;
closeLightbox();
const isImgur = /imgur/i.test(originalUrl);
let serviceName = 'image';
if (isImgur) serviceName = 'imgur';
else if (originalUrl.includes('ibb.co')) serviceName = 'img.bb';
else if (originalUrl.includes('tadaup.jp')) serviceName = 'tadaup';
else if (originalUrl.includes('ul.h3z.jp')) serviceName = 'h3z.jp';
else if (originalUrl.includes('postimg.cc')) serviceName = 'postimg.cc';
else if (originalUrl.includes('freeimage.host') || originalUrl.includes('iili.io')) serviceName = 'freeimage.host';
else if (originalUrl.includes('funakamome.com')) serviceName = 'funakamome.com';
const overlay = document.createElement('div');
overlay.id = 'lightboxOverlay';
overlay.className = 'lightboxOverlay';
overlay.style.width = '100%';
overlay.style.height = document.documentElement.scrollHeight + 'px';
overlay.style.display = 'block';
document.body.appendChild(overlay);
const lightbox = document.createElement('div');
lightbox.id = 'lightbox';
lightbox.className = 'lightbox';
lightbox.style.display = 'none';
let detailsHTML;
if (isImgur) {
let board = 'unknown', threadId = '0';
const urlMatch = window.location.href.match(/test\/read\.cgi\/([^\/]+)\/(\d+)/);
if (urlMatch) { board = urlMatch[1]; threadId = urlMatch[2]; }
const pid = `${board}-${threadId}-${postNumber}`;
const imgurPageUrl = imageUrl.replace(/\.(jpe?g|png|gif)$/i, '');
const twitterPostUrl = `https://${window.location.hostname}/test/read.cgi/${board}/${threadId}/${postNumber}-`;
detailsHTML = `
<div class="lb-details" style="min-width:300px">
<span class="lb-caption" style="display: inline; cursor: pointer;">
<u class="lb-ank" resnum="${postNumber}" href="#">>>${postNumber}</u>
</span>
<span class="lb-number" style="">全${imageDatabase.size}件中、${imageIndex}件目</span>
<span style="clear: left;display: block;" class="lb-save">
<div>
<a n="${postNumber}" pid="${pid}" class="lb-korabo-link gm-no-tooltip" href="${imageUrl}"><font size="2" color="white">コラボ</font></a>
<a class="lb-icon gm-no-tooltip" href="${imageUrl}"><font size="2" color="white">アイコン</font></a>
<a class="lb-search gm-no-tooltip" href="https://lens.google.com/uploadbyurl?hl=ja&url=${encodeURIComponent(imageUrl)}"><font size="2" color="white">画像検索</font></a>
<a class="lb-open-link gm-no-tooltip" href="${imageUrl}"><font size="2" color="white">直URL</font></a>
<a class="lb-open-link gm-no-tooltip" href="${imgurPageUrl}"><font size="2" color="white">imgur</font></a>
</div>
<div style="margin-top:5px">
<a class="lb-twiter gm-no-tooltip" url="${twitterPostUrl}" href="#"><font size="2" color="white">Twitterに貼る</font></a>
</div>
</span>
<span class="lb-korabo"></span>
</div>
`;
} else {
detailsHTML = `
<div class="lb-details" style="min-width:300px">
<span class="lb-caption" style="display: inline; cursor: pointer;">
<u class="lb-ank" resnum="${postNumber}" href="#">>>${postNumber}</u>
</span>
<span style="clear: left;display: block;" class="lb-save">
<div>
<a class="lb-search gm-no-tooltip" href="https://lens.google.com/uploadbyurl?hl=ja&url=${encodeURIComponent(imageUrl)}"><font size="2" color="white">画像検索</font></a>
<a class="lb-open-link gm-no-tooltip" href="${imageUrl}"><font size="2" color="white">直URL</font></a>
<a class="lb-service-link gm-no-tooltip" href="${originalUrl}"><font size="2" color="white">${serviceName}</font></a>
</div>
</span>
<span class="lb-korabo"></span>
</div>
`;
}
lightbox.innerHTML = `
<div class="lb-outerContainer">
<div class="lb-container">
<img class="lb-image" src="">
<div class="lb-nav">
<a class="lb-prev" href=""></a>
<a class="lb-next" href=""></a>
</div>
<div class="lb-loader" style="display: none;"><a class="lb-cancel"></a></div>
</div>
</div>
<div class="lb-dataContainer">
<div class="lb-data">
${detailsHTML}
<div class="lb-closeContainer"><a class="lb-close"></a></div>
</div>
</div>
`;
document.body.appendChild(lightbox);
const outerContainer = lightbox.querySelector('.lb-outerContainer');
const dataContainer = lightbox.querySelector('.lb-dataContainer');
const imageEl = lightbox.querySelector('.lb-image');
const prevLink = lightbox.querySelector('.lb-prev');
const nextLink = lightbox.querySelector('.lb-next');
const closeButton = lightbox.querySelector('.lb-close');
const loader = lightbox.querySelector('.lb-loader');
const ankLink = lightbox.querySelector('.lb-ank');
globalEscHandler = (e) => {
if (e.key === 'Escape') { closeLightbox(e); }
};
document.addEventListener('keydown', globalEscHandler);
overlay.addEventListener('click', (e) => {
e.stopPropagation();
closeLightbox();
});
closeButton.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
closeLightbox();
});
ankLink.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
closeLightbox();
window.location.href = generatePostLink(postNumber);
});
lightbox.addEventListener('click', e => {
if (e.target.id === 'lightbox') {
e.stopPropagation();
closeLightbox();
} else {
e.stopPropagation();
}
});
lightbox.querySelectorAll('.lb-save a').forEach(a => {
if (a.href && a.getAttribute('href') !== '#') {
a.target = '_blank'; a.rel = 'noopener noreferrer';
}
a.removeAttribute('title'); a.title = '';
a.addEventListener('mouseenter', (e) => {
e.target.removeAttribute('title'); e.target.title = '';
});
});
if (imageIndex > 1) {
prevLink.style.display = 'block';
prevLink.onclick = (e) => { e.preventDefault(); e.stopPropagation(); showLightbox(imageIndex - 1); };
} else {
prevLink.style.display = 'none';
}
if (imageIndex < imageDatabase.size) {
nextLink.style.display = 'block';
nextLink.onclick = (e) => { e.preventDefault(); e.stopPropagation(); showLightbox(imageIndex + 1); };
} else {
nextLink.style.display = 'none';
}
loader.style.display = 'block';
const tempImg = new Image();
tempImg.onload = function() {
const maxWidth = document.documentElement.clientWidth * 0.9;
const maxHeight = document.documentElement.clientHeight * 0.9 - 80;
let imgWidth = this.naturalWidth; let imgHeight = this.naturalHeight;
const ratio = Math.min(maxWidth / imgWidth, maxHeight / imgHeight, 1);
imgWidth = Math.round(imgWidth * ratio);
imgHeight = Math.round(imgHeight * ratio);
const framePadding = 8;
outerContainer.style.width = `${imgWidth + framePadding}px`;
outerContainer.style.height = `${imgHeight + framePadding}px`;
dataContainer.style.width = `${imgWidth + framePadding}px`;
imageEl.style.width = `${imgWidth}px`;
imageEl.style.height = `${imgHeight}px`;
imageEl.src = imageUrl;
imageEl.style.display = 'block';
lightbox.querySelector('.lb-nav').style.display = 'block';
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
const clientHeight = document.documentElement.clientHeight;
let top = scrollTop + (clientHeight - (imgHeight + framePadding + dataContainer.offsetHeight)) / 2;
if (top < scrollTop + 10) top = scrollTop + 10;
lightbox.style.top = `${top}px`;
lightbox.style.left = `0px`;
loader.style.display = 'none';
lightbox.style.display = 'block';
};
tempImg.onerror = function() {
loader.textContent = '画像の読み込みに失敗しました。';
loader.style.color = '#ff8a8a';
loader.style.display = 'block';
};
tempImg.src = imageUrl;
}
function getPostNumber(element) {
const postContainerSelectors = [
'article[id]', 'div.post[id]', 'div[data-res-id]', 'dl[val]',
'div.thread-post', '.post-container', '.message',
];
const postBlock = element.closest(postContainerSelectors.join(', '));
if (postBlock) {
const dataAttributes = ['data-res-id', 'data-res', 'data-num', 'data-id'];
for (const attr of dataAttributes) {
if (postBlock.hasAttribute(attr)) return postBlock.getAttribute(attr);
}
if (postBlock.id) {
const match = postBlock.id.match(/\d+/);
if (match) return match[0];
}
if (postBlock.hasAttribute('val')) return postBlock.getAttribute('val');
const numElementSelectors = ['.post-number', '.res-number', '.post-id', 'a.num', '.num b'];
const numElement = postBlock.querySelector(numElementSelectors.join(', '));
if (numElement) {
const match = numElement.textContent.match(/\d+/);
if (match) return match[0];
}
}
const ddElement = element.closest('dd[rnum]');
if (ddElement && ddElement.hasAttribute('rnum')) return ddElement.getAttribute('rnum');
const dtElement = element.closest('dl')?.querySelector('dt[res]');
if (dtElement && dtElement.hasAttribute('res')) return dtElement.getAttribute('res');
const hash = window.location.hash.match(/\d+/);
return hash ? hash[0] : 'N/A';
}
function bindLightboxOnClick(imageElement, imageUrl, originalUrl) {
if (imageElement.dataset.gmlbProcessed) return;
imageCounter++;
const currentImageIndex = imageCounter;
const postNumber = getPostNumber(imageElement) || currentImageIndex;
imageDatabase.set(currentImageIndex, { imageUrl, postNumber, originalUrl });
imageElement.addEventListener('click', (e) => {
e.stopPropagation(); e.preventDefault();
showLightbox(currentImageIndex);
}, true);
imageElement.dataset.gmlbProcessed = '1';
}
// lp-cardクラスを完全に除去する関数
function removeLpCardStyles(element) {
// lp-cardクラスを削除
element.classList.remove('lp-card');
// lp-で始まる全てのクラスを削除
const classesToRemove = [];
element.classList.forEach(cls => {
if (cls.startsWith('lp-')) {
classesToRemove.push(cls);
}
});
classesToRemove.forEach(cls => element.classList.remove(cls));
// インラインスタイルで強制的に透明にする
element.style.setProperty('background', 'transparent', 'important');
element.style.setProperty('background-color', 'transparent', 'important');
element.style.setProperty('border', 'none', 'important');
element.style.setProperty('box-shadow', 'none', 'important');
element.style.setProperty('padding', '0', 'important');
element.style.setProperty('margin', '0', 'important');
element.style.setProperty('outline', 'none', 'important');
// 親要素のurlタグもスタイルをリセット
const parentUrl = element.closest('url');
if (parentUrl) {
parentUrl.style.setProperty('background', 'transparent', 'important');
parentUrl.style.setProperty('border', 'none', 'important');
parentUrl.style.setProperty('box-shadow', 'none', 'important');
parentUrl.style.setProperty('padding', '0', 'important');
parentUrl.style.setProperty('margin', '0', 'important');
}
}
// 取得エラーを表示する関数
function showFetchError(linkElement, originalUrl) {
const errorLink = document.createElement('a');
errorLink.href = originalUrl;
errorLink.target = '_blank';
errorLink.rel = 'noopener noreferrer';
errorLink.className = 'gm-fetch-error';
errorLink.textContent = '取得エラー';
linkElement.innerHTML = '';
linkElement.appendChild(errorLink);
linkElement.style.display = 'inline';
linkElement.onclick = null;
}
function insertThumbnail(linkElement, imageUrl, originalUrl, isFromCache = false) {
linkElement.classList.add('gm-media-embed-container');
removeLpCardStyles(linkElement);
const img = document.createElement('img');
img.src = imageUrl;
img.style.cssText = `max-width:${GIF_DISPLAY_SIZE}; max-height:${GIF_DISPLAY_SIZE}; object-fit:contain; cursor:pointer; border:1px solid #ddd; border-radius:4px;`;
img.alt = "thumbnail";
img.onerror = () => {
showFetchError(linkElement, originalUrl);
};
const container = document.createElement('div');
container.style.display = 'inline-block';
container.appendChild(img);
linkElement.innerHTML = '';
linkElement.appendChild(container);
linkElement.style.display = 'inline-block';
linkElement.onclick = e => e.preventDefault();
linkElement.removeAttribute('title');
linkElement.onmouseover = (e) => {
e.stopPropagation(); e.target.removeAttribute('title');
return false;
};
bindLightboxOnClick(img, imageUrl, originalUrl);
}
// 画像URLが有効な拡張子を持っているかチェック
function hasValidImageExtension(url) {
return /\.(jpe?g|png|gif|webp)$/i.test(url);
}
// ギャラリーページとして処理すべきかチェック(postimg.cc, freeimage.host)
function isGalleryPage(url) {
return /^https?:\/\/postimg\.cc\/[0-9A-Za-z]+/.test(url) ||
/^https?:\/\/freeimage\.host\/i\/[0-9A-Za-z]+/.test(url);
}
// 画像をbase64として取得してキャッシュに保存
function fetchAndCacheImage(imageUrl, callback) {
GM_xmlhttpRequest({
method: "GET",
url: imageUrl,
responseType: "blob",
onload: (res) => {
if (res.status === 200 && res.response) {
const reader = new FileReader();
reader.onloadend = function() {
const base64Data = reader.result;
thumbnailCache.setWithBase64(imageUrl, base64Data);
callback(base64Data);
};
reader.onerror = function() {
// base64変換に失敗した場合はURLを使用
thumbnailCache.set(imageUrl, imageUrl);
callback(imageUrl);
};
reader.readAsDataURL(res.response);
} else {
callback(null);
}
},
onerror: () => {
callback(null);
}
});
}
function expandGalleryLink(a) {
const servicePageUrl = a.href;
const cachedImage = thumbnailCache.get(servicePageUrl);
if (cachedImage) {
insertThumbnail(a, cachedImage, servicePageUrl, true);
return;
}
GM_xmlhttpRequest({
method: "GET", url: servicePageUrl,
onload: (res) => {
if (res.status === 200) {
const match = res.responseText.match(/<meta property="og:image" content="([^"]+)"/);
if (match) {
const imgUrl = match[1];
// 画像本体をbase64で取得してキャッシュ
fetchAndCacheImage(imgUrl, (base64Data) => {
if (base64Data) {
insertThumbnail(a, base64Data, servicePageUrl);
} else {
showFetchError(a, servicePageUrl);
}
});
} else {
showFetchError(a, servicePageUrl);
}
} else {
showFetchError(a, servicePageUrl);
}
},
onerror: () => {
showFetchError(a, servicePageUrl);
}
});
}
function expandDirectLink(a) {
const imgUrl = a.href;
const cachedImage = thumbnailCache.get(imgUrl);
if (cachedImage) {
insertThumbnail(a, cachedImage, imgUrl, true);
return;
}
// 画像本体をbase64で取得してキャッシュ
fetchAndCacheImage(imgUrl, (base64Data) => {
if (base64Data) {
insertThumbnail(a, base64Data, imgUrl);
} else {
showFetchError(a, imgUrl);
}
});
}
function expandTadaupLink(a) {
const originalUrl = a.href;
// 拡張子がない場合は処理しない
if (!hasValidImageExtension(originalUrl)) {
a.dataset.gmlbProcessed = '1';
return;
}
const existingImg = a.querySelector('img');
if (existingImg && /tadaup\.jp/i.test(existingImg.src) && /\.(jpg|jpeg|png|gif)$/i.test(existingImg.src)) {
bindLightboxOnClick(existingImg, existingImg.src, originalUrl);
a.onclick = e => e.preventDefault();
return;
}
if (/\.(jpg|jpeg|png|gif)$/i.test(originalUrl)) {
expandDirectLink(a);
}
}
function embedImgurMp4(element) {
if (element.dataset.mp4Processed) return;
element.dataset.mp4Processed = '1';
const directUrl = element.href;
const imgurPageUrl = directUrl.replace(/\.mp4$/i, '');
const container = document.createElement('div');
container.className = 'gm-media-embed-container';
container.style.cssText = 'display: inline-flex; align-items: center; gap: 10px; vertical-align: middle;';
const video = document.createElement('video');
video.src = directUrl;
video.style.cssText = 'max-width:350px; max-height:350px; object-fit:contain; border:1px solid #ddd; border-radius:4px;';
video.autoplay = true;
video.loop = true;
video.muted = true;
video.playsInline = true;
video.controls = true;
video.onerror = () => {
console.error('Failed to load video:', directUrl); };
const linkContainer = document.createElement('div');
linkContainer.style.cssText = 'display: flex; flex-direction: column; align-items: flex-start; font-size: 12px;';
const directLink = document.createElement('a');
directLink.href = directUrl;
directLink.textContent = '直URL';
directLink.target = '_blank';
directLink.rel = 'noopener noreferrer';
directLink.addEventListener('click', (e) => e.stopPropagation());
const imgurLink = document.createElement('a');
imgurLink.href = imgurPageUrl;
imgurLink.textContent = 'imgur';
imgurLink.target = '_blank';
imgurLink.rel = 'noopener noreferrer';
imgurLink.addEventListener('click', (e) => e.stopPropagation());
linkContainer.appendChild(directLink);
linkContainer.appendChild(imgurLink);
container.appendChild(video);
container.appendChild(linkContainer);
if (element.parentNode) {
element.parentNode.insertBefore(container, element);
element.remove();
}
}
function replaceImgurGifWithNativeCompatibility(a) {
if (a.dataset.gifProcessed) return;
a.dataset.gifProcessed = '1';
const originalHref = a.href;
const flexContainer = document.createElement('div');
flexContainer.className = 'gm-media-wrapper';
flexContainer.style.cssText = 'display: inline-flex; align-items: flex-start; vertical-align: top;';
const wrapper = document.createElement('div');
wrapper.className = 'gm-imgur-gif-wrapper';
wrapper.style.cssText = 'display: inline-block; position: relative;';
const autoplayImg = document.createElement('img');
autoplayImg.src = originalHref;
autoplayImg.style.cssText = `max-width:${GIF_DISPLAY_SIZE}; max-height:${GIF_DISPLAY_SIZE}; object-fit:contain; border:1px solid #ddd; border-radius:4px; display: block;`;
autoplayImg.alt = "Imgur GIF (Auto-playing)";
const thumbnailButton = document.createElement('button');
thumbnailButton.className = 'gm-thumbnail-button';
thumbnailButton.textContent = '📦';
thumbnailButton.type = 'button';
thumbnailButton.title = 'サムネイル表示';
const thumbnailContainer = document.createElement('div');
thumbnailContainer.className = 'gm-thumbnail-container';
thumbnailContainer.style.display = 'none';
let thumbnailLoaded = false;
thumbnailButton.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
if (thumbnailContainer.style.display === 'none') {
if (!thumbnailLoaded) {
const thumbnailUrl = originalHref.replace(/\.gif$/i, 'm.gif');
const thumbLink = document.createElement('a');
thumbLink.href = originalHref;
thumbLink.addEventListener('click', (clickEvent) => {
clickEvent.preventDefault();
clickEvent.stopPropagation();
}, true);
const thumbnailImg = document.createElement('img');
thumbnailImg.className = 'gm-thumbnail-img';
thumbnailImg.src = thumbnailUrl;
thumbnailImg.alt = 'サムネイル';
thumbnailImg.style.cssText = `max-width:${GIF_DISPLAY_SIZE}; max-height:${GIF_DISPLAY_SIZE}; object-fit:contain; border:1px solid #ddd; border-radius:4px; cursor:pointer;`;
thumbnailImg.onerror = () => {
console.error('Failed to load thumbnail:', thumbnailUrl);
thumbnailImg.alt = 'サムネイル読み込み失敗';
};
bindLightboxOnClick(thumbnailImg, originalHref, originalHref);
thumbLink.appendChild(thumbnailImg);
thumbnailContainer.appendChild(thumbLink);
thumbnailLoaded = true;
}
thumbnailContainer.style.display = 'inline-block';
thumbnailButton.textContent = '📁';
thumbnailButton.title = 'サムネイル非表示';
} else {
thumbnailContainer.style.display = 'none';
thumbnailButton.textContent = '📦';
thumbnailButton.title = 'サムネイル表示';
}
});
wrapper.appendChild(autoplayImg);
wrapper.appendChild(thumbnailButton);
flexContainer.appendChild(wrapper);
flexContainer.appendChild(thumbnailContainer);
if (a.parentNode) {
a.parentNode.insertBefore(flexContainer, a);
a.remove();
} else {
return;
}
bindLightboxOnClick(autoplayImg, originalHref, originalHref);
}
function groupConsecutiveImages() {
const links = document.querySelectorAll('a[href]');
const imagePattern = /\.(jpe?g|png|gif|webp)$/i;
const servicePattern = /imgur|tadaup\.jp|ul\.h3z\.jp|ibb\.co|postimg\.cc|freeimage\.host|iili\.io|funakamome\.com/i;
let consecutiveGroups = [];
let currentGroup = [];
for (let i = 0; i < links.length; i++) {
const link = links[i];
const href = link.href;
if (link.closest('#lightbox, #lightboxOverlay, .lb-dataContainer, .gm-media-embed-container, .gm-imgur-gif-wrapper, .gm-image-row')
|| link.dataset.gmlbProcessed) {
if (currentGroup.length > 1) {
consecutiveGroups.push([...currentGroup]);
}
currentGroup = [];
continue;
}
const isImageUrl = imagePattern.test(href) || servicePattern.test(href);
if (isImageUrl) {
if (currentGroup.length === 0) {
currentGroup.push(link);
} else {
const lastLink = currentGroup[currentGroup.length - 1];
if (isConsecutiveImage(lastLink, link)) {
currentGroup.push(link);
} else {
if (currentGroup.length > 1) {
consecutiveGroups.push([...currentGroup]);
}
currentGroup = [link];
}
}
} else {
if (currentGroup.length > 1) {
consecutiveGroups.push([...currentGroup]);
}
currentGroup = [];
}
}
if (currentGroup.length > 1) {
consecutiveGroups.push(currentGroup);
}
consecutiveGroups.forEach(group => {
if (group.length > 1) {
createImageRow(group);
}
});
}
function isConsecutiveImage(elem1, elem2) {
if (areAdjacentInDOM(elem1, elem2)) {
return true;
}
const distance = getElementDistance(elem1, elem2);
if (distance < 100) {
return true;
}
if (areInSameParagraph(elem1, elem2)) {
return true;
}
return false;
}
function areAdjacentInDOM(elem1, elem2) {
let current = elem1.nextSibling;
let textOnlyBetween = true;
while (current && current !== elem2) {
if (current.nodeType === Node.TEXT_NODE) {
if (current.textContent.trim() !== '') {
textOnlyBetween = false;
break;
}
} else if (current.nodeType === Node.ELEMENT_NODE) {
if (current.tagName === 'BR' ||
(current.textContent && current.textContent.trim() === '')) {
} else {
textOnlyBetween = false;
break;
}
}
current = current.nextSibling;
}
return current === elem2 && textOnlyBetween;
}
function areInSameParagraph(elem1, elem2) {
const para1 = elem1.closest('p, dd, div.message, .post-content');
const para2 = elem2.closest('p, dd, div.message, .post-content');
return para1 && para2 && para1 === para2;
}
function getElementDistance(elem1, elem2) {
const rect1 = elem1.getBoundingClientRect();
const rect2 = elem2.getBoundingClientRect();
const verticalDistance = Math.abs(rect2.top - rect1.bottom);
return verticalDistance;
}
function createImageRow(imageLinks) {
if (imageLinks.length < 2) return;
const firstLink = imageLinks[0];
const rowContainer = document.createElement('div');
rowContainer.className = 'gm-image-row';
firstLink.parentNode.insertBefore(rowContainer, firstLink);
imageLinks.forEach(link => {
const wrapper = document.createElement('div');
wrapper.style.cssText = 'display: inline-block; vertical-align: top;';
wrapper.appendChild(link);
rowContainer.appendChild(wrapper);
});
}
function processLinks() {
const links = document.querySelectorAll('a[href]');
const baseDomainsToIgnore = ['ul.h3z.jp', 'tadaup.jp', 'ibb.co', 'i.ibb.co', 'i.postimg.cc', 'postimg.cc', 'freeimage.host', 'iili.io', 'funakamome.com'];
links.forEach(a => {
if (a.closest('#lightbox, #lightboxOverlay, .lb-dataContainer, .gm-media-embed-container, .gm-imgur-gif-wrapper, .gm-thumbnail-button, .gm-image-row') || a.dataset.gmlbProcessed) return;
const innerImg = a.querySelector('img');
if (innerImg && innerImg.dataset.gmlbProcessed) return;
const href = a.href;
try {
const url = new URL(href);
if (baseDomainsToIgnore.includes(url.hostname) && (url.pathname === '/' || url.pathname === '')) {
a.dataset.gmlbProcessed = '1'; return;
}
} catch (e) { return; }
const existingImg = a.querySelector('img');
if ((existingImg && /imgur/i.test(existingImg.className) && /\.gif/i.test(href)) || /i\.imgur\.com\/[0-9A-Za-z]+\.gif/i.test(href)) {
replaceImgurGifWithNativeCompatibility(a);
return;
}
if (!existingImg && /i\.imgur\.com\/[0-9A-Za-z]+\.mp4/i.test(href)) {
embedImgurMp4(a); return;
}
if (existingImg && /i\.imgur\.com\//.test(href) && /\.(jpe?g|png)$/i.test(href)) {
bindLightboxOnClick(existingImg, href, href);
a.onclick = e => e.preventDefault(); a.dataset.gmlbProcessed = '1'; return;
}
const isTadaup = /tadaup\.jp/.test(href) || (existingImg && /tadaup\.jp/.test(existingImg.src));
const isH3z = /ul\.h3z\.jp/.test(href);
const isIbbDirect = /^https?:\/\/i\.ibb\.co\//.test(href);
const isPostimgDirect = /i\.postimg\.cc/.test(href);
const isIilioDirect = /iili\.io/.test(href);
const isFunakamome = /funakamome\.com/.test(href);
const isIbbGallery = /^https?:\/\/ibb\.co\/[0-9A-Za-z]+/.test(href);
const isPostimgGallery = /^https?:\/\/postimg\.cc\/[0-9A-Za-z]+/.test(href);
const isFreeimageGallery = /^https?:\/\/freeimage\.host\/i\/[0-9A-Za-z]+/.test(href);
// ギャラリーページ(postimg.cc, freeimage.host)は拡張子なしでもOK
if (isPostimgGallery || isFreeimageGallery) {
expandGalleryLink(a);
a.dataset.gmlbProcessed = '1';
return;
}
// ibb.coギャラリーページも拡張子なしでもOK
if (isIbbGallery) {
expandGalleryLink(a);
a.dataset.gmlbProcessed = '1';
return;
}
// 直接リンクの場合は拡張子チェックを行う
if (isIbbDirect || isPostimgDirect || isH3z || isIilioDirect) {
if (hasValidImageExtension(href)) {
expandDirectLink(a);
}
// 拡張子がない場合は何もしない(白い枠も消さない)
a.dataset.gmlbProcessed = '1';
return;
}
// funakamome.comは拡張子チェックを行う
if (isFunakamome) {
if (hasValidImageExtension(href)) {
expandDirectLink(a);
}
// 拡張子がない場合は何もしない(白い枠も消さない)
a.dataset.gmlbProcessed = '1';
return;
}
// tadaupも拡張子チェックを行う
if (isTadaup) {
if (hasValidImageExtension(href)) {
expandTadaupLink(a);
}
// 拡張子がない場合は何もしない
a.dataset.gmlbProcessed = '1';
return;
}
a.dataset.gmlbProcessed = '1';
});
setTimeout(() => {
groupConsecutiveImages();
}, 500);
}
function disableTooltips() {
document.addEventListener('mouseover', function(e) {
if (e.target.matches('.lb-save a, .gm-no-tooltip, .gm-media-embed-container a, .gm-thumbnail-button')) {
e.target.removeAttribute('title'); e.target.title = '';
}
}, true);
setTimeout(() => {
document.querySelectorAll('.lb-save a, .gm-no-tooltip, .gm-thumbnail-button').forEach(el => {
el.removeAttribute('title'); el.title = '';
});
}, 100);
}
function enhanceSiteCompatibility() {
const observer = new MutationObserver((mutations) => {
let needsProcessing = false;
mutations.forEach(mutation => {
if (mutation.addedNodes.length > 0) {
mutation.addedNodes.forEach(node => {
if (node.nodeType === Node.ELEMENT_NODE) {
if (node.matches('a[href]') || node.querySelector('a[href]')) {
needsProcessing = true;
}
}
});
}
});
if (needsProcessing) {
setTimeout(processLinks, 200);
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
function init() {
addCustomCSS();
processLinks();
disableTooltips();
enhanceSiteCompatibility();
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();
|
| + | Open2ch ID横に検索ボタンをすべてのIDに追加 |
// ==UserScript==
// @name Open2ch ID横に検索ボタンをすべてのIDに追加
// @namespace http://tampermonkey.net/
// @version 1.2
// @license CC0-1.0
// @description 全てのIDに検索ボタンを追加
// @author jazapから(自作)
// @match https://*.open2ch.net/*
// @grant none
// @require https://code.jquery.com/jquery-3.6.0.min.js
// ==/UserScript==
(function() {
'use strict';
const bbs = 'livejupiter';
function addSearchButtons() {
$('span._id').each(function() {
const $idSpan = $(this);
if ($idSpan.find('.id-search-btn').length > 0) return;
const idVal = $idSpan.attr('val');
if (!idVal) return;
const $btn = $('<button>')
.text('検索')
.addClass('id-search-btn')
.css({
marginLeft: '6px',
fontSize: '10px',
cursor: 'pointer',
padding: '1px 5px',
borderRadius: '3px',
border: '1px solid #888',
background: '#eee',
verticalAlign: 'middle'
})
.attr('type', 'button')
.on('click', () => {
const url = `https://find.open2ch.net/?bbs=${bbs}&t=f&q=${encodeURIComponent(idVal)}`;
window.open(url, '_blank');
});
$idSpan.append($btn);
});
}
$(function() {
addSearchButtons();
setInterval(addSearchButtons, 500);
});
})();
|
| + | おんj通信量削減 |
// ==UserScript==
// @name おんj通信量削減
// @namespace tm-block-ga-only-strict
// @version 1.2
// @license CC0-1.0
// @description GA/GA4を完全遮断
// @match https://*.open2ch.net/*
// @run-at document-start
// ==/UserScript==
(() => {
'use strict';
const isGA = url =>
typeof url === 'string' &&
(
url.startsWith('https://analytics.google.com/g/collect') ||
url.startsWith('https://www.google-analytics.com/g/collect') ||
url.startsWith('https://www.google-analytics.com/collect')
);
/* fetch(Request対応) */
const _fetch = window.fetch;
window.fetch = function (input, init) {
const url =
typeof input === 'string'
? input
: input instanceof Request
? input.url
: '';
if (isGA(url)) {
return Promise.resolve(new Response(null, { status: 204 }));
}
return _fetch.apply(this, arguments);
};
/* XMLHttpRequest */
const _open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function (method, url) {
if (isGA(url)) {
this.abort();
return;
}
return _open.apply(this, arguments);
};
/* sendBeacon(GA4の本命) */
if (navigator.sendBeacon) {
const _beacon = navigator.sendBeacon;
navigator.sendBeacon = function (url, data) {
if (isGA(url)) {
return false;
}
return _beacon.call(this, url, data);
};
}
})();
|
| + | おんJ バツポチ修正 |
// ==UserScript==
// @name おんJ バツポチ修正
// @namespace onj-ignore-display-fix-preemptive
// @version 2.1
// @license CC0-1.0
// @description はよ直せさとる
// @match https://*.open2ch.net/test/read.cgi/*
// @grant GM_addStyle
// @run-at document-start
// ==/UserScript==
(function () {
'use strict';
const style = document.createElement('style');
style.textContent = `
dl[ignored="1"] {
display: none !important;
}
`;
function injectStyle() {
const target = document.head || document.documentElement;
if (target && !target.querySelector('style[data-ignore-fix]')) {
style.setAttribute('data-ignore-fix', 'true');
target.appendChild(style);
}
}
injectStyle();
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', injectStyle);
}
function applyIgnoreFixSync(root = document) {
const ignoredElements = root.querySelectorAll('dl[ignored="1"]');
ignoredElements.forEach(dl => {
dl.style.display = 'none';
});
return ignoredElements.length;
}
function initIgnoreFix() {
const count = applyIgnoreFixSync();
console.log(`バツポチ初期処理: ${count}件のレスを非表示化`);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initIgnoreFix);
} else {
initIgnoreFix();
}
function startObserver() {
const targetNode = document.querySelector('.thread') || document.body;
const observer = new MutationObserver(mutations => {
let fixedCount = 0;
for (const mutation of mutations) {
for (const node of mutation.addedNodes) {
if (node.nodeType !== Node.ELEMENT_NODE) continue;
if (node.matches && node.matches('dl[ignored="1"]')) {
node.style.display = 'none';
fixedCount++;
}
if (node.querySelectorAll) {
const ignoredChildren = node.querySelectorAll('dl[ignored="1"]');
ignoredChildren.forEach(dl => {
dl.style.display = 'none';
fixedCount++;
});
}
}
if (mutation.type === 'attributes' &&
mutation.attributeName === 'ignored' &&
mutation.target.getAttribute('ignored') === '1') {
mutation.target.style.display = 'none';
fixedCount++;
}
}
if (fixedCount > 0) {
console.log(`バツポチ動的処理: ${fixedCount}件のレスを非表示化`);
}
});
observer.observe(targetNode, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['ignored']
});
console.log('バツポチMutationObserver 開始');
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', startObserver);
} else {
startObserver();
}
setInterval(() => {
const count = applyIgnoreFixSync();
if (count > 0) {
console.log(`バツポチ定期補正: ${count}件のレスを非表示化`);
}
}, 1000);
console.log('バツポチ初期化完了(表示前抑制モード)');
})();
|
| + | 投稿内容を送信直前に自動変換 |
// ==UserScript==
// @name 投稿内容を送信直前に自動変換
// @namespace http://tampermonkey.net/
// @version 2.1
// @license CC0-1.0
// @description 投稿ボタンを押した瞬間に、テキストエリア内の特定の文字や単語を「&&#x…;」形式に変換します。
// @author ワイ
// @match https://*.open2ch.net/test/read.cgi/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
const CONVERT_TARGETS = ['多治見', '安倍', 'フラゲ', 'アフィ', '<', '興味', '大麻', '晋', '大']; //さとるが規制復活させるかもしれんから一応
const DELETE_TARGETS = ['NGワードをここにこんな風に記述', 'こんな感じにね']; //投稿に含まれていたら自動削除
const SUBMIT_BUTTON_SELECTORS = [
'input[type="submit"][value="書"]',
'input[name="submit"]',
'button[type="submit"]',
'#submit_button'
];
const TEXTAREA_SELECTOR = 'textarea[name="MESSAGE"]';
const convertCharToUnicodeEntity = (char) => {
const codePoint = char.codePointAt(0).toString(16);
return `&&#x${codePoint};#x${codePoint};`;
};
const isRestrictedScript = (char) => {
const code = char.codePointAt(0);
return (code >= 0x0600 && code <= 0x06FF) || //アラビア文字とか
(code >= 0x0750 && code <= 0x077F) ||
(code >= 0x08A0 && code <= 0x08FF) ||
(code >= 0xFB50 && code <= 0xFDFF) ||
(code >= 0xFE70 && code <= 0xFEFF) ||
(code >= 0xAC00 && code <= 0xD7AF) ||
(code >= 0x1100 && code <= 0x11FF) ||
(code >= 0x3130 && code <= 0x318F) ||
(code >= 0xA960 && code <= 0xA97F) ||
(code >= 0xD7B0 && code <= 0xD7FF) ||
(code >= 0x0E00 && code <= 0x0E7F) ||
(code >= 0x0F00 && code <= 0x0FFF) ||
(code >= 0x0590 && code <= 0x05FF) ||
(code >= 0x0900 && code <= 0x097F) ||
(code >= 0x0980 && code <= 0x09FF) ||
(code >= 0x0A00 && code <= 0x0A7F) ||
(code >= 0x0A80 && code <= 0x0AFF) ||
(code >= 0x0B00 && code <= 0x0B7F) ||
(code >= 0x0B80 && code <= 0x0BFF) ||
(code >= 0x0C00 && code <= 0x0C7F) ||
(code >= 0x0C80 && code <= 0x0CFF) ||
(code >= 0x0D00 && code <= 0x0D7F) ||
(code >= 0x0D80 && code <= 0x0DFF) ||
(code >= 0x1000 && code <= 0x109F) ||
(code >= 0x1200 && code <= 0x137F) ||
(code >= 0x13A0 && code <= 0x13FF) ||
(code >= 0x1400 && code <= 0x167F) ||
(code >= 0x1680 && code <= 0x169F) ||
(code >= 0x16A0 && code <= 0x16FF) ||
(code >= 0x1700 && code <= 0x171F) ||
(code >= 0x1720 && code <= 0x173F) ||
(code >= 0x1740 && code <= 0x175F) ||
(code >= 0x1760 && code <= 0x177F) ||
(code >= 0x1780 && code <= 0x17FF) ||
(code >= 0x1800 && code <= 0x18AF) ||
(code >= 0x1900 && code <= 0x194F) ||
(code >= 0x1950 && code <= 0x197F) ||
(code >= 0x1980 && code <= 0x19DF) ||
(code >= 0x19E0 && code <= 0x19FF) ||
(code >= 0x1A00 && code <= 0x1A1F) ||
(code >= 0x1A20 && code <= 0x1AAF) ||
(code >= 0x1B00 && code <= 0x1B7F) ||
(code >= 0x1B80 && code <= 0x1BBF) ||
(code >= 0x1BC0 && code <= 0x1BFF) ||
(code >= 0x1C00 && code <= 0x1C4F) ||
(code >= 0x1C50 && code <= 0x1C7F) ||
(code >= 0x1C80 && code <= 0x1C8F) ||
(code >= 0x1CC0 && code <= 0x1CCF) ||
(code >= 0x1CD0 && code <= 0x1CFF) ||
(code >= 0x2800 && code <= 0x28FF) ||
(code >= 0x2E80 && code <= 0x2EFF) ||
(code >= 0x2F00 && code <= 0x2FDF) ||
(code >= 0x3000 && code <= 0x303F) ||
(code >= 0x3200 && code <= 0x32FF) ||
(code >= 0x3300 && code <= 0x33FF) ||
(code >= 0xA000 && code <= 0xA48F) ||
(code >= 0xA490 && code <= 0xA4CF) ||
(code >= 0xA4D0 && code <= 0xA4FF) ||
(code >= 0xA500 && code <= 0xA63F) ||
(code >= 0xA640 && code <= 0xA69F) ||
(code >= 0xA6A0 && code <= 0xA6FF) ||
(code >= 0xA700 && code <= 0xA71F) ||
(code >= 0xA720 && code <= 0xA7FF) ||
(code >= 0xA800 && code <= 0xA82F) ||
(code >= 0xA830 && code <= 0xA83F) ||
(code >= 0xA840 && code <= 0xA87F) ||
(code >= 0xA880 && code <= 0xA8DF) ||
(code >= 0xA8E0 && code <= 0xA8FF) ||
(code >= 0xA900 && code <= 0xA92F) ||
(code >= 0xA930 && code <= 0xA95F) ||
(code >= 0xAA00 && code <= 0xAA5F) ||
(code >= 0xAA60 && code <= 0xAA7F) ||
(code >= 0xAA80 && code <= 0xAADF) ||
(code >= 0xAAE0 && code <= 0xAAFF) ||
(code >= 0xAB00 && code <= 0xAB2F) ||
(code >= 0xAB30 && code <= 0xAB6F) ||
(code >= 0xAB70 && code <= 0xABBF) ||
(code >= 0xABC0 && code <= 0xABFF) ||
(code >= 0x10000 && code <= 0x1007F) ||
(code >= 0x10080 && code <= 0x100FF) ||
(code >= 0x10100 && code <= 0x1013F) ||
(code >= 0x10140 && code <= 0x1018F) ||
(code >= 0x10190 && code <= 0x101CF) ||
(code >= 0x101D0 && code <= 0x101FF) ||
(code >= 0x10280 && code <= 0x1029F) ||
(code >= 0x102A0 && code <= 0x102DF) ||
(code >= 0x10300 && code <= 0x1032F) ||
(code >= 0x10330 && code <= 0x1034F) ||
(code >= 0x10350 && code <= 0x1037F) ||
(code >= 0x10380 && code <= 0x1039F) ||
(code >= 0x103A0 && code <= 0x103DF) ||
(code >= 0x10400 && code <= 0x1044F) ||
(code >= 0x10450 && code <= 0x1047F) ||
(code >= 0x10480 && code <= 0x104AF) ||
(code >= 0x10800 && code <= 0x1083F) ||
(code >= 0x10840 && code <= 0x1085F) ||
(code >= 0x10900 && code <= 0x1091F) ||
(code >= 0x10920 && code <= 0x1093F) ||
(code >= 0x10980 && code <= 0x1099F) ||
(code >= 0x109A0 && code <= 0x109FF) ||
(code >= 0x10A00 && code <= 0x10A5F) ||
(code >= 0x10A60 && code <= 0x10A7F) ||
(code >= 0x10B00 && code <= 0x10B3F) ||
(code >= 0x10B40 && code <= 0x10B5F) ||
(code >= 0x10B60 && code <= 0x10B7F) ||
(code >= 0x10C00 && code <= 0x10C4F) ||
(code >= 0x11000 && code <= 0x1107F) ||
(code >= 0x11080 && code <= 0x110CF) ||
(code >= 0x12000 && code <= 0x123FF) ||
(code >= 0x12400 && code <= 0x1247F) ||
(code >= 0x13000 && code <= 0x1342F) ||
(code >= 0x14400 && code <= 0x1467F) ||
(code >= 0x16800 && code <= 0x16A3F) ||
(code >= 0x16F00 && code <= 0x16F9F) ||
(code >= 0x1B000 && code <= 0x1B0FF) ||
(code >= 0x1BC00 && code <= 0x1BC9F) ||
(code >= 0x1D000 && code <= 0x1D0FF) ||
(code >= 0x1D100 && code <= 0x1D1FF) ||
(code >= 0x1D200 && code <= 0x1D24F) ||
(code >= 0x1D300 && code <= 0x1D35F) ||
(code >= 0x1D360 && code <= 0x1D37F) ||
(code >= 0x1D400 && code <= 0x1D7FF) ||
(code >= 0x1F000 && code <= 0x1F02F) ||
(code >= 0x1F030 && code <= 0x1F09F) ||
(code >= 0x1F0A0 && code <= 0x1F0FF) ||
(code >= 0x1F100 && code <= 0x1F1FF) ||
(code >= 0x1F200 && code <= 0x1F2FF) ||
(code >= 0x1F300 && code <= 0x1F5FF) ||
(code >= 0x1F600 && code <= 0x1F64F) ||
(code >= 0x1F650 && code <= 0x1F67F) ||
(code >= 0x1F680 && code <= 0x1F6FF) ||
(code >= 0x1F700 && code <= 0x1F77F) ||
(code >= 0x1F780 && code <= 0x1F7FF) ||
(code >= 0x1F800 && code <= 0x1F8FF) ||
(code >= 0x1F900 && code <= 0x1F9FF) ||
(code >= 0x1FA00 && code <= 0x1FA6F) ||
(code >= 0x1FA70 && code <= 0x1FAFF) ||
(code >= 0x20000 && code <= 0x2A6DF) ||
(code >= 0x2A700 && code <= 0x2B73F) ||
(code >= 0x2B740 && code <= 0x2B81F) ||
(code >= 0x2B820 && code <= 0x2CEAF) ||
(code >= 0x2CEB0 && code <= 0x2EBEF) ||
(code >= 0x2F800 && code <= 0x2FA1F);
};
const modifyTextOnSubmit = () => {
const textarea = document.querySelector(TEXTAREA_SELECTOR);
if (!textarea || !textarea.value) {
return;
}
let originalText = textarea.value;
let convertedText = originalText;
DELETE_TARGETS.forEach(targetWord => {
const regex = new RegExp(targetWord.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g');
convertedText = convertedText.replace(regex, '');
});
CONVERT_TARGETS.forEach(targetWord => {
const regex = new RegExp(targetWord.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g');
convertedText = convertedText.replace(regex, (matchedWord) => {
let result = '';
for (const char of matchedWord) {
result += convertCharToUnicodeEntity(char);
}
return result;
});
});
let finalText = '';
for (const char of convertedText) {
if (isRestrictedScript(char)) {
finalText += convertCharToUnicodeEntity(char);
} else {
finalText += char;
}
}
if (originalText !== finalText) {
textarea.value = finalText;
}
};
const setupListeners = () => {
SUBMIT_BUTTON_SELECTORS.forEach(selector => {
document.querySelectorAll(selector).forEach(submitButton => {
if (submitButton.dataset.autoConvertListener) return;
submitButton.addEventListener('click', modifyTextOnSubmit, true);
submitButton.dataset.autoConvertListener = 'true';
});
});
};
const observer = new MutationObserver(() => {
setupListeners();
});
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', setupListeners);
} else {
setupListeners();
}
observer.observe(document.body, {
childList: true,
subtree: true
});
})();
|
| + | おんJピアノ自動演奏 |
コメント:
おんjのピアノを自動演奏するよ 保存した物はちゃんとファイルに保存しないともしかしたら時間経過で消えるかもしれないから注意🥺 機械的な遅延などもあるので楽譜をそのまま落とし込むだけだと多分ズレる 途中から再生モードも機械的遅延でほぼ役に立たない 長いので割愛
|
続き:スクリプト(2)