Bypass FileCrypt (New)

Bypass FileCrypt

当前为 2025-03-08 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Bypass FileCrypt (New)
  3. // @namespace Bhunter
  4. // @version 1.0.1
  5. // @description Bypass FileCrypt
  6. // @author Bhunter
  7. // @license MIT
  8. // @match http://filecrypt.cc/*
  9. // @match http://www.filecrypt.cc/*
  10. // @match http://filecrypt.co/*
  11. // @match http://www.filecrypt.co/*
  12. // @match https://filecrypt.cc/*
  13. // @match https://www.filecrypt.cc/*
  14. // @match https://filecrypt.co/*
  15. // @match https://www.filecrypt.co/*
  16. // @run-at document-end
  17. // @connect dcrypt.it
  18. // @connect self
  19. // @grant GM.xmlHttpRequest
  20. // ==/UserScript==
  21.  
  22. (function() {
  23. 'use strict';
  24. // Determine if dark theme is used
  25. const isDarkTheme = document.head.querySelector('meta[name="theme-color"]') !== null ||
  26. document.body.classList.contains('dark') ||
  27. window.getComputedStyle(document.body).backgroundColor.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)/)?.[1] < 100;
  28. // Add stylesheet to document
  29. addStylesheet(isDarkTheme);
  30. // Remove ads
  31. removeAds();
  32. // Apply main functionality based on URL
  33. if (document.location.href.includes("/Link/")) {
  34. processSingleLink();
  35. } else if (document.location.href.includes("/Container/")) {
  36. waitForCaptchaSolved();
  37. }
  38. })();
  39.  
  40. // Add stylesheet to document
  41. function addStylesheet(isDarkTheme) {
  42. const style = document.createElement('style');
  43. // Define the colors based on theme
  44. const colors = isDarkTheme ? {
  45. background: '#1e1e2e',
  46. text: '#cdd6f4',
  47. accent: '#cba6f7',
  48. border: '#313244',
  49. itemBg: '#181825',
  50. itemHover: '#11111b',
  51. actionBg: '#45475a',
  52. actionText: '#cdd6f4'
  53. } : {
  54. background: '#ffffff',
  55. text: '#333333',
  56. accent: '#4f46e5',
  57. border: '#e5e7eb',
  58. itemBg: '#f9fafb',
  59. itemHover: '#f3f4f6',
  60. actionBg: '#e0e7ff',
  61. actionText: '#4f46e5'
  62. };
  63. // Stylesheet content
  64. style.textContent = `
  65. /* Main container */
  66. .fc-container {
  67. background-color: ${colors.background};
  68. color: ${colors.text};
  69. border: 1px solid ${colors.border};
  70. border-radius: 12px;
  71. box-shadow: 0 10px 15px -3px ${isDarkTheme ? 'rgba(0, 0, 0, 0.4)' : 'rgba(0, 0, 0, 0.1)'};
  72. max-width: 660px;
  73. margin: 20px auto 30px;
  74. overflow: hidden;
  75. font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
  76. font-size: 14px;
  77. line-height: 1.5;
  78. position: relative;
  79. z-index: 10;
  80. }
  81. /* Header */
  82. .fc-header {
  83. padding: 14px 18px;
  84. border-bottom: 1px solid ${colors.border};
  85. display: flex;
  86. justify-content: space-between;
  87. align-items: center;
  88. }
  89. .fc-title {
  90. margin: 0;
  91. font-weight: 600;
  92. font-size: 16px;
  93. }
  94. .fc-counter {
  95. padding: 4px 10px;
  96. border-radius: 20px;
  97. font-size: 12px;
  98. background-color: ${colors.actionBg};
  99. color: ${colors.actionText};
  100. }
  101. /* Content area */
  102. .fc-content {
  103. max-height: 350px;
  104. overflow-y: auto;
  105. padding: 12px 0;
  106. scrollbar-width: thin;
  107. scrollbar-color: ${colors.border} transparent;
  108. }
  109. .fc-content::-webkit-scrollbar {
  110. width: 6px;
  111. }
  112. .fc-content::-webkit-scrollbar-track {
  113. background: transparent;
  114. }
  115. .fc-content::-webkit-scrollbar-thumb {
  116. background-color: ${colors.border};
  117. border-radius: 3px;
  118. }
  119. /* Loading */
  120. .fc-loading {
  121. padding: 16px;
  122. text-align: center;
  123. }
  124. .fc-loading p {
  125. margin-top: 12px;
  126. font-size: 14px;
  127. }
  128. .fc-spinner {
  129. animation: fc-rotate 2s linear infinite;
  130. }
  131. .fc-spinner-path {
  132. stroke-dasharray: 1, 200;
  133. stroke-dashoffset: 0;
  134. animation: fc-dash 1.5s ease-in-out infinite;
  135. stroke: ${colors.accent};
  136. }
  137. @keyframes fc-rotate {
  138. 100% {
  139. transform: rotate(360deg);
  140. }
  141. }
  142. @keyframes fc-dash {
  143. 0% {
  144. stroke-dasharray: 1, 200;
  145. stroke-dashoffset: 0;
  146. }
  147. 50% {
  148. stroke-dasharray: 89, 200;
  149. stroke-dashoffset: -35px;
  150. }
  151. 100% {
  152. stroke-dasharray: 89, 200;
  153. stroke-dashoffset: -124px;
  154. }
  155. }
  156. /* Domain headers */
  157. .fc-domain-header {
  158. padding: 6px 16px;
  159. font-size: 13px;
  160. font-weight: 500;
  161. color: ${colors.accent};
  162. display: flex;
  163. align-items: center;
  164. gap: 6px;
  165. }
  166. .fc-domain-header:not(:first-child) {
  167. margin-top: 10px;
  168. }
  169. .fc-domain-count {
  170. background-color: ${colors.actionBg};
  171. border-radius: 10px;
  172. padding: 1px 6px;
  173. font-size: 11px;
  174. }
  175. /* Link items */
  176. .fc-link-item {
  177. padding: 8px 16px;
  178. margin: 2px 0;
  179. display: flex;
  180. align-items: center;
  181. gap: 10px;
  182. border-radius: 4px;
  183. transition: background-color 0.2s;
  184. cursor: pointer;
  185. }
  186. .fc-link-item:hover {
  187. background-color: ${colors.itemHover};
  188. }
  189. .fc-link-text {
  190. white-space: nowrap;
  191. overflow: hidden;
  192. text-overflow: ellipsis;
  193. flex: 1;
  194. font-size: 14px;
  195. }
  196. .fc-link-path {
  197. opacity: 0.7;
  198. }
  199. /* Copy button */
  200. .fc-copy-btn {
  201. width: 28px;
  202. height: 28px;
  203. min-width: 28px;
  204. background-color: transparent;
  205. color: ${colors.accent};
  206. border: none;
  207. border-radius: 50%;
  208. display: flex;
  209. align-items: center;
  210. justify-content: center;
  211. cursor: pointer;
  212. padding: 0;
  213. transition: background-color 0.2s;
  214. margin: 0;
  215. }
  216. .fc-copy-btn:hover {
  217. background-color: ${colors.actionBg};
  218. }
  219. /* Footer */
  220. .fc-footer {
  221. padding: 12px 16px;
  222. border-top: 1px solid ${colors.border};
  223. display: flex;
  224. justify-content: space-between;
  225. align-items: center;
  226. }
  227. .fc-info-text {
  228. opacity: 0.7;
  229. font-size: 12px;
  230. }
  231. .fc-copy-all {
  232. padding: 8px 12px;
  233. background-color: ${colors.accent};
  234. color: white;
  235. border: none;
  236. border-radius: 6px;
  237. cursor: pointer;
  238. font-size: 14px;
  239. transition: all 0.2s ease;
  240. }
  241. .fc-copy-all:disabled {
  242. opacity: 0.5;
  243. cursor: not-allowed;
  244. }
  245. .fc-copy-all:hover:not(:disabled) {
  246. filter: brightness(1.1);
  247. }
  248. /* Notification */
  249. .fc-notification {
  250. position: fixed;
  251. top: 10px;
  252. right: 10px;
  253. background-color: rgba(50, 50, 50, 0.9);
  254. color: white;
  255. padding: 10px 15px;
  256. border-radius: 8px;
  257. font-size: 14px;
  258. z-index: 9999;
  259. box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
  260. transition: opacity 0.3s ease;
  261. }
  262. `;
  263. document.head.appendChild(style);
  264. }
  265.  
  266. // Remove ads
  267. function removeAds() {
  268. const usenetAds = document.querySelectorAll('a[href*="/pink/"]');
  269. for (const ad of usenetAds) {
  270. if (ad.parentNode) {
  271. ad.parentNode.remove();
  272. }
  273. }
  274. }
  275.  
  276. // Check if captcha is solved by looking for download buttons
  277. function waitForCaptchaSolved() {
  278.  
  279. // Function to check if captcha is solved based on visible elements
  280. function isCaptchaSolved() {
  281. // Look for download buttons or elements that appear after captcha
  282. return document.querySelectorAll('.dlcdownload').length > 0;
  283. }
  284.  
  285. // If captcha is already solved, proceed immediately
  286. if (isCaptchaSolved()) {
  287. processContainerPage();
  288. return;
  289. }
  290.  
  291. // Otherwise, wait for captcha to be solved
  292. const captchaObserver = new MutationObserver((mutations, observer) => {
  293. if (isCaptchaSolved()) {
  294. observer.disconnect();
  295. processContainerPage();
  296. }
  297. });
  298.  
  299. captchaObserver.observe(document.body, {
  300. childList: true,
  301. subtree: true
  302. });
  303. }
  304.  
  305. // Process single link page
  306. async function processSingleLink() {
  307. if (document.body.getElementsByTagName("SCRIPT").length === 0) {
  308. window.stop();
  309. let htmlContent = document.body.innerHTML;
  310. if (!htmlContent || document.body.children.length === 0) {
  311. try {
  312. const response = await fetch(document.location.href);
  313. htmlContent = await response.text();
  314. } catch (error) {
  315. console.error("Failed to fetch page content:", error);
  316. return;
  317. }
  318. }
  319. const httpIndex = htmlContent.lastIndexOf("http");
  320. if (httpIndex !== -1) {
  321. const endIndex = htmlContent.indexOf('id=', httpIndex) + 43;
  322. let finalUrl = htmlContent.substring(httpIndex, endIndex).replace(/&amp;/g, '&');
  323. window.location.href = finalUrl;
  324. }
  325. }
  326. }
  327.  
  328. // Process container page
  329. function processContainerPage() {
  330. // Find the best container to insert our link box
  331. const containerSection = findBestContainer();
  332. // Create container elements
  333. const { container, content, counter, copyAllBtn } = createLinkBox();
  334. // Insert the box at the appropriate location
  335. containerSection.insertBefore(container, containerSection.firstChild);
  336. // Try to get DLC file
  337. const dlcButtons = document.getElementsByClassName("dlcdownload");
  338. if (dlcButtons.length > 0) {
  339. const dlcId = dlcButtons[0].getAttribute("onclick")?.split("'")[1];
  340. if (dlcId) {
  341. fetchDlcAndDecrypt(dlcId, { content, counter, copyAllBtn });
  342. return;
  343. }
  344. }
  345. // Fall back to manual link extraction
  346. extractLinks({ content, counter, copyAllBtn });
  347. }
  348.  
  349. // Find the best container for inserting our box
  350. function findBestContainer() {
  351. // Try various selectors in order of preference
  352. const selectors = [
  353. '.content .window',
  354. '.download',
  355. '.content',
  356. 'main',
  357. 'article',
  358. '.container',
  359. '#container'
  360. ];
  361. for (const selector of selectors) {
  362. const element = document.querySelector(selector);
  363. if (element) {
  364. return element;
  365. }
  366. }
  367. // Fallback to body if no suitable container found
  368. return document.body;
  369. }
  370.  
  371. // Create DOM structure for the link box
  372. function createLinkBox() {
  373. // Create container
  374. const container = document.createElement("div");
  375. container.className = "fc-container";
  376. // Create header
  377. const header = document.createElement("div");
  378. header.className = "fc-header";
  379. const title = document.createElement("h3");
  380. title.className = "fc-title";
  381. title.innerHTML = "🔓 Decrypted Links";
  382. const counter = document.createElement("span");
  383. counter.className = "fc-counter";
  384. counter.id = "fc-counter";
  385. counter.textContent = "Loading...";
  386. header.appendChild(title);
  387. header.appendChild(counter);
  388. container.appendChild(header);
  389. // Create content area
  390. const content = document.createElement("div");
  391. content.className = "fc-content";
  392. content.id = "fc-content";
  393. // Add loading animation
  394. const loadingDiv = document.createElement("div");
  395. loadingDiv.className = "fc-loading";
  396. loadingDiv.id = "fc-loading";
  397. loadingDiv.innerHTML = `
  398. <svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
  399. <circle class="fc-spinner fc-spinner-path" cx="12" cy="12" r="10" fill="none" stroke-width="2" />
  400. </svg>
  401. <p>Decrypting links...</p>
  402. `;
  403. content.appendChild(loadingDiv);
  404. container.appendChild(content);
  405. // Create footer
  406. const footer = document.createElement("div");
  407. footer.className = "fc-footer";
  408. // Add info text
  409. const infoText = document.createElement("small");
  410. infoText.className = "fc-info-text";
  411. infoText.textContent = "Click link to open, or use copy button";
  412. // Add copy all button
  413. const copyAllBtn = document.createElement("button");
  414. copyAllBtn.className = " fc-copy-all";
  415. copyAllBtn.id = "fc-copy-all";
  416. copyAllBtn.textContent = "Copy All";
  417. copyAllBtn.disabled = true;
  418. footer.appendChild(infoText);
  419. footer.appendChild(copyAllBtn);
  420. container.appendChild(footer);
  421. return { container, content, counter, copyAllBtn };
  422. }
  423.  
  424. // Fetch DLC file and decrypt it
  425. async function fetchDlcAndDecrypt(dlcId, elements) {
  426. try {
  427. // Update the loading message
  428. const loadingDiv = document.getElementById("fc-loading");
  429. const loadingText = loadingDiv.querySelector("p");
  430. loadingText.textContent = "Fetching DLC file...";
  431. // Fetch the DLC file
  432. const response = await fetch(`https://${document.location.hostname}/DLC/${dlcId}.dlc`);
  433. if (!response.ok) throw new Error('Failed to fetch DLC file');
  434. const dlcContent = await response.text();
  435. loadingText.textContent = "Decrypting links via dcrypt.it...";
  436. // Use GM.xmlHttpRequest for dcrypt.it (since it may require CORS handling)
  437. GM.xmlHttpRequest({
  438. method: "POST",
  439. url: "http://dcrypt.it/decrypt/paste",
  440. headers: {
  441. "Content-Type": "application/x-www-form-urlencoded"
  442. },
  443. data: "content=" + encodeURIComponent(dlcContent),
  444. onload: function(response) {
  445. try {
  446. const result = JSON.parse(response.response);
  447. if (result.success && result.success.links && result.success.links.length > 0) {
  448. displayLinks(result.success.links, elements);
  449. } else {
  450. throw new Error("No links were found in the dcrypt.it response");
  451. }
  452. } catch (error) {
  453. console.error("Error parsing dcrypt.it response:", error);
  454. extractLinks(elements);
  455. }
  456. },
  457. onerror: function() {
  458. console.error("Error connecting to dcrypt.it");
  459. extractLinks(elements);
  460. }
  461. });
  462. } catch (error) {
  463. console.error("Error fetching DLC:", error);
  464. extractLinks(elements);
  465. }
  466. }
  467.  
  468. // Extract links directly from page
  469. function extractLinks(elements) {
  470. const loadingDiv = document.getElementById("fc-loading");
  471. const loadingText = loadingDiv.querySelector("p");
  472. loadingText.textContent = "Extracting links directly...";
  473. const encLinks = document.querySelectorAll("[onclick^=openLink]");
  474. if (encLinks.length === 0) {
  475. showError("No links found on this page.");
  476. return;
  477. }
  478. // Update counter to show progress
  479. elements.counter.textContent = `0/${encLinks.length}`;
  480. let completedLinks = 0;
  481. const validLinks = [];
  482. // Process each link with a small delay between requests to avoid overloading
  483. const processLink = (index) => {
  484. if (index >= encLinks.length) {
  485. if (validLinks.length > 0) {
  486. displayLinks(validLinks, elements);
  487. } else {
  488. showError("Failed to extract any valid links.");
  489. }
  490. return;
  491. }
  492. const link = encLinks[index];
  493. const onclick = link.getAttribute("onclick");
  494. const encParam = onclick.split("'")[1];
  495. const encValue = link.getAttribute(encParam);
  496. const linkUrl = `http://${document.location.hostname}/Link/${encValue}.html`;
  497. fetchFinalLink(linkUrl)
  498. .then(finalLink => {
  499. completedLinks++;
  500. elements.counter.textContent = `${completedLinks}/${encLinks.length}`;
  501. if (finalLink) {
  502. validLinks.push(finalLink);
  503. }
  504. // Process next link with a small delay
  505. setTimeout(() => processLink(index + 1), 100);
  506. })
  507. .catch(() => {
  508. completedLinks++;
  509. elements.counter.textContent = `${completedLinks}/${encLinks.length}`;
  510. setTimeout(() => processLink(index + 1), 100);
  511. });
  512. };
  513. // Start processing links
  514. processLink(0);
  515. }
  516.  
  517. // Show error message
  518. function showError(message) {
  519. const loadingDiv = document.getElementById("fc-loading");
  520. loadingDiv.innerHTML = `
  521. <div style="color:var(--fc-accent,#4f46e5);font-size:24px;margin-bottom:10px">❌</div>
  522. <p style="margin:0">${message}</p>
  523. `;
  524. const counter = document.getElementById("fc-counter");
  525. if (counter) counter.textContent = "Error";
  526. }
  527.  
  528. // Fetch a single link's destination
  529. async function fetchFinalLink(url) {
  530. try {
  531. const response = await fetch(url);
  532. if (!response.ok) return null;
  533. const html = await response.text();
  534. const parser = new DOMParser();
  535. const doc = parser.parseFromString(html, "text/html");
  536. // Try to find the redirect URL in scripts
  537. const scripts = doc.querySelectorAll("script");
  538. for (const script of scripts) {
  539. if (script.textContent.includes("top.location.href=")) {
  540. const matches = script.textContent.match(/top\.location\.href\s*=\s*['"]([^'"]+)['"]/);
  541. if (matches && matches[1]) {
  542. return await resolveRedirect(matches[1]);
  543. }
  544. }
  545. }
  546. return null;
  547. } catch (error) {
  548. console.error("Error fetching link:", error);
  549. return null;
  550. }
  551. }
  552.  
  553. // Resolve final URL from redirect
  554. async function resolveRedirect(url) {
  555. try {
  556. // Using fetch with HEAD method to get the final URL
  557. const controller = new AbortController();
  558. const signal = controller.signal;
  559. // Set a timeout to abort the request
  560. const timeoutId = setTimeout(() => controller.abort(), 5000);
  561. const response = await fetch(url, {
  562. method: 'HEAD',
  563. signal,
  564. redirect: 'follow'
  565. });
  566. clearTimeout(timeoutId);
  567. return response.url;
  568. } catch (error) {
  569. // If HEAD fails, try GET with GM.xmlHttpRequest
  570. return new Promise((resolve) => {
  571. GM.xmlHttpRequest({
  572. method: "GET",
  573. url: url,
  574. onreadystatechange: function(response) {
  575. if (response.readyState === 2) { // HEADERS_RECEIVED
  576. resolve(response.finalUrl);
  577. this.abort();
  578. }
  579. },
  580. onerror: function() {
  581. resolve(url); // Return original URL if everything fails
  582. }
  583. });
  584. });
  585. }
  586. }
  587.  
  588. // Display links with modern UI
  589. function displayLinks(links, elements) {
  590. // Update counter
  591. elements.counter.textContent = `${links.length} Links`;
  592. // Clear loading indicator
  593. elements.content.innerHTML = '';
  594. // Enable copy all button
  595. elements.copyAllBtn.disabled = false;
  596. elements.copyAllBtn.addEventListener('click', () => {
  597. navigator.clipboard.writeText(links.join('\n'))
  598. .then(() => {
  599. const originalText = elements.copyAllBtn.textContent;
  600. elements.copyAllBtn.textContent = "✓ Copied";
  601. setTimeout(() => {
  602. elements.copyAllBtn.textContent = originalText;
  603. }, 2000);
  604. });
  605. });
  606. // Group links by domain for better organization
  607. const linksByDomain = {};
  608. links.forEach(link => {
  609. try {
  610. const url = new URL(link);
  611. const domain = url.hostname;
  612. if (!linksByDomain[domain]) {
  613. linksByDomain[domain] = [];
  614. }
  615. linksByDomain[domain].push(link);
  616. } catch (e) {
  617. // If parsing fails, put in "Other" category
  618. if (!linksByDomain["Other"]) {
  619. linksByDomain["Other"] = [];
  620. }
  621. linksByDomain["Other"].push(link);
  622. }
  623. });
  624. // Sort domains alphabetically
  625. const domains = Object.keys(linksByDomain).sort();
  626. // Create link items by domain
  627. domains.forEach((domain, domainIndex) => {
  628. // Add domain header if multiple domains exist
  629. if (domains.length > 1) {
  630. const domainHeader = document.createElement("div");
  631. domainHeader.className = "fc-domain-header";
  632. domainHeader.innerHTML = `
  633. <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  634. <circle cx="12" cy="12" r="10"></circle>
  635. <circle cx="12" cy="12" r="4"></circle>
  636. </svg>
  637. <span>${domain}</span>
  638. <span class="fc-domain-count">${linksByDomain[domain].length}</span>
  639. `;
  640. elements.content.appendChild(domainHeader);
  641. }
  642. // Add links for this domain
  643. linksByDomain[domain].forEach(link => {
  644. const linkItem = createLinkItem(link);
  645. elements.content.appendChild(linkItem);
  646. });
  647. });
  648. }
  649.  
  650. // Create a link item element
  651. function createLinkItem(link) {
  652. const linkItem = document.createElement("div");
  653. linkItem.className = "fc-link-item";
  654. // Link text container
  655. const linkText = document.createElement("span");
  656. linkText.className = "fc-link-text";
  657. linkText.title = link;
  658. // Parse and display URL
  659. try {
  660. const url = new URL(link);
  661. // If there's a path or query, show them differently
  662. if (url.pathname !== "/" || url.search) {
  663. linkText.innerHTML = `${url.hostname}<span class="fc-link-path">${url.pathname}${url.search}</span>`;
  664. } else {
  665. linkText.textContent = url.hostname;
  666. }
  667. } catch (e) {
  668. linkText.textContent = link;
  669. }
  670. // Link click handler to open link
  671. linkItem.addEventListener('click', () => {
  672. window.open(link, '_blank');
  673. });
  674. // Copy button
  675. const copyBtn = document.createElement("button");
  676. copyBtn.className = "fc-copy-btn";
  677. copyBtn.innerHTML = `
  678. <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  679. <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
  680. <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
  681. </svg>
  682. `;
  683. copyBtn.addEventListener('click', (e) => {
  684. e.stopPropagation();
  685. navigator.clipboard.writeText(link)
  686. .then(() => {
  687. // Visual feedback when copied
  688. copyBtn.innerHTML = `
  689. <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  690. <path d="M20 6L9 17l-5-5"></path>
  691. </svg>
  692. `;
  693. setTimeout(() => {
  694. copyBtn.innerHTML = `
  695. <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  696. <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
  697. <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
  698. </svg>
  699. `;
  700. }, 1500);
  701. });
  702. });
  703. linkItem.appendChild(linkText);
  704. linkItem.appendChild(copyBtn);
  705. return linkItem;
  706. }

QingJ © 2025

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