Guest User

Untitled

a guest
Jun 1st, 2022
38
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name     4chan2reddit
  3. // @grant GM.getValue
  4. // @grant GM.setValue
  5. // @version  1
  6. // @description Destroy free speech and rely on the discernment of children
  7. // @include      *://boards.4chan.org/*
  8. // @include      *://boards.4channel.org/*
  9. // ==/UserScript==
  10.  
  11. // User preferences will be loaded.
  12. const defaultMin = "-10";
  13. const defaultMax = "10";
  14. var thresholdMinPreference = defaultMin;
  15. var thresholdMaxPreference = defaultMax;
  16.  
  17. function generateRandomColor() {
  18.   return `rgb(${Math.floor((Math.random() * 256 + 255) / 2)},${Math.floor((Math.random() * 256 + 255) / 2)},${Math.floor((Math.random() * 256 + 255) / 2)})`;
  19. }
  20.  
  21. // The script will read posts and apply rules when it sees "+1", "-1", and #hashtags.
  22. 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;
  23. 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;
  24. const tagSearchQuery = /[^0-9a-z]#([0-9a-z]{2,})/gi;
  25.  
  26. function voteAndTag(reply, replyText, post) {
  27.   if (!post || !replyText) return;
  28.   replyText = ` ${replyText} `;
  29.   const upvoted = replyText.match(upvoteFilter);
  30.   const downvoted = replyText.match(downvoteFilter);
  31.   const tags = replyText.match(tagSearchQuery);
  32.   if (post !== reply)
  33.     if (upvoted && (!replyText.includes("-1") || replyText.includes("+1"))) post.voteScore++;
  34.     else if (downvoted) post.voteScore--;
  35.   for (let i = 0; i < tags?.length; i++) {
  36.     const tag = post.tags[tags[i].toString().trim().toLowerCase()] || {
  37.       tag: tags[i].toString().trim(),
  38.       count: 0,
  39.       color: generateRandomColor(),
  40.     };
  41.     tag.count++;
  42.     post.tags[tags[i].toString().trim().toLowerCase()] = tag;
  43.   }
  44. }
  45.  
  46. function updateScores() {
  47.   // User preferences will be stored.
  48.   const thresholdMin0 = document.getElementById("thresholdMin0");
  49.   const thresholdMin1 = document.getElementById("thresholdMin1");
  50.   const thresholdMax0 = document.getElementById("thresholdMax0");
  51.   const thresholdMax1 = document.getElementById("thresholdMax1");
  52.  
  53.   if (thresholdMin0 && thresholdMin0.value !== thresholdMinPreference) {
  54.     thresholdMinPreference = thresholdMin0.value || thresholdMinPreference || defaultMin;
  55.     GM.setValue("minThreshold", thresholdMinPreference);
  56.   } else if (thresholdMin1 && thresholdMin1.value !== thresholdMinPreference) {
  57.     thresholdMinPreference = thresholdMin1.value || thresholdMinPreference || defaultMin;
  58.     GM.setValue("minThreshold", thresholdMinPreference);
  59.   }
  60.  
  61.   if (parseInt(thresholdMinPreference) > parseInt(thresholdMaxPreference)) {
  62.     thresholdMaxPreference = thresholdMinPreference;
  63.     if (thresholdMax0) thresholdMax0.value = thresholdMaxPreference;
  64.     if (thresholdMax1) thresholdMax1.value = thresholdMaxPreference;
  65.     GM.setValue("maxThreshold", thresholdMaxPreference);
  66.   }
  67.  
  68.   if (thresholdMax0 && thresholdMax0.value !== thresholdMaxPreference) {
  69.     thresholdMaxPreference =
  70.       thresholdMax0.value || thresholdMaxPreference || defaultMax;
  71.     GM.setValue("maxThreshold", thresholdMaxPreference);
  72.   } else if (thresholdMax1 && thresholdMax1.value !== thresholdMaxPreference) {
  73.     thresholdMaxPreference =
  74.       thresholdMax1.value || thresholdMaxPreference || defaultMax;
  75.     GM.setValue("maxThreshold", thresholdMaxPreference);
  76.   }
  77.  
  78.   if (parseInt(thresholdMinPreference) > parseInt(thresholdMaxPreference)) {
  79.     thresholdMinPreference = thresholdMaxPreference;
  80.     GM.setValue("minThreshold", thresholdMinPreference);
  81.   }
  82.  
  83.   if (thresholdMin0) thresholdMin0.value = thresholdMinPreference;
  84.   if (thresholdMin1) thresholdMin1.value = thresholdMinPreference;
  85.   if (thresholdMax0) thresholdMax0.value = thresholdMaxPreference;
  86.   if (thresholdMax1) thresholdMax1.value = thresholdMaxPreference;
  87.  
  88.   // Posts are upvoted, downvoted, and tagged by replies, so tabulate votes by most recent.
  89.   const posts = [...document.getElementsByClassName("postMessage")].filter(
  90.     (p) => !p.id.includes("_")
  91.   );
  92.   posts.forEach((p) => {
  93.     p.voteScore = 0;
  94.     if (p.tags) Object.keys(p.tags).forEach((k) => (p.tags[k].count = 0));
  95.     else p.tags = {};
  96.   });
  97.   const oldTags = document.getElementsByClassName("tag");
  98.   while (oldTags.length > 0) {
  99.     oldTags[0].parentNode.removeChild(oldTags[0]);
  100.   }
  101.   for (let i = posts.length - 1; i >= 0; i--) {
  102.     const post = posts[i];
  103.     const op = post.parentElement.parentElement.parentElement.getElementsByClassName("postMessage")[0];
  104.     // Parse replies to posts into votes and tags.
  105.     let replyTo = {};
  106.     let currentTargets = [];
  107.     let hasData = false;
  108.     // Segment replies by quote links
  109.     for (let j = 0; j < post.childNodes.length; j++) {
  110.       const node = post.childNodes[j];
  111.       if (node.className?.startsWith("quotelink")) {
  112.         if (hasData) {
  113.           currentTargets = [];
  114.           hasData = false;
  115.         }
  116.         let currentTarget = node.hash.substring(2);
  117.         currentTargets.push(currentTarget);
  118.         if (!replyTo[currentTarget]) replyTo[currentTarget] = "";
  119.       } else if (node.data) {
  120.         if (!currentTargets.length) {
  121.           // Posters reply to OP by default.
  122.           let currentTarget = op.id.substring(1);
  123.           currentTargets = [currentTarget];
  124.           if (!replyTo[currentTarget]) replyTo[currentTarget] = "";
  125.         }
  126.         currentTargets.forEach((currentTarget) => {
  127.           replyTo[currentTarget] += node.data + " ";
  128.         });
  129.         hasData = true;
  130.       }
  131.     }
  132.     Object.keys(replyTo).forEach((r) => {
  133.       voteAndTag(
  134.         post,
  135.         replyTo[r],
  136.         posts.find((p) => p.id.substring(1) === r)
  137.       );
  138.     });
  139.  
  140.     // Posts outside the user's thresholds will be hidden.
  141.     if (post.voteScore < parseInt(thresholdMinPreference) ||
  142.       post.voteScore > parseInt(thresholdMaxPreference)
  143.     ) {
  144.       if (post.parentElement.classList.contains("op")) {
  145.         post.parentElement.parentElement.parentElement.style.display = "none";
  146.         post.parentElement.parentElement.parentElement.nextElementSibling.style.display = "none";
  147.       } else post.parentElement.parentElement.style.display = "none";
  148.     } else {
  149.       if (post.parentElement.classList.contains("op")) {
  150.         post.parentElement.parentElement.parentElement.style = "";
  151.         post.parentElement.parentElement.parentElement.nextElementSibling.style = "";
  152.       } else post.parentElement.parentElement.style = "";
  153.       // Individual posts will add a vote total and a tag cloud.
  154.       let total = document.getElementById("total" + post.id.substring(1));
  155.       let votes = document.getElementById("votes" + post.id.substring(1));
  156.       if (!total) {
  157.         const postQuote = ">>" + post.id.substring(1) + "\n";
  158.         const upvote = document.createElement("a");
  159.         upvote.addEventListener("click", () => {
  160.           [...document.getElementsByTagName("textArea")].forEach((t) => {
  161.             t.value += (t.value.includes(postQuote) ? " " : postQuote) + "+1";
  162.           });
  163.         });
  164.         upvote.style = "display:inline;color:#0f0;font-weight:bolder;background-color:#888";
  165.         upvote.innerHTML = "&nbsp;⬆&nbsp;";
  166.         const downvote = document.createElement("a");
  167.         downvote.innerHTML = "&nbsp;⬇&nbsp;";
  168.         downvote.addEventListener("click", () => {
  169.           [...document.getElementsByTagName("textArea")].forEach((t) => {
  170.             t.value += (t.value.includes(postQuote) ? " " : postQuote) + "-1";
  171.           });
  172.         });
  173.         downvote.style = "display:inline;color:#f00;font-weight:bolder;background-color:#888";
  174.         total = document.createElement("div");
  175.         total.id = "total" + post.id.substring(1);
  176.         total.style = "display:inline;color:#222";
  177.         votes = document.createElement("div");
  178.         votes.id = "votes" + post.id.substring(1);
  179.         votes.innerHTML = " ";
  180.         votes.className = "totals";
  181.         votes.appendChild(upvote);
  182.         votes.appendChild(downvote);
  183.         votes.appendChild(total);
  184.         post.appendChild(votes);
  185.       }
  186.       votes.style =
  187.         "width:40%" +
  188.         (post.voteScore > 0
  189.           ? ";background-color:#8f8"
  190.           : post.voteScore < 0
  191.           ? ";background-color:#f88"
  192.           : "");
  193.       total.innerHTML = "&nbsp;" + post.voteScore;
  194.         Object.keys(post.tags).forEach((k) => {
  195.           const t = post.tags[k];
  196.           if (t.count < 1) return;
  197.           const tag = document.createElement("div");
  198.           tag.innerHTML = t.tag + (t.count > 1 ? " x" + t.count : "");
  199.           tag.className = "tag";
  200.           tag.style = "display:inline;color:#222;background-color:" + t.color;
  201.           post.appendChild(tag);
  202.           post.innerHTML += " ";
  203.         });
  204.     }
  205.   }
  206. }
  207.  
  208. GM.getValue("minThreshold", defaultMin).then(async (v) => {
  209.   thresholdMinPreference = v || defaultMin;
  210.   thresholdMaxPreference = (await GM.getValue("maxThreshold", defaultMax)) || defaultMax;
  211.   updateScores();
  212.   setTimeout(() => {
  213.     const navLinkContainers = document.getElementsByClassName("navLinks");
  214.     for (let i = 0; i < navLinkContainers.length; i++) {
  215.       const mainContainer = document.createElement("div");
  216.       mainContainer.style = "display:inline";
  217.       if (i < 2) {
  218.         // Threshold Min/Max textboxes will be added to the thread.
  219.         const thresholdMin = document.createElement("input");
  220.         thresholdMin.id = "thresholdMin" + i;
  221.         thresholdMin.type = "number";
  222.         thresholdMin.value = thresholdMinPreference;
  223.         const thresholdMinLabel = document.createElement("label");
  224.         thresholdMinLabel.for = thresholdMin.id;
  225.         thresholdMinLabel.innerHTML = "Minimum score";
  226.         mainContainer.innerHTML += " ";
  227.         mainContainer.appendChild(thresholdMinLabel);
  228.         mainContainer.innerHTML += " ";
  229.         mainContainer.appendChild(thresholdMin);
  230.         const thresholdMax = document.createElement("input");
  231.         thresholdMax.id = "thresholdMax" + i;
  232.         thresholdMax.type = "number";
  233.         thresholdMax.value = thresholdMaxPreference;
  234.         const thresholdMaxLabel = document.createElement("label");
  235.         thresholdMaxLabel.for = thresholdMax.id;
  236.         thresholdMaxLabel.innerHTML = "Max";
  237.         mainContainer.innerHTML += " ";
  238.         mainContainer.appendChild(thresholdMaxLabel);
  239.         mainContainer.innerHTML += " ";
  240.         mainContainer.appendChild(thresholdMax);
  241.       }
  242.       navLinkContainers[i].appendChild(mainContainer);
  243.     }
  244.     updateScores();
  245.     setInterval(updateScores, 2000);
  246.   }, 3500);
  247. });
Add Comment
Please, Sign In to add comment