BiliBili-文字收藏夹列表

(感谢闲鱼买家ZEP的有偿定制) 用纯文字列表的方式展示B站收藏夹结果,方便按各列排序。

  1. // ==UserScript==
  2. // @name BiliBili-TextFavList
  3. // @name:zh-CN BiliBili-文字收藏夹列表
  4. // @namespace https://github.com/Mehver
  5. // @version 1.0
  6. // @description (Thanks to ZEP's paid customization) Display Bilibili favourite list results in a text list, which is convenient for sorting by each column.
  7. // @description:zh-CN (感谢闲鱼买家ZEP的有偿定制) 用纯文字列表的方式展示B站收藏夹结果,方便按各列排序。
  8. // @sponsor ZEP
  9. // @author https://github.com/Mehver
  10. // @icon data:image/png;base64,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
  11. // @match http*://space.bilibili.com/*/favlist*
  12. // @exclude http*://space.bilibili.com/*/favlist*ctype*
  13. // @license MPL-2.0
  14. // @license^ Mozilla Public License 2.0
  15. // @charset UTF-8
  16. // @homepageURL https://github.com/SynRGB/BiliBili-TextFavList
  17. // @contributionURL https://github.com/SynRGB/BiliBili-TextFavList
  18. // @copyright Copyright © 2022-PRESENT, Mehver (https://github.com/Mehver)
  19. // @grant GM_addStyle
  20. // @grant GM_getResourceText
  21. // @grant GM_getValue
  22. // @grant GM_setValue
  23. // @grant GM_registerMenuCommand
  24. // @resource DataTablesCSS https://cdn.datatables.net/1.11.3/css/jquery.dataTables.min.css
  25. // ==/UserScript==
  26.  
  27. let table_font_size = GM_getValue('table_font_size', 16);
  28. let network_delay = GM_getValue('network_delay', 400);
  29.  
  30. GM_registerMenuCommand('设置表格字体大小', async () => {
  31. let newFontSize = prompt('请输入新的字体大小(单位px):', table_font_size);
  32. if (newFontSize) {
  33. table_font_size = newFontSize;
  34. await GM_setValue('table_font_size', table_font_size);
  35. alert('字体大小已更新!请刷新页面以查看更改。');
  36. }
  37. });
  38.  
  39. GM_registerMenuCommand('设置脚本加载时延', async () => {
  40. let newNetworkDelay = prompt('脚本依赖外部组件,对于不同的网络环境和电脑性能,\n组件加载速度也不同。如果出现显示错误、白屏等BUG,\n可以适度调高这个数字确保外部引入的组件完成加载。\n默认400(单位ms):', network_delay);
  41. if (newNetworkDelay) {
  42. network_delay = newNetworkDelay;
  43. await GM_setValue('network_delay', network_delay);
  44. alert('脚本加载时延已更新!请刷新页面以查看更改。');
  45. }
  46. });
  47.  
  48. //////////////////////////////////////
  49. //////////// DataTables //////////////
  50. let cssTxt = GM_getResourceText("DataTablesCSS");
  51. GM_addStyle(cssTxt);
  52. let head = document.head || document.getElementsByTagName('head')[0];
  53. let link = document.createElement('link');
  54. link.type = 'text/css';
  55. link.rel = 'stylesheet';
  56. link.href = 'https://cdn.datatables.net/1.11.3/css/jquery.dataTables.min.css';
  57. head.appendChild(link);
  58. (function() {
  59. let jQueryScript = document.createElement("script");
  60. jQueryScript.src = "https://code.jquery.com/jquery-3.6.0.min.js";
  61. jQueryScript.onload = () => {
  62. let dtScript = document.createElement("script");
  63. dtScript.src = "https://cdn.datatables.net/1.11.3/js/jquery.dataTables.min.js";
  64. // 加载完成后首次运行
  65. dtScript.onload = () => {
  66. main();
  67. };
  68. document.body.appendChild(dtScript);
  69. };
  70. document.body.appendChild(jQueryScript);
  71. })();
  72. //////////// DataTables //////////////
  73. //////////////////////////////////////
  74.  
  75. //////////////////////////////////////
  76. /////////////// 触发器 ////////////////
  77. // 延时避免在 dtScript 和 jQueryScript 加载完成前就运行
  78. setTimeout(function() {
  79. setTimeout(function() {
  80. main();
  81. }, network_delay / 2);
  82. let observerElement = new window.MutationObserver(function() {
  83. setTimeout(function() {
  84. main();
  85. }, network_delay / 3);
  86. });
  87. // 收藏夹切换触发
  88. let targetForObserver1 = document.querySelector('#page-fav > div.col-full.clearfix.master > div.fav-main.section > div.favList-info');
  89. if (targetForObserver1) {
  90. observerElement.observe(targetForObserver1, {
  91. childList: true,
  92. subtree: true,
  93. characterData: true
  94. });
  95. }
  96. // 手动选择分区或收藏时间
  97. let targetElement2 = document.querySelector('#page-fav > div.col-full.clearfix.master > div.fav-main.section > div.fav-header.fav-header-info > div > div');
  98. if (targetElement2) {
  99. targetElement2.addEventListener('click', function() {
  100. setTimeout(function() {
  101. main();
  102. }, network_delay / 2);
  103. });
  104. }
  105. // 翻页触发
  106. let targetElement3 = document.querySelector('#page-fav > div.col-full.clearfix.master > div.fav-main.section > div.fav-content.section > ul.be-pager');
  107. if (targetElement3) {
  108. targetElement3.addEventListener('click', function() {
  109. setTimeout(function() {
  110. main();
  111. }, network_delay / 2);
  112. });
  113. }
  114. // 搜索触发
  115. let targetElement4 = document.querySelector('#page-fav > div.col-full.clearfix.master > div.fav-main.section > div.fav-header.fav-header-info > div > div > div.filter-item.search');
  116. if (targetElement4) {
  117. targetElement4.addEventListener('click', function() {
  118. setTimeout(function() {
  119. main();
  120. }, network_delay * 2);
  121. });
  122. }
  123. // 订阅等其他类型的收藏夹,点击后应避免脚本生效
  124. let excludeElement1 = document.querySelector('#page-fav > div.col-full.clearfix.master > div.fav-sidenav > div:nth-child(2)');
  125. if (excludeElement1) {
  126. excludeElement1.addEventListener('click', function() {
  127. setTimeout(function() {
  128. revert_main();
  129. }, network_delay / 2);
  130. });
  131. }
  132. let excludeElement2 = document.querySelector('#page-fav > div.col-full.clearfix.master > div.fav-sidenav > div:nth-child(3)');
  133. if (excludeElement2) {
  134. excludeElement2.addEventListener('click', function() {
  135. setTimeout(function() {
  136. revert_main();
  137. }, network_delay / 2);
  138. });
  139. }
  140. }, network_delay * 2);
  141. /////////////// 触发器 ////////////////
  142. //////////////////////////////////////
  143.  
  144. /////////////////////////////////////
  145. /////////////// main ////////////////
  146. function revert_main() {
  147. try {
  148. // 隐藏列表
  149. try { document.querySelector('#biliResultsTable').style.display = 'none'; } catch (e) {}
  150. // 显示收藏夹
  151. try { document.querySelector("#page-fav > div.col-full.clearfix.master > div.fav-main.section > div.fav-content.section > ul.fav-video-list.clearfix.content").style.display = 'block'; } catch (e) {}
  152. } catch (e) {
  153. console.log(e);
  154. }
  155. }
  156. function main() {
  157. try {
  158. // 隐藏”批量操作“按钮
  159. try { document.querySelector('#page-fav > div.col-full.clearfix.master > div.fav-main.section > div.fav-header.fav-header-info > div > div > div.filter-item.do-batch').style.display = 'none'; } catch (e) {}
  160. // 隐藏收藏夹
  161. try { document.querySelector("#page-fav > div.col-full.clearfix.master > div.fav-main.section > div.fav-content.section > ul.fav-video-list.clearfix.content").style.display = 'none'; } catch (e) {}
  162.  
  163. // Create table with thead for DataTables
  164. let table = document.createElement('table');
  165. table.id = "biliResultsTable";
  166. let thead = document.createElement('thead');
  167. let tbody = document.createElement('tbody');
  168. let header = ["收藏于", "时长", "标题"];
  169. let trHead = document.createElement('tr');
  170. header.forEach(text => {
  171. let th = document.createElement('th');
  172. th.textContent = text;
  173. trHead.appendChild(th);
  174. });
  175. thead.appendChild(trHead);
  176.  
  177. setTimeout(function() {
  178. let videoCards = document.querySelectorAll('li');
  179. videoCards.forEach(videoCard => {
  180. let title;
  181. let length;
  182. let pubdate;
  183.  
  184. try {
  185. title = videoCard.querySelector('a.title')?.textContent.trim();
  186. length = videoCard.querySelector('span.length')?.textContent.trim();
  187. pubdate = videoCard.querySelector('div.meta.pubdate')?.textContent.trim().replace('收藏于: ', '');
  188. // let link_video = videoCard.querySelectorAll('a')[0].getAttribute('href');
  189. } catch (e) {}
  190.  
  191. let tr = document.createElement('tr');
  192.  
  193. // 确保没有为空的数据
  194. if (
  195. (title !== undefined) &&
  196. (length !== undefined) &&
  197. (pubdate !== undefined)
  198. // (link_video !== undefined)
  199. ) {
  200. [pubdate, length, title].forEach(text => {
  201. let td = document.createElement('td');
  202. td.textContent = text;
  203. tr.appendChild(td);
  204. });
  205. // let tdTitle = tr.querySelector('td:nth-child(3)');
  206. // tdTitle.innerHTML = `<a href="${link_video}" target="_blank">${title}</a>`;
  207. // b230815.02 时长加粗
  208. tr.querySelector('td:nth-child(2)').style.fontWeight = 'bold';
  209. // b230815.02 标题用 `#00AEEC` 颜色
  210. tr.querySelector('td:nth-child(3)').style.color = '#00AEEC';
  211. tbody.appendChild(tr);
  212. }
  213. });
  214. table.appendChild(thead);
  215. table.appendChild(tbody);
  216.  
  217. // 回调获取异步数据,适用于异步加载
  218. if (tbody.childElementCount === 0) {
  219. main();
  220. return;
  221. }
  222.  
  223. let tables = document.querySelectorAll('#biliResultsTable');
  224. if (tables.length === 0) {
  225. let targetDiv_bott = document.querySelector("#page-fav > div.col-full.clearfix.master > div.fav-main.section > div.fav-content.section > ul.be-pager");
  226. targetDiv_bott.parentNode.insertBefore(table, targetDiv_bott);
  227. } else {
  228. tables[0].parentNode.replaceChild(table, tables[0]);
  229. }
  230.  
  231.  
  232. // DataTables 的自定义排序算法
  233. $.fn.dataTable.ext.type.order['length-sort-pre'] = function (d) {return convertLength(d);};
  234. $.fn.dataTable.ext.type.order['pubdate-sort-pre'] = function (d) {return convertPubDate(d);};
  235. // Initialize DataTables
  236. $(table).DataTable({
  237. "paging": false,
  238. "searching": false,
  239. "info": false,
  240. "columnDefs": [
  241. { "type": "length-sort", "targets": 1 },
  242. { "type": "pubdate-sort", "targets": 0 }
  243. ]
  244. });
  245.  
  246. // b230815.02 去掉底边横线
  247. GM_addStyle("table.dataTable.no-footer { border-bottom: 0px none !important; }");
  248. // b230815.02 去掉表头横线 (因CSS复杂,所以创建白色色块覆盖)
  249. GM_addStyle(".dataTable thead th { border-bottom: 0px none !important; }");
  250. // b230815.02 调大字号
  251. GM_addStyle(`.dataTable { font-size: ${table_font_size}px !important; }`);
  252. // 左侧留30px空白
  253. GM_addStyle(`.dataTable { margin-left: 30px !important; }`);
  254. }, 100);
  255. } catch (e) {
  256. console.log(e);
  257. }
  258. }
  259. /////////////// main ////////////////
  260. /////////////////////////////////////
  261.  
  262. ///////////////////////////////////
  263. /////// DataTable 的排序算法 ////////
  264. function convertLength(duration) {
  265. let parts = duration.split(':').map(part => parseInt(part, 10));
  266. if (parts.length === 3) {
  267. return parts[0] * 3600 + parts[1] * 60 + parts[2];
  268. } else if (parts.length === 2) {
  269. return parts[0] * 60 + parts[1];
  270. } else {
  271. return NaN;
  272. }
  273. }
  274. function convertPubDate(date) {
  275. const now = new Date();
  276. if (date.includes('刚刚')) {
  277. return now.getTime();
  278. }
  279. if (date.includes('小时前')) {
  280. const hoursAgo = parseFloat(date.replace('小时前', ''));
  281. return now - hoursAgo * 3600 * 1000; // Convert hours to milliseconds
  282. }
  283. if (date === "昨天") {
  284. return now - 24 * 3600 * 1000; // 24 hours in milliseconds
  285. }
  286. if (date.includes('-')) {
  287. const parts = date.split('-').map(part => {
  288. return part.padStart(2, '0');
  289. });
  290. // If only month and day are given, use the current year.
  291. if (parts.length === 2) {
  292. parts.unshift(now.getFullYear().toString());
  293. }
  294. // Create a new Date object and return its time value in milliseconds
  295. return new Date(parts.join('-')).getTime();
  296. }
  297. }
  298. /////// DataTable 的排序算法 ////////
  299. ///////////////////////////////////
  300.  
  301. console.log("JS script BiliBili-TextFavList (BiliBili-文字收藏夹列表) loaded. See more details at https://github.com/SynRGB/BiliBili-TextFavList");
  302.  

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址