Advertisement
Snuggledash

4chan Post Randomizer

May 23rd, 2018
1,355
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name         4chan Post Randomizer
  3. // @namespace    http://www.4chan.org/
  4. // @version      0.8
  5. // @description  Adds a button that redirects to a random post on a random board
  6. // @include      http://boards.4chan.org/*
  7. // @include      https://boards.4chan.org/*
  8. // @grant        none
  9. // @run-at       document-end
  10. // ==/UserScript==
  11.  
  12. function insertBefore(node, reference) {
  13.   if (node && reference !== null) {
  14.     reference.parentNode.insertBefore(node, reference);
  15.     return true;
  16.   } else {
  17.     return false;
  18.   }
  19. }
  20.  
  21. function insertAfter(node, reference) {
  22.   if (reference !== null) {
  23.     if (reference.nextSibling) {
  24.       return insertBefore(node, reference.nextSibling);
  25.     } else {
  26.       return node && reference.parentNode.appendChild(node);
  27.     }
  28.   } else {
  29.     return false;
  30.   }
  31. }
  32.  
  33. // use fancy mobile-like buttons on 4chan X, simple HTML form button otherwise
  34. var is_4chanx = document.documentElement.classList.contains('fourchan-x');
  35. if (is_4chanx) {
  36.   var randomizer_button = document.createElement('a');
  37.   randomizer_button.classList.add('qr-link');
  38.   // dummy href like original button
  39.   randomizer_button.href = 'javascript:;';
  40.   var randomizer_container = document.createElement('div');
  41.   randomizer_container.classList.add('qr-link-container');
  42.   // always force visible (Onee-Chan hides the quicklink by default)
  43.   randomizer_container.style['display'] = 'block';
  44.   // no extra margins please
  45.   randomizer_container.appendChild(randomizer_button);
  46. } else {
  47.   var randomizer_button = document.createElement('button');
  48.   randomizer_button.style['display'] = 'block';
  49.   randomizer_button.style['margin-left'] = 'auto';
  50.   randomizer_button.style['margin-right'] = 'auto';
  51.   randomizer_button.style['margin-bottom'] = '8px';
  52.   randomizer_button.style['font-family'] = 'inherit';
  53.   var randomizer_container = randomizer_button;
  54. }
  55. randomizer_button.setAttribute('id', 'throwthedice');
  56. randomizer_button.appendChild(document.createTextNode('Go to Random Post'));
  57. // insert below blotter, or the full-width <hr> on /f/, or "Back to (board)" link on the 404 page
  58. if (location.pathname.startsWith('/f/')) {
  59.   if (!insertAfter(randomizer_container, document.querySelector('form[name="post"]'))) {
  60.     console.log('Could not find insertion anchor on /f/!');
  61.     return;
  62.   }
  63. // hehe, lambda bracket mayhem
  64. } else if ((() => {
  65.   var boxbar = document.querySelector('div.boxbar > h2');
  66.   return boxbar !== null && (boxbar.textContent === '404 Not Found' ||
  67.                              boxbar.textContent === '403 Forbidden')})()) {
  68.   var insert_parent = document.querySelector('.boxcontent');
  69.   if (insert_parent !== null && insertAfter(randomizer_container, insert_parent.lastChild)) {
  70.     // 4chan X does not apply styles to error pages
  71.     if (is_4chanx) {
  72.       randomizer_container.classList.remove('qr-link-container');
  73.       randomizer_container.style['text-align'] = 'center';
  74.       // DOM functions not invented here, or at least one reason to keep insertBefore around :P
  75.       insertBefore(document.createTextNode('['), randomizer_container.firstChild);
  76.       insertAfter(document.createTextNode(']'), randomizer_container.lastChild);
  77.     }
  78.   } else {
  79.     console.log('Could not find insertion anchor on error page!');
  80.     return;
  81.   }
  82. // native catalog -- 4chan X catalog mode behaves like index page
  83. } else if (location.pathname.endsWith('/catalog')) {
  84.   if (!insertAfter(randomizer_container, document.querySelector('body > form'))) {
  85.     console.log('Could not find insertion anchor on catalog!');
  86.     return;
  87.   }
  88. } else {
  89.   if (!insertAfter(randomizer_container, document.querySelector('body > hr.aboveMidAd'))) {
  90.     console.log('Could not find insertion anchor on board!');
  91.     return;
  92.   }
  93. }
  94.  
  95. randomizer_button.addEventListener('click', function() {
  96.   randomizer_button.textContent = 'Picking random board...';
  97.   var xhr = new XMLHttpRequest();
  98.   // cascaded re-use of the XMLHttpRequest for the board list, catalog and thread
  99.   xhr.open('GET', '//a.4cdn.org/boards.json');
  100.   xhr.onreadystatechange = function() {
  101.     if (xhr.readyState == 4 && xhr.status == 200 && xhr.getResponseHeader("Content-Type") == "application/json") {
  102.       var boards = JSON.parse(xhr.response)['boards'].map(b => b.board);
  103.       var random_board = boards[Math.floor(boards.length * Math.random())];
  104.       randomizer_button.textContent = 'Picking random thread on /' + random_board + '/...';
  105.       xhr.open('GET', '//a.4cdn.org/' + random_board + '/catalog.json');
  106.       xhr.onreadystatechange = function() {
  107.         if (xhr.readyState == 4 && xhr.status == 200 && xhr.getResponseHeader("Content-Type") == "application/json") {
  108.           var threads = JSON.parse(xhr.response).map(page => page['threads'].map(thread => thread['no'])).reduce((p1, p2) => p1.concat(p2), []).slice(-150);
  109.           var random_thread = threads[Math.floor(threads.length * Math.random())];
  110.           randomizer_button.textContent = 'Picking random post in thread...';
  111.           xhr.open('GET', '//a.4cdn.org/' + random_board + '/thread/' + random_thread + '.json');
  112.           xhr.onreadystatechange = function() {
  113.             if (xhr.readyState == 4 && xhr.status == 200 && xhr.getResponseHeader("Content-Type") == "application/json") {
  114.               var posts = JSON.parse(xhr.response)['posts'].map(p => p.no);
  115.               var redirect_link = '//boards.4chan.org/' + random_board + '/thread/' + random_thread;
  116.               var post_index = Math.floor(posts.length * Math.random());
  117.               if (post_index > 0) {
  118.                 redirect_link += '#p' + posts[post_index];
  119.               }
  120.               randomizer_button.textContent = 'Off we go!';
  121.               location.href = redirect_link;
  122.             }
  123.           };
  124.           xhr.send();
  125.         }
  126.       };
  127.       xhr.send();
  128.     }
  129.   };
  130.   xhr.send();
  131. });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement