bangumi-sort-index

Build your UserScript with webpack

  1. // ==UserScript==
  2. // @name bangumi-sort-index
  3. // @name:zh 排序首页条目
  4. // @namespace https://trim21.me/
  5. // @description Build your UserScript with webpack
  6. // @version 0.0.10
  7. // @author Trim21 <i@trim21.me>
  8. // @source https://github.com/trim21/bgm-tv-userscripts
  9. // @supportURL https://github.com/trim21/bgm-tv-userscripts/issues
  10. // @license MIT
  11. // @include /^https://(bangumi\.tv|bgm\.tv|chii\.in)/[^/]*/
  12. // @require https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js
  13. // @run-at document-end
  14. // @grant GM_info
  15. // ==/UserScript==
  16.  
  17. /******/ (() => { // webpackBootstrap
  18. /******/ "use strict";
  19.  
  20. ;// external "$"
  21. const external_$_namespaceObject = $;
  22. ;// ./scripts/sort-index/src/style.css
  23. /* harmony default export */ const style = ("#prgManagerHeader ul#prgManagerOrder li a span {\n}\n\n#prgManagerHeader ul#prgManagerOrder li a.focus span {\n filter: invert();\n}\n\n/* https://www.flaticon.com/free-icons/sort */\n\n#prgManagerHeader ul#prgManagerOrder li a#switchSmartOrder span {\n /* https://icons8.com/icon/69918/sort-by-recently-viewed */\n background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAKaSURBVGhD7dlLyExhHMfxcS2KolxzS5SFpNwtWBAKZaVkI0VZocRCoiQrKynKQiyssLF0CRsJWdkQSRayQIhy/f6m+ff+Oz3nvPM+zTznHJ1ffXqb55xnen5zzsycM2+rSZMmTf6rrMYujGk/KidrsR0j2o8isgJ/8BdXNVBCtsDWcEoDMdkHPYG81kAJ0eJtDfc0EBNf5I0GIjIeczAJMafGadgaHmggJjFFtNhNuIL3sPnyDXexFxPRTUopsg7PYXOKfMFhjEZRkhbRUTgH23conmAG8pKsiF7Rm7D9jD5prmMbFkMfoVqUjkR233dYiFCSFNGRuAbbx/zCDoQyFy+QnfMWoSOTpMhR2HbvOIqyCD+RnfcI2fdM34voVAgt5gfGwTIbKrah/WggN5CdK8fg0/cioVNK9Kr6PIXGdbot0EAnh5CdK9+h7x5L34vcgm3zHsLnFWzbMg10cgB+nvmNybD0vYi+M2yb9wmjYFkFfXodbD8ayCWE5l+AT5I3+0XYdm83ijIdX5Gdp+u5CfBJUmQsdCrZPkZHZSlC0QfBfWTn6PLFn3qWJEUUXQyGLku0sBOYh2HQK70TL5HdV2/wjQglWRFFi8x78w9GF5Z6H+UlaRFlJPZDp5XNKaJLmMuYiqIkL2KZAn1HPIPN9XQEzmIJuklpRXz0fbAGW7Ee8zEcQ0klivQiTRGfpkgP0xTxaYr0MD0psgf2JB9xpAT6HczWcBtRWQl7kio4g+jk3Vun9gHTEB3d7ekQ38HjCH4x+hkotE8R3e+cx0yUGl9kswbqmqZI1VLLIsuh+w7PF9FPrNnt+gGjctE/Tru91ZWTqGy6LVPpEpbBytSihCWvTK1KWFTmM2pdwmJlal3CMqvzt49ptf4B0C4sGC5Wg58AAAAASUVORK5CYII=)\n no-repeat top;\n background-size: 20px 20px;\n}\n\n#prgManagerHeader ul#prgManagerOrder li a#switchNormalOrder span {\n /* https://icons8.com/icon/69920/sort-by-modified-date */\n background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHySURBVGhD7Zg9LwRBHIcPkSA6lXj5DApv0VBQ0ZLoNAoRnUQhKhGJRCQqjVqhEJ0GEY3CN1AIrQIlEfx+e/tPJnP7cju3tzN7mSd5snbudrLP7U1uV8Xj8Xhaiim4AruDPTtMwyXYEewZMAF/4R8844AFFqCcwx4HTFiDnIA+cyAneuERvIL8pJPgycs53HHABDXkhQM5wIh7KPPy096AcexDeS+PM6IZIXPwB8q8NCnG2RCyCKNiZqCOUyH8Om3CtmCvSlTMDtRxJkRdE6cwLobbUajjRIi+sGlUzBdcDvZqsR4SFSHqMQPhNgqrIUkRoh4Th7WQeiIo1wRvf9KwEpIlIm5N6BQewhu6WyjvjzNLBLFyRfrgJZRjdLNGEGtrZBXKMaomEcRayAj8hnIcNY0g1kJIFxyD57CRCFJYCK/AevXPGhjTSAQpLOQA8s41LqZRCglph6+QrzMm7WnPhEJCBiEfgY/hJAeagNXFnic+RMWH5IgPUWmZEPUG8B1uWVB9NLiGRvC3QSZxwUNozAWMmrRo32A/NKYT8hLfwEcD1ZN5Csey+ABP4BC0ihoyz4Gy4kNco5Qh43BWUw3ZDsdUe6Bz8D+HH1A9+SR3obPUG+N0hJAWU4oIIS6mVBECYz5hqSMEiSl1hDAcbptIpfIPemrPlazYnP4AAAAASUVORK5CYII=)\n no-repeat top;\n background-size: 20px 20px;\n}\n\n#prgManagerHeader ul#prgManagerOrder li a span {\n display: block;\n text-indent: -9999px;\n height: 18px;\n width: 20px;\n}\n");
  24. ;// ./scripts/sort-index/src/index.ts
  25.  
  26.  
  27. function addStyle(css) {
  28. 'use strict';
  29.  
  30. const head = document.getElementsByTagName('head')[0];
  31. if (head) {
  32. const style = document.createElement('style');
  33. style.setAttribute('type', 'text/css');
  34. style.textContent = css;
  35. head.appendChild(style);
  36. }
  37. }
  38. addStyle(style);
  39. const castKeyword = '首播';
  40. const configKey = 'index-sort-order';
  41. function bangumiSortIndex() {
  42. class Subject {
  43. constructor(el) {
  44. this.el = el;
  45. const titleEL = el.find('.epGird .tinyHeader .textTip').last();
  46. this.title = titleEL.attr('data-subject-name-cn') ?? titleEL.attr('data-original-title') ?? titleEL.attr('data-subject-name') ?? 'title';
  47. const nextWatch = el.find('li a:not(.epBtnWatched)').first();
  48. const rel = nextWatch.attr('rel');
  49. if (rel) {
  50. this.nextDate = getDate(rel);
  51. } else {
  52. this.nextDate = 0;
  53. }
  54. this.airing = el.find('li a.epBtnNA, li a.epBtnToday').length !== 0 ? -1 : 1;
  55. }
  56. }
  57. const container = external_$_namespaceObject('#cloumnSubjectInfo .infoWrapper_tv');
  58. const originals = Array.from(external_$_namespaceObject('.infoWrapper_tv [id^=subjectPanel_]')).map(element => {
  59. return new Subject(external_$_namespaceObject(element));
  60. });
  61. const subjects = [...originals];
  62. function getDate(rel) {
  63. const castDate = Array.from(document.querySelector(rel)?.querySelector('span.tip')?.childNodes ?? []).filter(e => e.nodeType === Node.TEXT_NODE).map(e => e.textContent ?? '').filter(t => t.includes(castKeyword));
  64. if (castDate.length) {
  65. return new Date(castDate[0].replace(`${castKeyword}:`, '')).getTime();
  66. }
  67. return 0;
  68. }
  69. function render(subjects) {
  70. subjects.forEach(s => {
  71. s.el.remove();
  72. });
  73. subjects.forEach((s, i) => {
  74. s.el.removeClass('odd');
  75. s.el.removeClass('even');
  76. if (i % 2) {
  77. s.el.addClass('even');
  78. } else {
  79. s.el.addClass('odd');
  80. }
  81. container.append(s.el);
  82. });
  83. }
  84. function smart(subjects) {
  85. subjects.sort((a, b) => {
  86. if (a.airing === b.airing) {
  87. return (b.nextDate - a.nextDate) * a.airing;
  88. }
  89. return a.airing;
  90. });
  91. render(subjects);
  92. }
  93. function normal() {
  94. render(originals);
  95. }
  96. function onLoad() {
  97. const orderUI = external_$_namespaceObject(`<ul id='prgManagerOrder' class='categoryTab clearit rr'>
  98.  
  99. <li data-mode='normal'><a href='javascript:void(0);' id='switchNormalOrder' title='修改順序'><span>標準</span></a></li>
  100. <li data-mode='smart' ><a href='javascript:void(0);' id='switchSmartOrder' title='智障順序'><span>智能</span></a></li>
  101.  
  102. </ul>`);
  103. external_$_namespaceObject('#prgManagerHeader').append(orderUI[0]);
  104. if (!localStorage['index-sort-order']) {
  105. localStorage['index-sort-order'] = 'smart';
  106. }
  107. const optionUIs = orderUI.find('li');
  108. let mode = localStorage.getItem(configKey) ?? 'normal';
  109. function click(ctx) {
  110. optionUIs.find('a').removeClass('focus');
  111. if (ctx) {
  112. const el = external_$_namespaceObject(ctx);
  113. mode = el.attr('data-mode')?.toString();
  114. localStorage.setItem(configKey, mode);
  115. }
  116. switch (mode) {
  117. case 'smart':
  118. smart(subjects);
  119. break;
  120. case 'normal':
  121. normal();
  122. break;
  123. default:
  124. mode = 'normal';
  125. localStorage.setItem(configKey, mode);
  126. normal();
  127. }
  128. external_$_namespaceObject(`#prgManagerOrder li[data-mode="${mode}"]`).find('a').addClass('focus');
  129. }
  130. optionUIs.on('click', function () {
  131. click(this);
  132. });
  133. click();
  134. }
  135. onLoad();
  136. }
  137. bangumiSortIndex();
  138. /******/ })()
  139. ;