Reddit - Subs - default sort

Apply default sort to subs listing (feature missing in SHreddit)

当前为 2025-01-23 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Reddit - Subs - default sort
  3. // @namespace https://github.com/Procyon-b
  4. // @version 0.5
  5. // @description Apply default sort to subs listing (feature missing in SHreddit)
  6. // @author Achernar
  7. // @match https://www.reddit.com/*
  8. // @run-at document-start
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. "use strict";
  14.  
  15. var sort={};
  16.  
  17. const RE=/^(?:https:\/\/(?:sh|www)\.reddit\.com)?(\/(?:r\/[^\/]+\/)?)(?:(best|new|hot|top|rising)\/)?(?:\?.*)?$/;
  18. const REval=/^(best|new|hot|top|rising)?$/;
  19. var SR=[];
  20.  
  21. var done=false;
  22. function init() {
  23. if (done) return;
  24. done=true;
  25. document && document.body && chk();
  26. newObs(document.body);
  27. window.addEventListener('focus', function(){
  28. if (load()) {
  29. chk(null, true);
  30. updLeftNav();
  31. }
  32. });
  33.  
  34. if (window == top) {
  35. var e=document.createElement('div');
  36. e.style='position: fixed; top: 0; left: 0; width: 15px; height: 15px; z-index: 9999;';
  37. document.body.appendChild(e);
  38. e.ondblclick=function(){
  39. var p, s='';
  40.  
  41. do {
  42. p=prompt(s+'Default sort\nChoose between: [empty] - hot - new - top - rising', sort.default);
  43. if (p == null) break;
  44. s='ERROR. Invalid value.\nTry again\n';
  45. } while (!REval.test(p));
  46.  
  47. if (p != null) {
  48. if (p) sort.default=p;
  49. else delete sort.default;
  50. store();
  51. chk(null, true);
  52. updLeftNav();
  53. }
  54.  
  55. p=prompt('Auto-redirect to correct sort ?\nEither: [empty field] - true - force - ask', sort.redir);
  56. if (p != null) {
  57. if (p) sort.redir = p;
  58. else delete sort.redir;
  59. store();
  60. }
  61.  
  62. };
  63. }
  64. }
  65.  
  66. function gen(re) {
  67. var s=sort[re[1]] || '';
  68. if (s) s+='/';
  69. else if ((re[1] != '/') && sort.default) s=sort.default+'/';
  70. return s;
  71. }
  72.  
  73. function chk(r, force=false) {
  74. var a=(r||document).getElementsByTagName("a");
  75. if (r && (r.nodeName == 'A')) a=[r, ...a];
  76. for (let i=0,e; e=a[i]; i++) {
  77. if (!force && e._sortfixed) continue;
  78. e._sortfixed=true;
  79. if (e.hostname == 'www.reddit.com') {
  80. let re;
  81. if (re=RE.exec(e.pathname + (!e.pathname.endsWith('/') ? '/':'' ) )) {
  82. if (e.closest('[slot="dropdown-items"], faceplate-dropdown-menu')) continue;
  83. e.classList.add('_marked_');
  84. let s=gen(re);
  85. e.pathname=re[1]+s;
  86. }
  87. }
  88. }
  89. a=(r||document).querySelectorAll('pdp-back-button[subreddit-prefixed-name]');
  90. for (let i=0,e; e=a[i]; i++) {
  91. if (!force && e._sortfixed) continue;
  92. e._sortfixed=true;
  93. let re, v=e.attributes['subreddit-prefixed-name'].value;
  94. if (re=RE.exec('/'+v+'/')) {
  95. e.classList.add('_marked_');
  96. let s=gen(re);
  97. e.attributes['subreddit-prefixed-name'].value=(re[1]+s).replace(/^\/(.+)\/$/, "$1");
  98. }
  99. }
  100. }
  101.  
  102. var AS=HTMLElement.prototype.attachShadow;
  103. HTMLElement.prototype.attachShadow=function(m){/*[native */
  104. var e=this;
  105. let sr=AS.call(e,m);
  106.  
  107. if (e.tagName == 'REDDIT-RECENT-PAGES') {
  108. SR.push(sr);
  109. newObs(sr, cbRec);
  110. e.SR=true;
  111. }
  112. else if (e.tagName.startsWith('LEFT-NAV-') || (e.tagName == 'SHREDDIT-SUBREDDIT-HEADER') || (e.tagName == 'MOD-NAV') ) {
  113. SR.push(sr);
  114. newObs(sr);
  115. e.SR=true;
  116. }
  117. return sr;
  118. }
  119.  
  120. function updLeftNav() {
  121. for(let r, i=0; r=SR[i]; i++) {
  122. for(let e, j=0; e=r.children[j]; j++) {
  123. chk(e, true);
  124. }
  125. }
  126. }
  127.  
  128. function ds(sub, s) {
  129. let d= sub == '/' ? 'best' : (sort.default?'DEF':'');
  130. return s == d ? '' : s;
  131. }
  132.  
  133. function patchFetch() {
  134. // XHR - Fetch
  135. const _fetch=window.fetch;
  136. window.fetch = async (...args) => {
  137. let [resource, config ] = args;
  138. let response = await _fetch(resource, config);
  139. let re;
  140. if ( re=RE.exec(resource) ) {
  141. let s=ds(re[1], re[2]);
  142. if (s != ds(re[1],sort[re[1]] || '') ) {
  143. if ( (re[1] != '/') && sort.default && (s == sort.default) ) s='';
  144. if (s) sort[re[1]] = s;
  145. else delete sort[re[1]];
  146. store();
  147. chk(null, true);
  148. updLeftNav();
  149. }
  150. }
  151. return response;
  152. };
  153. }
  154.  
  155. function newObs(r, f=cb) {
  156. var o=new MutationObserver(f), config = { attributes: false, childList: true, subtree: true};
  157. o.observe(r, config);
  158. return o;
  159. }
  160.  
  161. function cb(mutL) {
  162. for(let mut of mutL) {
  163. if (mut.type == 'childList') {
  164. for (let e,i=0; e=mut.addedNodes[i]; i++) {
  165. if (e.nodeType == 1) chk(e);
  166. }
  167. }
  168. }
  169. }
  170.  
  171. function cbRec(mutL) {
  172. for(let mut of mutL) {
  173. if (mut.type == 'childList') {
  174. for (let e,i=0; e=mut.addedNodes[i]; i++) {
  175. if (e.nodeType == 1) {
  176. let r=e.closest('details');
  177. if (r) chk(r, true);
  178. else chk(e);
  179. }
  180. }
  181. }
  182. }
  183. }
  184.  
  185. function load() {
  186. var o=sort.upd;
  187. sort=JSON.parse(localStorage.getItem('_sort_') || '{}');
  188. if (o != sort.upd) return true;
  189. }
  190.  
  191. function store() {
  192. sort.upd=Date.now();
  193. localStorage.setItem('_sort_', JSON.stringify(sort) );
  194. }
  195.  
  196. patchFetch();
  197. load();
  198.  
  199. if (document.readyState != 'loading') init();
  200. else {
  201. document.addEventListener('DOMContentLoaded', init);
  202. window.addEventListener('load', init);
  203. }
  204.  
  205. var redir=sort.redir;
  206.  
  207. if (redir) {
  208. let re;
  209. if (re = RE.exec(location.pathname)) {
  210. if ( !re[2] || (redir == 'force') ) {
  211. let l=re[1]+gen(re);
  212. if (l != location.pathname) {
  213. if (redir == 'ask') {
  214. if ( (window == top) && (window.document.visibilityState == 'visible') && confirm('Redirect to correct order ?\n'+location.href+'\n'+l) ) redir=true;
  215. else redir=false;
  216. }
  217. if (redir) location.pathname=l;
  218. }
  219. }
  220. }
  221. }
  222.  
  223. })();