Digit77 Helper

自动复制提取码,跳过ouo.io的三秒等待时间!

当前为 2024-05-16 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Digit77 Helper
  3. // @namespace cn.XYZliang.digit77Helper
  4. // @version 2.4.5
  5. // @description 自动复制提取码,跳过ouo.io的三秒等待时间!
  6. // @require https://code.jquery.com/jquery-3.7.1.min.js
  7. // @license GNU General Public License v3.0
  8. // @author XYZliang
  9. // @homepage https://greasyfork.org/zh-CN/scripts/445961-digit77-helper
  10. // @match *://www.digit77.com/*
  11. // @match *://ouo.io/*
  12. // @match *://ouo.press/*
  13. // @match *://cloaking.link/*
  14. // @match *://*.sharepoint.com/*
  15. // @match *://www.aliyundrive.com/*
  16. // @match *://pan.quark.cn/*
  17. // @icon https://www.digit77.com/_nuxt/logo-s.BqVYlxIi.png
  18. // @grant unsafeWindow
  19. // @grant GM_setClipboard
  20. // @grant GM_setValue
  21. // @grant GM_getValue
  22. // @grant GM_deleteValue
  23. // @grant GM_listValues
  24. // @grant GM_xmlhttpRequest
  25. // @grant GM_notification
  26. // @grant GM_getClipboard
  27. // @run-at document-end
  28. // @connect *
  29. // ==/UserScript==
  30. /* globals jQuery, $ */
  31. 'use strict';
  32.  
  33. // 用户设置
  34. let settings = GM_getValue('settings', {
  35. autofill: true,
  36. ouo: true,
  37. cloaking: true,
  38. quark: true,
  39. baidu: true,
  40. onedrive: true,
  41. aliyun: true,
  42. error: true,
  43. });
  44.  
  45. // Clean up values if exceeding 200 entries
  46. let values = GM_listValues();
  47. if (values.length > 200) {
  48. values.forEach((value) => {
  49. if (value !== 'settings') GM_deleteValue(value);
  50. if (values.length < 30) return;
  51. });
  52. consoleLog('已自动清除缓存!');
  53. }
  54.  
  55. let url = location.host;
  56. // Main logic goes here ---------------------------------------------------------
  57. if (url.includes('digit77.com')) {
  58. handleDigit77();
  59. } else if (url.includes('ouo')) {
  60. handleOuo();
  61. } else if (url.includes('cloaking')) {
  62. handleCloaking();
  63. } else if (url.includes('pan.quark.cn')) {
  64. hanndleQuark();
  65. } else if (url.includes('sharepoint.com')) {
  66. if (settings.onedrive)
  67. doFillAction('#txtPassword', '#btnSubmitPassword', 'digit77');
  68. } else {
  69. console.log('Unknown url! (' + url + ')');
  70. return;
  71. }
  72.  
  73. // Function definitions ---------------------------------------------------------
  74. function handleCloakingGo(pw) {
  75. GM_xmlhttpRequest({
  76. method: 'POST',
  77. url: `${location.origin}/links/go`,
  78. data: $('#go-link').serialize(),
  79. headers: {
  80. 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
  81. },
  82. onload: function (response) {
  83. console.log('Onload response:', response.responseText);
  84. if (response.status === 200) {
  85. try {
  86. var data = JSON.parse(response.responseText);
  87. if (data.status !== 'error') {
  88. let realLink = data.url;
  89. let finalUrlWithPwd = addGetParameter(
  90. realLink,
  91. 'Digit77HelperPwd',
  92. GM_getValue(pw),
  93. );
  94. setTimeout(() => {
  95. window.location.href = finalUrlWithPwd;
  96. }, 1000);
  97. } else {
  98. console.error('Error from server:', data);
  99. }
  100. } catch (e) {
  101. console.error('Failed to parse response:', e);
  102. }
  103. } else {
  104. console.error('Failed to get the real link', response.status);
  105. }
  106. },
  107. onerror: function (response) {
  108. console.error(
  109. 'Request failed:',
  110. response.status,
  111. response.statusText,
  112. );
  113. },
  114. });
  115. }
  116.  
  117. // Function definitions ---------------------------------------------------------
  118. function handleCloaking() {
  119. if (!settings.cloaking) return;
  120. console.group(`[Digital77 Helper] -- ${location.origin}`);
  121. consoleLog('正在跳过Cloaking');
  122. // Directly set text using .text() for better consistency and compatibility.
  123. $('h1').text('Digit77 Helper正在跳过等待!');
  124. $('#form-continue > button').text('欢迎使用Digit77 Helper');
  125. let pathSegments = location.pathname.split('/')[1];
  126.  
  127. if (settings.error) consoleLog('path segments: ' + pathSegments);
  128. // set cloaking status to 0 for the first time
  129. GM_setValue('cloaking', 0);
  130. // if the cloaking status is 0, then set the cloaking status to 1
  131. if (GM_getValue('cloaking') === 0) {
  132. GM_setValue('cloaking', 1);
  133. // click the continue button
  134. $('#form-continue > button').click();
  135.  
  136. //request url from cloaking is https://cloaking.link/links/go
  137. setTimeout(() => {
  138. handleCloakingGo(pathSegments);
  139. }, 1000);
  140. }
  141. // if find element body > div.container > div > div > div > div:nth-child(5) > a, then extract the link form it
  142. if (
  143. $('body > div.container > div > div > div > div:nth-child(5) > a')
  144. .length > 0
  145. ) {
  146. WaitForLink();
  147. }
  148. console.groupEnd();
  149. }
  150.  
  151. function WaitForLink() {
  152. // focuse on the link
  153. $(
  154. 'body > div.container > div > div > div > section.link-tab-body.mb-5 > div > div > div:nth-child(2) > div > fieldset > div > div.col-md-3.g-link-body > div > div > a',
  155. ).focus();
  156. // wait for 5 seconds to get the link
  157. setTimeout(() => {
  158. let link = $(
  159. 'body > div.container > div > div > div > section.link-tab-body.mb-5 > div > div > div:nth-child(2) > div > fieldset > div > div.col-md-3.g-link-body > div > div > a',
  160. ).attr('href');
  161. if (link.includes('javascript')) WaitForLink();
  162. let pw = location.pathname.split('/')[1];
  163. if (settings.error)
  164. consoleLog('Cloaking link: ' + pw + ' pwd: ' + GM_getValue(pw));
  165. let finalUrl = addGetParameter(
  166. link,
  167. 'Digit77HelperPwd',
  168. GM_getValue(pw),
  169. );
  170. window.location.href = finalUrl;
  171. }, 2800);
  172. }
  173.  
  174. function hanndleQuark() {
  175. if (!settings.quark) return;
  176. // get the password from parameter
  177. const urlObj = new URL(window.location.href);
  178.  
  179. const queryParams = new URLSearchParams(urlObj.search);
  180. const digit77HelperPwd = queryParams.get('Digit77HelperPwd');
  181. if (settings.error) {
  182. console.log('Debugging <夸克网盘>: ');
  183. console.log('href: ', window.location.href);
  184. console.log('code: ', digit77HelperPwd);
  185. }
  186. if (digit77HelperPwd !== undefined) {
  187. doFillAction(
  188. '#ice-container > div.ShareReceivePC--wrapcontainer--3OAJUiU.share-container-cls-name-for-get-dom > div.ShareReceivePC--wrapcontent--2fA9pbO > div > div.ShareReceivePC--content--3zjCAuj > div.ShareReceivePC--input-wrap--2FUw27N > input',
  189. '#ice-container > div.ShareReceivePC--wrapcontainer--3OAJUiU.share-container-cls-name-for-get-dom > div.ShareReceivePC--wrapcontent--2fA9pbO > div > div.ShareReceivePC--content--3zjCAuj > div:nth-child(5) > button',
  190. digit77HelperPwd,
  191. );
  192. } else alert('请手动粘贴提取码:', GM_getClipboard());
  193. }
  194.  
  195. function handleOuo() {
  196. if (!settings.ouo) return;
  197.  
  198. console.group(`[Digital77 Helper] -- ${location.href}`);
  199. consoleLog('正在跳过ouo');
  200.  
  201. // Use .ready() to ensure the DOM is fully loaded before attempting to modify elements.
  202. $(document).ready(function () {
  203. // Directly set text using .text() for better consistency and compatibility.
  204. $('h4').text('Digit77 Helper正在跳过等待!');
  205. $('.btn-main').text('欢迎使用Digit77 Helper');
  206.  
  207. let pathSegments = location.pathname.split('/');
  208. if (settings.error)
  209. consoleLog(
  210. 'path segments: ' +
  211. pathSegments +
  212. ' pwd key: ' +
  213. pathSegments[2] +
  214. ' pwd: ' +
  215. GM_getValue(pathSegments[2]),
  216. );
  217. // Check if the path contains 'go' and proceed with the specific logic for those pages.
  218. if (pathSegments[1] === 'go') {
  219. let reallyUrlGetter = `${location.origin}/xreallcygo/${pathSegments[2]}`;
  220. let reallyUrlData = $('#form-go').serialize();
  221.  
  222. // Use GM_xmlhttpRequest for cross-origin requests.
  223. GM_xmlhttpRequest({
  224. method: 'POST',
  225. url: reallyUrlGetter,
  226. data: reallyUrlData,
  227. headers: {
  228. 'Content-Type':
  229. 'application/x-www-form-urlencoded;charset=UTF-8',
  230. },
  231. onload: function (response) {
  232. // Construct the final URL with the password parameter if the request was successful.
  233. let finalUrl = addGetParameter(
  234. response.finalUrl,
  235. 'Digit77HelperPwd',
  236. GM_getValue(pathSegments[2]),
  237. );
  238. if (response.status === 200) {
  239. // Redirect after a slight delay to enhance ad revenue potentially.
  240. setTimeout(
  241. () => (window.location.href = finalUrl),
  242. 1000,
  243. );
  244. } else {
  245. failedToGetJumpAddress(GM_getValue(pathSegments[2]));
  246. }
  247. },
  248. onerror: function () {
  249. failedToGetJumpAddress(GM_getValue(pathSegments[2]));
  250. },
  251. });
  252. } else {
  253. // For non-'go' pages, wait before clicking the main button to pass through ads.
  254. setTimeout(() => $('.btn-main').click(), 1500);
  255. }
  256. });
  257.  
  258. console.groupEnd();
  259. }
  260.  
  261. // Main logic for Digit77 ---------------------------------------------------------
  262. function handleDigit77() {
  263. $(document).ready(function () {
  264. // Create settings form directly
  265. const settingsFormHtml = `
  266. <details style="margin-top: 20px;">
  267. <summary style="background-color: crimson;border-radius: 5px;color:white">Digit77 Helper设置</summary>
  268. <div class="table-wrapper" style="padding-right: 10px;overflow-x: hidden;">
  269. <div id="settingsForm" class="settings-form"></div>
  270. </div>
  271. </details>`;
  272.  
  273. console.group(`[Digital77 Helper] -- ${location.href}`);
  274.  
  275. console.log('Digit77 Helper 加载成功!');
  276.  
  277. // Options for the observer (which mutations to observe)
  278. const config = { childList: true, subtree: true };
  279.  
  280. // Callback function to execute when mutations are observed
  281. const callback = function (mutationsList, observer) {
  282. for (let mutation of mutationsList) {
  283. if (mutation.type === 'childList') {
  284. let table = document.querySelector('table > tbody');
  285. if (
  286. table &&
  287. table.querySelectorAll('tr > td > div > button')
  288. .length > 0
  289. ) {
  290. observer.disconnect(); // Stop observing
  291. handleLinks();
  292.  
  293. // Select description part from the page
  294. let description = $(
  295. '#__nuxt > div > section > section > main > div.page_single > div.single_content > div.post_content',
  296. );
  297. if (description.length) {
  298. description.empty();
  299. description.append(settingsFormHtml);
  300. populateSettingsForm();
  301. }
  302.  
  303. $(
  304. '#__nuxt > div > section > section > main > div.page_single > div.single_content > div.AdBox > div > div > div.el-table__inner-wrapper > div.el-table__body-wrapper > div > div.el-scrollbar__wrap.el-scrollbar__wrap--hidden-default > div > table > thead > tr > th.el-table_1_column_4.is-center.is-leaf.el-table__cell > div',
  305. ).text('下载链接 (已成功加载Digit77 Helper)');
  306.  
  307. break;
  308. }
  309. }
  310. }
  311. };
  312.  
  313. // Create an instance of MutationObserver
  314. const observer = new MutationObserver(callback);
  315.  
  316. // Select the node that will be observed for mutations
  317. const targetNode = document.querySelector('#__nuxt');
  318.  
  319. // Start observing the target node for configured mutations
  320. observer.observe(targetNode, config);
  321.  
  322. console.groupEnd();
  323. });
  324. }
  325.  
  326. function handleLinks() {
  327. const nuxtDataElement = document.querySelector('#__NUXT_DATA__');
  328.  
  329. // Early exit if no Nuxt data found
  330. if (!nuxtDataElement) {
  331. console.error('Failed to get #__NUXT_DATA__');
  332. return;
  333. }
  334.  
  335. try {
  336. // Parse the JSON data directly from the innerHTML
  337. const data = JSON.parse(nuxtDataElement.innerHTML);
  338.  
  339. // Validate parsed data and slice from 21 to 42
  340. if (!Array.isArray(data)) {
  341. throw new Error('Parsed data is not an array');
  342. }
  343. const relevantData = data.slice(21, 42);
  344.  
  345. // Process each relevant data element
  346. relevantData.forEach((item, i) => {
  347. if (
  348. typeof item === 'string' &&
  349. (item.includes('cloaking.link') || item.includes('ouo.io'))
  350. ) {
  351. const nextItem = relevantData[i + 1];
  352. if (
  353. nextItem &&
  354. typeof nextItem === 'string' &&
  355. nextItem.length < 5 &&
  356. settings.cloaking &&
  357. !nextItem.includes('盘') &&
  358. !nextItem.includes('drive')
  359. ) {
  360. const key = item.split('/')[3];
  361. const pwd = nextItem;
  362. if (settings.error)
  363. console.log('Key:', key, 'Password:', pwd);
  364. if (settings.autofill) GM_setValue(key, pwd);
  365. }
  366. }
  367. });
  368. } catch (e) {
  369. console.error('Failed to parse #__NUXT_DATA__:', e);
  370. }
  371.  
  372. if (settings.error) GM_ShowAllValues();
  373. }
  374.  
  375. // Helper functions ---------------------------------------------------------
  376. function failedToGetJumpAddress(pwd) {
  377. if (!settings.error) {
  378. return;
  379. }
  380. GM_notification(
  381. '获取ouo跳转链接失败!这导致无法自动填写提取码,请手动粘贴提取码!',
  382. 'Digit77 helper错误',
  383. );
  384. GM_setClipboard(pwd);
  385. }
  386.  
  387. function addGetParameter(url, name, value) {
  388. url += (url.split('?')[1] ? '&' : '?') + name + '=' + value;
  389. return url;
  390. }
  391.  
  392. function consoleLog(info, ...args) {
  393. if (typeof info === 'object') {
  394. Object.entries(info).forEach(([key, value]) => {
  395. console.log(
  396. `%c${key}:`,
  397. 'color: #007BFF; font-weight: bold;',
  398. value,
  399. );
  400. });
  401. console.log(...args);
  402. } else
  403. console.log(
  404. '%cDetails:',
  405. 'color: #007BFF; font-weight: bold;',
  406. info,
  407. ...args,
  408. );
  409. }
  410.  
  411. //  以下代码修改自 网盘智能识别助手
  412. let util = {
  413. parseQuery(name) {
  414. let reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
  415. let r = location.search.substr(1).match(reg);
  416. if (r != null) return r[2];
  417. return null;
  418. },
  419.  
  420. getValue(name) {
  421. return GM_getValue(name);
  422. },
  423.  
  424. setValue(name, value) {
  425. GM_setValue(name, value);
  426. },
  427.  
  428. sleep(time) {
  429. return new Promise((resolve) => setTimeout(resolve, time));
  430. },
  431.  
  432. addStyle(id, tag, css) {
  433. tag = tag || 'style';
  434. let doc = document,
  435. styleDom = doc.getElementById(id);
  436. if (styleDom) return;
  437. let style = doc.createElement(tag);
  438. style.rel = 'stylesheet';
  439. style.id = id;
  440. tag === 'style' ? (style.innerHTML = css) : (style.href = css);
  441. document.head.appendChild(style);
  442. },
  443.  
  444. isHidden(el) {
  445. try {
  446. return el.offsetParent === null;
  447. } catch (e) {
  448. return false;
  449. }
  450. },
  451.  
  452. query(selector) {
  453. if (Array.isArray(selector)) {
  454. let obj = null;
  455. for (let i = 0; i < selector.length; i++) {
  456. let o = document.querySelector(selector[i]);
  457. if (o) {
  458. obj = o;
  459. break;
  460. }
  461. }
  462. return obj;
  463. }
  464. return document.querySelector(selector);
  465. },
  466. };
  467.  
  468. function doFillAction(inputSelector, buttonSelector, pwd) {
  469. let maxTime = 10;
  470. let ins = setInterval(async () => {
  471. maxTime--;
  472. let input = util.query(inputSelector);
  473. let button = util.query(buttonSelector);
  474. if (input && !util.isHidden(input)) {
  475. clearInterval(ins);
  476. let lastValue = input.value;
  477. input.value = pwd;
  478. //Vue & React 触发 input 事件
  479. let event = new Event('input', {
  480. bubbles: true,
  481. });
  482. let tracker = input._valueTracker;
  483. if (tracker) {
  484. tracker.setValue(lastValue);
  485. }
  486. input.dispatchEvent(event);
  487. await util.sleep(500); //1秒后点击按钮
  488. button.click();
  489. } else {
  490. maxTime === 0 && clearInterval(ins);
  491. }
  492. }, 333);
  493. }
  494.  
  495. function populateSettingsForm() {
  496. const setting_template = [
  497. {
  498. id: 'autofill',
  499. text: '开启自动填写提取码',
  500. checked: settings.autofill,
  501. },
  502. {
  503. id: 'cloaking',
  504. text: '跳过cloaking广告页面的等待时间',
  505. checked: settings.cloaking,
  506. },
  507. { id: 'ouo', text: '跳过ouo广告页面的等待时间', checked: settings.ouo },
  508. { id: 'quark', text: '开启夸克网盘自动提取', checked: settings.quark },
  509. { id: 'baidu', text: '开启百度网盘自动提取', checked: settings.baidu },
  510. {
  511. id: 'onedrive',
  512. text: '开启OneDrive自动提取',
  513. checked: settings.onedrive,
  514. },
  515. { id: 'error', text: 'Debug 模式', checked: settings.error },
  516. // Continue with other settings as needed...
  517. ];
  518.  
  519. const formContainer = $('#settingsForm');
  520. formContainer.empty(); // Clear previous contents if any
  521.  
  522. // Dynamically create and append settings controls
  523. setting_template.forEach((setting) => {
  524. const settingControlHtml = `
  525. <div class="custom-switch custom-control">
  526. <input class="custom-control-input" type="checkbox" ${
  527. setting.checked ? 'checked="checked"' : ''
  528. } id="${setting.id}" name="${setting.id}" />
  529. <label class="custom-control-label" for="${setting.id}">
  530. ${setting.text}
  531. </label>
  532. </div>`;
  533. formContainer.append(settingControlHtml);
  534. });
  535.  
  536. // Append action buttons
  537. const actionButtonsHtml = `
  538. <a class="btn btn-rd btn-block btn-lg btn-coral-pink" id="save">保存设置</a>
  539. <a class="btn btn-rd btn-block btn-lg btn-coral-pink" id="clean">清除缓存</a>
  540. <a href="https://github.com/usleolihao/Digit77Helper" target="_blank">关于插件<span class="icon-md fab fa-github linklogo"></span></a>`;
  541. formContainer.append(actionButtonsHtml);
  542.  
  543. // Attach event listeners for buttons
  544. $('#save').on('click', function () {
  545. let updatedSettings = {};
  546. $('#settingsForm .custom-control-input').each(function () {
  547. let settingId = $(this).attr('id');
  548. let isChecked = $(this).is(':checked');
  549. updatedSettings[settingId] = isChecked;
  550. });
  551.  
  552. // Save the updated settings object directly
  553. GM_setValue('settings', updatedSettings);
  554. alert('Settings have been saved successfully.');
  555. if (settings.error) {
  556. console.log('Debugging: ', GM_getValue('settings'));
  557. }
  558. });
  559.  
  560. $('#clean').on('click', function () {
  561. let allValues = GM_listValues();
  562. allValues.forEach((value) => {
  563. if (value !== 'settings') GM_deleteValue(value);
  564. });
  565. alert('Cache cleared, except for settings.');
  566. });
  567. }
  568.  
  569. function GM_ShowAllValues() {
  570. let detail = 'All values: \n';
  571. GM_listValues().forEach((value) => {
  572. detail += `${value}: ${GM_getValue(value)}\n`;
  573. });
  574. consoleLog(detail);
  575. }