Replace Dropdown Lists for Bangumi

调整页面上的下拉列表选项顺序,保留原本的默认值,并按首字母排序,并且使用懒加载功能

  1. // ==UserScript==
  2. // @name Replace Dropdown Lists for Bangumi
  3. // @name:zh-CN bangumi下拉列表排序
  4. // @namespace https://github.com/Adachi-Git/ReplaceDropdownListsForBangumi
  5. // @version 0.6
  6. // @description 调整页面上的下拉列表选项顺序,保留原本的默认值,并按首字母排序,并且使用懒加载功能
  7. // @author Adachi
  8. // @match *://bangumi.tv/subject/*
  9. // @match *://bgm.tv/subject/*
  10. // @match *://chii.in/subject/*
  11. // @grant none
  12. // @license MIT
  13. // ==/UserScript==
  14. (function() {
  15. 'use strict';
  16.  
  17. var delay = 2000; // 设置延迟执行时间,单位是毫秒
  18.  
  19. // 汉字拼音首字母映射表
  20. var pinyinMap = {
  21. '原': 'Y',
  22. '总': 'Z',
  23. '导': 'D',
  24. '副': 'F',
  25. '脚': 'J',
  26. '分': 'F',
  27. '主': 'Z',
  28. '演': 'Y',
  29. '音': 'Y',
  30. '人': 'R',
  31. '构': 'G',
  32. '系': 'X',
  33. '美': 'M',
  34. '色': 'S',
  35. '机': 'J',
  36. '道': 'D',
  37. '作': 'Z',
  38. '动': 'D',
  39. '摄': 'S',
  40. 'C': 'C',
  41. '3': '3',
  42. '监': 'J',
  43. '第': 'D',
  44. 'O': 'O',
  45. '制': 'Z',
  46. '背': 'B',
  47. '数': 'S',
  48. '剪': 'J',
  49. '插': 'C',
  50. '企': 'Q',
  51. '宣': 'X',
  52. '录': 'L',
  53. '製': 'Z',
  54. '设': 'S',
  55. '特': 'T',
  56. '配': 'P',
  57. '联': 'L',
  58. '补': 'B',
  59. '执': 'Z',
  60. '助': 'Z',
  61. '台': 'T',
  62. '后': 'H',
  63. '协': 'X',
  64. '连': 'L',
  65. '译': 'Y',
  66. '客': 'K',
  67. '文': 'W',
  68. '出': 'C',
  69. '改': 'G',
  70. '前': 'Q',
  71. '续': 'X',
  72. '全': 'Q',
  73. '番': 'F',
  74. '相': 'X',
  75. '不': 'B',
  76. '衍': 'Y',
  77. '角': 'J',
  78. '其': 'Q',
  79. '开': 'K',
  80. '发': 'F',
  81. '游': 'Y',
  82. '剧': 'J',
  83. 'S': 'S',
  84. '程': 'C',
  85. 'Q': 'Q',
  86. '关': 'G',
  87. '创': 'C',
  88. '编': 'B',
  89. '共': 'G',
  90. '故': 'G',
  91. '艺': 'Y',
  92. '厂': 'C',
  93. '片': 'P',
  94. '印': 'Y',
  95. '广': 'G',
  96. };
  97.  
  98. // 定义一个函数来处理下拉列表的逻辑
  99. function adjustSelectOptions(select) {
  100. // 保存原本的默认值
  101. var defaultValue = select.value;
  102.  
  103. // 获取所有选项并转换为数组
  104. var optionsArray = Array.from(select.options);
  105.  
  106. // 移除所有选项
  107. optionsArray.forEach(function(option) {
  108. select.remove(option.index);
  109. });
  110.  
  111. // 按汉字的拼音首字母排序选项数组
  112. optionsArray.sort(function(a, b) {
  113. var pinyinA = pinyinMap[a.textContent[0]];
  114. var pinyinB = pinyinMap[b.textContent[0]];
  115.  
  116. // 如果拼音首字母不存在,则将其视为 -Infinity,确保空值被放到列表的最上面
  117. pinyinA = pinyinA ? pinyinA : -Infinity;
  118. pinyinB = pinyinB ? pinyinB : -Infinity;
  119.  
  120. // 排序时忽略空值
  121. if (pinyinA === -Infinity && pinyinB === -Infinity) {
  122. return 0;
  123. } else if (pinyinA === -Infinity) {
  124. return -1;
  125. } else if (pinyinB === -Infinity) {
  126. return 1;
  127. } else {
  128. return pinyinA.localeCompare(pinyinB);
  129. }
  130. });
  131.  
  132. // 将重新排序后的选项重新添加到下拉列表中,并在选项文本前添加拼音首字母
  133. optionsArray.forEach(function(option) {
  134. var originalText = option.textContent;
  135. var pinyin = pinyinMap[originalText[0]];
  136.  
  137. // 如果拼音首字母存在,则在文本前添加拼音首字母;否则只保留原始文本
  138. option.textContent = (pinyin ? pinyin + ' - ' : '') + originalText;
  139. select.add(option);
  140. });
  141.  
  142. // 保留原本的默认值
  143. select.value = defaultValue;
  144. }
  145.  
  146. // 延迟执行处理函数
  147. setTimeout(function() {
  148. // 查找可见的下拉列表并处理它们
  149. var selects = document.querySelectorAll('select[name^="infoArr"]:not([data-adjusted])');
  150. selects.forEach(function(select) {
  151. if (isElementInViewport(select)) {
  152. adjustSelectOptions(select);
  153. select.setAttribute('data-adjusted', 'true');
  154. }
  155. });
  156. }, delay);
  157.  
  158. // 添加 DOM 变化的监听器
  159. var observer = new MutationObserver(function(mutations) {
  160. mutations.forEach(function(mutation) {
  161. // 查找新增的下拉列表并处理
  162. var newSelects = mutation.target.querySelectorAll('select[name^="infoArr"]:not([data-adjusted])');
  163. newSelects.forEach(function(newSelect) {
  164. if (isElementInViewport(newSelect)) {
  165. adjustSelectOptions(newSelect);
  166. newSelect.setAttribute('data-adjusted', 'true');
  167. }
  168. });
  169. });
  170. });
  171.  
  172. // 监听整个文档的变化
  173. observer.observe(document.documentElement, {
  174. childList: true,
  175. subtree: true
  176. });
  177.  
  178. // 添加滚动事件监听器
  179. window.addEventListener('scroll', function() {
  180. // 查找尚未处理的下拉列表
  181. var selects = document.querySelectorAll('select[name^="infoArr"]:not([data-adjusted])');
  182. selects.forEach(function(select) {
  183. // 如果该下拉列表在视图内,进行处理并标记为已处理
  184. if (isElementInViewport(select)) {
  185. adjustSelectOptions(select);
  186. select.setAttribute('data-adjusted', 'true');
  187. }
  188. });
  189. });
  190.  
  191. // 检查元素是否在视图内
  192. function isElementInViewport(element) {
  193. var rect = element.getBoundingClientRect();
  194. return (
  195. rect.top >= 0 &&
  196. rect.left >= 0 &&
  197. rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
  198. rect.right <= (window.innerWidth || document.documentElement.clientWidth)
  199. );
  200. }
  201. })();