U2历史记录

查看种子历史记录

目前为 2022-10-03 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name U2历史记录
  3. // @namespace https://u2.dmhy.org/
  4. // @version 0.5.0
  5. // @description 查看种子历史记录
  6. // @author kysdm
  7. // @grant none
  8. // @match *://u2.dmhy.org/details.php?*
  9. // @match *://u2.dmhy.org/offers.php?*
  10. // @match *://u2.dmhy.org/forums.php?action=viewtopic*
  11. // @icon https://u2.dmhy.org/favicon.ico
  12. // @require https://cdnjs.cloudflare.com/ajax/libs/localforage/1.10.0/localforage.min.js
  13. // @require https://unpkg.com/thenby@1.3.4/thenBy.min.js
  14. // @license Apache-2.0
  15. // ==/UserScript==
  16.  
  17. /*
  18. 本脚本基于 Bamboo Green 界面风格进行修改
  19. /*
  20.  
  21. /*
  22. GreasyFork 地址
  23. https://gf.qytechs.cn/zh-CN/scripts/428545
  24. */
  25.  
  26. /*
  27. 使用说明
  28. https://u2.dmhy.org/forums.php?action=viewtopic&topicid=13495&page=p150133#pid150133
  29. */
  30.  
  31. /*
  32. 更新日志
  33. https://github.com/kysdm/u2_share/commits/main/u2share_history.user.js
  34. */
  35.  
  36. 'use strict';
  37.  
  38. // 声明全局变量
  39. var lang, torrent_id, db, user_id, topicid, key, token;
  40.  
  41. (async () => {
  42. // 初始化
  43. lang = new lang_init($('#locale_selection').val()); // 获取当前网页语言
  44. let em = /.*id=(?<tid>\d{3,5})/i.exec(location.search); if (em) torrent_id = em.groups.tid; else torrent_id = null; // 当前种子ID
  45. topicid = location.href.match(/topicid=(\d+)/i) || ['', '']; if (topicid[1] !== '') topicid = topicid[1];
  46. user_id = $('#info_block').find('a:first').attr('href').match(/\.php\?id=(\d{3,5})/i) || ['', '']; if (user_id[1] !== '') user_id = user_id[1]; // 当前用户ID
  47. db = localforage.createInstance({ name: "history" });
  48. // key = await db.getItem('key');
  49. token = await db.getItem('token');
  50. if (token === null || token.length !== 96) { new auth(); return; };
  51. if (torrent_id && /\/(offers|details)\.php/i.test(location.pathname) && $('#outer').find('h2').text().match(/错误|錯誤|Ошибка|error/i)) { torrentInfoHistoryReset(); torrentCommentHistoryReset(); }// 为已经删除的种子显示历史
  52. else if (torrent_id && '/offers.php' === location.pathname && !/(cmtpage|offer_vote|vote)=(1|p)/i.test(location.href) && /off_details=1/i.test(location.href)) { torrentInfoHistory(); torrentCommentHistory(); } // 为正常种子显示历史
  53. else if (torrent_id && '/details.php' === location.pathname && !/(cmtpage|offer_vote|vote)=(1|p)/i.test(location.href)) { torrentInfoHistory(); torrentCommentHistory(); } // 为正常种子显示历史
  54. else if (torrent_id && /\/(offers|details)\.php/i.test(location.pathname) && /cmtpage=1/i.test(location.href)) { torrentCommentHistory(); } // 为正常种子显示历史 <仅评论>
  55. else if (/\/forums\.php\?action=viewtopic/i.test(location.href) && $('#outer').find('h2').text().match(/错误|錯誤|Ошибка|error/i)) { forumCommentHistoryReset(); } // 为被删除的论坛帖子显示历史
  56. else if (/\/forums\.php\?action=viewtopic/i.test(location.href)) { forumCommentHistory(); }; // 为论坛帖子显示历史
  57. })();
  58.  
  59. function auth() {
  60.  
  61. $('#outer').html(`<h1 align="center">U2种子历史记录 自动鉴权工具</h1>
  62. <table border="0" align="center" cellspacing="0" cellpadding="5">
  63. <tbody>
  64. <tr>
  65. <td valign="top" width="500" align="center"><span style="word-break: break-all; word-wrap: break-word;">
  66. <bdo dir="ltr">点击开始按钮,将自动进行鉴权,提示完成请刷新界面。<br>(建议手动备份下个人说明)<br></bdo></span></td>
  67. </tr>
  68. <tr>
  69. <td valign="top" align="left"><span style="word-break: break-all; word-wrap: break-word;">
  70. <bdo id="auth_log" dir="ltr"></bdo></span></td>
  71. </tr>
  72. <tr>
  73. <td align="center">
  74. <button id="auth_token" class="codebuttons" style="font-size:11px;margin-right:3px;" type="button">开始鉴权</button>
  75. <button id="auth_token_d" class="codebuttons" style="font-size:11px;margin-right:3px;" type="button">已有TOKEN</button>
  76. </td>
  77. </tr>
  78. </tbody>
  79. </table>`);
  80.  
  81. $("#auth_token_d").click(async function () {
  82. let __token = window.prompt("请输入Token"); // 弹窗提示输入Token
  83. if (__token === null || __token.length === 0) return; // 没有任何输入时 无视本次操作
  84. else if (__token.length !== 96) {
  85. await outPutLog(`Token: ${__token}`);
  86. await outPutLog(`Token长度不正确`);
  87. return;
  88. } // TOKEN长度不正确时 无视本次操作
  89. else {
  90. await db.setItem('token', __token);
  91. await outPutLog(`Token: ${__token}`);
  92. await outPutLog('鉴权结束');
  93. };
  94. });
  95.  
  96. function getProfile() {
  97. return new Promise(async (resolve, reject) => {
  98. $.ajax({
  99. type: 'get',
  100. url: 'https://u2.dmhy.org/usercp.php?action=personal',
  101. cache: false,
  102. success: async r => {
  103. const usercp = $.parseHTML(r)
  104. // const profile = $(usercp).find('[name="info"]').text(); // 获取用户信息
  105. const profile = {
  106. "action": "personal",
  107. "type": "save",
  108. "acceptpms": $(usercp).find('[name="acceptpms"]:checked').val(), // 接受以下短讯
  109. // 如果不需要开启对应功能,则不发送该参数
  110. "deletepms": $(usercp).find('[name="deletepms"]').is(':checked') ? 'on' : '', // 回复后删除短讯
  111. "savepms": $(usercp).find('[name="savepms"]').is(':checked') ? 'on' : '', // 保存短讯至发件箱
  112. "commentpm": $(usercp).find('[name="commentpm"]').is(':checked') ? 'yes' : '', // 我发布的种子有新评论时通知我
  113. "atpm": $(usercp).find('[name="atpm"]').is(':checked') ? '1' : '',// 有人在群聊区@我时通知
  114. "quotepm": $(usercp).find('[name="quotepm"]').is(':checked') ? '1' : '',// 有人在论坛、种子评论或候选评论引用我时通知。
  115. // 如果不需要开启对应功能,则不发送该参数
  116. "country": $(usercp).find('[name="country"]').val(), // 国家/地区
  117. "download": $(usercp).find('[name="download"]').val(),// 下行带宽
  118. "upload": $(usercp).find('[name="upload"]').val(),// 上行带宽
  119. "isp": $(usercp).find('[name="isp"]').val(),// 互联网服务提供商
  120. "savatar": $(usercp).find('[name="savatar"]').val(), // 选择头像
  121. "avatar": $(usercp).find('[name="avatar"]').val(), // 自定义头像
  122. "info": $(usercp).find('[name="info"]').text() // 个人说明
  123. };
  124. let profileAuth = { ...profile }; // 复制
  125. profileAuth.info = `-----BEGIN API KEY-----\n${key}\n-----END API KEY-----\n\n${profile.info}`; // 在个人说明加入鉴权信息
  126. const p = profileAuth.info.replace(/\r\n/g, () => { return '<br>' }).replace(/\n/g, () => { return '<br>' }).replace(/\r/g, () => { return '<br>' });
  127. await outPutLog(`请检查准备写入个人说明的BBCODE是否正确<br><br><table class="spoiler" width="100%">
  128. <tbody>
  129. <tr>
  130. <td class="colhead">个人说明&nbsp;&nbsp;<button class="spoiler-button-show" style="">检查一下</button>
  131. <button id="auth_profile_check" class="spoiler-button-hide" style="display: none;">检查完成</button></td>
  132. </tr>
  133. <tr>
  134. <td><span class="spoiler-content" style="display: none;">${p}</span></td>
  135. </tr>
  136. </tbody>
  137. </table>`);
  138. await db.setItem('profile', profile); // 存储用户信息
  139. $("#auth_profile_check").click(async function (ev) {
  140. $(this).hide();
  141. $(this).siblings(".spoiler-button-show").show();
  142. $(this).parentsUntil(".spoiler").find("span.spoiler-content:first").hide();
  143. ev.preventDefault();
  144. return resolve(profileAuth);
  145. });
  146. },
  147. error: async d => {
  148. await outPutLog('获取个人说明BBCODE失败');
  149. await outPutLog(`错误信息: ${d.responseText}`);
  150. return reject(Error(d.responseText));
  151. },
  152. });
  153. });
  154. };
  155.  
  156. function postProfile(data) {
  157. return new Promise(async (resolve, reject) => {
  158. $.ajax({
  159. type: 'post',
  160. url: 'https://u2.dmhy.org/usercp.php',
  161. cache: false,
  162. contentType: "application/x-www-form-urlencoded",
  163. data: data,
  164. success: async r => {
  165. await outPutLog('修改个人说明BBCODE成功');
  166. return resolve(key);
  167. },
  168. error: async d => {
  169. await outPutLog('修改个人说明BBCODE失败');
  170. await outPutLog(`错误信息: ${d.responseText}`);
  171. return reject(Error(d.responseText));
  172. },
  173. });
  174. });
  175. };
  176.  
  177. function getAuthKey() {
  178. return new Promise(async (resolve, reject) => {
  179. $.ajax({
  180. type: 'post',
  181. url: 'https://u2.kysdm.com/api/v1/token',
  182. contentType: "application/json",
  183. dataType: 'json',
  184. // async: false,
  185. data: JSON.stringify({ "uid": user_id }),
  186. success: async function (d) {
  187. if (d.msg === 'success') {
  188. key = d.data.key
  189. db.setItem('key', key);
  190. await outPutLog('获取Key成功');
  191. await outPutLog(`Key: ${key}`);
  192. return resolve(key);
  193. } else {
  194. await outPutLog('获取Key失败');
  195. await outPutLog(`错误信息: ${JSON.stringify(d)}`);
  196. return reject(Error('获取Key失败'));
  197. };
  198. },
  199. error: async function (d) {
  200. await outPutLog('获取Key失败');
  201. await outPutLog(`错误信息: ${d.responseText}`);
  202. return reject(Error('获取Key失败'));
  203. },
  204. });
  205. });
  206. };
  207.  
  208. function getToken() {
  209. return new Promise(async (resolve, reject) => {
  210. $.ajax({
  211. type: 'post',
  212. url: 'https://u2.kysdm.com/api/v1/token',
  213. contentType: "application/json",
  214. dataType: 'json',
  215. data: JSON.stringify({ "uid": user_id, "key": key }),
  216. success: async function (d) {
  217. if (d.msg === 'success') {
  218. let __token = d.data.token
  219. await outPutLog('获取Token成功');
  220. await outPutLog(`Token: ${__token}`);
  221. await db.setItem('token', __token);
  222. return resolve(__token);
  223. } else {
  224. await outPutLog('获取Token失败');
  225. await outPutLog(`错误信息: ${JSON.stringify(d)}`);
  226. return reject(Error('获取Token失败'));
  227. };
  228. },
  229. error: async function (d) {
  230. await outPutLog('获取Token失败');
  231. await outPutLog(`错误信息: ${d.responseText}`);
  232. return reject(Error('获取Token失败'));
  233. },
  234. });
  235. });
  236. };
  237.  
  238. function outPutLog(text) {
  239. return new Promise(async (resolve, reject) => {
  240. const log = $('#auth_log').html();
  241. $('#auth_log').html(`${log}${getDateString()} - ${text}<br>`);
  242. resolve(await sleep(0));
  243. });
  244. };
  245.  
  246. async function sleep(interval) {
  247. return new Promise(resolve => {
  248. setTimeout(resolve, interval);
  249. })
  250. };
  251.  
  252. $("#auth_token").click(async function () {
  253. await outPutLog('鉴权开始');
  254. await outPutLog('获取鉴权所需的Key');
  255. getAuthKey()
  256. .then(async () => {
  257. await outPutLog('获取个人说明BBCODE');
  258. return getProfile();
  259. })
  260. .then(async data => {
  261. await outPutLog('修改个人说明BBCODE');
  262. await postProfile(data);
  263. })
  264. .then(async () => {
  265. await outPutLog('获取鉴权所需的Token');
  266. await getToken();
  267. })
  268. .then(async () => {
  269. await outPutLog('还原个人说明BBCODE');
  270. await postProfile(await db.getItem('profile'));
  271. })
  272. .catch(async err => {
  273. await outPutLog(err);
  274. })
  275. .finally(async () => {
  276. await outPutLog('鉴权结束');
  277. });
  278. });
  279. };
  280.  
  281. async function forumCommentHistoryReset() {
  282. const errorstr = $('#outer').find('td.text').text();
  283. // 正在努力加载中...
  284. $('#outer').find('td.text').html(errorstr + '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i>' + lang['history_text_loading'] + '</i>');
  285.  
  286. $.ajax({
  287. type: 'post',
  288. url: 'https://u2.kysdm.com/api/v1/comment',
  289. contentType: "application/json",
  290. dataType: 'json',
  291. data: JSON.stringify({ "uid": user_id, "token": token, "topicid": topicid, "type": "forum" }),
  292. success: function (d) {
  293. if (d.msg === 'success') {
  294. console.log('获取论坛评论成功');
  295. let __comment = d.data.comment[topicid].sort(firstBy((a, b) => a.pid - b.pid).thenBy((a, b) => b.self - a.self)); // 如果用self排序,消息顺序不正确,则改用编辑日期排序
  296.  
  297. if (__comment.length === 0) { // 没有评论 可以说不会出现这种情况
  298. console.log('没有历史记录.');
  299. $('#outer').find('td.text').html(errorstr + '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;' + lang['history_text_empty'] + '</i>');
  300. return;
  301. };
  302.  
  303. // 计算pid出现次数
  304. let pidList = __comment.map(x => x.pid);
  305. let counts = new Object();
  306. pidList.forEach(x => counts[x] = counts[x] ? counts[x] + 1 : 1);
  307. const pidListSet = [...new Set(pidList)]; // 去重
  308.  
  309. // 还原网页
  310. $('#outer').html(`
  311. <table class="main" width="940" border="0" cellspacing="0" cellpadding="0">
  312. <tbody>
  313. <tr>
  314. <td class="embedded" align="center">
  315. <h1 align="center"><span id="top"></span></h1><br><br>
  316. </td>
  317. </tr>
  318. </tbody>
  319. </table>
  320. <table class="main" width="940" border="0" cellspacing="0" cellpadding="0">
  321. <tbody>
  322. <tr>
  323. <td class="embedded">
  324. <table width="100%" border="1" cellspacing="0" cellpadding="10">
  325. <tbody>
  326. <tr>
  327. <td id="comments" class="text">
  328. </td>
  329. </tr>
  330. </tbody>
  331. </table>
  332. </td>
  333. </tr>
  334. </tbody>
  335. </table>`
  336. );
  337.  
  338. // 还原标题
  339. $('span[id="top"]').html(__comment[0]['topics']);
  340.  
  341. __comment.forEach(x => {
  342. const bbcode_html = `<div style="margin-top: 8pt; margin-bottom: 8pt;">
  343. <table id="pid${x.pid}" border="0" cellspacing="0" cellpadding="0" width="100%">
  344. <tbody>
  345. <tr>
  346. <td class="embedded" width="99%">
  347. <a href="forums.php?action=viewtopic&amp;topicid=${x.topicid}&amp;page=p${x.pid}#pid${x.pid}">#${x.pid}</a>
  348. <!-- 论坛应该不能匿名发帖吧 -->
  349. <span class="nowrap"><a href="userdetails.php?id=${x.userid}"><b>
  350. <bdo dir="ltr">${x.username}</bdo></b></a></span>&nbsp;
  351. <time>${x.edit_time.replace('T', ' ')}</time>
  352. </td>
  353. <td class="embedded nowrap" width="1%">
  354. <font class="big">#<b>${pidListSet.findIndex((a) => a == x.pid) + 1}</b> 楼&nbsp;&nbsp;</font>
  355. <a href="#top"><img class="top" src="pic/trans.gif" alt="Top" title="${lang['back_to_top']}"></a>&nbsp;&nbsp;
  356. </td>
  357. </tr>
  358. </tbody>
  359. </table>
  360. </div>
  361. <table class="main-inner" border="1" cellspacing="0" cellpadding="5">
  362. <tbody>
  363. <tr>
  364. <td class="rowfollow" width="150" valign="top" align="left" style="padding: 0px">
  365. <img src="//u2.dmhy.org/pic/default_avatar.png" alt="avatar" width="150px">
  366. </td>
  367. <td class="rowfollow" valign="top"><br>
  368. <div class="post-body" id="pid${x.pid}body">
  369. <span style="word-break: break-all; word-wrap: break-word;"><bdo dir="ltr">
  370. ${(() => {
  371. if (x.action === 'edit') {
  372. return `${bbcode2html(x.bbcode)}</bdo></span>
  373. ${(() => {
  374. if ($('#locale_selection').val() === 'en_US') return `<p class="small">${lang['last_edited']} <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> at <time>${x.edit_time.replace('T', ' ')}</time>.</p><br><br>`;
  375. else if ($('#locale_selection').val() === 'ru_RU') return `<p class="small">${lang['last_edited']} <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> в <time>${x.edit_time.replace('T', ' ')}</time>.</p><br><br>`;
  376. else return `<p class="small">[<time>${x.edit_time.replace('T', ' ')}</time>] <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> ${lang['last_edited']} </p><br><br>`;
  377. })()}`;
  378. } else {
  379. return `${bbcode2html(x.bbcode)}<br><br></bdo></span>`;
  380. };
  381. })()}
  382. </div>
  383. </td>
  384. </tr>
  385. </tbody>
  386. </table>`
  387.  
  388. if (counts[x.pid] > 1) {
  389. console.log('有编辑记录 直接添加下拉菜单');
  390. // 插入下拉菜单基本框架
  391. if ($(`#history_comment${x.pid}_select`).length === 0) {
  392. $('#comments').append(bbcode_html); // 先插入整体框架
  393. console.log('添加下拉菜单基本框架');
  394. $(`[id="pid${x.pid}"]`).find('td:last').before(`<td class="embedded nowrap" width="1%"><select name="type" id="history_comment${x.pid}_select" style="margin-top: 1px;"></select>&nbsp;&nbsp;</td>`);
  395.  
  396. };
  397. // 向下拉菜单写入信息
  398. $(`#history_comment${x.pid}_select`).append(`<option value="${x.self}">${x.edit_time.replace('T', ' ')}
  399. ${(() => { return x.action === 'edit' ? ' E' : x.action === 'reply' ? ' R' : ' N' })()}
  400. ${(() => { return x.username === null && x.userid === null ? lang['anonymous_user'] : ` ${x.username}(${x.userid})` })()}
  401. </option>`)
  402. } else {
  403. $('#comments').append(bbcode_html);
  404. };
  405. });
  406.  
  407. $("[id^=history_comment]").change(function () { // 监听菜单选择
  408. let self = $(this).val();
  409. for (let i = 0, len = __comment.length; i < len; i++) {
  410. if (self != __comment[i].self) continue;
  411. let html;
  412. let x = __comment[i];
  413. if (x.action === 'edit') {
  414. html = `<span style="word-break: break-all; word-wrap: break-word;"><bdo dir="ltr">${bbcode2html(x.bbcode)}</bdo></span>
  415. ${(() => {
  416. if ($('#locale_selection').val() === 'en_US') return `<p><font class="small">${lang['last_edited']} <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> at <time>${x.edit_time.replace('T', ' ')}</time>.</font></p>`;
  417. else if ($('#locale_selection').val() === 'ru_RU') return `<p><font class="small">${lang['last_edited']} <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> в <time>${x.edit_time.replace('T', ' ')}</time>.</font></p>`;
  418. else return `<br><p><font class="small">[<time>${x.edit_time.replace('T', ' ')}</time>] <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> ${lang['last_edited']} </font></p>`;
  419. })()}`;
  420. } else {
  421. html = `<span style="word-break: break-all; word-wrap: break-word;"><bdo dir="ltr">${bbcode2html(x.bbcode)}</bdo></span>`;
  422. };
  423. $(this).parents('[id^=pid]').parent().next().find('.post-body').html(html);
  424. return;
  425. };
  426. });
  427.  
  428. } else {
  429. console.log('获取论坛评论错误');
  430. $('#outer').find('td.text').html(`${errorstr}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i>${lang['history_text_error']}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a id="apifailure" href="javascript:void(0);" style="color:#FF1212">${lang['reset_token']}</a></i>`);
  431. $("#apifailure").click(function () {
  432. let confirm = prompt("输入 YES 确认本次操作 (大写)");
  433. if (confirm === 'YES') {
  434. db.removeItem('key');
  435. db.removeItem('token');
  436. alert("成功");
  437. };
  438. });
  439. };
  440. },
  441. error: function (d) {
  442.  
  443. },
  444. });
  445. };
  446.  
  447. async function forumCommentHistory() {
  448. db = localforage.createInstance({ name: "history" });
  449.  
  450. $.ajax({
  451. type: 'post',
  452. url: 'https://u2.kysdm.com/api/v1/comment',
  453. contentType: "application/json",
  454. dataType: 'json',
  455. data: JSON.stringify({ "uid": user_id, "token": token, "topicid": topicid, "type": "forum" }),
  456. success: async function (d) {
  457. if (d.msg === 'success') {
  458. console.log('获取论坛评论成功');
  459. let __comment = d.data.comment[topicid].sort((a, b) => b.self - a.self);
  460. let pid_list = __comment.map(x => x.pid);
  461. let counts = new Object();
  462. pid_list.forEach(x => counts[x] = counts[x] ? counts[x] + 1 : 1);
  463.  
  464. let pid_list_unique = Array.from(new Set(pid_list)).sort((a, b) => a - b); // 去重排序
  465. console.log(pid_list_unique);
  466. let p = $('#outer').find('p[align="center"]:first').text().replace(/\n/g, '<br>');
  467. let pg = /(?<p>\d+)<br>$/i.exec(p);
  468. let page_total = Number(pg.groups.p); // 有多少页评论
  469. let page_now = Number($('#outer').find('p:first').find('.gray b:last').text());
  470. console.log(`现在在评论第 ${page_now} | ${page_total}`);
  471. var pid_each = await db.getItem('forum_pid_each') || 0;; // 每页最大显示楼层数量 <当数据库没有值时,pid_list_valid会是空值,>
  472.  
  473. if (page_now < page_total) {
  474. // 评论完整填满一个页面时,计算单个页面最大显示评论数量
  475. // 后期改动最大显示评论数量的数值后,直接进入帖子最后一页可能会出现不属于当前页面的评论
  476. console.log(`页面评论数量达到最大值`);
  477. pid_each = $('table[id^=pid]').length;
  478. await db.setItem('forum_pid_each', pid_each);
  479. };
  480.  
  481. var pid_list_valid = pid_list_unique.slice(pid_each * page_now - pid_each, pid_each * page_now); // 截取属于当前页面的PID
  482. console.log(pid_list_valid);
  483.  
  484. __comment.forEach(x => {
  485. let del_tag = 1;
  486. $('[id^="pid"]').each(function () {
  487. let pid = $(this).find('[class="embedded"]').children('a').first().text().replace('#', ''); // 获取网页上每个评论的PID
  488. if (x.pid == pid) {
  489. del_tag = 0; // 标记网页上有对应的PID
  490. if (counts[pid] > 1) {
  491. if ($(`#history_comment${pid}_select`).length === 0) $(this).find('td:last').before(`<td class="embedded nowrap" width="1%"><select name="type" id="history_comment${x.pid}_select" style="margin-top: 1px;"></select>&nbsp;&nbsp;</td>`);
  492. $(`#history_comment${pid}_select`).append(`<option value="${x.self}">${x.edit_time.replace('T', ' ')}
  493. ${(() => { return x.action === 'edit' ? ' E' : x.action === 'reply' ? ' R' : ' N' })()}
  494. ${(() => { return x.username === null && x.userid === null ? lang['anonymous_user'] : ` ${x.username}(${x.userid})` })()}
  495. </option>`);
  496. };
  497. };
  498. });
  499.  
  500. if (del_tag === 1) {
  501. // console.log(`${x.pid} | 被删除`);
  502. if (!pid_list_valid.includes(x.pid)) return; // 不属于当前页面的PID直接跳出
  503. // 只看该作者 启用时,仅还原改用户的记录
  504. let em = /authorid=(?<authorid>\d{1,5})/i.exec(location.search);
  505. if (em && x.userid != em.groups.authorid) return true;
  506.  
  507. if ($('[id="pid10000000000"]').length === 0) {
  508. $('[id="outer"]').find('td.text:first').append(
  509. `<div style="margin-top: 8pt; margin-bottom: 8pt; display:none;">
  510. <table id="pid10000000000" border="0" cellspacing="0" cellpadding="0" width="100%">
  511. <tbody>
  512. <tr>
  513. <td class="embedded" width="99%">
  514. <a href="javascript:void(0);">#10000000000</a>
  515. </td>
  516. </tr>
  517. </tbody>
  518. </table>
  519. </div>`
  520. );
  521. };
  522.  
  523. $('[id^="pid"]').each(function () {
  524. let pid = $(this).find('[class="embedded"]').children('a').first().text().replace('#', ''); // 获取网页上每个评论的PID
  525.  
  526. if (x.pid < Number(pid)) {
  527.  
  528. const bbcode_html = `<div style="margin-top: 8pt; margin-bottom: 8pt;">
  529. <table id="pid${x.pid}" border="0" cellspacing="0" cellpadding="0" width="100%">
  530. <tbody>
  531. <tr>
  532. <td class="embedded" width="99%">
  533. <a href="forums.php?action=viewtopic&amp;topicid=${x.topicid}&amp;page=p${x.pid}#pid${x.pid}">#${x.pid}</a>
  534. <!-- 论坛应该不能匿名发帖吧 -->
  535. <span class="nowrap">
  536. <a href="userdetails.php?id=${x.userid}"><b>
  537. <bdo dir="ltr">${x.username}</bdo></b></a></span>&nbsp;
  538. <time>${x.edit_time.replace('T', ' ')}</time>
  539. </td>
  540. <td class="embedded nowrap" width="1%">
  541. <a href="#top"><img class="top" src="pic/trans.gif" alt="Top" title="${lang['back_to_top']}"></a>&nbsp;&nbsp;
  542. </td>
  543. </tr>
  544. </tbody>
  545. </table>
  546. </div>
  547. <table class="main-inner" border="1" cellspacing="0" cellpadding="5">
  548. <tbody>
  549. <tr>
  550. <td class="rowfollow" width="150" valign="top" align="left" style="padding: 0px">
  551. <img src="//u2.dmhy.org/pic/default_avatar.png" alt="avatar" width="150px">
  552. </td>
  553. <td class="rowfollow" valign="top"><br>
  554. <div class="post-body" id="pid${x.pid}body">
  555. <span style="word-break: break-all; word-wrap: break-word;"><bdo dir="ltr">
  556. ${(() => {
  557. if (x.action === 'edit') {
  558. return `${bbcode2html(x.bbcode)}</bdo></span>
  559. ${(() => {
  560. if ($('#locale_selection').val() === 'en_US') return `<p class="small">${lang['last_edited']} <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> at <time>${x.edit_time.replace('T', ' ')}</time>.</p><br><br>`;
  561. else if ($('#locale_selection').val() === 'ru_RU') return `<p class="small">${lang['last_edited']} <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> в <time>${x.edit_time.replace('T', ' ')}</time>.</p><br><br>`;
  562. else return `<p class="small">[<time>${x.edit_time.replace('T', ' ')}</time>] <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> ${lang['last_edited']} </p><br><br>`;
  563. })()}`;
  564. } else {
  565. return `${bbcode2html(x.bbcode)}<br><br></bdo></span>`;
  566. };
  567. })()}
  568. </div>
  569. </td>
  570. </tr>
  571. </tbody>
  572. </table>`
  573.  
  574. $(`[id="pid${pid}"]`).parent().before(bbcode_html);
  575.  
  576. if (counts[x.pid] > 1) {
  577. if ($(`#history_comment${x.pid}_select`).length === 0) $(`[id="pid${x.pid}"]`).find('td:last').before(`<td class="embedded nowrap" width="1%"><select name="type" id="history_comment${x.pid}_select"></td>`);
  578. $(`#history_comment${x.pid}_select`).append(`<option value="${x.self}">${x.edit_time.replace('T', ' ')}
  579. ${(() => { return x.action === 'edit' ? ' E' : x.action === 'reply' ? ' R' : ' N' })()}
  580. ${(() => { return x.username === null && x.userid === null ? lang['anonymous_user'] : ` ${x.username}(${x.userid})` })()}
  581. </option>`);
  582. };
  583.  
  584. return false;
  585. };
  586. });
  587.  
  588. };
  589. });
  590.  
  591. $("[id^=history_comment]").change(function () { // 监听菜单选择
  592. let self = $(this).val();
  593. for (let i = 0, len = __comment.length; i < len; i++) {
  594. if (self != __comment[i].self) continue;
  595. let html;
  596. let x = __comment[i];
  597. if (x.action === 'edit') {
  598. html = `<span style="word-break: break-all; word-wrap: break-word;"><bdo dir="ltr">${bbcode2html(x.bbcode)}</bdo></span>
  599. ${(() => {
  600. if ($('#locale_selection').val() === 'en_US') return `<p><font class="small">${lang['last_edited']} <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> at <time>${x.edit_time.replace('T', ' ')}</time>.</font></p>`;
  601. else if ($('#locale_selection').val() === 'ru_RU') return `<p><font class="small">${lang['last_edited']} <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> в <time>${x.edit_time.replace('T', ' ')}</time>.</font></p>`;
  602. else return `<br><p><font class="small">[<time>${x.edit_time.replace('T', ' ')}</time>] <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> ${lang['last_edited']} </font></p>`;
  603. })()}`;
  604. } else {
  605. html = `<span style="word-break: break-all; word-wrap: break-word;"><bdo dir="ltr">${bbcode2html(x.bbcode)}</bdo></span>`;
  606. };
  607. $(this).parents('[id^=pid]').parent().next().find('.post-body').html(html);
  608. return;
  609. };
  610. });
  611. } else {
  612. console.log('获取论坛评论错误');
  613. };
  614. },
  615. error: function (d) {
  616.  
  617. },
  618. });
  619. };
  620.  
  621. async function torrentCommentHistory() {
  622. $.ajax({
  623. type: 'post',
  624. url: 'https://u2.kysdm.com/api/v1/comment',
  625. contentType: "application/json",
  626. dataType: 'json',
  627. data: JSON.stringify({ "uid": user_id, "token": token, "torrent_id": torrent_id, "type": "torrent" }),
  628. success: function (d) {
  629. if (d.msg === 'success') {
  630. console.log('获取种子评论成功');
  631. let __comment = d.data.comment[torrent_id].sort((a, b) => b.self - a.self);
  632. let cid_list = __comment.map(x => x.cid);
  633. let counts = new Object();
  634. cid_list.forEach(x => counts[x] = counts[x] ? counts[x] + 1 : 1);
  635.  
  636. // let startcomments = $('#startcomments').text();
  637. if ($('[id^="cid"]').length === 0) {
  638. // 候选没有评论 || 通过的种子没有评论
  639. console.log('完全没有评论');
  640. var cid_list_valid = Array.from(new Set(cid_list));
  641. } else {
  642. // 有评论
  643. let x = $('#startcomments').nextAll('p:first').text();
  644. let pg = /(?<p>\d+)$/i.exec(x);
  645. let page_total = Math.ceil(pg.groups.p / 10); // 有多少页评论
  646. let cid_list_unique = Array.from(new Set(cid_list)).sort((a, b) => a - b); // 去重排序
  647. console.log(cid_list_unique);
  648. let page_now = $('#startcomments').nextAll('p:first').find('.gray:last').text();
  649. pg = /(?<p>\d+)$/i.exec(page_now);
  650. for (let i = 1; i <= page_total; i++) {
  651. if (Number(pg.groups.p) <= 10 * i) {
  652. console.log(`现在在评论第 ${i} 页`);
  653. var cid_list_valid = cid_list_unique.slice(10 * i - 10, 10 * i); // 截取属于当前页面的评论
  654. console.log(cid_list_valid);
  655. break;
  656. };
  657. };
  658. };
  659.  
  660. __comment.forEach(x => {
  661. let del_tag = 1;
  662. $('[id^="cid"]').each(function () {
  663. let cid = $(this).find('[class="embedded"]').children('a').attr('name');
  664. if (x.cid == cid) {
  665. del_tag = 0; // 标记网页上有对应的CID
  666. if (x.cid == cid && counts[cid] > 1) {
  667. if ($(`#history_comment${cid}_select`).length === 0) $(this).find('td:last').before(`<td class="embedded nowrap" width="1%"><select name="type" id="history_comment${cid}_select" ></select>&nbsp;&nbsp;</td>`);
  668. $(`#history_comment${cid}_select`).append(`<option value="${x.self}">${x.edit_time.replace('T', ' ')}
  669. ${(() => { return x.action === 'edit' ? ' E' : x.action === 'reply' ? ' R' : ' N' })()}
  670. ${(() => { return x.username === null && x.userid === null ? lang['anonymous_user'] : ` ${x.username}(${x.userid})` })()}
  671. </option>`);
  672. };
  673. };
  674. });
  675.  
  676. if (del_tag === 1) {
  677. // console.log(`${x.cid} | 被删除`);
  678. if (!cid_list_valid.includes(x.cid)) return; // 不属于当前页面的评论直接跳出
  679. if ($('[id^="cid"]').length === 0) {
  680. // 所有评论都被删除
  681. console.log('所有评论都被删除');
  682. $('#outer').find('table:last').hide();
  683. $('#outer').find('table:last').prevAll('br').remove();
  684. $('#startcomments').remove();
  685. $('#outer').find('table:last').before('<br><h1 id="startcomments" align="center">用户评论</h1>');
  686. $('#outer').find('table:last').after(`<br>
  687. <table class="main" width="940" border="0" cellspacing="0" cellpadding="0">
  688. <tbody>
  689. <tr>
  690. <td class="embedded">
  691. <table width="100%" border="1" cellspacing="0" cellpadding="10">
  692. <tbody>
  693. <tr>
  694. <td class="text">
  695. <div style="margin-top: 8pt; margin-bottom: 8pt; display:none;">
  696. <table id="cid1000000000" border="0" cellspacing="0" cellpadding="0" width="100%">
  697. <tbody>
  698. <tr>
  699. <td class="embedded" width="99%">
  700. <a href="javascript:void(0);" name="1000000000">#1000000000</a>
  701. </td>
  702. </tr>
  703. </tbody>
  704. </table>
  705. </div>
  706. </td>
  707. </tr>
  708. </tbody>
  709. </table>
  710. </td>
  711. </tr>
  712. </tbody>
  713. </table>`
  714. );
  715. } else if ($('[id="cid1000000000"]').length === 0) {
  716. $('#startcomments').nextAll('table.main:first').find('.text').append(
  717. `<div style="margin-top: 8pt; margin-bottom: 8pt; display:none;">
  718. <table id="cid1000000000" border="0" cellspacing="0" cellpadding="0" width="100%">
  719. <tbody>
  720. <tr>
  721. <td class="embedded" width="99%">
  722. <a href="javascript:void(0);" name="1000000000">#1000000000</a>
  723. </td>
  724. </tr>
  725. </tbody>
  726. </table>
  727. </div>`);
  728. };
  729.  
  730. $('[id^="cid"]').each(function () {
  731. let cid = $(this).find('[class="embedded"]').children('a').attr('name'); // 获取网页上每个评论的CID
  732.  
  733. if (x.cid < Number(cid)) {
  734. if (x.userid === null && x.username === null) {
  735. var userInfo = `<span style="color: gray">&nbsp;<i>${lang['anonymous']}</i>&nbsp;</span>`
  736. } else {
  737. var userInfo = `<span style="color: gray">&nbsp;<span class="nowrap"><a href="userdetails.php?id=${x.userid}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span>`
  738. }
  739.  
  740. const bbcode_html = `<div style="margin-top: 8pt; margin-bottom: 8pt;">
  741. <table id="cid${x.cid}" border="0" cellspacing="0" cellpadding="0" width="100%">
  742. <tbody>
  743. <tr>
  744. <td class="embedded" width="99%">
  745. <a href="${cidUrl(x.torrent_id, x.cid)}" name="${x.cid}">#${x.cid}</a>
  746. ${userInfo}
  747. <span style="color: gray">&nbsp;<time>${x.edit_time.replace('T', ' ')}</time></span></span>
  748. </td>
  749. <td class="embedded nowrap" width="1%">
  750. <a href="#top"><img class="top" src="pic/trans.gif" alt="Top" title="Top"></a>&nbsp;&nbsp;
  751. </td>
  752. </tr>
  753. </tbody>
  754. </table>
  755. </div>
  756. <table class="main-inner" width="100%" border="0" cellspacing="0" cellpadding="5">
  757. <tbody>
  758. <tr>
  759. <td class="rowfollow" width="150" valign="top" style="padding: 0">
  760. <img src="//u2.dmhy.org/pic/default_avatar.png" alt="avatar" width="150px"></td>
  761. <td class="rowfollow" valign="top"><br>
  762. ${(() => {
  763. if (x.action === 'edit') {
  764. return `<span style="word-break: break-all; word-wrap: break-word;"><bdo dir="ltr">${bbcode2html(x.bbcode)}</bdo></span>
  765. ${(() => {
  766. if ($('#locale_selection').val() === 'en_US') return `<p class="small">${lang['last_edited']} <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> at <time>${x.edit_time.replace('T', ' ')}</time>.</p><br><br>`;
  767. else if ($('#locale_selection').val() === 'ru_RU') return `<p class="small">${lang['last_edited']} <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> в <time>${x.edit_time.replace('T', ' ')}</time>.</p><br><br>`;
  768. else return `<p class="small">[<time>${x.edit_time.replace('T', ' ')}</time>] <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> ${lang['last_edited']} </p><br><br>`;
  769. })()}`;
  770. } else {
  771. return `<span style="word-break: break-all; word-wrap: break-word;"><bdo dir="ltr">${bbcode2html(x.bbcode)}<br><br></bdo></span>`;
  772. };
  773. })()}
  774. </td>
  775. </tr>
  776. </tbody>
  777. </table>`;
  778.  
  779. $(`[id="cid${cid}"]`).parent().before(bbcode_html); // 先插入整体框架
  780.  
  781. if (counts[x.cid] > 1) {
  782. console.log('有编辑记录 直接添加下拉菜单');
  783. // 插入下拉菜单基本框架
  784. if ($(`#history_comment${x.cid}_select`).length === 0) {
  785. console.log('添加下拉菜单基本框架');
  786. $(`[id="cid${x.cid}"]`).find('td:last').before(`<td class="embedded nowrap" width="1%"><select name="type" id="history_comment${x.cid}_select" ></select>&nbsp;&nbsp;</td>`);
  787. };
  788. // 向下拉菜单写入信息
  789. $(`#history_comment${x.cid}_select`).append(`<option value="${x.self}">${x.edit_time.replace('T', ' ')}
  790. ${(() => { return x.action === 'edit' ? ' E' : x.action === 'reply' ? ' R' : ' N' })()}
  791. ${(() => { return x.username === null && x.userid === null ? lang['anonymous_user'] : ` ${x.username}(${x.userid})` })()}
  792. </option>`);
  793. };
  794.  
  795. return false;
  796. };
  797.  
  798. });
  799. };
  800.  
  801. });
  802.  
  803. $("[id^=history_comment]").change(function () { // 监听菜单选择
  804. let self = $(this).val();
  805.  
  806. for (let i = 0, len = __comment.length; i < len; i++) {
  807. if (self != __comment[i].self) continue;
  808. let html;
  809. let x = __comment[i];
  810. if (x.action === 'edit') {
  811. html = `<br>
  812. <span style="word-break: break-all; word-wrap: break-word;">
  813. <bdo dir="ltr">${bbcode2html(x.bbcode)}</bdo>
  814. </span>
  815. ${(() => {
  816. if ($('#locale_selection').val() === 'en_US') return `<p class="small">${lang['last_edited']} <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> at <time>${x.edit_time.replace('T', ' ')}</time>.</p>`;
  817. else if ($('#locale_selection').val() === 'ru_RU') return `<p class="small">${lang['last_edited']} <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> в <time>${x.edit_time.replace('T', ' ')}</time>.</p>`;
  818. else return `<br><p class="small">[<time>${x.edit_time.replace('T', ' ')}</time>] <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> ${lang['last_edited']} </p>`;
  819. })()}`;
  820.  
  821. } else {
  822. html = `<br>
  823. <span style="word-break: break-all; word-wrap: break-word;">
  824. <bdo dir="ltr">${bbcode2html(x.bbcode)}</bdo>
  825. </span>`;
  826. };
  827. $(this).parents('[id^=cid]').parent().next().find('[class="rowfollow"]:last').html(html);
  828. return;
  829. };
  830. });
  831.  
  832. } else {
  833. console.log('获取种子评论错误');
  834. };
  835. },
  836. error: function (d) {
  837.  
  838. },
  839. });
  840. };
  841.  
  842.  
  843. async function torrentInfoHistory() {
  844. if ($('h3').length === 1) { // 插入 select 基本框架
  845. const right = ($('#outer').width() - $('h3').next().width()) / 2 + 5; // 计算偏移量
  846. $('#top').after('<div id="hsty" style="position: relative;"><div id="history" style="position: absolute; right:' + right + 'px; margin-top: 4px;"><select name="type" id="history_select"></div></div>');
  847. $(window).resize(function () { $('#history').css("right", ($('#outer').width() - $('h3').next().width()) / 2 + 5); });
  848. } else {
  849. const right = ($('#outer').width() - $('#top').next().width()) / 2 + 5; // 计算偏移量
  850. $('#top').after('<div id="history" style="position: relative; float: right; margin-bottom: 10px; margin-right: ' + right + 'px"><select name="type" id="history_select"></div>');
  851. $(window).resize(function () { $('#history').css("margin-right", ($('#outer').width() - $('#history').next().width()) / 2 + 5 + 'px'); });
  852. };
  853.  
  854. $("#history_select").append("<option>" + lang['history_select_loading'] + "</option>");
  855.  
  856. const __json = await getapi(); // 从 API 获取数据
  857.  
  858. if (__json.msg !== 'success') { // 加载失败时
  859. console.log('获取历史记录失败.');
  860. $("#history_select").empty(); // 插入前先清空 option
  861. $("#history_select").append('<option value="80000">' + lang['history_select_error'] + '</option>'); // 希望你不要看到这个 (ノДT)
  862. $("#history_select").append(`<option value="90000">${lang['reset_token']}</option>`); // 删除本地授权信息
  863. $("#history_select").change(function () { // 监听菜单选择
  864. let self = Number($(this).val());
  865. if (self === 90000) {
  866. let confirm = prompt("输入 YES 确认本次操作 (大写)");
  867. if (confirm === 'YES') {
  868. db.removeItem('key');
  869. db.removeItem('token');
  870. $('#history_select').val(80000); // 将焦点设置到 80000
  871. $('#history_select').change(); // 手动触发列表更改事件
  872. alert("成功");
  873. } else {
  874. $('#history_select').val(80000); // 将焦点设置到 80000
  875. $('#history_select').change(); // 手动触发列表更改事件
  876. };
  877. };
  878. });
  879. return;
  880. };
  881.  
  882. console.log('获取历史记录成功.');
  883. let history_data = __json.data.history;
  884.  
  885. $("#history_select").empty(); // 插入前先清空 option
  886. for (let i = 0, len = history_data.length; i < len; i++) { // 循环插入到选择列表中
  887. $("#history_select").append("<option value='" + history_data[i].self + "'>"
  888. + history_data[i].get_time.replace('T', ' ')
  889. + ((edited_type) => {
  890. switch (edited_type) {
  891. case 0: return ' H'; // 添加候选
  892. case 1: return ' E' // 普通用户编辑
  893. case 2: return ' M' // MOD编辑
  894. case 3: return ' T' // 允许候选
  895. case 4: return ' U' // 上传种子
  896. default: return ' ' // 早期记录
  897. };
  898. })(history_data[i].edited_type)
  899. + (() => {
  900. if (history_data[i].self === 0) return lang['current_time']
  901. else if (history_data[i].edited_name === null && history_data[i].edited_id === null) return ''
  902. else if (history_data[i].edited_name === '匿名' && history_data[i].edited_id === null) return lang['anonymous_user']
  903. else if (history_data[i].edited_name !== null && history_data[i].edited_id !== null) return ' ' + history_data[i].edited_name + '(' + history_data[i].edited_id + ')'
  904. else return ' @BUG@'
  905. })()
  906. + "</option>");
  907. };
  908.  
  909. // 草 为什么会这样呢 明明原来很整齐的
  910. $("#history_select").change(function () { // 监听菜单选择
  911. let self = Number($(this).val());
  912. for (let i = 0, len = history_data.length; i < len; i++) {
  913. if (self !== history_data[i].self) continue;
  914. history_data[i].banned === 1 ? $('#top').html(history_data[i].title + '&nbsp;&nbsp;&nbsp; <b>[<font class="striking">' + lang['banned'] + '</font>]</b>') : $('#top').text(history_data[i].title);
  915. // 检查副标题一栏是否存在
  916. if ($("td[class='rowhead nowrap']:contains(" + lang['subtitle'] + ")").length === 0 && history_data[i].subtitle !== null) {
  917. $("td[class='rowhead nowrap']:contains(" + lang['uploaded'] + ")").parent().before('<tr><td class="rowhead nowrap" valign="top" align="right">' + lang['subtitle'] + '</td><td class="rowfollow" valign="top" align="left"></td></tr>');
  918. }
  919. else if ($("td[class='rowhead nowrap']:contains(" + lang['subtitle'] + ")").length === 1 && history_data[i].subtitle === null) {
  920. $("td[class='rowhead nowrap']:contains(" + lang['subtitle'] + ")").parent().remove();
  921. };
  922. $("td[class='rowhead nowrap']:contains(" + lang['subtitle'] + ")").next().text(history_data[i].subtitle); // 副标题
  923. $("td[class='rowhead nowrap']:contains(" + lang['description'] + ")").last().next().html('<span style="word-break: break-all; word-wrap: break-word;"><bdo dir="ltr">' + bbcode2html(history_data[i].description_info) + '</bdo></span>'); // 描述
  924. if ($('h3').length === 1) { // 已经通过候选的种子
  925. $("td[class='rowhead nowrap']:contains(" + lang['uploaded'] + ")").next().html(((p) => {
  926. if (p.uploader_id === null && p.uploader_name === '匿名') return '<i>' + lang['anonymous'] + '</i>'; // 匿名发布
  927. if (p.uploader_id === null && p.uploader_name !== '匿名') return p.uploader_name; // 自定义署名 不带UID
  928. if (p.uploader_id !== null && p.uploader_name !== '匿名') return '<a href="userdetails.php?id=' + p.uploader_id + '"><b>' + p.uploader_name + '</b></a>'; // 正常显示 || 自定义署名 带UID
  929. })(history_data[i])); // 发布人
  930. $("td[class='rowhead nowrap']:contains(" + lang['basic_info'] + ")").next().html('<b>' + lang['uploaded_at'] + ':</b> ' + history_data[i].uploaded_at.replace('T', ' ')
  931. + (() => { if (history_data[i].torrent_size) { return '&nbsp;&nbsp;&nbsp;<b>' + lang['size'] + ':</b>&nbsp;' + convert(history_data[i].torrent_size) } else { return ''; } })()
  932. + '&nbsp;&nbsp;&nbsp;<b>' + lang['category'] + ':</b> ' + history_data[i].category)
  933. } else { // 还在候选的种子
  934. $("td[class='rowhead nowrap']:contains(" + lang['basic_info'] + ")").next().html('<b>' + lang['submitted_by'] + '</b>:&nbsp;'
  935. + ((p) => {
  936. if (p.uploader_id === null && p.uploader_name === '匿名') return '<i>' + lang['anonymous'] + '</i>'; // 匿名发布
  937. if (p.uploader_id !== null && p.uploader_name !== '匿名') return '<a href="userdetails.php?id=' + p.uploader_id + '"><b>' + p.uploader_name + '</b></a>'; // 正常显示
  938. })(history_data[i])
  939. + '&nbsp;&nbsp;&nbsp;<b>' + lang['submitted_at'] + '</b>:&nbsp;<time>'
  940. + history_data[i].uploaded_at.replace('T', ' ')
  941. + '</time>&nbsp;&nbsp;&nbsp;<b>'
  942. + (() => { if (history_data[i].torrent_size) { return `${lang['size']}</b>:&nbsp;${convert(history_data[i].torrent_size)}&nbsp;&nbsp;&nbsp;<b>` } else { return ''; } })()
  943. + lang['category'] + '</b>:&nbsp;'
  944. + history_data[i].category
  945. );
  946. };
  947. };
  948. });
  949. };
  950.  
  951. async function torrentCommentHistoryReset() {
  952.  
  953. const callback = (mutations, observer) => {
  954. mutations.forEach(function (mutation) {
  955. if (mutation.addedNodes.length === 0) return;
  956.  
  957. console.log('检测到种子页面已经完成加载');
  958. observer.disconnect(); // 停止监听
  959.  
  960. $('#description').after(`<br><br><h1 align="center" id="startcomments" style="font-weight:normal; font-style: italic">正在加载用户评论...</h1><br>`);
  961. $.ajax({
  962. type: 'post',
  963. url: 'https://u2.kysdm.com/api/v1/comment',
  964. contentType: "application/json",
  965. dataType: 'json',
  966. data: JSON.stringify({ "uid": user_id, "token": token, "torrent_id": torrent_id, "type": "torrent" }),
  967. success: function (d) {
  968. if (d.msg !== 'success') { console.log('获取种子评论错误'); }
  969. else {
  970. console.log('获取种子评论成功');
  971. let __comment = d.data.comment[torrent_id].sort(firstBy((a, b) => a.cid - b.cid).thenBy((a, b) => b.self - a.self)); // 如果用self排序,消息顺序不正确,则改用编辑日期排序
  972. if (__comment.length === 0) { // 没有评论
  973. $('#startcomments').text('没有评论');
  974. $('#startcomments').removeAttr("style");
  975. return;
  976. } else {
  977. $('#startcomments').text('用户评论');
  978. $('#startcomments').removeAttr("style");
  979. };
  980.  
  981. let cidList = __comment.map(x => x.cid);
  982. let counts = new Object();
  983. cidList.forEach(x => counts[x] = counts[x] ? counts[x] + 1 : 1);
  984.  
  985. $('#startcomments').after(`<br>
  986. <table class="main" width="940" border="0" cellspacing="0" cellpadding="0">
  987. <tbody>
  988. <tr>
  989. <td class="embedded">
  990. <table width="100%" border="1" cellspacing="0" cellpadding="10">
  991. <tbody>
  992. <tr>
  993. <td id="comments" class="text"></td>
  994. </tr>
  995. </tbody>
  996. </table>
  997. </td>
  998. </tr>
  999. </tbody>
  1000. </table>`
  1001. );
  1002.  
  1003. __comment.forEach(x => {
  1004. if (x.userid === null && x.username === null) {
  1005. var userInfo = `<span style="color: gray">&nbsp;<i>${lang['anonymous']}</i>&nbsp;</span>`
  1006. } else {
  1007. var userInfo = `<span style="color: gray">&nbsp;<span class="nowrap"><a href="userdetails.php?id=${x.userid}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span>`
  1008. }
  1009.  
  1010. const bbcode_html = `<div style="margin-top: 8pt; margin-bottom: 8pt;">
  1011. <table id="cid${x.cid}" border="0" cellspacing="0" cellpadding="0" width="100%">
  1012. <tbody>
  1013. <tr>
  1014. <td class="embedded" width="99%">
  1015. <a href="${cidUrl(x.torrent_id, x.cid)}" name="${x.cid}">#${x.cid}</a>
  1016. ${userInfo}
  1017. <span style="color: gray">&nbsp;<time>${x.edit_time.replace('T', ' ')}</time></span></span>
  1018. </td>
  1019. <td class="embedded nowrap" width="1%">
  1020. <a href="#top"><img class="top" src="pic/trans.gif" alt="Top" title="Top"></a>&nbsp;&nbsp;
  1021. </td>
  1022. </tr>
  1023. </tbody>
  1024. </table>
  1025. </div>
  1026. <table class="main-inner" width="100%" border="0" cellspacing="0" cellpadding="5">
  1027. <tbody>
  1028. <tr>
  1029. <td class="rowfollow" width="150" valign="top" style="padding: 0">
  1030. <img src="//u2.dmhy.org/pic/default_avatar.png" alt="avatar" width="150px"></td>
  1031. <td class="rowfollow" valign="top"><br>
  1032. ${(() => {
  1033. if (x.action === 'edit') {
  1034. return `<span style="word-break: break-all; word-wrap: break-word;"><bdo dir="ltr">${bbcode2html(x.bbcode)}</bdo></span>
  1035. ${(() => {
  1036. if ($('#locale_selection').val() === 'en_US') return `<p class="small">${lang['last_edited']} <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> at <time>${x.edit_time.replace('T', ' ')}</time>.</p><br><br>`;
  1037. else if ($('#locale_selection').val() === 'ru_RU') return `<p class="small">${lang['last_edited']} <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> в <time>${x.edit_time.replace('T', ' ')}</time>.</p><br><br>`;
  1038. else return `<p class="small">[<time>${x.edit_time.replace('T', ' ')}</time>] <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> ${lang['last_edited']} </p><br><br>`;
  1039. })()}`;
  1040. } else {
  1041. return `<span style="word-break: break-all; word-wrap: break-word;"><bdo dir="ltr">${bbcode2html(x.bbcode)}<br><br></bdo></span>`;
  1042. };
  1043. })()}
  1044. </td>
  1045. </tr>
  1046. </tbody>
  1047. </table>`;
  1048.  
  1049. if (counts[x.cid] > 1) {
  1050. console.log('有编辑记录 直接添加下拉菜单');
  1051. // 插入下拉菜单基本框架
  1052. if ($(`#history_comment${x.cid}_select`).length === 0) {
  1053. $('#comments').append(bbcode_html); // 先插入整体框架
  1054. console.log('添加下拉菜单基本框架');
  1055. $(`[id="cid${x.cid}"]`).find('[class="embedded nowrap"]').before(`<div id="hsty" style="position: relative;">
  1056. <div id="history_comment" style="position: absolute; right:10px; margin-top: -2px;">
  1057. <select name="type" id="history_comment${x.cid}_select">
  1058. </div>
  1059. </div>`);
  1060. };
  1061. // 向下拉菜单写入信息
  1062. $(`#history_comment${x.cid}_select`).append(`<option value="${x.self}">${x.edit_time.replace('T', ' ')}
  1063. ${(() => { return x.action === 'edit' ? ' E' : x.action === 'reply' ? ' R' : ' N' })()}
  1064. ${(() => { return x.username === null && x.userid === null ? lang['anonymous_user'] : ` ${x.username}(${x.userid})` })()}
  1065. </option>`)
  1066. } else {
  1067. $('#comments').append(bbcode_html);
  1068. };
  1069. });
  1070.  
  1071. $("[id^=history_comment]").change(function () { // 监听菜单选择
  1072. let self = $(this).val();
  1073. for (let i = 0, len = __comment.length; i < len; i++) {
  1074. if (self != __comment[i].self) continue;
  1075. let html;
  1076. let x = __comment[i];
  1077. if (x.action === 'edit') {
  1078. html = `<br>
  1079. <span style="word-break: break-all; word-wrap: break-word;">
  1080. <bdo dir="ltr">${bbcode2html(x.bbcode)}</bdo>
  1081. </span>
  1082. ${(() => {
  1083. if ($('#locale_selection').val() === 'en_US') return `<p class="small">${lang['last_edited']} <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> at <time>${x.edit_time.replace('T', ' ')}</time>.</p><br><br>`;
  1084. else if ($('#locale_selection').val() === 'ru_RU') return `<p class="small">${lang['last_edited']} <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> в <time>${x.edit_time.replace('T', ' ')}</time>.</p><br><br>`;
  1085. else return `<br><p class="small">[<time>${x.edit_time.replace('T', ' ')}</time>] <span class="nowrap"><a href="userdetails.php?id=${x.user_id}"><b><bdo dir="ltr">${x.username}</bdo></b></a></span> ${lang['last_edited']} </p><br><br>`;
  1086. })()}`;
  1087. } else {
  1088. html = `<br>
  1089. <span style="word-break: break-all; word-wrap: break-word;">
  1090. <bdo dir="ltr">${bbcode2html(x.bbcode)}<br><br></bdo>
  1091. </span>`;
  1092. };
  1093. $(this).parents('[id^=cid]').parent().next().find('[class="rowfollow"]:last').html(html);
  1094. return;
  1095. };
  1096. });
  1097. };
  1098. },
  1099. error: function (d) {
  1100. },
  1101. });
  1102. })
  1103. };
  1104.  
  1105. const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
  1106. const element = document.getElementById("outer");
  1107. var observer = new MutationObserver(callback);
  1108. observer.observe(element, { childList: true });
  1109. };
  1110.  
  1111. async function torrentInfoHistoryReset() {
  1112. const errorstr = $('#outer').find('td.text').text();
  1113. // 正在努力加载中...
  1114. $('#outer').find('td.text').html(errorstr + '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i>' + lang['history_text_loading'] + '</i>');
  1115.  
  1116. const __json = await getapi(); // 从 API 获取数据
  1117.  
  1118. if (__json.msg !== 'success') { // 加载失败时
  1119. console.log('获取历史记录失败.');
  1120. $('#outer').find('td.text').html(`${errorstr}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i>${lang['history_text_error']}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a id="apifailure" href="javascript:void(0);" style="color:#FF1212">${lang['reset_token']}</a></i>`);
  1121. $("#apifailure").click(function () {
  1122. let confirm = prompt("输入 YES 确认本次操作 (大写)");
  1123. if (confirm === 'YES') {
  1124. db.removeItem('key');
  1125. db.removeItem('token');
  1126. alert("成功");
  1127. };
  1128. });
  1129.  
  1130. return;
  1131. } else if (__json.data.history.length === 0) { // 获取成功 但没有历史记录时
  1132. console.log('没有历史记录.');
  1133. $('#outer').find('td.text').html(errorstr + '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;' + lang['history_text_empty'] + '</i>');
  1134. return;
  1135. };
  1136.  
  1137. console.log('获取历史记录成功.');
  1138. let history_data = __json.data.history;
  1139. // let gdListObj = JSON.parse(localStorage.getItem("u2_gd_list")); // 读取谷歌备份列表
  1140. // 还原网页
  1141. $('#outer').html('<h1 align="center" id="top">'
  1142. + (() => { return history_data[0].banned === 1 ? history_data[0].title + '&nbsp;&nbsp;&nbsp; <b>[<font class="striking">' + lang['banned'] + '</font>]</b>' : history_data[0].title; })()
  1143. + '</h1>'
  1144. + '<div id="hsty" style="position: relative;"><div id="history" style="position: absolute; right:75px; margin-top: 4px;">'
  1145. + '<select name="type" id="history_select" style="visibility: visible;"></select></div></div>'
  1146. + '<h3>(#' + torrent_id + ')</h3>'
  1147. + '<table id="description" width="90%" min-width="940px" cellspacing="0" cellpadding="5"><tbody><tr><td class="rowhead" width="13%">' + lang['torrent_title'] + '</td>'
  1148. + '<td class="rowfollow" width="87%" align="left">'
  1149. + '<b>[U2].' + history_data[0].torrent_name + '.torrent</b></td></tr>'
  1150. + (() => { return history_data[0].subtitle ? '<tr><td class="rowhead nowrap" valign="top" align="right">' + lang['subtitle'] + '</td><td class="rowfollow" valign="top" align="left">' + history_data[0].subtitle + '</td></tr></td></tr>' : '' })()
  1151. + '<tr><td class="rowhead nowrap" valign="top" align="right">' + lang['basic_info'] + '</td>'
  1152. + '<td class="rowfollow" valign="top" align="left"><b>' + lang['submitted_by'] + '</b>:&nbsp;'
  1153. + ((p) => {
  1154. if (p.uploader_id === null && p.uploader_name === '匿名') return '<i>' + lang['anonymous'] + '</i>'; // 匿名发布
  1155. if (p.uploader_id !== null && p.uploader_name !== '匿名') return '<a href="userdetails.php?id=' + p.uploader_id + '"><b>' + p.uploader_name + '</b></a>'; // 正常显示
  1156. })(history_data[0])
  1157. + '&nbsp;&nbsp;&nbsp;<b>' + lang['submitted_at'] + '</b>:&nbsp;<time>' + history_data[0].uploaded_at.replace('T', ' ')
  1158. + '</time>'
  1159. + (() => { if (history_data[0].torrent_size) { return '&nbsp;&nbsp;&nbsp;<b>大小:</b>&nbsp;' + convert(history_data[0].torrent_size) } else { return ''; } })()
  1160. + '&nbsp;&nbsp;&nbsp;<b>' + lang['category'] + '</b>:&nbsp;' + history_data[0].category
  1161. // + (() => {
  1162. // const r = '&nbsp;&nbsp;&nbsp;<b>' + lang['google_backup'] + '</b>:&nbsp;'
  1163. // if (gdListObj === null) return ``; // 列表不存在时,直接返回
  1164. // const gdList = gdListObj.list; // 载入种子列表
  1165. // let d = gdList.findIndex((value) => value == Number(torrent_id)); // 查找数据库中是否有备份,没有返回-1
  1166. // if (d === -1) return r + `×`; // 没有备份时
  1167. // return `${r}<a href="sendmessage.php?receiver=45940#${torrent_id}" target="_blank" title="${lang['google_send']}">√</a>`
  1168. // })()
  1169. + '</td></tr>'
  1170. + '<tr><td class="rowhead nowrap" valign="top" align="right">'
  1171. + '<a href="javascript: klappe_news(\'descr\')"><span class="nowrap">'
  1172. + '<img class="minus" src="pic/trans.gif" alt="Show/Hide" id="picdescr" title="' + lang['show_or_hide'] + '"> ' + lang['description'] + '</span></a></td>'
  1173. + '<td class="rowfollow" valign="top" align="left">'
  1174. + '<div id="kdescr"><span style="word-break: break-all; word-wrap: break-word;"><bdo dir="ltr">'
  1175. + bbcode2html(history_data[0].description_info) + '</bdo></span></div></td></tr><tr>'
  1176. + '<td class="rowhead nowrap" valign="top" align="right">' + lang['torrent_info'] + '</td>'
  1177. + `<td id="file_tree" class="rowfollow" valign="top" align="left"></td></tr></tbody></table></td></tr></tbody></table><br><br></br>`
  1178. );
  1179.  
  1180. const putFileTree = (__json) => {
  1181. // 插入ID
  1182. let counter = 0;
  1183. const InsertSeq = (data) => {
  1184. for (key in data) {
  1185. data[key]['id'] = counter;
  1186. counter++;
  1187. if (data[key]['type'] == 'directory') InsertSeq(data[key]['children']);
  1188. };
  1189. return data;
  1190. };
  1191. // 获取文件ID
  1192. const getFile = (data) => {
  1193. let a = []
  1194. for (key in data) {
  1195. if (data[key]['type'] == 'file') a.push(data[key]['id']);
  1196. };
  1197. a = a.concat(getDirectory(data));
  1198. return a;
  1199. };
  1200. // 获取文件夹ID
  1201. const getDirectory = (data, directory = []) => {
  1202. for (key in data) {
  1203. if (data[key]['type'] == 'directory') directory.push(data[key]['id']);
  1204. };
  1205. return directory;
  1206. };
  1207. // 获取文件体积
  1208. const getSize = (data, size = 0) => {
  1209. // console.log(data);
  1210. for (key in data) {
  1211. if (data[key]['type'] == 'file') {
  1212. size = size + data[key]['length'];
  1213. } else {
  1214. size = getSize(data[key]['children'], size);
  1215. };
  1216. }
  1217. return size;
  1218. };
  1219. // 遍历JSON
  1220. const tree = (j, i) => {
  1221. for (let key in j) {
  1222. // console.log(j);
  1223. // console.log(j['key']);
  1224. if (j[key]['type'] == 'directory') {
  1225. let children = j[key]['children'];
  1226. let f_id_sh = getFile(children); // 获取文件夹需要的id
  1227. let f_size = convert(getSize(children)) // 文件夹大小
  1228. if (f_id === 0) {
  1229. f_html = f_html + `<tr id="f_id_0" tag="closed"><td class="rowfollow"><a href="javascript:void(0)" onclick="showorhide([${f_id_sh}],0)" class="faqlink">${key}</a></td><td class="rowfollow dir_size" align="right">[${f_size}]</td></tr>`;
  1230. } else {
  1231. f_html = f_html + `<tr id="f_id_${f_id}" style="display: none;" tag="closed"><td class="rowfollow">${space.repeat(i)}<a href="javascript:void(0)" onclick="showorhide([${f_id_sh}],${f_id})" class="faqlink">${key}</a></td><td class="rowfollow dir_size" align="right">[${f_size}]</td></tr>`;
  1232. };
  1233. f_id++;
  1234. tree(children, i + 1);
  1235. }
  1236. else {
  1237. if (f_id === 0) {
  1238. // 单文件种子
  1239. f_html = f_html + `<tr id="f_id_${f_id}"><td class="rowfollow">${space.repeat(i)}${key}</td><td class="rowfollow" align="right">${convert(j[key]['length'])}</td></tr>`;
  1240. } else {
  1241. f_html = f_html + `<tr id="f_id_${f_id}" style="display: none;"><td class="rowfollow">${space.repeat(i)}${key}</td><td class="rowfollow" align="right">${convert(j[key]['length'])}</td></tr>`;
  1242. };
  1243. f_id++;
  1244. };
  1245. };
  1246. };
  1247.  
  1248. // let __json = history_data[0].torrent_tree;
  1249. if (__json === null) {
  1250. // console.log('tree 为空');
  1251. $('#file_tree').html(
  1252. `<table>
  1253. <tbody>
  1254. <tr>
  1255. <td class="no_border_wide"><b>${lang['files']}</b>: ${history_data[0].torrent_files_qty}<br></td>
  1256. <td class="no_border_wide"><b>${lang['info_hash']}:</b>&nbsp;${history_data[0].torrent_hash}</td>
  1257. </tr>
  1258. </tbody>
  1259. </table>`
  1260. );
  1261. return;
  1262. };
  1263. __json = stringify(__json, function (a, b) {
  1264. // 对keys排序
  1265. if (typeof (a.value) !== 'object' || typeof (b.value) !== 'object') return 0;
  1266. if (a.value.type === 'directory' && b.value.type === 'file') {
  1267. return -1;
  1268. } else if (a.value.type === 'file' && b.value.type === 'directory') {
  1269. return 1;
  1270. } else {
  1271. return a.key.toLowerCase() < b.key.toLowerCase() ? -1 : 1;
  1272. };
  1273. });
  1274. __json = JSON.parse(__json);
  1275. __json = InsertSeq(__json);
  1276. // console.log(__json);
  1277. let f_id = 0; // 元素id
  1278. let f_html = ''; // 文件列表
  1279. const space = '&nbsp;&nbsp;&nbsp;&nbsp;'; // 缩进
  1280. tree(__json, 0);
  1281. // $('#filelist').find('tr').after(f_html);
  1282. $('#file_tree').html(
  1283. `<table>
  1284. <tbody>
  1285. <tr>
  1286. <td class="no_border_wide"><b>${lang['files']}</b>: ${history_data[0].torrent_files_qty}<br>
  1287. <span id="showfl" style="display: inline;">
  1288. <a href="javascript: viewfilelist()">[查看列表]</a>
  1289. </span>
  1290. <span id="hidefl" style="display: none;">
  1291. <a href="javascript: hidefilelist()">[隐藏列表]</a>
  1292. </span>
  1293. ${(() => {
  1294. return f_id > 1
  1295. ? `<span id="expandall" style="display: none;"><a href="javascript: expandall(true)">[全部展开]</a></span>
  1296. <span id="closeall" style="display: none;"><a href="javascript: expandall(false)">[全部关闭]</a></span>`
  1297. : ''
  1298. })()}
  1299. </td>
  1300. <td class="no_border_wide"><b>${lang['info_hash']}:</b>&nbsp;${history_data[0].torrent_hash}</td>
  1301. </tr>
  1302. </tbody>
  1303. </table>
  1304. <span id="filelist" style="display: none;">
  1305. <style>
  1306. .dir_size {
  1307. color: gray;
  1308. white-space: nowrap;
  1309. }
  1310. </style>
  1311. <table border="1" cellspacing="0" cellpadding="5">
  1312. <tbody>
  1313. <tr>
  1314. <td class="colhead">路径</td>
  1315. <td class="colhead" align="center"><img class="size" src="pic/trans.gif" alt="size"></td>
  1316. </tr>
  1317. ${f_html}
  1318. </tbody>
  1319. </table>
  1320. </span>`
  1321. );
  1322. };
  1323. putFileTree(history_data[0].torrent_tree); // 运行一次,生成列表
  1324.  
  1325. for (let i = 0, len = history_data.length; i < len; i++) { // 循环插入到选择列表中
  1326. $("#history_select").append("<option value='" + history_data[i].self + "'>"
  1327. + history_data[i].get_time.replace('T', ' ')
  1328. + ((edited_type) => {
  1329. switch (edited_type) {
  1330. case 0: return ' H'; // 添加候选
  1331. case 1: return ' E' // 普通用户编辑
  1332. case 2: return ' M' // MOD编辑
  1333. case 3: return ' T' // 允许候选
  1334. case 4: return ' U' // 上传种子
  1335. default: return ' ' // 早期记录
  1336. };
  1337. })(history_data[i].edited_type)
  1338. + (() => {
  1339. if (history_data[i].self === 0) return lang['current_time']
  1340. else if (history_data[i].edited_name === null && history_data[i].edited_id === null) return ''
  1341. else if (history_data[i].edited_name === '匿名' && history_data[i].edited_id === null) return lang['anonymous_user']
  1342. else if (history_data[i].edited_name !== null && history_data[i].edited_id !== null) return ' ' + history_data[i].edited_name + '(' + history_data[i].edited_id + ')'
  1343. else return ' @BUG@'
  1344. })()
  1345. + "</option>");
  1346. };
  1347.  
  1348. $("#history_select").change(function () { // 监听菜单选择
  1349. let self = Number($(this).val());
  1350. for (let i = 0, len = history_data.length; i < len; i++) {
  1351. if (self !== history_data[i].self) continue;
  1352. history_data[i].banned === 1 ? $('#top').html(history_data[i].title + '&nbsp;&nbsp;&nbsp; <b>[<font class="striking">' + lang['banned'] + '</font>]</b>') : $('#top').text(history_data[i].title);
  1353. // 检查副标题一栏是否存在
  1354. if ($("td[class='rowhead nowrap']:contains(" + lang['subtitle'] + ")").length === 0 && history_data[i].subtitle !== null) {
  1355. $("td[class='rowhead nowrap']:contains(" + lang['uploaded'] + ")").parent().before('<tr><td class="rowhead nowrap" valign="top" align="right">' + lang['subtitle'] + '</td><td class="rowfollow" valign="top" align="left"></td></tr>');
  1356. }
  1357. else if ($("td[class='rowhead nowrap']:contains(" + lang['subtitle'] + ")").length === 1 && history_data[i].subtitle === null) {
  1358. $("td[class='rowhead nowrap']:contains(" + lang['subtitle'] + ")").parent().remove();
  1359. };
  1360. $("td[class='rowhead nowrap']:contains(" + lang['subtitle'] + ")").next().text(history_data[i].subtitle); // 副标题
  1361. $("td[class='rowhead nowrap']:contains(" + lang['description'] + ")").last().next().html('<span style="word-break: break-all; word-wrap: break-word;"><bdo dir="ltr">' + bbcode2html(history_data[i].description_info) + '</bdo></span>'); // 描述
  1362. $("td[class='rowhead nowrap']:contains(" + lang['basic_info'] + ")").next().html('<b>' + lang['submitted_by'] + '</b>:&nbsp;'
  1363. + ((p) => {
  1364. if (p.uploader_id === null && p.uploader_name === '匿名') return '<i>' + lang['anonymous'] + '</i>'; // 匿名发布
  1365. if (p.uploader_id !== null && p.uploader_name !== '匿名') return '<a href="userdetails.php?id=' + p.uploader_id + '"><b>' + p.uploader_name + '</b></a>'; // 正常显示
  1366. })(history_data[i])
  1367. + '&nbsp;&nbsp;&nbsp;<b>' + lang['submitted_at'] + '</b>:&nbsp;<time>' + history_data[i].uploaded_at.replace('T', ' ')
  1368. + '</time>'
  1369. + (() => { if (history_data[i].torrent_size) { return '&nbsp;&nbsp;&nbsp;<b>' + lang['size'] + ':</b>&nbsp;' + convert(history_data[i].torrent_size) } else { return ''; } })()
  1370. + '&nbsp;&nbsp;&nbsp;<b>' + lang['category'] + '</b>:&nbsp;' + history_data[i].category
  1371. );
  1372. putFileTree(history_data[i].torrent_tree);
  1373. };
  1374. });
  1375. };
  1376.  
  1377.  
  1378. function bbcode2html(bbcodestr) {
  1379. const f_reg = new RegExp("^\"?\"?$|^(?:&quot;)?(?:&quot;)?$");
  1380.  
  1381. var tempCode = new Array();
  1382. var tempCodeCount = 0;
  1383.  
  1384. function addTempCode(value) {
  1385. tempCode[tempCodeCount] = value;
  1386. let returnstr = "<tempCode_" + tempCodeCount + ">";
  1387. tempCodeCount++;
  1388. return returnstr;
  1389. }
  1390.  
  1391. const escape_reg = new RegExp("[&\"\'<>]", "g");
  1392. bbcodestr = bbcodestr.replace(escape_reg, function (s, x) {
  1393. switch (s) {
  1394. case '&':
  1395. return '&amp;';
  1396. case '"':
  1397. return '&quot;';
  1398. case "'":
  1399. return '&#039;';
  1400. case '<':
  1401. return '&lt;';
  1402. case '>':
  1403. return '&gt;';
  1404. default:
  1405. return s;
  1406. }
  1407. });
  1408.  
  1409. bbcodestr = bbcodestr.replace(/ /g, () => { return ' &nbsp;' });
  1410. bbcodestr = bbcodestr.replace(/\r\n/g, () => { return '<br>' });
  1411. bbcodestr = bbcodestr.replace(/\n/g, () => { return '<br>' });
  1412. bbcodestr = bbcodestr.replace(/\r/g, () => { return '<br>' });
  1413.  
  1414. // info/code 标签
  1415. const info_reg = new RegExp("\\[(mediainfo|info|code)\\](.+?)\\[\\/(\\1)\\]", "gis");
  1416. bbcodestr = bbcodestr.replace(info_reg, function (s, x, y) {
  1417. switch (x) {
  1418. case 'info':
  1419. return addTempCode('<fieldset class="codemain" style="background-color: transparent; word-break: break-all"><legend><b><span style="color: blue">'
  1420. + lang['info'] + '</span></b></legend>' + y + '</fieldset>');
  1421. case 'mediainfo':
  1422. return addTempCode('<fieldset class="codemain" style="background-color: transparent; word-break: break-all"><legend><b><span style="color: red">'
  1423. + lang['mediainfo'] + '</span></b></legend>' + y + '</fieldset>');
  1424. case 'code':
  1425. return addTempCode(`<br><div class="codetop">${lang['code']}</div><div class="codemain">${y}</div><br />`);
  1426. default:
  1427. return s;
  1428. }
  1429. });
  1430.  
  1431. // 超链接 (绝对)
  1432. bbcodestr = bbcodestr.replace(/\[url=((?:https?|ftp|gopher|news|telnet|mms|rtsp):\/\/((?!&lt;|&gt;|\s|"|>|'|<|\(|\)|\[|\]).)+)\](.+?)\[\/url\]/gis, function (s, x, y, z) {
  1433. return addTempCode('<a class="faqlink" rel="nofollow noopener noreferer" href="' + x + '">' + z + '</a>');
  1434. });
  1435.  
  1436. bbcodestr = bbcodestr.replace(/\[url\]((?:https?|ftp|gopher|news|telnet|mms|rtsp):\/\/((?!&lt;|&gt;|\s|"|>|'|<|\(|\)|\[|\]).)+)\[\/url\]/gis, function (s, x) {
  1437. return addTempCode('<a class="faqlink" rel="nofollow noopener noreferer" href="' + x + '">' + x + '</a>')
  1438. });
  1439.  
  1440. // 超链接 (相对)
  1441. bbcodestr = bbcodestr.replace(/\[url=(((?!&lt;|&gt;|\s|"|>|'|<|\(|\)|\[|\]).)+)\](.+?)\[\/url\]/gis, function (s, x, y, z) {
  1442. return addTempCode('<a class="faqlink" rel="nofollow noopener noreferer" href="' + x + '">' + z + '</a>');
  1443. });
  1444.  
  1445. bbcodestr = bbcodestr.replace(/\[url\](((?!&lt;|&gt;|\s|"|>|'|<|\(|\)|\[|\]).)+)\[\/url\]/gis, function (s, x) {
  1446. return addTempCode('<a class="faqlink" rel="nofollow noopener noreferer" href="' + x + '">' + x + '</a>')
  1447. });
  1448.  
  1449. // 单个标签 不带参
  1450. const o_reg = new RegExp("\\[(\\*|siteurl|site)\\]", "gi");
  1451. bbcodestr = bbcodestr.replace(o_reg, function (s, x, y) {
  1452. switch (x) {
  1453. case '*':
  1454. return '<img class="listicon listitem" src="pic/trans.gif" alt="list">';
  1455. case 'site':
  1456. return 'U2分享園@動漫花園';
  1457. case 'siteurl':
  1458. return 'https://u2.dmhy.org';
  1459. default:
  1460. return s;
  1461. }
  1462. });
  1463.  
  1464. // 成对标签 带参
  1465. const d_reg = new RegExp("\\[(rt|font)=([^\\]]+)\\](.*?)\\[(/\\1)\\]", "gis");
  1466. while (d_reg.test(bbcodestr)) {
  1467. bbcodestr = bbcodestr.replace(d_reg, function (s, w, x, y, z) {
  1468. switch (w) {
  1469. case 'rt':
  1470. if (f_reg.test(x)) {
  1471. return '[' + addTempCode('p3F#oW2@cEn_JHstp-&37DgD' + w) + '=' + x + ']'
  1472. + y + '[' + addTempCode('p3F#oW2@cEn_JHstp-&37DgD' + z) + ']'
  1473. }
  1474. else {
  1475. return addTempCode('<ruby>' + y + '<rp>(</rp><rt>' + x.replace(/^(?:&quot;)?(.*?)(?:&quot;)?$/, "$1") + '</rt><rp>)</rp></ruby>');
  1476. }
  1477. case 'font':
  1478. if (f_reg.test(x)) {
  1479. return '[' + addTempCode('p3F#oW2@cEn_JHstp-&37DgD' + w) + '=' + x + ']'
  1480. + y + '[' + addTempCode('p3F#oW2@cEn_JHstp-&37DgD' + z) + ']';
  1481. }
  1482. else {
  1483. return '<span style="font-family: ' + x.replace(/^(?:&quot;)?(.*?)(?:&quot;)?$/, "$1") + '">' + y + '</span>';
  1484. }
  1485. default:
  1486. return s;
  1487. }
  1488. })
  1489. };
  1490.  
  1491. // 成对标签 不带参
  1492. const a_reg = new RegExp("\\[(pre|b|i|u|s)\\](.*?)\\[/(\\1)\\]", "gs");
  1493. while (a_reg.test(bbcodestr)) {
  1494. bbcodestr = bbcodestr.replace(a_reg, function (s, x, y, z) {
  1495. switch (x) {
  1496. case 'b':
  1497. return '<b>' + y + '</b>';
  1498. case 'i':
  1499. return '<em>' + y + '</em>';
  1500. case 'u':
  1501. return '<u>' + y + '</u>';
  1502. case 's':
  1503. return '<s>' + y + '</s>';
  1504. case 'pre':
  1505. return '<pre>' + y + '</pre>';
  1506. default:
  1507. return s;
  1508. }
  1509. })
  1510. };
  1511.  
  1512. // 颜色
  1513. const color_reg = new RegExp("\\[color=(?:&quot;)?([#0-9a-z]{1,15}|[a-z]+?)(?:&quot;)?\\](.*?)\\[/color\\]", "gis");
  1514. while (color_reg.test(bbcodestr)) {
  1515. bbcodestr = bbcodestr.replace(color_reg, function (s, x, y) {
  1516. return '<span style="color: ' + x + '">' + y + '</span>';
  1517. })
  1518. };
  1519.  
  1520. // 文字大小
  1521. const size_reg = new RegExp("\\[size=(?:&quot;)?([1-7])(?:&quot;)?\\](.*?)\\[/size\\]", "gis");
  1522. while (size_reg.test(bbcodestr)) {
  1523. bbcodestr = bbcodestr.replace(size_reg, function (s, x, y) {
  1524. return '<font size="' + x + '">' + y + '</font>';
  1525. })
  1526. };
  1527.  
  1528. // 图片
  1529. bbcodestr = bbcodestr.replace(/\[(img|imglnk)\]([^\]]+)\[\/(?:\1)\]/gi, function (s, x, y) {
  1530. if (/^((?!&lt;|&gt;|"|>|'|<|;|\(|\)|\[|\]|#).)+\.(?:png|jpg|jpeg|gif|svg|bmp|webp)$/i.test(y)) {
  1531. // url 以 .png 之类结尾
  1532. switch (x) {
  1533. case 'img':
  1534. return addTempCode('<img alt="image" src="' + y + '" style="height: auto; width: auto; max-width: 100%;">');
  1535. case 'imglnk':
  1536. return addTempCode('<a class="faqlink" rel="nofollow noopener noreferer" href="' + y + '"><img alt="image" src="'
  1537. + y + '" style="height: auto; width: auto; max-width: 100%;"></a>');
  1538. };
  1539. };
  1540. return addTempCode(s);
  1541. });
  1542.  
  1543. bbcodestr = bbcodestr.replace(/\[img=([^\]]+)\]/gi, function (s, x) {
  1544. if (/^((?!&lt;|&gt;|"|>|'|<|;|\(|\)|\[|\]|#).)+\.(?:png|jpg|jpeg|gif|svg|bmp|webp)$/i.test(x)) {
  1545. // url 以 .png 之类结尾
  1546. return addTempCode('<img alt="image" src="' + x + '" style="height: auto; width: auto; max-width: 100%;">');
  1547. };
  1548. return s;
  1549. });
  1550.  
  1551. // 没有bbcode包裹的超链接
  1552. bbcodestr = bbcodestr.replace(/((?:https?|ftp|gopher|news|telnet|mms|rtsp):\/\/((?!&lt;|&gt;|\s|"|>|'|<|\(|\)|\[|\]).)+)/gi, function (s, x) {
  1553. return '<a class="faqlink" rel="nofollow noopener noreferer" href="' + s + '">' + s + '</a>';
  1554. });
  1555.  
  1556. // 引用
  1557. const quote_reg1 = new RegExp("\\[quote\\](.*?)\\[/quote\\]", "gsi");
  1558. while (quote_reg1.test(bbcodestr)) {
  1559. bbcodestr = bbcodestr.replace(quote_reg1, function (s, x) {
  1560. return '<fieldset><legend>' + lang['quote'] + '</legend>' + x + '</fieldset>';
  1561. });
  1562. };
  1563. const quote_reg2 = new RegExp("\\[quote=([^\\[\\]]*)\\](.*?)\\[/quote\\]", "gsi");
  1564. while (quote_reg2.test(bbcodestr)) {
  1565. bbcodestr = bbcodestr.replace(quote_reg2, function (s, x, y) {
  1566. if (f_reg.test(x)) {
  1567. return '<fieldset><legend>' + lang['quote'] + '</legend>' + y + '</fieldset>';
  1568. }
  1569. else {
  1570. return '<fieldset><legend>' + lang['quote'] + ': ' + x.replace(/^(?:&quot;)?(.*?)(?:&quot;)?$/, "$1") + '</legend>' + y + '</fieldset>';
  1571. }
  1572. });
  1573. };
  1574.  
  1575. // spoiler
  1576. const spoiler_reg1 = new RegExp("\\[spoiler\\](.*?)\\[/spoiler\\]", "gsi");
  1577. const spoiler_reg2 = new RegExp("\\[spoiler=([^\\]]+)\\](.*?)\\[/spoiler\\]", "gsi");
  1578. while (spoiler_reg1.test(bbcodestr)) {
  1579. bbcodestr = bbcodestr.replace(spoiler_reg1, function (s, x) {
  1580. return '<table class="spoiler" width="100%"><tbody><tr><td class="colhead">'
  1581. + lang['spoiler'] + '&nbsp;&nbsp;'
  1582. + '<button class="spoiler-button-show">' + lang['spoiler_button_1'] + '</button>'
  1583. + '<button class="spoiler-button-hide" style="display: none;">' + lang['spoiler_button_2'] + '</button>'
  1584. + '</td></tr><tr><td><span class="spoiler-content">'
  1585. + x + '</span></td></tr></tbody></table>';
  1586. });
  1587. };
  1588. while (spoiler_reg2.test(bbcodestr)) {
  1589. bbcodestr = bbcodestr.replace(spoiler_reg2, function (s, x, y) {
  1590. if (f_reg.test(x)) {
  1591. return '<table class="spoiler" width="100%"><tbody><tr><td class="colhead">'
  1592. + lang['spoiler'] + '&nbsp;&nbsp;'
  1593. + '<button class="spoiler-button-show">' + lang['spoiler_button_1'] + '</button>'
  1594. + '<button class="spoiler-button-hide" style="display: none;">' + lang['spoiler_button_2'] + '</button>'
  1595. + '</td></tr><tr><td><span class="spoiler-content">'
  1596. + y + '</span></td></tr></tbody></table>';
  1597. }
  1598. else {
  1599. return '<table class="spoiler" width="100%"><tbody><tr><td class="colhead">'
  1600. + x.replace(/^(?:&quot;)?(.*?)(?:&quot;)?$/, "$1") + '&nbsp;&nbsp;'
  1601. + '<button class="spoiler-button-show">' + lang['spoiler_button_1'] + '</button>'
  1602. + '<button class="spoiler-button-hide" style="display: none;">' + lang['spoiler_button_2'] + '</button>'
  1603. + '</td></tr><tr><td><span class="spoiler-content">'
  1604. + y + '</span></td></tr></tbody></table>';
  1605. }
  1606. });
  1607. };
  1608.  
  1609. // 表情
  1610. const em_reg = new RegExp("\\[(em[1-9][0-9]*)\\]", "gi");
  1611. bbcodestr = bbcodestr.replace(em_reg, function (s, x) {
  1612. switch (x) {
  1613. case (x.match(/^em[1-9][0-9]*/i) || {}).input:
  1614. return '<img src="pic/smilies/' + x.replace("em", "") + '.gif" alt="[' + x + ']">';
  1615. default:
  1616. return s;
  1617. }
  1618. })
  1619.  
  1620. for (let i = 0, len = tempCode.length; i < len; i++) {
  1621. // console.log(i + " : " + tempCode[i]);
  1622. bbcodestr = bbcodestr.replace("<tempCode_" + i + ">", tempCode[i]);
  1623. }
  1624.  
  1625. bbcodestr = bbcodestr.replace(/p3F#oW2@cEn_JHstp-&37DgD/g, "");
  1626.  
  1627. if (/(<br>)$/.test(bbcodestr)) { bbcodestr = bbcodestr + '<br>' };
  1628.  
  1629. var htmlobj = $.parseHTML('<div>' + bbcodestr + '</div>');
  1630.  
  1631. $(htmlobj).children('fieldset').children('fieldset').children('fieldset').children('fieldset').each(function () {
  1632. $(this).html($(this).html().replace(/(^<legend>[^<]*?<\/legend>)(.*)/i, function (s, x, y) {
  1633. return x + '<table class="spoiler" width="100%"><tbody>'
  1634. + '<tr><td class="colhead">' + lang['auto_fold'] + '&nbsp;&nbsp;'
  1635. + '<button class="spoiler-button-show">' + lang['spoiler_button_1'] + '</button>'
  1636. + '<button class="spoiler-button-hide" style="display: none;">' + lang['spoiler_button_2'] + '</button>'
  1637. + '</td></tr><tr><td><span class="spoiler-content">'
  1638. + y + '</span></td></tr></tbody></table>';
  1639. }))
  1640. });
  1641.  
  1642. return $(htmlobj).html();
  1643. };
  1644.  
  1645.  
  1646. function getapi() {
  1647. return new Promise((resolve, reject) => {
  1648. // https://www.w3school.com.cn/jquery/ajax_ajax.asp
  1649. $.ajax({
  1650. type: 'get',
  1651. url: 'https://u2.kysdm.com/api/v1/history?token=' + token + '&maximum=50&uid=' + user_id + '&torrent=' + torrent_id,
  1652. contentType: 'application/json',
  1653. dataType: 'json',
  1654. cache: true,
  1655. success: r => resolve(r),
  1656. error: r => {
  1657. console.log('发生错误,HTTP状态码[' + r.status + ']。');
  1658. reject(r.status)
  1659. },
  1660. });
  1661. }).catch(() => { return { "state": "404", "msg": "failure", "data": { "history": [] } }; });
  1662. };
  1663.  
  1664.  
  1665. function lang_init(lang) {
  1666. const lang_json = {
  1667. "zh_CN": {
  1668. "quote": "引用",
  1669. "info": "发布信息",
  1670. "mediainfo": "媒体信息",
  1671. "code": "代码",
  1672. "spoiler": "警告!下列文字很可能泄露剧情,请谨慎选择是否观看。",
  1673. "spoiler_button_1": "我就是手贱",
  1674. "spoiler_button_2": "我真是手贱",
  1675. "main_title": "主标题",
  1676. "rt_text": "请输入上标",
  1677. "main_body": "请输入正文",
  1678. "main_body_prefix": "请输入标题",
  1679. "url_name": "请输入网址名称",
  1680. "url_link": "请输入网址链接",
  1681. "select_type": "请选择分类...",
  1682. "preview": "预览",
  1683. "auto_fold": "过深引用自动折叠",
  1684. "subtitle": "副标题",
  1685. "uploaded": "发布人",
  1686. "basic_info": "基本信息",
  1687. "description": "描述",
  1688. "history_select_loading": "正在努力加载中...",
  1689. "history_select_error": "加载失败啦 (ノДT)",
  1690. "anonymous": "匿名",
  1691. "uploaded_at": "发布时间",
  1692. "size": "大小",
  1693. "category": "类型",
  1694. "submitted_by": "提供者",
  1695. "submitted_at": "提交时间",
  1696. "history_text_loading": "~~正在检查历史数据中~~",
  1697. "history_text_error": "加载失败啦 (ノДT) %%",
  1698. "history_text_empty": "半条历史记录都没有 (ノДT) @@",
  1699. "torrent_title": "种子标题",
  1700. "torrent_info": "种子信息",
  1701. "files": "文件数",
  1702. "info_hash": "种子散列值",
  1703. "show_or_hide": "显示&nbsp;/&nbsp;隐藏",
  1704. "KiB": " KiB",
  1705. "MiB": " MiB",
  1706. "GiB": " GiB",
  1707. "TiB": " TiB",
  1708. "current_time": " 当前时间",
  1709. "anonymous_user": " 匿名用户",
  1710. "banned": "已屏蔽",
  1711. "google_backup": "谷歌备份",
  1712. "google_send": "发送请求",
  1713. "last_edited": "最后编辑",
  1714. "back_to_top": "返回顶部",
  1715. "reset_token": "重置Token (・_・)ヾ",
  1716. },
  1717. "zh_TW": {
  1718. "quote": "引用",
  1719. "info": "發佈訊息",
  1720. "mediainfo": "媒體訊息",
  1721. "code": "代碼",
  1722. "spoiler": "警告!下列文字很可能洩露劇情,請謹慎選擇是否觀看。",
  1723. "spoiler_button_1": "我就是手賤",
  1724. "spoiler_button_2": "我真是手賤",
  1725. "main_title": "主標題",
  1726. "rt_text": "請輸入上標",
  1727. "main_body": "請輸入正文",
  1728. "main_body_prefix": "請輸入標題",
  1729. "url_name": "請輸入網址名稱",
  1730. "url_link": "請輸入網址連結",
  1731. "select_type": "請選擇分類...",
  1732. "preview": "預覽",
  1733. "auto_fold": "過深引用自動摺疊",
  1734. "subtitle": "副標題",
  1735. "uploaded": "發布人",
  1736. "basic_info": "基本訊息",
  1737. "description": "描述",
  1738. "history_select_loading": "正在努力載入中...",
  1739. "history_select_error": "載入失敗啦 (ノДT)",
  1740. "anonymous": "匿名",
  1741. "uploaded_at": "發布時間",
  1742. "size": "大小",
  1743. "category": "類型",
  1744. "submitted_by": "提供者",
  1745. "submitted_at": "提交時間",
  1746. "history_text_loading": "~~正在檢查歷史數據中~~",
  1747. "history_text_error": "載入失敗啦 (ノДT) %%",
  1748. "history_text_empty": "半條歷史記錄都沒有 (ノДT) @@",
  1749. "torrent_title": "種子標題",
  1750. "torrent_info": "種子訊息",
  1751. "files": "文件數",
  1752. "info_hash": "種子散列值",
  1753. "show_or_hide": "顯示&nbsp;/&nbsp;隱藏",
  1754. "KiB": " KiB",
  1755. "MiB": " MiB",
  1756. "GiB": " GiB",
  1757. "TiB": " TiB",
  1758. "current_time": " 當前時間",
  1759. "anonymous_user": " 匿名用戶",
  1760. "banned": "已屏蔽",
  1761. "google_backup": "Google備份",
  1762. "google_send": "發送請求",
  1763. "last_edited": "最後編輯",
  1764. "back_to_top": "返回頂部",
  1765. "reset_token": "重設Token (・_・)ヾ",
  1766. },
  1767. "zh_HK": {
  1768. "quote": "引用",
  1769. "info": "發佈訊息",
  1770. "mediainfo": "媒體訊息",
  1771. "code": "代碼",
  1772. "spoiler": "警告!下列文字很可能洩露劇情,請謹慎選擇是否觀看。",
  1773. "spoiler_button_1": "我就是手賤",
  1774. "spoiler_button_2": "我真是手賤",
  1775. "main_title": "主標題",
  1776. "rt_text": "請輸入上標",
  1777. "main_body": "請輸入正文",
  1778. "main_body_prefix": "請輸入標題",
  1779. "url_name": "請輸入網址名稱",
  1780. "url_link": "請輸入網址鏈接",
  1781. "select_type": "請選擇分類...",
  1782. "preview": "預覽",
  1783. "auto_fold": "過深引用自動摺疊",
  1784. "subtitle": "副標題",
  1785. "uploaded": "發布人",
  1786. "basic_info": "基本訊息",
  1787. "description": "描述",
  1788. "history_select_loading": "正在努力加載中...",
  1789. "history_select_error": "加載失敗啦 (ノДT)",
  1790. "anonymous": "匿名",
  1791. "uploaded_at": "發佈時間",
  1792. "size": "大小",
  1793. "category": "類型",
  1794. "submitted_by": "提供者",
  1795. "submitted_at": "提交時間",
  1796. "history_text_loading": "~~正在檢查歷史數據中~~",
  1797. "history_text_error": "加載失敗啦 (ノДT) %%",
  1798. "history_text_empty": "半條歷史記錄都沒有 (ノДT) @@",
  1799. "torrent_title": "種子標題",
  1800. "torrent_info": "種子訊息",
  1801. "files": "文件數",
  1802. "info_hash": "種子散列值",
  1803. "show_or_hide": "顯示&nbsp;/&nbsp;隱藏",
  1804. "KiB": " KiB",
  1805. "MiB": " MiB",
  1806. "GiB": " GiB",
  1807. "TiB": " TiB",
  1808. "current_time": " 當前時間",
  1809. "anonymous_user": " 匿名用戶",
  1810. "banned": "已屏蔽",
  1811. "google_backup": "Google備份",
  1812. "google_send": "發送請求",
  1813. "last_edited": "最後編輯",
  1814. "back_to_top": "返回頂部",
  1815. "reset_token": "重置Token (・_・)ヾ",
  1816. },
  1817. "en_US": {
  1818. "quote": "Quote",
  1819. "info": "Infobox",
  1820. "mediainfo": "Media Info",
  1821. "code": "CODE",
  1822. "spoiler": "Warning! This section contains spoiler!",
  1823. "spoiler_button_1": "I agree to view this.",
  1824. "spoiler_button_2": "Hide this.",
  1825. "main_title": "Main Title",
  1826. "rt_text": "Please enter superscript",
  1827. "main_body": "Please enter the text",
  1828. "main_body_prefix": "Please enter a title",
  1829. "url_name": "Please enter the URL name",
  1830. "url_link": "Please enter the URL link",
  1831. "select_type": "Please select a type.",
  1832. "preview": "Preview",
  1833. "auto_fold": "Over quote auto fold",
  1834. "subtitle": "Small Description",
  1835. "uploaded": "Uploader",
  1836. "basic_info": "Basic Info",
  1837. "description": "Description",
  1838. "history_select_loading": "Trying to load now ...",
  1839. "history_select_error": "Load failure (ノДT)",
  1840. "anonymous": "Anonymous",
  1841. "uploaded_at": "Uploaded at",
  1842. "size": "Size",
  1843. "category": "Category",
  1844. "submitted_by": "Submitted by",
  1845. "submitted_at": "Submitted at",
  1846. "history_text_loading": "~~Checking historical data now~~",
  1847. "history_text_error": "Load failure (ノДT) %%",
  1848. "history_text_empty": "Half of the history is missing (ノДT) @@",
  1849. "torrent_title": "Torrent Title",
  1850. "torrent_info": "Torrent Info",
  1851. "files": "Files",
  1852. "info_hash": "Info hash",
  1853. "show_or_hide": "Show&nbsp;or&nbsp;Hide",
  1854. "KiB": " KiB",
  1855. "MiB": " MiB",
  1856. "GiB": " GiB",
  1857. "TiB": " TiB",
  1858. "current_time": " CurrentTime",
  1859. "anonymous_user": " AnonymousUser",
  1860. "banned": "Banned",
  1861. "google_backup": "Google Backup",
  1862. "google_send": "Send request",
  1863. "last_edited": "Last edited by",
  1864. "back_to_top": "Back to top",
  1865. "reset_token": "Reset Token (・_・)ヾ",
  1866. },
  1867. "ru_RU": {
  1868. "quote": "Цитата",
  1869. "info": "Отправленные",
  1870. "mediainfo": "Данные о Медиа",
  1871. "code": "CODE",
  1872. "spoiler": "Предупреждение! Данный раздел содержит СПОЙЛЕРЫ!",
  1873. "spoiler_button_1": "I agree to view this.",
  1874. "spoiler_button_2": "Hide this.",
  1875. "main_title": "Основное название",
  1876. "rt_text": "Пожалуйста, введите надстрочный индекс",
  1877. "main_body": "Пожалуйста, введите текст",
  1878. "main_body_prefix": "Пожалуйста, введите название",
  1879. "url_name": "Пожалуйста, введите имя URL",
  1880. "url_link": "Пожалуйста, введите URL-ссылку",
  1881. "select_type": "выберите тип ...",
  1882. "preview": "Предварительный просмотр",
  1883. "auto_fold": "Автоматическое складывание для более глубоких ссылок",
  1884. "subtitle": "Краткое Описание",
  1885. "uploaded": "Загрузил",
  1886. "basic_info": "Базовая инф.",
  1887. "description": "Описание",
  1888. "history_select_loading": "Пытаюсь загрузить сейчас ...",
  1889. "history_select_error": "Отказ нагрузки (ノДT)",
  1890. "anonymous": "Анонимно",
  1891. "uploaded_at": "Загружен",
  1892. "size": "Размер",
  1893. "category": "Категория",
  1894. "submitted_by": "Разместивший Запрос",
  1895. "submitted_at": "Дата размещения",
  1896. "history_text_loading": "~~Проверка исторических данных сейчас~~",
  1897. "history_text_error": "Отказ нагрузки (ノДT) %%",
  1898. "history_text_empty": "Половина истории отсутствует (ノДT) @@",
  1899. "torrent_title": "Имя торрента",
  1900. "torrent_info": "Информация о торренте ",
  1901. "files": "Файлов в торренте",
  1902. "info_hash": "Информация о ХЕШЕ",
  1903. "show_or_hide": "Показать&nbsp;/&nbsp;Скрыть",
  1904. "KiB": " KiБ",
  1905. "MiB": " MiБ",
  1906. "GiB": " GiБ",
  1907. "TiB": " TiБ",
  1908. "current_time": " Текущее время",
  1909. "anonymous_user": " Анонимный пользователь",
  1910. "banned": "Забанен",
  1911. "google_backup": "Резервное копирование Google",
  1912. "google_send": "послать запрос",
  1913. "last_edited": "Последний раз редактировалось",
  1914. "back_to_top": "На главную",
  1915. "reset_token": "Токен сброса (・_・)ヾ",
  1916. }
  1917. };
  1918. return lang_json[lang];
  1919. };
  1920.  
  1921. // 当前时间 字符串格式
  1922. function getDateString() {
  1923. function zero(obj) { return obj < 10 ? '0' + obj : obj };
  1924. const time = new Date();
  1925. return time.getFullYear().toString() + '-' + zero(time.getMonth() + 1).toString() + '-' + zero(time.getDate()).toString()
  1926. + ' ' + zero(time.getHours()) + ':' + zero(time.getMinutes()) + ':' + zero(time.getSeconds())
  1927. };
  1928.  
  1929. function convert(s) {
  1930. if (s / 1024 < 1024) return (s / 1024).toFixed(3) + lang['KiB']
  1931. if (s / 1024 / 1024 < 1024) return (s / 1024 / 1024).toFixed(3) + lang['MiB']
  1932. if (s / 1024 / 1024 / 1024 < 1024) return (s / 1024 / 1024 / 1024).toFixed(3) + lang['GiB']
  1933. if (s / 1024 / 1024 / 1024 / 1024 < 1024) return (s / 1024 / 1024 / 1024 / 1024).toFixed(3) + lang['TiB']
  1934. };
  1935.  
  1936. // 生成种子评论cid定位url
  1937. const cidUrl = (t, c) => {
  1938. if (/\/offers\.php/i.test(location.href)) {
  1939. return `offers.php?id=${t}&off_details=1#cid${c}`
  1940. } else if (/\/details\.php/i.test(location.href))
  1941. return `details.php?id=${t}#cid${c}`
  1942. else {
  1943. return '/'
  1944. };
  1945. };
  1946.  
  1947. // 对JSON进行排序
  1948. // https://github.com/substack/json-stable-stringify
  1949. const stringify = function (obj, opts) {
  1950. if (!opts) opts = {};
  1951. if (typeof opts === 'function') opts = { cmp: opts };
  1952. var space = opts.space || '';
  1953. if (typeof space === 'number') space = Array(space + 1).join(' ');
  1954. var cycles = (typeof opts.cycles === 'boolean') ? opts.cycles : false;
  1955. var replacer = opts.replacer || function (key, value) { return value; };
  1956.  
  1957. var cmp = opts.cmp && (function (f) {
  1958. return function (node) {
  1959. return function (a, b) {
  1960. var aobj = { key: a, value: node[a] };
  1961. var bobj = { key: b, value: node[b] };
  1962. return f(aobj, bobj);
  1963. };
  1964. };
  1965. })(opts.cmp);
  1966.  
  1967. var seen = [];
  1968. return (function stringify(parent, key, node, level) {
  1969. var indent = space ? ('\n' + new Array(level + 1).join(space)) : '';
  1970. var colonSeparator = space ? ': ' : ':';
  1971.  
  1972. if (node && node.toJSON && typeof node.toJSON === 'function') {
  1973. node = node.toJSON();
  1974. }
  1975.  
  1976. node = replacer.call(parent, key, node);
  1977.  
  1978. if (node === undefined) {
  1979. return;
  1980. }
  1981. if (typeof node !== 'object' || node === null) {
  1982. return JSON.stringify(node);
  1983. }
  1984. if (isArray(node)) {
  1985. var out = [];
  1986. for (var i = 0; i < node.length; i++) {
  1987. var item = stringify(node, i, node[i], level + 1) || JSON.stringify(null);
  1988. out.push(indent + space + item);
  1989. }
  1990. return '[' + out.join(',') + indent + ']';
  1991. }
  1992. else {
  1993. if (seen.indexOf(node) !== -1) {
  1994. if (cycles) return JSON.stringify('__cycle__');
  1995. throw new TypeError('Converting circular structure to JSON');
  1996. }
  1997. else seen.push(node);
  1998.  
  1999. var keys = objectKeys(node).sort(cmp && cmp(node));
  2000. var out = [];
  2001. for (var i = 0; i < keys.length; i++) {
  2002. var key = keys[i];
  2003. var value = stringify(node, key, node[key], level + 1);
  2004.  
  2005. if (!value) continue;
  2006.  
  2007. var keyValue = JSON.stringify(key)
  2008. + colonSeparator
  2009. + value;
  2010. ;
  2011. out.push(indent + space + keyValue);
  2012. }
  2013. seen.splice(seen.indexOf(node), 1);
  2014. return '{' + out.join(',') + indent + '}';
  2015. }
  2016. })({ '': obj }, '', obj, 0);
  2017. };
  2018.  
  2019. const isArray = Array.isArray || function (x) {
  2020. return {}.toString.call(x) === '[object Array]';
  2021. };
  2022.  
  2023. const objectKeys = Object.keys || function (obj) {
  2024. var has = Object.prototype.hasOwnProperty || function () { return true };
  2025. var keys = [];
  2026. for (var key in obj) {
  2027. if (has.call(obj, key)) keys.push(key);
  2028. }
  2029. return keys;
  2030. };

QingJ © 2025

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