Digit77 Helper

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

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

QingJ © 2025

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