qB-WebUI 根据辅种数添加标签

在 qBittorrent WebUI 中根据辅种数为种子添加标签,支持all和list两种模式,并输出调试信息

  1. // ==UserScript==
  2. // @name qB-WebUI 根据辅种数添加标签
  3. // @name:en qB-WebUI Add Tags Based on Reseed Count
  4. // @namespace localhost
  5. // @version 0.5.0
  6. // @author Schalkiii
  7. // @description 在 qBittorrent WebUI 中根据辅种数为种子添加标签,支持all和list两种模式,并输出调试信息
  8. // @description:en Add tags to torrents in qBittorrent WebUI based on reseed count, supporting all and list modes with debug info
  9. // @license MIT
  10. // @run-at document-end
  11. // @match http://192.168.10.72:9091/*
  12. // @match http://127.0.0.1:9091/*
  13. // @grant GM_xmlhttpRequest
  14. // ==/UserScript==
  15.  
  16. /* globals torrentsTable */
  17.  
  18. const baseURL = window.location.origin + '/api/v2/torrents/';
  19. const reseedAPI = 'http://api.iyuu.cn/index.php?s=App.Api.GetSubject&info_hash='; // 替换为实际的辅种查询API
  20. const tagPrefix = 'Reseed-'; // 标签前缀,例如 Reseed-0, Reseed-1, ..., Reseed-6, Reseed-7+
  21.  
  22. // 获取种子列表(支持all和list模式)
  23. function getTorrentList(scope) {
  24. if (scope === 'all') {
  25. return getFetch('info'); // 获取所有种子
  26. } else if (scope === 'list') {
  27. return torrentsTable.getFilteredAndSortedRows().map(row => row.full_data); // 获取当前显示的种子
  28. } else {
  29. return null;
  30. }
  31. }
  32.  
  33. // 发起 fetch 请求
  34. async function getFetch(route) {
  35. try {
  36. const response = await fetch(baseURL + route);
  37. if (!response.ok) {
  38. throw new Error('Error fetching data!');
  39. }
  40. return await response.json();
  41. } catch (error) {
  42. console.error('Error fetching data:', error);
  43. return null;
  44. }
  45. }
  46.  
  47. // 检查种子是否已有Reseed-开头的标签
  48. function hasReseedTag(tags) {
  49. if (!tags) return false;
  50. const tagArray = tags.split(', ');
  51. return tagArray.some(tag => tag.startsWith(tagPrefix));
  52. }
  53.  
  54. // 根据哈希值查询辅种数
  55. function queryReseedCount(hash) {
  56. return new Promise((resolve) => {
  57. console.log(`查询辅种数:正在查询哈希值 ${hash}...`);
  58. GM_xmlhttpRequest({
  59. url: `${reseedAPI}${hash}`,
  60. method: 'GET',
  61. responseType: 'json',
  62. onload: function (response) {
  63. console.log(`查询辅种数:请求成功,状态码:${response.status}`);
  64. if (response.status === 200) {
  65. try {
  66. const json = JSON.parse(response.responseText);
  67. if (json.ret === 200) {
  68. const reseedCount = Math.max(json.data.pid_total, json.data.tid_total);
  69. console.log(`查询辅种数:哈希值 ${hash} 的辅种数为 ${reseedCount}`);
  70. resolve({ hash, reseedCount });
  71. } else {
  72. console.warn(`查询辅种数:API返回的ret不是200,实际返回: ${json.ret},默认辅种数为 0`);
  73. resolve({ hash, reseedCount: -1 }); // 返回辅种数为 0
  74. }
  75. } catch (e) {
  76. console.error(`查询辅种数:JSON解析失败: ${e},默认辅种数为 0`);
  77. resolve({ hash, reseedCount: -1 }); // 返回辅种数为 0
  78. }
  79. } else {
  80. console.warn(`查询辅种数:请求失败,状态码: ${response.status},默认辅种数为 0`);
  81. resolve({ hash, reseedCount: -1 }); // 返回辅种数为 0
  82. }
  83. },
  84. onerror: function (error) {
  85. console.error(`查询辅种数:请求发生错误: ${error},默认辅种数为 0`);
  86. resolve({ hash, reseedCount: 0 }); // 返回辅种数为 0
  87. },
  88. });
  89. });
  90. }
  91.  
  92. // 为种子添加标签
  93. async function addTagToTorrent(hash, tag) {
  94. const url = `${baseURL}addTags`;
  95. const data = new URLSearchParams();
  96. data.append('hashes', hash);
  97. data.append('tags', tag);
  98.  
  99. try {
  100. const response = await fetch(url, {
  101. method: 'POST',
  102. headers: {
  103. 'Content-Type': 'application/x-www-form-urlencoded',
  104. },
  105. body: data,
  106. });
  107. if (!response.ok) {
  108. throw new Error('Error adding tag!');
  109. }
  110. console.log(`标签添加成功:哈希值 ${hash} 已添加标签 "${tag}"`);
  111. } catch (error) {
  112. console.error(`标签添加失败:哈希值 ${hash} 添加标签 "${tag}" 时出错:`, error);
  113. }
  114. }
  115.  
  116. // 根据辅种数生成标签
  117. function getReseedTag(reseedCount) {
  118. if (reseedCount >= 7) {
  119. return `${tagPrefix}7+`; // 大于等于7的合并为一个标签
  120. } else {
  121. return `${tagPrefix}${reseedCount}`; // 0, 1, 2, ..., 6
  122. }
  123. }
  124.  
  125. // 主函数:处理种子并添加标签
  126. async function processTorrents(scope) {
  127. const torrentList = await getTorrentList(scope);
  128. if (!torrentList || torrentList.length === 0) {
  129. console.log('未找到种子。');
  130. return;
  131. }
  132.  
  133. console.log(`在模式 "${scope}" 下找到 ${torrentList.length} 个种子。`);
  134. console.log('获取到的种子哈希值列表:', torrentList.map(torrent => torrent.hash));
  135.  
  136. let successCount = 0;
  137. let errorCount = 0;
  138. let skippedCount = 0;
  139.  
  140. for (const torrent of torrentList) {
  141. try {
  142. // 检查是否已有Reseed-开头的标签
  143. if (hasReseedTag(torrent.tags)) {
  144. console.log(`跳过种子:名称 "${torrent.name}" 已有Reseed标签 "${torrent.tags}"`);
  145. skippedCount++;
  146. continue;
  147. }
  148.  
  149. const { hash, reseedCount } = await queryReseedCount(torrent.hash);
  150. console.log(`处理种子:名称 "${torrent.name}", 哈希值 ${hash}, 辅种数 ${reseedCount}`);
  151.  
  152. // 根据辅种数生成标签并添加
  153. const tag = getReseedTag(reseedCount);
  154. await addTagToTorrent(hash, tag);
  155. successCount++;
  156. } catch (error) {
  157. console.error(`处理种子失败:名称 "${torrent.name}", 哈希值 ${torrent.hash}:`, error);
  158. errorCount++;
  159. }
  160. }
  161.  
  162. alert(`处理完成!\n成功:${successCount} 个,失败:${errorCount} 个,跳过已有标签:${skippedCount} 个`);
  163. }
  164.  
  165. // 添加按钮到页面
  166. function addButton() {
  167. const newBtn = document.createElement("li");
  168. newBtn.innerHTML = "<a class='js-modal'><b> 打可辅种数标签 </b></a>";
  169. document.querySelector("#desktopNavbar > ul").append(newBtn);
  170.  
  171. newBtn.addEventListener("click", async function() {
  172. const scope = window.prompt("!!!请先手动删除[tagNames]中包含的标签!!!\n检查全部种子请输入 [all]\n仅检查当前表格中显示的种子请输入 [list]", "all")
  173. if (!scope) return;
  174. await processTorrents(scope);
  175. });
  176. }
  177.  
  178. // 初始化
  179. (function () {
  180. addButton();
  181. })();

QingJ © 2025

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