Better R34

Adds Next/Back button to rule34s Post site

  1. // ==UserScript==
  2. // @name Better R34
  3. // @namespace https://rule34.xxx/index.php
  4. // @version 0.5
  5. // @description Adds Next/Back button to rule34s Post site
  6. // @author <Nom/>#4491
  7. // @match https://rule34.xxx/index.php?page=post*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=rule34.xxx
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. //TODO: when navigating back to a post load previous postIDs & middleclick doesnt work scroll mobile scroll = next/back
  14. 'use strict';
  15.  
  16. //CONFIG:-------------------------
  17. const setKeybinds = true;
  18. //--------------------------------
  19.  
  20.  
  21. let currPostID = 0;
  22. let postIDs = localStorage.postIDs ? JSON.parse(localStorage.postIDs): [];
  23. let postOffset = localStorage.postOffset ? +JSON.parse(localStorage.postOffset) : 0;
  24.  
  25. Element.prototype.getTreeElementByClass = function(className) {
  26. if (!this.parentElement) { return null; }
  27. if (this.classList.contains(className)) { return this; }
  28. else { return this.parentElement.getTreeElementByClass(className); }
  29. }
  30.  
  31. async function createNavDiv(){
  32. let linkDiv = document.createElement("h4");
  33. linkDiv.innerHTML =
  34. `<a id="prevBtn" ${ !await getPrevPostID() ? '' : 'href=https://rule34.xxx/index.php?page=post&s=view&id='+await getPrevPostID() }><< Back</a>` +
  35. " | " +
  36. `<a id="nextBtn" ${ !await getNextPostID() ? '' : 'href=https://rule34.xxx/index.php?page=post&s=view&id='+await getNextPostID() }>Next >></a>`;
  37. linkDiv.classList.add("image-sublinks");
  38. return document.getElementsByClassName("image-sublinks")[0].insertBefore(linkDiv, null);
  39. }
  40.  
  41. async function getPrevPostID(){
  42. if(postIDs.indexOf(currPostID)-1 === -1){ //previous site or first post of search
  43. await loadPrevPostIDs();
  44. return postIDs[postIDs.indexOf(currPostID)-1];
  45. }else{
  46. return postIDs[postIDs.indexOf(currPostID)-1];
  47. }
  48. }
  49.  
  50. async function getNextPostID(){
  51. const currIndex = postIDs.indexOf(currPostID);
  52. if(currIndex+1 > postIDs.length-1){ //load more posts or last post of search
  53. await loadNextPostIDs();
  54. return postIDs[currIndex + 1];
  55. }else{
  56. return postIDs[currIndex+1];
  57. }
  58. }
  59.  
  60. async function loadNextPostIDs(){
  61. if(localStorage.prompt){
  62. const response = await fetch(`https://api.rule34.xxx/index.php?page=dapi&s=post&q=index&json=1&limit=42&pid=${(postIDs.length+postOffset)/42}&${JSON.parse(localStorage.prompt)}`)
  63. await response.json().then((jsonR) => {
  64. if(jsonR.length === 0){
  65. console.log("last post reached");
  66. return;
  67. }
  68. console.log("load next postIDs");
  69. postIDs.push(...jsonR.map((post) => post.id.toString()));
  70. localStorage.postIDs = JSON.stringify(postIDs);
  71. })
  72. }
  73. }
  74.  
  75. async function loadPrevPostIDs(){
  76. if(localStorage.prompt && postOffset > 0){
  77. console.log("load prev postIDs");
  78. const response = await fetch(`https://api.rule34.xxx/index.php?page=dapi&s=post&q=index&json=1&limit=42&pid=${(postIDs.length+postOffset)/42-2}&${JSON.parse(localStorage.prompt)}`)
  79. await response.json().then((jsonR) => {
  80. postIDs.unshift(...jsonR.map((post) => post.id.toString()));
  81. localStorage.postIDs = JSON.stringify(postIDs);
  82. });
  83. }else {
  84. console.log("first Post");
  85. }
  86. }
  87.  
  88. //MAIN:
  89. if(window.location.search.includes("s=view")){ //post-view
  90. currPostID = window.location.href.match("id=([^&]+)")[1];
  91. createNavDiv().then(() => {
  92. if(setKeybinds){
  93. window.addEventListener("keydown", (event) => {
  94. if (event.code === "ArrowLeft") {
  95. document.getElementById("prevBtn").click();
  96. } else if (event.code === "ArrowRight") {
  97. document.getElementById("nextBtn").click();
  98. }
  99. })
  100. }
  101. });
  102. } else if(window.location.search.includes("s=list")){ //list-view
  103. localStorage.removeItem("postIDs");
  104. localStorage.removeItem("prompt");
  105. localStorage.removeItem("postOffset");
  106. [...document.getElementsByClassName("thumb")].forEach((elm) => {
  107. elm.addEventListener("click", () => {
  108. const postIDs = [...document.getElementsByClassName("thumb")].map((elm) => elm.id.slice(1));
  109. localStorage.postIDs = JSON.stringify(postIDs);
  110. localStorage.prompt = JSON.stringify(window.location.href.match("tags=([^&]+)")[0]);
  111. localStorage.postOffset = JSON.stringify(window.location.href.match("pid=([^&]+)").length > 0 ? window.location.href.match("pid=([^&]+)")[1] : 0);
  112. })
  113. })
  114. }
  115. })();