Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name 4chan2reddit
- // @grant GM.getValue
- // @grant GM.setValue
- // @version 1
- // @description Destroy free speech and rely on the discernment of children
- // @include *://boards.4chan.org/*
- // @include *://boards.4channel.org/*
- // ==/UserScript==
- // User preferences will be loaded.
- const defaultMin = "-10";
- const defaultMax = "10";
- var thresholdMinPreference = defaultMin;
- var thresholdMaxPreference = defaultMax;
- function generateRandomColor() {
- return `rgb(${Math.floor((Math.random() * 256 + 255) / 2)},${Math.floor((Math.random() * 256 + 255) / 2)},${Math.floor((Math.random() * 256 + 255) / 2)})`;
- }
- // The script will read posts and apply rules when it sees "+1", "-1", and #hashtags.
- const upvoteFilter = /\s\+\d+\s|up(vot|doot|boat)|t ?h ?a ?n ?k ?(y ?o ?)?[su]|bump|s(au|our)ce|good ?job|\b(I l(ov|ik)e|based|nice|cool|cute|qt|haha|lmao|kek|patrician|.pbp\b|lol\b)/i;
- const downvoteFilter = /\s\-\d+\s|down(vot|doot|boat)|\bkys\b|touch.*grass|\bcringe\b|\bcope\b|f[a]g|gay|reddit|kil+ yourself|f.ck|r.tard|nig(s|ger)|j[e]w|\bb(8|ait)\b|schizo|stfu|rent.?free|cancer|\bloser/i;
- const tagSearchQuery = /[^0-9a-z]#([0-9a-z]{2,})/gi;
- function voteAndTag(reply, replyText, post) {
- if (!post || !replyText) return;
- replyText = ` ${replyText} `;
- const upvoted = replyText.match(upvoteFilter);
- const downvoted = replyText.match(downvoteFilter);
- const tags = replyText.match(tagSearchQuery);
- if (post !== reply)
- if (upvoted && (!replyText.includes("-1") || replyText.includes("+1"))) post.voteScore++;
- else if (downvoted) post.voteScore--;
- for (let i = 0; i < tags?.length; i++) {
- const tag = post.tags[tags[i].toString().trim().toLowerCase()] || {
- tag: tags[i].toString().trim(),
- count: 0,
- color: generateRandomColor(),
- };
- tag.count++;
- post.tags[tags[i].toString().trim().toLowerCase()] = tag;
- }
- }
- function updateScores() {
- // User preferences will be stored.
- const thresholdMin0 = document.getElementById("thresholdMin0");
- const thresholdMin1 = document.getElementById("thresholdMin1");
- const thresholdMax0 = document.getElementById("thresholdMax0");
- const thresholdMax1 = document.getElementById("thresholdMax1");
- if (thresholdMin0 && thresholdMin0.value !== thresholdMinPreference) {
- thresholdMinPreference = thresholdMin0.value || thresholdMinPreference || defaultMin;
- GM.setValue("minThreshold", thresholdMinPreference);
- } else if (thresholdMin1 && thresholdMin1.value !== thresholdMinPreference) {
- thresholdMinPreference = thresholdMin1.value || thresholdMinPreference || defaultMin;
- GM.setValue("minThreshold", thresholdMinPreference);
- }
- if (parseInt(thresholdMinPreference) > parseInt(thresholdMaxPreference)) {
- thresholdMaxPreference = thresholdMinPreference;
- if (thresholdMax0) thresholdMax0.value = thresholdMaxPreference;
- if (thresholdMax1) thresholdMax1.value = thresholdMaxPreference;
- GM.setValue("maxThreshold", thresholdMaxPreference);
- }
- if (thresholdMax0 && thresholdMax0.value !== thresholdMaxPreference) {
- thresholdMaxPreference =
- thresholdMax0.value || thresholdMaxPreference || defaultMax;
- GM.setValue("maxThreshold", thresholdMaxPreference);
- } else if (thresholdMax1 && thresholdMax1.value !== thresholdMaxPreference) {
- thresholdMaxPreference =
- thresholdMax1.value || thresholdMaxPreference || defaultMax;
- GM.setValue("maxThreshold", thresholdMaxPreference);
- }
- if (parseInt(thresholdMinPreference) > parseInt(thresholdMaxPreference)) {
- thresholdMinPreference = thresholdMaxPreference;
- GM.setValue("minThreshold", thresholdMinPreference);
- }
- if (thresholdMin0) thresholdMin0.value = thresholdMinPreference;
- if (thresholdMin1) thresholdMin1.value = thresholdMinPreference;
- if (thresholdMax0) thresholdMax0.value = thresholdMaxPreference;
- if (thresholdMax1) thresholdMax1.value = thresholdMaxPreference;
- // Posts are upvoted, downvoted, and tagged by replies, so tabulate votes by most recent.
- const posts = [...document.getElementsByClassName("postMessage")].filter(
- (p) => !p.id.includes("_")
- );
- posts.forEach((p) => {
- p.voteScore = 0;
- if (p.tags) Object.keys(p.tags).forEach((k) => (p.tags[k].count = 0));
- else p.tags = {};
- });
- const oldTags = document.getElementsByClassName("tag");
- while (oldTags.length > 0) {
- oldTags[0].parentNode.removeChild(oldTags[0]);
- }
- for (let i = posts.length - 1; i >= 0; i--) {
- const post = posts[i];
- const op = post.parentElement.parentElement.parentElement.getElementsByClassName("postMessage")[0];
- // Parse replies to posts into votes and tags.
- let replyTo = {};
- let currentTargets = [];
- let hasData = false;
- // Segment replies by quote links
- for (let j = 0; j < post.childNodes.length; j++) {
- const node = post.childNodes[j];
- if (node.className?.startsWith("quotelink")) {
- if (hasData) {
- currentTargets = [];
- hasData = false;
- }
- let currentTarget = node.hash.substring(2);
- currentTargets.push(currentTarget);
- if (!replyTo[currentTarget]) replyTo[currentTarget] = "";
- } else if (node.data) {
- if (!currentTargets.length) {
- // Posters reply to OP by default.
- let currentTarget = op.id.substring(1);
- currentTargets = [currentTarget];
- if (!replyTo[currentTarget]) replyTo[currentTarget] = "";
- }
- currentTargets.forEach((currentTarget) => {
- replyTo[currentTarget] += node.data + " ";
- });
- hasData = true;
- }
- }
- Object.keys(replyTo).forEach((r) => {
- voteAndTag(
- post,
- replyTo[r],
- posts.find((p) => p.id.substring(1) === r)
- );
- });
- // Posts outside the user's thresholds will be hidden.
- if (post.voteScore < parseInt(thresholdMinPreference) ||
- post.voteScore > parseInt(thresholdMaxPreference)
- ) {
- if (post.parentElement.classList.contains("op")) {
- post.parentElement.parentElement.parentElement.style.display = "none";
- post.parentElement.parentElement.parentElement.nextElementSibling.style.display = "none";
- } else post.parentElement.parentElement.style.display = "none";
- } else {
- if (post.parentElement.classList.contains("op")) {
- post.parentElement.parentElement.parentElement.style = "";
- post.parentElement.parentElement.parentElement.nextElementSibling.style = "";
- } else post.parentElement.parentElement.style = "";
- // Individual posts will add a vote total and a tag cloud.
- let total = document.getElementById("total" + post.id.substring(1));
- let votes = document.getElementById("votes" + post.id.substring(1));
- if (!total) {
- const postQuote = ">>" + post.id.substring(1) + "\n";
- const upvote = document.createElement("a");
- upvote.addEventListener("click", () => {
- [...document.getElementsByTagName("textArea")].forEach((t) => {
- t.value += (t.value.includes(postQuote) ? " " : postQuote) + "+1";
- });
- });
- upvote.style = "display:inline;color:#0f0;font-weight:bolder;background-color:#888";
- upvote.innerHTML = " ⬆ ";
- const downvote = document.createElement("a");
- downvote.innerHTML = " ⬇ ";
- downvote.addEventListener("click", () => {
- [...document.getElementsByTagName("textArea")].forEach((t) => {
- t.value += (t.value.includes(postQuote) ? " " : postQuote) + "-1";
- });
- });
- downvote.style = "display:inline;color:#f00;font-weight:bolder;background-color:#888";
- total = document.createElement("div");
- total.id = "total" + post.id.substring(1);
- total.style = "display:inline;color:#222";
- votes = document.createElement("div");
- votes.id = "votes" + post.id.substring(1);
- votes.innerHTML = " ";
- votes.className = "totals";
- votes.appendChild(upvote);
- votes.appendChild(downvote);
- votes.appendChild(total);
- post.appendChild(votes);
- }
- votes.style =
- "width:40%" +
- (post.voteScore > 0
- ? ";background-color:#8f8"
- : post.voteScore < 0
- ? ";background-color:#f88"
- : "");
- total.innerHTML = " " + post.voteScore;
- Object.keys(post.tags).forEach((k) => {
- const t = post.tags[k];
- if (t.count < 1) return;
- const tag = document.createElement("div");
- tag.innerHTML = t.tag + (t.count > 1 ? " x" + t.count : "");
- tag.className = "tag";
- tag.style = "display:inline;color:#222;background-color:" + t.color;
- post.appendChild(tag);
- post.innerHTML += " ";
- });
- }
- }
- }
- GM.getValue("minThreshold", defaultMin).then(async (v) => {
- thresholdMinPreference = v || defaultMin;
- thresholdMaxPreference = (await GM.getValue("maxThreshold", defaultMax)) || defaultMax;
- updateScores();
- setTimeout(() => {
- const navLinkContainers = document.getElementsByClassName("navLinks");
- for (let i = 0; i < navLinkContainers.length; i++) {
- const mainContainer = document.createElement("div");
- mainContainer.style = "display:inline";
- if (i < 2) {
- // Threshold Min/Max textboxes will be added to the thread.
- const thresholdMin = document.createElement("input");
- thresholdMin.id = "thresholdMin" + i;
- thresholdMin.type = "number";
- thresholdMin.value = thresholdMinPreference;
- const thresholdMinLabel = document.createElement("label");
- thresholdMinLabel.for = thresholdMin.id;
- thresholdMinLabel.innerHTML = "Minimum score";
- mainContainer.innerHTML += " ";
- mainContainer.appendChild(thresholdMinLabel);
- mainContainer.innerHTML += " ";
- mainContainer.appendChild(thresholdMin);
- const thresholdMax = document.createElement("input");
- thresholdMax.id = "thresholdMax" + i;
- thresholdMax.type = "number";
- thresholdMax.value = thresholdMaxPreference;
- const thresholdMaxLabel = document.createElement("label");
- thresholdMaxLabel.for = thresholdMax.id;
- thresholdMaxLabel.innerHTML = "Max";
- mainContainer.innerHTML += " ";
- mainContainer.appendChild(thresholdMaxLabel);
- mainContainer.innerHTML += " ";
- mainContainer.appendChild(thresholdMax);
- }
- navLinkContainers[i].appendChild(mainContainer);
- }
- updateScores();
- setInterval(updateScores, 2000);
- }, 3500);
- });
Add Comment
Please, Sign In to add comment