🏠 Home 

PT站点魔力计算器

在使用NexusPHP架构的PT站点显示每个种子的A值和每GB的A值。


Install this script?
  1. // ==UserScript==
  2. // @name PT站点魔力计算器
  3. // @namespace https://github.com/neoblackxt/PTMyBonusCalc
  4. // @version 2.0.8
  5. // @description 在使用NexusPHP架构的PT站点显示每个种子的A值和每GB的A值。
  6. // @author neoblackxt, LaneLau
  7. // @require https://cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js
  8. // @require https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js
  9. // @match *://*.beitai.pt/torrents*
  10. // @match *://*.pttime.org/torrents*
  11. // @match *://*.ptsbao.club/torrents*
  12. // @match *://*.pthome.net/torrents*
  13. // @match *://kp.m-team.cc/*
  14. // @match *://zp.m-team.io/*
  15. // @match *://*.hddolby.com/torrents*
  16. // @match *://*.leaguehd.com/torrents*
  17. // @match *://*.hdhome.org/torrents*
  18. // @match *://*.hdsky.me/torrents*
  19. // @match *://*.ourbits.club/torrents*
  20. // @match *://*.u2.dmhy.org/torrents*
  21. // @match *://*.hdzone.me/torrents*
  22. // @match *://*.hdatmos.club/torrents*
  23. // @match *://*.pt.soulvoice.club/torrents*
  24. // @match *://*.pt.soulvoice.club/live*
  25. // @match *://*.discfan.net/torrents*
  26. // @match *://*.hdtime.org/torrents*
  27. // @match *://*.nicept.net/torrents*
  28. // @match *://*.pterclub.com/torrents*
  29. // @match *://*.hdarea.co/torrents*
  30. // @match *://*.hdfans.org/torrents*
  31. // @match *://pt.btschool.club/torrents*
  32. // @match *://*.1ptba.com/torrents*
  33. // @match *://www.oshen.win/torrents*
  34. // @match *://*.rousi.zip/torrents*
  35. // @match *://*.kufei.org/torrents*
  36. // @match *://*.tjupt.org/torrents*
  37. // @match *://*.tjupt.org/bonus*
  38. // @match *://*/mybonus*
  39. // @license GPL License
  40. // @grant GM_setValue
  41. // @grant GM_getValue
  42. // @grant window.onurlchange
  43. // ==/UserScript==
  44. function run() {
  45. var $ = jQuery;
  46. let argsReady = true;
  47. let T0 = GM_getValue(host + ".T0");
  48. let N0 = GM_getValue(host + ".N0");
  49. let B0 = GM_getValue(host + ".B0");
  50. let L = GM_getValue(host + ".L");
  51. if (!(T0 && N0 && B0 && L)) {
  52. argsReady = false
  53. if (!isMybonusPage) {
  54. alert("未找到魔力值参数,请打开魔力值系统说明获取(/mybonus)");
  55. }
  56. }
  57. if (isMybonusPage) {
  58. T0 = parseInt($("li:has(b:contains('T0'))")[1].innerText.split(" = ")[1]);
  59. N0 = parseInt($("li:has(b:contains('N0'))")[1].innerText.split(" = ")[1]);
  60. B0 = parseInt($("li:has(b:contains('B0'))")[1].innerText.split(" = ")[1]);
  61. L = parseInt($("li:has(b:contains('L'))")[1].innerText.split(" = ")[1]);
  62. GM_setValue(host + ".T0", T0);
  63. GM_setValue(host + ".N0", N0);
  64. GM_setValue(host + ".B0", B0);
  65. GM_setValue(host + ".L", L);
  66. if (!argsReady) {
  67. if (T0 && N0 && B0 && L) {
  68. alert("魔力值参数已更新")
  69. } else {
  70. alert("魔力值参数获取失败")
  71. }
  72. }
  73. function calcB(A) {
  74. return B0 * (2 / Math.PI) * Math.atan(A / L)
  75. }
  76. function calcAbyB(B) {
  77. //从B值反推A值
  78. return Math.tan(B / B0 / (2 / Math.PI)) * L
  79. }
  80. let A = isMTeam ? 0 : parseFloat($("div:contains(' (A = ')")[0].innerText.split(" = ")[1]);
  81. let B = isMTeam ? parseFloat($("td:contains('基本獎勵')+td+td")[0].innerText) : calcB(A);
  82. // 剔除M-Team的基本奖励中做种数奖励
  83. if (isMTeam) {
  84. let matches = $("h5:contains('做種每小時將得到如下的魔力值')").next().children().first().text()
  85. .match(/(\d+(\.\d+)?)個魔力值.*最多計(\d+)個/);
  86. let seedingBonusPerSeed = parseFloat(matches[1]);
  87. let seedingBonusLimit = parseInt(matches[3]);
  88. let currentSeedingNode = $("span:contains('當前活動')").parent().clone();
  89. currentSeedingNode.find('img').replaceWith(function () {
  90. return "img";
  91. });
  92. let currentSeeding = parseInt(currentSeedingNode.text().match(/(\d+)/)[1]);
  93. B = B - (currentSeeding > seedingBonusLimit ?
  94. seedingBonusPerSeed * seedingBonusLimit : seedingBonusPerSeed * currentSeeding);
  95. }
  96. // 对于M-Team,B>B0是因为网页获取的基本奖励包括了做种数的奖励,上面代码已经进行排除。
  97. // 其他站暂不明确是否有该问题,下面一行的代码暂时保留
  98. B = B >= B0 ? B0 * 0.98 : B
  99. if (isMTeam) {
  100. A = calcAbyB(B);
  101. }
  102. let spot = [A, B]
  103. let data = []
  104. for (let i = 0; i < (1.1 * A > 25 * L ? 1.1 * A : 25 * L); i = i + L / 4) {
  105. data.push([i, calcB(i)])
  106. }
  107. let insertPos = isMTeam ? $("ul+table") : $("table+h1")
  108. insertPos.before('<div id="main" style="width: 600px;height:400px; margin:auto;"></div>')
  109. var myChart = echarts.init(document.getElementById('main'));
  110. // 指定图表的配置项和数据
  111. var option = {
  112. title: {
  113. text: 'B - A 图',
  114. top: 'bottom',
  115. left: 'center'
  116. },
  117. tooltip: {
  118. trigger: 'axis',
  119. axisPointer: {
  120. type: 'cross'
  121. },
  122. backgroundColor: 'rgba(255, 255, 255, 0.8)',
  123. position: function (pos, params, el, elRect, size) {
  124. var obj = {top: 10};
  125. obj[['left', 'right'][+(pos[0] < size.viewSize[0] / 2)]] = 30;
  126. return obj;
  127. },
  128. extraCssText: 'width: 170px'
  129. },
  130. xAxis: {
  131. name: 'A',
  132. },
  133. yAxis: {
  134. name: 'B'
  135. },
  136. axisPointer: {
  137. label: {
  138. backgroundColor: '#777'
  139. }
  140. },
  141. series: [
  142. {
  143. type: 'line',
  144. data: data,
  145. symbol: 'none'
  146. },
  147. {
  148. type: 'line',
  149. data: [spot],
  150. symbolSize: 6
  151. }
  152. ]
  153. };
  154. // 使用刚指定的配置项和数据显示图表。
  155. myChart.setOption(option);
  156. }
  157. function calcA(T, S, N) {
  158. var c1 = 1 - Math.pow(10, -(T / T0));
  159. // 当断种时,显示续种后的实际值,因为当前状态值无意义
  160. N = N ? N : 1;
  161. // 当前状态值,加入做种后实际值会小于当前值
  162. // TODO: 改为双行显示为当前值和实际值
  163. var c2 = 1 + Math.pow(2, .5) * Math.pow(10, -(N - 1) / (N0 - 1));
  164. return c1 * S * c2;
  165. }
  166. function makeA($this, i_T, i_S, i_N) {
  167. var time = $this.children('td:eq(' + i_T + ')').find("span").attr("title");
  168. // 适配m-team的发生时间
  169. if (time == undefined || time == "") {
  170. time = $this.children('td:eq(' + i_T + ')').find("span").text();
  171. }
  172. // 适配tjupt的发生时间
  173. if (time == undefined || time == "") {
  174. time = $this.children('td:eq(' + i_T + ')').html().replace("<br>", " ").trim();
  175. }
  176. var T = (new Date().getTime() - new Date(time).getTime()) / 1e3 / 86400 / 7;
  177. var size = $this.children('td:eq(' + i_S + ')').text().trim();
  178. var size_tp = 1;
  179. var S = size.replace(/[KMGT]i?B/, function (tp) {
  180. if (tp == "KB"|| tp == "KiB") {
  181. size_tp = 1 / #### / ####;
  182. } else if (tp == "MB" || tp == "MiB") {
  183. size_tp = 1 / ####;
  184. } else if (tp == "GB" || tp == "GiB") {
  185. size_tp = 1;
  186. } else if (tp == "TB" || tp == "TiB") {
  187. size_tp = ####;
  188. }
  189. return "";
  190. });
  191. S = parseFloat(S) * size_tp;
  192. var number = $this.children('td:eq(' + i_N + ')').text().trim();
  193. var N = parseInt(number);
  194. var A = calcA(T, S, N).toFixed(2);
  195. var ave = (A / S).toFixed(2);
  196. if ((A > S * 2) && (N != 0)) {
  197. //标红A大于体积2倍且不断种的种子
  198. return '<span style="color:#ff0000;font-weight:900;">' + A + '@' + ave + '</span>'
  199. } else {
  200. return '<span style="">' + A + '@' + ave + "</span>"
  201. }
  202. }
  203. function addDataColGeneral() {
  204. var i_T, i_S, i_N
  205. $(seedTableSelector).each(function (row) {
  206. var $this = $(this);
  207. if (row == 0) {
  208. $this.children('td').each(function (col) {
  209. if ($(this).find('img.time').length) {
  210. i_T = col
  211. } else if ($(this).find('img.size').length) {
  212. i_S = col
  213. } else if ($(this).find('img.seeders').length) {
  214. i_N = col
  215. }
  216. })
  217. if (!i_T || !i_S || !i_N) {
  218. alert('未能找到数据列')
  219. return
  220. }
  221. $this.children("td:last").before("<td class=\"colhead\" title=\"A值@每GB的A值\">A@A/GB</td>");
  222. } else {
  223. var textA = makeA($this, i_T, i_S, i_N)
  224. $this.children("td:last").before("<td class=\"rowfollow\">" + textA + "</td>");
  225. }
  226. })
  227. }
  228. function addDataColMTeam() {
  229. let i_T, i_S, i_N, addFlag = false
  230. let colLen = $('div.mt-4>table>thead>tr>th').length
  231. if ($('div.mt-4>table>thead>tr>th:last').text().indexOf('A@A/GB') != -1) {
  232. addFlag = true
  233. colLen -= 1
  234. }
  235. i_T = colLen - 4
  236. i_S = colLen - 3
  237. i_N = colLen - 2
  238. if (!addFlag) {
  239. $('div.mt-4>table>thead>tr>th:last').after("<th class=\"border border-solid border-black p-2\" style=\"width: 100px;\" title=\"A值@每GB的A值\"> <div class=\"flex items-center cursor-pointer\"> <div class=\"flex-grow\">A@A/GB</div> </div> </th>");
  240. }
  241. $(seedTableSelector).each(function (row) {
  242. var $this = $(this);
  243. var textA = makeA($this, i_T, i_S, i_N)
  244. let tdTextA = "<td class=\"border border-solid border-black p-2 \" align=\"center\">" + textA + "</td>"
  245. if (addFlag) {
  246. $this.children("td:last").html(textA)
  247. } else {
  248. $this.children("td:last").after(tdTextA)
  249. //<span class=\"block mx-[-5px]\">"+textA+"</span>
  250. }
  251. })
  252. }
  253. if (isMTeam) {
  254. addDataColMTeam()
  255. } else {
  256. addDataColGeneral()
  257. }
  258. }
  259. function MTteamWaitPageLoadAndRun() {
  260. let $ = jQuery
  261. let count = 0
  262. let tableBlured = false
  263. let T0Found = false
  264. let seedTableFound = false
  265. // 页面局部刷新后重新判断 isMybonusPage
  266. isMybonusPage = window.location.toString().indexOf("mybonus") != -1
  267. let itv = setInterval(() => {
  268. if (isMybonusPage) {
  269. T0Found = $("li:has(b:contains('T0'))")[1]
  270. }
  271. if (T0Found || seedTableFound || count >= 100) {
  272. clearInterval(itv);
  273. run()
  274. }
  275. count++
  276. }, 100);
  277. let count2 = 0
  278. let itvTableBlur = setInterval(() => {
  279. if ($('div.ant-spin-blur')[0] || count2 >= 50) {
  280. tableBlured = true
  281. clearInterval(itvTableBlur)
  282. }
  283. count2++
  284. }, 100)
  285. let count3 = 0
  286. let itvTableUnblur = setInterval(() => {
  287. if (tableBlured && !$('div.ant-spin-blur')[0] || count3 >= 100) {
  288. seedTableFound = $(seedTableSelector)[1]
  289. if (seedTableFound || count3 >= 100) {
  290. clearInterval(itvTableUnblur)
  291. }
  292. }
  293. count3++
  294. }, 100)
  295. }
  296. let host = window.location.host.match(/\b[^\.]+\.[^\.]+$/)[0]
  297. let isMTeam = window.location.toString().indexOf("m-team") != -1
  298. let seedTableSelector = isMTeam ? 'div.mt-4>table>tbody>tr' : '.torrents:last-of-type>tbody>tr'
  299. let isMybonusPage = window.location.toString().indexOf("mybonus") != -1
  300. if (window.location.toString().indexOf("tjupt.org") != -1) {
  301. isMybonusPage = window.location.toString().indexOf("bonus.php") != -1
  302. }
  303. if (isMTeam) {
  304. if (isMybonusPage || window.location.toString().indexOf("browse") != -1) {
  305. MTteamWaitPageLoadAndRun()
  306. }
  307. } else {
  308. run()
  309. }
  310. var currentUrl = window.location.href;
  311. if (window.onurlchange === null) {
  312. // M-Team 页面局部刷新时重新运行函数
  313. window.addEventListener('urlchange', (info) => MTteamWaitPageLoadAndRun());
  314. }