Tries to detect and un-break Session IDs posted on 4chan
当前为
// ==UserScript==
// @name 4chan Session ID Unbreaker
// @license GPLv3
// @namespace https://boards.4chan.org/
// @version 2.3
// @description Tries to detect and un-break Session IDs posted on 4chan
// @author ceodoe
// @match https://boards.4chan.org/*/thread/*
// @match https://boards.4chan.org/*/res/*
// @match https://archived.moe/*/thread/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=4chan.org
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_addStyle
// ==/UserScript==
let rememberCopiedIDs = GM_getValue("rememberCopiedIDs", true);
let rememberedIDs = GM_getValue("rememberedIDs", []);
GM_addStyle(`
.fcsidu-rememberedID {
color: #aaa;
border-bottom: 1px dotted #aaa;
}
`);
function parsePosts() {
let posts = document.querySelectorAll("blockquote.postMessage");
if(location.href.startsWith("https://archived.moe/")) {
posts = document.querySelectorAll("article > div.text, div.post_wrapper > div.text");
}
for(let i = 0; i < posts.length; i++) {
if(posts[i].getAttribute("data-fcsidu-parsed") !== "1") {
posts[i].setAttribute("data-fcsidu-parsed", "1");
// Strip all backlinks as they are likely to contain the magic number 05 that all Session IDs start with
let postText = posts[i].innerText.replace(/\>\>\b[0-9]+\b/g, "");
let idStartIndex = postText.indexOf("05");
if(idStartIndex > -1) {
let id = "";
// "Smart" detection mechanism removes all non-alphanumeric chars, then ignores words with
// non-hexadecimal chars in them, and tries to build a string exactly 66 chars long
let words = postText.substring(idStartIndex).split(/\s/);
for(let j = 0; j < words.length && id.length < 66; j++) {
let word = words[j].replace(/[^A-Za-z0-9]/g, "");
if(!word.match(/[^A-Fa-f0-9]/g)) {
id += word;
}
}
if(id.length == 66) { // All IDs are 66 chars; if we didn't get exactly 66, ID is invalid
let opPost = "";
if(posts[i].parentNode.classList.contains("op")) {
opPost = "overflow: auto;";
}
let archivePost = "border-top: 1px solid; width: fit-content;";
if(posts[i].parentNode.tagName.toLowerCase() == "article") {
archivePost = "";
}
let html = `
<div style="margin-top: 1em; padding: 0.5em; ${archivePost} ${opPost}">
<span style="color: #66cc33; font-weight: bold;">Session ID:</span> <span class="fcsidu-session-id ${rememberCopiedIDs && rememberedIDs.includes(id) ? `fcsidu-rememberedID" title="ID has been previously copied` : ``}">${id}</span>
<input type="button" class="fcsidu-copy-btn" id="fcsidu-copy-btn-${i}" data-fcsidu-session-id="${id}" style="margin-left: 0.5em;" value="Copy">
</div>
`;
posts[i].insertAdjacentHTML("beforeend", html);
document.getElementById(`fcsidu-copy-btn-${i}`).addEventListener("click", async function() {
let tempInput = document.createElement("input");
let id = this.getAttribute("data-fcsidu-session-id").trim();
tempInput.value = id;
tempInput.select();
tempInput.setSelectionRange(0,66);
try {
await navigator.clipboard.writeText(tempInput.value);
this.value = "✓";
if(rememberCopiedIDs) {
// Refresh remembered ID list in case it was updated in another tab
rememberedIDs = GM_getValue("rememberedIDs", []);
rememberedIDs.push(id);
GM_setValue("rememberedIDs", rememberedIDs);
updateIDs();
}
window.setTimeout(function() {
document.getElementById(`fcsidu-copy-btn-${i}`).value = "Copy";
}, 3000);
} catch (err) {
alert("Failed to copy to clipboard: " + err);
}
});
}
}
}
}
if(rememberCopiedIDs) {
updateIDs();
}
}
function setupOptions() {
let parent = document.querySelector("div.bottomCtrl");
if(location.href.startsWith("https://archived.moe/")) {
parent = document.querySelector("#footer");
}
let html = `
<span id="fcsidu-options">
<input type="checkbox" name="fcsidu-rememberIDs-check" id="fcsidu-rememberIDs-check" ${rememberCopiedIDs ? `checked` : ``}>
<label for="fcsidu-rememberIDs-check" title="Disabling also clears already remembered IDs">Remember copied Session IDs</label> |
</span>
`;
parent.insertAdjacentHTML("afterbegin", html);
document.querySelector("#fcsidu-rememberIDs-check").addEventListener("change", function() {
GM_setValue("rememberCopiedIDs", this.checked);
if(!this.checked) {
// Clear already remembered IDs on disable
GM_setValue("rememberedIDs", []);
}
location.reload();
});
}
function updateIDs() {
rememberedIDs = GM_getValue("rememberedIDs", []);
let idElems = document.querySelectorAll(".fcsidu-session-id");
for(let i = 0; i < idElems.length; i++) {
if(rememberedIDs.includes(idElems[i].innerText.trim())) {
idElems[i].classList.add("fcsidu-rememberedID");
idElems[i].title = "ID has been previously copied";
}
}
}
new MutationObserver(function(event) { parsePosts(); }).observe(document.querySelector("div.thread"), {childList: true});
setupOptions();
parsePosts();