AO3: Reorder Fandoms by Size

Sorts fandoms by no. of works on AO3's fandoms list.

  1. // ==UserScript==
  2. // @name AO3: Reorder Fandoms by Size
  3. // @namespace adustyspectacle
  4. // @description Sorts fandoms by no. of works on AO3's fandoms list.
  5. // @version 1.2
  6. // @history 1.2 - added exclude rule for the uncategorized fandoms page
  7. // @history 1.1 - added another range because marvel broke 250k
  8. // @history 1.0 - initial release
  9. // @grant none
  10. // @include *archiveofourown.org/media/*
  11. // @exclude *archiveofourown.org/media/Uncategorized*
  12. // ==/UserScript==
  13.  
  14.  
  15. function insertBefore(el, referenceNode) {
  16. referenceNode.parentNode.insertBefore(el, referenceNode);
  17. }
  18.  
  19. function insertAfter(el, referenceNode) {
  20. referenceNode.parentNode.insertBefore(el, referenceNode.nextSibling);
  21. }
  22.  
  23. function numShorten(i) {
  24. if (i >= 1000000000) return (i/1000000000).toLocaleString().replace(".", "_") + "b";
  25. else if (i >= 1000000) return (i/1000000).toLocaleString().replace(".", "_") + "m";
  26. else if (i >= 1000) return (i/1000).toLocaleString().replace(".", "_") + "k";
  27. else return i.toLocaleString();
  28. }
  29.  
  30. function changeAlphabetNavId() {
  31. var alphabetNav = document.getElementById("alphabet");
  32. alphabetNav.setAttribute("id", "alphabet-nav");
  33. }
  34.  
  35. function createReorderOptions() {
  36. var reorderOptionsForm = document.createElement("form");
  37. var reorderOptionsFieldset = document.createElement("fieldset");
  38. var reorderOptionsLegend = document.createElement("legend");
  39. insertAfter(reorderOptionsForm, document.querySelector("#main.fandoms-index p"));
  40. reorderOptionsForm.setAttribute("id", "reorder-options");
  41. reorderOptionsForm.setAttribute("class", "verbose");
  42. reorderOptionsLegend.innerHTML = "Sorting Options";
  43. reorderOptionsFieldset.appendChild(reorderOptionsLegend);
  44. reorderOptionsForm.appendChild(reorderOptionsFieldset);
  45. }
  46.  
  47. var alphabetGroup = document.querySelectorAll("ol.fandom.index.group");
  48. var numericalGroup = alphabetGroup[0].cloneNode(false);
  49. numericalGroup.classList.add("sort-by-fandomsize")
  50. insertAfter(numericalGroup, alphabetGroup[0]);
  51.  
  52. var fandomSizeRanges = [
  53.  
  54. [1000000, 1250000],
  55. [750000, 1000000],
  56. [500000, 750000],
  57. [250000, 500000],
  58. [100000, 250000],
  59. [50000, 100000],
  60. [25000, 50000],
  61. [10000, 25000],
  62. [5000, 10000],
  63. [1000, 5000],
  64. [500, 1000],
  65. [100, 500],
  66. [50, 100],
  67. [25, 50],
  68. [10, 25],
  69. [5, 10],
  70. [2, 5],
  71. [1, 1]
  72. ]
  73.  
  74. if (alphabetGroup[0] != undefined && alphabetGroup[0].classList.contains("sort-by-alphabet") == false) {
  75. alphabetGroup[0].classList.add("sort-by-alphabet");
  76. var fandomList = document.querySelectorAll("ul.tags.index.group > li");
  77. var numericalList = [];
  78.  
  79. function extractLinkcounts(e) {
  80. var t = fandomList[e].innerHTML;
  81. var n = t.indexOf("</a>") + 4;
  82. var r = fandomList[e].querySelector('a').getAttribute('href');
  83. var i = t.slice(t.indexOf(">") + 1, t.lastIndexOf("<"));
  84. var s = t.substr(n);
  85. var o = s.slice(s.indexOf("(") + 1, s.indexOf(")"));
  86. numericalList.push({
  87. href: r,
  88. text: i,
  89. count: +o
  90. })
  91. }
  92. for (var i = 0; i < fandomList.length; i++) {
  93. extractLinkcounts(i);
  94. }
  95. numericalList.sort(function(e, t) {
  96. return t.count - e.count
  97. });
  98. var alphabetElems = document.querySelectorAll("#alphabet, .sort-by-alphabet");
  99. for (var i = 0; i < alphabetElems.length; i++) {
  100. alphabetElems[i].setAttribute("style", "display: none");
  101. }
  102. var fandomNumericalGroup = [];
  103. for (var i = 0; i < fandomSizeRanges.length; i++) {
  104. var fandomNumerical = document.createElement("li");
  105. var numericalHeading = document.createElement("h3");
  106. var numericalToTop = document.querySelector("span.action.top").cloneNode(true);
  107. var numericalToTopLink = numericalToTop.querySelector("a");
  108. numericalToTop.setAttribute("style", "margin: 0 0.5em; vertical-align: 0.1em;");
  109. numericalToTopLink.setAttribute("href", "#numerical-nav");
  110. fandomNumerical.setAttribute("class", "letter listbox group");
  111. numericalHeading.setAttribute("class", "heading");
  112. fandomNumerical.setAttribute("id", "range-" + numShorten(fandomSizeRanges[i][0]) + "-" + numShorten(fandomSizeRanges[i][1]));
  113. if (fandomSizeRanges[i][0] == 1 && fandomSizeRanges[i][1] == 1) {
  114. numericalHeading.innerHTML = "1 Work";
  115. } else {
  116. numericalHeading.innerHTML = fandomSizeRanges[i][0].toLocaleString() + " - " + fandomSizeRanges[i][1].toLocaleString() + " Works";
  117. }
  118. numericalHeading.appendChild(numericalToTop);
  119. fandomNumerical.appendChild(numericalHeading);
  120. var fandomIndex = document.createElement("ul");
  121. fandomIndex.setAttribute("class", "tags index group");
  122. fandomNumerical.appendChild(fandomIndex);
  123. fandomNumericalGroup.push(fandomNumerical);
  124. }
  125. for (var i = 0; i < fandomSizeRanges.length; i++) {
  126. numericalGroup.appendChild(fandomNumericalGroup[i]);
  127. }
  128. for (var i = 0; i < numericalList.length; i++) {
  129. var fandomItem = document.createElement("li");
  130. if (i % 2 == 0) {
  131. fandomItem.setAttribute("class", "odd")
  132. } else {
  133. fandomItem.setAttribute("class", "even")
  134. }
  135. var fandomAnchor = document.createElement("a");
  136. fandomAnchor.setAttribute("href", numericalList[i].href);
  137. fandomAnchor.setAttribute("class", "tag");
  138. fandomAnchor.innerHTML = numericalList[i].text;
  139. fandomItem.appendChild(fandomAnchor);
  140. if (numericalList[i].count > 0) {
  141. var fandomCount = document.createTextNode(" (" + numericalList[i].count + ")");
  142. fandomItem.appendChild(fandomCount);
  143. }
  144. var x = fandomSizeRanges.length - 1;
  145. while (!(numericalList[i].count >= fandomSizeRanges[x][0] && numericalList[i].count <= fandomSizeRanges[x][1])) {
  146. x--;
  147. }
  148. fandomNumericalGroup[x].querySelector('ul').appendChild(fandomItem);
  149. }
  150. var numericalNav = document.createElement("ul");
  151. numericalNav.setAttribute("id", "numerical-nav");
  152. numericalNav.setAttribute("class", "alphabet actions");
  153. numericalNav.setAttribute("role", "navigation");
  154. for (var i = 0; i < fandomSizeRanges.length; i++) {
  155. var numericalNavItem = document.querySelector("#alphabet li").cloneNode(true);
  156. var numericalNavItemLink = numericalNavItem.querySelector("a");
  157. numericalNavItem.setAttribute("style", "margin: 0 0.25em;");
  158. numericalNavItemLink.setAttribute("href", "#range-" + numShorten(fandomSizeRanges[i][0]) + "-" + numShorten(fandomSizeRanges[i][1]));
  159. if (fandomSizeRanges[i][0] == 1 && fandomSizeRanges[i][1] == 1) {
  160. numericalNavItemLink.innerHTML = "1";
  161. } else {
  162. numericalNavItemLink.innerHTML = numShorten(fandomSizeRanges[i][0]) + "-" + numShorten(fandomSizeRanges[i][1]);
  163. }
  164. numericalNavItem.appendChild(numericalNavItemLink);
  165. numericalNav.appendChild(numericalNavItem);
  166. }
  167. insertBefore(numericalNav, document.getElementById("alphabet"));
  168. }