Rule34 Artist favorites

A simple script to add the possibility to favorite artists to rule34

  1. // ==UserScript==
  2. // @name Rule34 Artist favorites
  3. // @description A simple script to add the possibility to favorite artists to rule34
  4. // @namespace User_314159_AFav
  5. // @version 1.32
  6. // @author User_314159
  7. // @license MIT
  8. // @match https://rule34.xxx/index.php?page=account&s=home
  9. // @match https://rule34.xxx/index.php?page=post&s=view*
  10. // @icon https://www.google.com/s2/favicons?sz=64&domain=rule34.xxx
  11. // @grant none
  12. // ==/UserScript==
  13.  
  14. /* Functions used to interact with the local storage */
  15. function getArtists() { // gets the localstorage array and parses it into an actual array, creates a new one if there is no key in localStorage
  16. let artists;
  17. if (localStorage.getItem('rule34FavArtists') === null) {
  18. console.log('generated new artists array');
  19. artists = [];
  20. saveArtists(artists);
  21. }
  22. else {
  23. artists = JSON.parse(localStorage.getItem('rule34FavArtists'));
  24. }
  25. return artists;
  26. }
  27.  
  28. function deleteArtist(artist) { // deletes the specified artist out of the array and saves it
  29. let artists = getArtists();
  30. let target = artists.indexOf(artist);
  31. artists.splice(target, 1);
  32. saveArtists(artists);
  33. console.log('Deleted ' + artist);
  34. }
  35.  
  36. function saveArtists(artists) { // saves an updated version of the artists to local storage
  37. localStorage.setItem('rule34FavArtists', JSON.stringify(artists.sort()));
  38. }
  39.  
  40. function exportArtists() { // gets the local storage and logs it to the console as a string
  41. let artists = localStorage.getItem('rule34FavArtists');
  42. console.log(artists); // Don't need to stringify here the localstorage got it stringified
  43. navigator.clipboard.writeText(artists);
  44. alert("Copied artists to clipboard");
  45. }
  46.  
  47. function importArtists() { // takes an inputted array string and overwrites the local storage with it
  48. let input = window.prompt("Enter previously exported artists"); // window.prompt seems to return a double-escaped string
  49. let data = JSON.parse(input); // due to this, we need to de-escape twice to get the actual json
  50. let current_artists = getArtists();
  51. for(let index = 0; index < data.length; index++) {
  52. if(current_artists.includes(data[index])) {
  53. continue;
  54. } else {
  55. current_artists.push(data[index]);
  56. console.log("New artist: " + data[index]);
  57. }
  58. }
  59. localStorage.setItem('rule34FavArtists', JSON.stringify(current_artists));
  60. }
  61.  
  62. /* These are the functions for the Favorites displaying */
  63. function generateArtistEntry(name) { // generates a container with a delete button calling the deleteArtist function and a link to the artist page
  64. let link = document.createElement('a');
  65. let deleteButton = document.createElement('button');
  66. let container = document.createElement('div');
  67.  
  68. deleteButton.innerHTML = 'delete';
  69. deleteButton.setAttribute('id', 'artistFavDel');
  70. link.innerHTML = name;
  71.  
  72. link.setAttribute('href', 'https://rule34.xxx/index.php?page=post&s=list&tags=' + name);
  73. deleteButton.setAttribute('name', name);
  74.  
  75. deleteButton.addEventListener("click", function () {
  76. deleteArtist(name)
  77. }, false);
  78.  
  79. container.appendChild(deleteButton);
  80. container.appendChild(link);
  81.  
  82. return container;
  83. }
  84.  
  85. /* Functions for the adding of artists to the favorites */
  86. function generateAddButton(name) { // generates a button that is added to the bottom of the post to add an artist
  87. var button = document.createElement('button');
  88. button.innerHTML = ('Add ' + name + ' to favorites');
  89. button.addEventListener("click", function () {
  90. addArtist(name)
  91. }, false);
  92. return button;
  93. }
  94.  
  95. function generateArtistAddable() { // adds the artists as single buttons to the bottom of the page, the buttons are generated in the generateAddButton function
  96. let possibles = document.getElementsByClassName('tag-type-artist tag');
  97. let artists = document.getElementsByClassName('link-list')[0];
  98. for (let i = 0; i < possibles.length; i++) {
  99. let artist = possibles[i].children[1].firstChild.data.split(' ').join('_'); // this hell of a selector is the name of the artist with the spaces replaced with underscores
  100. console.log(artist);
  101. artists.appendChild(generateAddButton(artist));
  102. }
  103.  
  104. }
  105.  
  106. function addArtist(artist) { // adds the name of the artist to the array and saves the array, cancels if the artist already is in the most recent save
  107. let artists = getArtists();
  108. if (artists.includes(artist)) {
  109. console.log(artist + ' already in favorites.');
  110. return;
  111. }
  112. artists.push(artist);
  113. saveArtists(artists);
  114. console.log('Added ' + artist + ' to favorites');
  115.  
  116. }
  117.  
  118. /* Main Function */
  119. (function () {
  120. 'use strict';
  121.  
  122. let url = window.location.href;
  123. if (url.includes('page=post&s=view')) {
  124. generateArtistAddable();
  125. }; // this part checks if you are on a post and if so, the 'add to favorites' gets added
  126. if (url.includes('&s=home')) {
  127. let artists = getArtists(); // gets the artists and parses them from a string to an iterable
  128. let favoritesHeader = document.createElement('h4'); //header 4 element
  129. let favoritesCollapse = document.createElement('details'); // collapsible list of favorites
  130. let favoritesTitle = document.createElement('summary'); // title element of the collapsible
  131. let exp = document.createElement('button');
  132. let imp = document.createElement('button');
  133. // the two buttons are for import and export
  134. exp.addEventListener("click", function () {
  135. exportArtists();
  136. }, false);
  137. imp.addEventListener("click", function () {
  138. importArtists();
  139. location.reload();
  140. }, false);
  141. imp.innerHTML = 'Import';
  142. exp.innerHTML = 'Export';
  143. // the buttons values get declared and the onclick functions get set to the export / import functions
  144.  
  145. favoritesTitle.innerHTML = 'Favorite Artists'; //setting the title
  146. for (let i = 0; i < artists.length; i++) {
  147. favoritesCollapse.appendChild(generateArtistEntry(artists[i]));
  148. } // this adds one link for each favorite artist to the collapsible
  149.  
  150. let desc = document.createElement('p'); //description, paragraph element
  151. desc.innerHTML = 'View all of your favorite artists and remove them if you wish.';
  152.  
  153. favoritesCollapse.appendChild(favoritesTitle); // the title of the collapsible gets added
  154.  
  155. favoritesHeader.appendChild(favoritesCollapse); // the collapsible gets added to the main container
  156.  
  157. let mainPosts = document.getElementById("user-index").lastElementChild; // the last child of the user-index div is gotten, which is the "To main post page"
  158. let space = document.getElementById('user-index'); // the space variable is the container element for the whole thing
  159.  
  160. space.insertBefore(favoritesHeader, mainPosts); // main container for the artist entries
  161. space.insertBefore(desc, mainPosts); // the description
  162. space.insertBefore(exp, mainPosts); // export button
  163. space.insertBefore(imp, mainPosts); // import button
  164. if (artists.length > 0) { // this adds a button that resets the data if there is any data
  165. let delete_all_artists = document.createElement('button');
  166. delete_all_artists.addEventListener("click", function () {
  167. if(window.confirm("WARNING: This will delete all favourites and cannot be undone")) {
  168. if(window.confirm("Are you sure?")) {
  169. localStorage.removeItem('rule34FavArtists');
  170. console.log("removed all favorites");
  171. alert("To confirm reset, reload the page");
  172. return;
  173. }
  174. }
  175. console.log('cancelled reset'); // this only executes if one of the confirms were cancelled because of the return
  176. }, false);
  177. delete_all_artists.innerHTML = 'Reset';
  178. space.insertBefore(delete_all_artists, mainPosts);
  179. }
  180. // this block just adds all the objects to the page before the "To main post page" link
  181. }
  182. })();