Auto somi

자동 복호화/국룰입력/다운

  1. // ==UserScript==
  2. // @name Auto somi
  3. // @name:ko 자동 소미
  4. // @namespace http://tampermonkey.net/
  5. // @description 자동 복호화/국룰입력/다운
  6. // @version new 6.3.5
  7. // @author 김머시기
  8. // @match https://kiosk.ac/c/*
  9. // @match https://kio.ac/c/*
  10. // @match https://kone.gg/*
  11. // @match https://arca.live/b/*
  12. // @match https://mega.nz/*
  13. // @match https://gofile.io/d/*
  14. // @match https://workupload.com/*
  15. // @match https://drive.google.com/file/d/*
  16. // @match https://drive.google.com/drive/folders/*
  17. // @match https://drive.usercontent.google.com/download?id*
  18. // @icon https://lh3.google.com/u/0/d/18OVO7VmnwIuHK6Ke-z7035wKFmMKZ28W=w1854-h959-iv1
  19. // @grant GM.setValue
  20. // @grant GM.getValue
  21. // @require https://openuserjs.org/src/libs/sizzle/GM_config.js
  22. // @grant GM.registerMenuCommand
  23. // @grant GM_registerMenuCommand
  24. // @grant GM_unregisterMenuCommand
  25. // @grant GM_getValue
  26. // @grant GM_setValue
  27. // @grant GM.xmlHttpRequest
  28. // @license MIT
  29. // @run-at document-end
  30. // ==/UserScript==
  31. 'use strict';
  32. let chkp = [,,,, atob('c29taXNvZnQ='), null], Down_Option, PageLoading = [], isT = [,,], MenuID = [null, null, null], host = document.URL.split('/')[2], npw = [], pw = [atob('c29taXNvZnQ='),atob('MjAyNXNvbWlzb2Z0'),
  33. // ================================== Settings ==========================================
  34. // 추가하길 원하는 비밀번호 따옴표 - 쉼표로 구분해서 바로 아래줄에 넣으면 됨 ex) '1234', '2024국룰', '!국룰!'
  35.  
  36. ];
  37. PageLoading[0] = 1000;
  38. Down_Option = 0;
  39. // ======================================================================================
  40.  
  41. const dlsitePreview = {
  42. element: null,
  43. images: [],
  44. currentIndex: 0,
  45. isShowing: false,
  46. activeKeyListener: null,
  47. activeWheelListener: null, // 마우스 휠 리스너 저장용
  48. globalKeydownListener: null, // 유지 (document 레벨 키 이벤트)
  49. isEnabled: true
  50. };
  51.  
  52. function getKoneGGContentElement() {
  53. if (host !== 'kone.gg') return null;
  54. const proseContainer = document.querySelector('div.prose-container');
  55. if (!proseContainer || !proseContainer.shadowRoot) return null;
  56. const contentDiv = proseContainer.shadowRoot.querySelector('div.contents');
  57. return contentDiv;
  58. }
  59.  
  60. async function handleBlockingModals(currentHost) {
  61. function hideElement(selector) {
  62. try {
  63. const elements = document.querySelectorAll(selector);
  64. if (elements.length > 0) {
  65. elements.forEach(el => {
  66. if (el.offsetParent !== null) {
  67. el.style.setProperty('display', 'none', 'important');
  68. }
  69. });
  70. }
  71. } catch (e) {
  72. }
  73. }
  74.  
  75. if (currentHost === 'kone.gg') {
  76. const nsfwOverlayContainer = document.querySelector('div.relative.min-h-60 > div.absolute.w-full.h-full.backdrop-blur-2xl');
  77. if (nsfwOverlayContainer && nsfwOverlayContainer.offsetParent !== null) {
  78. const viewContentButton = nsfwOverlayContainer.querySelector('div.flex.gap-4 button:nth-child(2)');
  79. if (viewContentButton && viewContentButton.textContent?.includes('콘텐츠 보기')) {
  80. viewContentButton.click();
  81. await new Promise(resolve => setTimeout(resolve, 500));
  82. } else {
  83. const modalSelectorsKone = [
  84. '.age-verification-popup',
  85. '.content-overlay.block',
  86. ];
  87. modalSelectorsKone.forEach(selector => hideElement(selector));
  88. }
  89. }
  90. } else if (currentHost === 'arca.live') {
  91. const modalSelectorsArca = [
  92. { selector: '.adult-confirm-modal', action: 'hide' },
  93. { selector: '.fc-dialog', action: 'hide' },
  94. { selector: '#preview-block-layer', action: 'hide' },
  95. { selector: 'div[class*="adult-channel-confirm"]', action: 'hide' },
  96. { selector: 'div.modal[data-id="confirmAdult"] div.modal-footer button.btn-primary', action: 'click'},
  97. { selector: 'button.btn-primary.btn.text-light[data-bs-dismiss="modal"]', action: 'click' }
  98. ];
  99. modalSelectorsArca.forEach(item => {
  100. const elements = document.querySelectorAll(item.selector);
  101. elements.forEach(element => {
  102. if (element && element.offsetParent !== null) {
  103. if (item.action === 'click') {
  104. element.click();
  105. } else {
  106. hideElement(item.selector);
  107. }
  108. }
  109. });
  110. });
  111. }
  112. }
  113.  
  114. async function toggleDown(){
  115. isT[0]=!isT[0];
  116. if(!isT[0] && isT[1]){
  117. isT[1]=false;
  118. await GM.setValue('isT[1]', isT[1]);
  119. }
  120. await GM.setValue('isT[0]', isT[0]);
  121. updateDown();
  122. updateTab();
  123. toggleDlsitePreview();
  124. }
  125.  
  126. async function toggleTab(){
  127. isT[1]=!isT[1];
  128. if(!isT[0] && isT[1]){
  129. isT[0]=true;
  130. await GM.setValue('isT[0]', isT[0]);
  131. }
  132. await GM.setValue('isT[1]', isT[1]);
  133. updateDown();
  134. updateTab();
  135. toggleDlsitePreview();
  136. }
  137.  
  138. async function toggleDlsitePreview() {
  139. dlsitePreview.isEnabled = !dlsitePreview.isEnabled;
  140. await GM.setValue('dlsitePreviewEnabled', dlsitePreview.isEnabled);
  141. updateDown();
  142. updateTab();
  143. updateDlsitePreviewMenu();
  144. if (!dlsitePreview.isEnabled && dlsitePreview.isShowing) {
  145. hideDlsitePreview();
  146. }
  147. const allDlsiteLinks = document.querySelectorAll('a[href*="dlsite.com"]');
  148. allDlsiteLinks.forEach(link => {
  149. link.removeEventListener('mouseenter', showDlsitePreview);
  150. link.removeEventListener('mouseleave', hideDlsitePreview);
  151. delete link.dataset._dlsite_preview_hooked;
  152. if (dlsitePreview.isEnabled) {
  153. link.addEventListener('mouseenter', showDlsitePreview);
  154. link.dataset._dlsite_preview_hooked = '1';
  155. }
  156. });
  157. }
  158.  
  159. function updateDown(){
  160. if(MenuID[0] !==null)GM_unregisterMenuCommand(MenuID[0]);
  161. MenuID[0]=GM_registerMenuCommand(`자동 다운로드 ${isT[0] ? 'ON' : 'OFF'}`, toggleDown, { autoClose: false, title: `자동 다운로드 ${isT[0] ? '켜짐' : '꺼짐'}`});
  162. }
  163.  
  164. function updateTab(){
  165. if(MenuID[1] !==null)GM_unregisterMenuCommand(MenuID[1]);
  166. MenuID[1]=GM_registerMenuCommand(`자동 닫기 ${isT[1] ? 'ON' : 'OFF'}`, toggleTab, { autoClose: false, title: `자동 닫기 ${isT[1] ? '켜짐' : '꺼짐'}`});
  167. }
  168.  
  169. function updateDlsitePreviewMenu(){
  170. if(MenuID[2] !==null)GM_unregisterMenuCommand(MenuID[2]);
  171. MenuID[2]=GM_registerMenuCommand(`DLsite 미리보기 ${dlsitePreview.isEnabled ? 'ON' : 'OFF'}`, toggleDlsitePreview, { autoClose: false, title: `DLsite 미리보기 ${dlsitePreview.isEnabled ? '켜짐' : '꺼짐'}`});
  172. }
  173.  
  174. function decodeContent(target, reg) {
  175. try {
  176. if (!target || !target.innerHTML) return;
  177. const originalHTML = target.innerHTML;
  178. let newHTML = originalHTML;
  179.  
  180. const matches = [...originalHTML.matchAll(reg)];
  181. if (matches.length === 0) return;
  182.  
  183. for (const match of matches) {
  184. let encodedString = match[0];
  185. let decodedPotentialUrl = encodedString;
  186.  
  187. try {
  188. let previousDecoded = "";
  189. for (let i = 0; i < 5; i++) {
  190. if (!decodedPotentialUrl || typeof decodedPotentialUrl !== 'string') break;
  191. let currentDecoded;
  192. try {
  193. currentDecoded = atob(decodedPotentialUrl);
  194. } catch(e) {
  195. break;
  196. }
  197.  
  198. if (currentDecoded.toLowerCase().startsWith('http://') || currentDecoded.toLowerCase().startsWith('https://')) {
  199. decodedPotentialUrl = currentDecoded;
  200. break;
  201. }
  202. if (previousDecoded === currentDecoded) {
  203. break;
  204. }
  205. previousDecoded = currentDecoded;
  206. decodedPotentialUrl = currentDecoded;
  207. }
  208.  
  209.  
  210. if (decodedPotentialUrl && typeof decodedPotentialUrl === 'string' &&
  211. (decodedPotentialUrl.toLowerCase().startsWith('http://') || decodedPotentialUrl.toLowerCase().startsWith('https://'))) {
  212.  
  213. try {
  214. const parsedUrl = new URL(decodedPotentialUrl);
  215. if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") {
  216. continue;
  217. }
  218.  
  219. const cleanHref = parsedUrl.href;
  220.  
  221. const textSpan = document.createElement('span');
  222. textSpan.textContent = cleanHref;
  223. const safeLinkDisplayText = textSpan.innerHTML;
  224.  
  225. const linkHTML = `<a href="${cleanHref}" target="_blank" rel="noreferrer" style="color:#007bff; text-decoration:underline; word-break:break-all;">${safeLinkDisplayText}</a>`;
  226. newHTML = newHTML.replace(encodedString, linkHTML);
  227.  
  228. } catch (urlError) {
  229. }
  230. }
  231. } catch (decodeError) {
  232. }
  233. }
  234.  
  235. if (target.innerHTML !== newHTML) {
  236. target.innerHTML = newHTML;
  237. }
  238. } catch (e) {
  239. }
  240. }
  241.  
  242. function doDec() {
  243. if (chkp[3] !== chkp[4]) return;
  244.  
  245. let targets = [];
  246.  
  247. if (host === 'arca.live') {
  248. targets = [
  249. document.querySelector('body div.article-body > div.fr-view.article-content'),
  250. ...document.querySelectorAll('div.article-comment#comment div.comment-content, div.article-comment div.comment-content')
  251. ].filter(el => el !== null);
  252. } else if (host === 'kone.gg') {
  253. const koneContentElement = getKoneGGContentElement();
  254. const comments = document.querySelectorAll('p.text-sm.whitespace-pre-wrap');
  255. const listItems = document.querySelectorAll('ol.list-decimal li p');
  256. targets = [koneContentElement, ...comments, ...listItems].filter(el => el !== null);
  257. }
  258.  
  259. if (targets.length === 0 || (targets.length === 1 && !targets[0])) return;
  260.  
  261. for (const target of targets) {
  262. if (!target) continue;
  263. const links = target.querySelectorAll('a');
  264. links.forEach(a => {
  265. a.setAttribute('rel', 'noreferrer');
  266. });
  267.  
  268. decodeContent(target, /aHR0c[0-9A-Za-z+/=]{8,}/g);
  269. decodeContent(target, /YUhSMG[0-9A-Za-z+/=]{8,}/g);
  270. decodeContent(target, /WVVoU[0-9A-Za-z+/=]{8,}/g);
  271. decodeContent(target, /V1ZWb[0-9A-Za-z+/=]{8,}/g);
  272. decodeContent(target, /ttps:\/\/[0-9A-Za-z./?=&#%_-]+/g);
  273. doDlsiteContextAwareForElement(target);
  274. }
  275.  
  276. if (host === 'kone.gg') {
  277. const koneContentElement = getKoneGGContentElement();
  278. if (!koneContentElement || koneContentElement.querySelector('.dlsite-link-appended')) return;
  279.  
  280. const titleText = document.querySelector('h1.flex, h1.text-xl')?.textContent || '';
  281. const commentTexts = [...document.querySelectorAll('p.text-sm.whitespace-pre-wrap')]
  282. .map(el => el.textContent || '')
  283. .join(' ');
  284. const bodyText = koneContentElement?.textContent || '';
  285.  
  286. const allText = `${titleText} ${bodyText} ${commentTexts}`;
  287. const rjMatches = [...allText.matchAll(/\b(RJ|rj|Rj|rJ)([0-9]{5,10})\b/g)];
  288. const rjSet = new Set(rjMatches.map(m => m[1].toUpperCase() + m[2]));
  289.  
  290. if (rjSet.size === 1) {
  291. const onlyCode = [...rjSet][0];
  292. const linkUrl = `https://www.dlsite.com/maniax/work/=/product_id/${onlyCode}.html`;
  293.  
  294. const finalLine = document.createElement('div');
  295. finalLine.className = 'dlsite-link-appended';
  296. finalLine.style.marginTop = '1em';
  297. finalLine.innerHTML = `<a href="${linkUrl}" target="_blank" rel="noreferrer" style="color:#1e90ff; font-weight:bold;">▶ ${onlyCode} DLsite 링크</a>`;
  298. koneContentElement.appendChild(finalLine);
  299.  
  300. const appendedLink = finalLine.querySelector('a[href*="dlsite.com"]');
  301. if (appendedLink && !appendedLink.dataset._dlsite_preview_hooked) {
  302. if (dlsitePreview.isEnabled) {
  303. appendedLink.addEventListener('mouseenter', showDlsitePreview);
  304. appendedLink.addEventListener('mouseleave', hideDlsitePreview, { once: true });
  305. }
  306. appendedLink.dataset._dlsite_preview_hooked = '1';
  307. }
  308. }
  309. }
  310. }
  311.  
  312. function updateDlsitePreviewImage() {
  313. if (!dlsitePreview.element || dlsitePreview.images.length === 0) {
  314. return;
  315. }
  316.  
  317. dlsitePreview.element.innerHTML = '';
  318. const img = document.createElement('img');
  319. img.src = dlsitePreview.images[dlsitePreview.currentIndex];
  320. img.referrerPolicy = 'no-referrer';
  321. img.style.maxWidth = '100%';
  322. img.style.maxHeight = '100%';
  323. dlsitePreview.element.appendChild(img);
  324. }
  325.  
  326. function handleDlsiteKeydown(event) {
  327. if (!dlsitePreview.element || !dlsitePreview.isShowing || dlsitePreview.images.length <= 1) {
  328. return;
  329. }
  330.  
  331. if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
  332. event.stopPropagation();
  333. event.preventDefault();
  334.  
  335. if (event.key === 'ArrowLeft') {
  336. dlsitePreview.currentIndex = (dlsitePreview.currentIndex - 1 + dlsitePreview.images.length) % dlsitePreview.images.length;
  337. } else if (event.key === 'ArrowRight') {
  338. dlsitePreview.currentIndex = (dlsitePreview.currentIndex + 1) % dlsitePreview.images.length;
  339. }
  340. updateDlsitePreviewImage();
  341. }
  342. }
  343.  
  344. function handleDlsiteMouseWheel(event) {
  345. if (!dlsitePreview.element || !dlsitePreview.isShowing || dlsitePreview.images.length <= 1) {
  346. return;
  347. }
  348.  
  349. event.stopPropagation();
  350. event.preventDefault();
  351.  
  352. if (event.deltaY < 0) { // Wheel up
  353. dlsitePreview.currentIndex = (dlsitePreview.currentIndex - 1 + dlsitePreview.images.length) % dlsitePreview.images.length;
  354. } else if (event.deltaY > 0) { // Wheel down
  355. dlsitePreview.currentIndex = (dlsitePreview.currentIndex + 1) % dlsitePreview.images.length;
  356. }
  357. updateDlsitePreviewImage();
  358. }
  359.  
  360.  
  361. function showDlsitePreview(event) {
  362. if (!dlsitePreview.isEnabled) return;
  363.  
  364. const link = event.target;
  365. const productUrl = link.href;
  366.  
  367. if (dlsitePreview.isShowing) return;
  368. dlsitePreview.isShowing = true;
  369.  
  370. dlsitePreview.element = document.createElement('div');
  371. dlsitePreview.element.style.cssText = `
  372. position: fixed;
  373. z-index: 9999;
  374. background-color: rgba(0, 0, 0, 0.8);
  375. border: 1px solid #333;
  376. box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
  377. max-width: 480px;
  378. max-height: 480px;
  379. overflow: hidden;
  380. pointer-events: auto; /* Make sure wheel events are captured by this element */
  381. display: flex;
  382. justify-content: center;
  383. align-items: center;
  384. `;
  385. document.body.appendChild(dlsitePreview.element);
  386.  
  387. moveDlsitePreview(event);
  388. document.addEventListener('mousemove', moveDlsitePreview);
  389.  
  390. GM.xmlHttpRequest({
  391. method: "GET",
  392. url: productUrl,
  393. onload: function(response) {
  394. const parser = new DOMParser();
  395. const doc = parser.parseFromString(response.responseText, "text/html");
  396. const imgContainer = doc.querySelector('.product-slider');
  397.  
  398. if (!imgContainer) {
  399. if (dlsitePreview.element) {
  400. dlsitePreview.element.textContent = '미리보기를 불러올 수 없습니다.';
  401. dlsitePreview.element.style.color = '#fff';
  402. }
  403. return;
  404. }
  405.  
  406. dlsitePreview.images = [];
  407. dlsitePreview.currentIndex = 0;
  408.  
  409. const imageDataElements = imgContainer.querySelectorAll('.product-slider-data > div[data-src]');
  410. imageDataElements.forEach(dataEl => {
  411. const imageUrl = dataEl.dataset.src;
  412. if (
  413. imageUrl &&
  414. !imageUrl.includes('data:image') &&
  415. !imageUrl.toLowerCase().startsWith('javascript:') &&
  416. !imageUrl.includes('/resize/')
  417. ) {
  418. dlsitePreview.images.push(imageUrl);
  419. }
  420. });
  421.  
  422. if (dlsitePreview.element && dlsitePreview.images.length > 0) {
  423. updateDlsitePreviewImage();
  424.  
  425. if (dlsitePreview.globalKeydownListener) {
  426. document.removeEventListener('keydown', dlsitePreview.globalKeydownListener);
  427. }
  428. dlsitePreview.globalKeydownListener = handleDlsiteKeydown;
  429. document.addEventListener('keydown', dlsitePreview.globalKeydownListener);
  430.  
  431. if (dlsitePreview.activeWheelListener) {
  432. dlsitePreview.element.removeEventListener('wheel', dlsitePreview.activeWheelListener);
  433. }
  434. dlsitePreview.activeWheelListener = handleDlsiteMouseWheel;
  435. dlsitePreview.element.addEventListener('wheel', dlsitePreview.activeWheelListener, { passive: false });
  436.  
  437.  
  438. } else if (dlsitePreview.element) {
  439. dlsitePreview.element.textContent = '이미지를 찾을 수 없습니다.';
  440. dlsitePreview.element.style.color = '#fff';
  441. }
  442. },
  443. onerror: function() {
  444. if (dlsitePreview.element) {
  445. dlsitePreview.element.textContent = '미리보기 로드 실패';
  446. dlsitePreview.element.style.color = '#fff';
  447. }
  448. }
  449. });
  450.  
  451. link.addEventListener('mouseleave', hideDlsitePreview);
  452. }
  453.  
  454.  
  455. function moveDlsitePreview(event) {
  456. if (dlsitePreview.element) {
  457. dlsitePreview.element.style.top = `${event.clientY + 15}px`;
  458. dlsitePreview.element.style.left = `${event.clientX + 15}px`;
  459. }
  460. }
  461.  
  462. function hideDlsitePreview() {
  463. if (dlsitePreview.element) {
  464. if (dlsitePreview.activeWheelListener) {
  465. dlsitePreview.element.removeEventListener('wheel', dlsitePreview.activeWheelListener);
  466. dlsitePreview.activeWheelListener = null;
  467. }
  468. document.body.removeChild(dlsitePreview.element);
  469. dlsitePreview.element = null;
  470. }
  471. dlsitePreview.isShowing = false;
  472. dlsitePreview.images = [];
  473. dlsitePreview.currentIndex = 0;
  474.  
  475. document.removeEventListener('mousemove', moveDlsitePreview);
  476.  
  477. if (dlsitePreview.globalKeydownListener) {
  478. document.removeEventListener('keydown', dlsitePreview.globalKeydownListener);
  479. dlsitePreview.globalKeydownListener = null;
  480. }
  481. }
  482.  
  483. function doDlsiteContextAwareForElement(element) {
  484. if (!element) return;
  485.  
  486. const dlsiteCodePattern = /(?:(RJ|R\s*J|꺼|거|DL|D\s*L)|(VJ|V\s*J|퍼))\s*((?:[\s:()\[\]#.-]*[0-9]){5,10})/gi;
  487. const textContent = element.textContent || '';
  488. let tempHTML = element.innerHTML;
  489. const processedOriginalTexts = new Set();
  490.  
  491. let match;
  492. while ((match = dlsiteCodePattern.exec(textContent)) !== null) {
  493. const originalText = match[0];
  494. if (processedOriginalTexts.has(originalText)) {
  495. continue;
  496. }
  497.  
  498. const rjPrefix = match[1];
  499. const numbersWithJunk = match[3];
  500.  
  501. const prefix = rjPrefix ? 'RJ' : 'VJ';
  502. const code = numbersWithJunk.replace(/[^0-9]/g, '');
  503.  
  504. if (code.length < 5 || code.length > 10) {
  505. continue;
  506. }
  507.  
  508. const fullCode = `${prefix}${code}`;
  509. const linkUrl = `https://www.dlsite.com/maniax/work/=/product_id/${fullCode}.html`;
  510.  
  511. const textSpan = document.createElement('span');
  512. textSpan.textContent = originalText;
  513. const safeLinkText = textSpan.innerHTML;
  514.  
  515. const escapedOriginalText = originalText.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  516. const replaceRegex = new RegExp(escapedOriginalText, 'g');
  517. const safeHref = linkUrl.replace(/"/g, '&quot;');
  518.  
  519. let replaced = false;
  520. tempHTML = tempHTML.replace(replaceRegex, (match) => {
  521. if (replaced) return match;
  522.  
  523. const contextBefore = tempHTML.substring(tempHTML.lastIndexOf('<', tempHTML.indexOf(match)), tempHTML.indexOf(match));
  524. const contextAfter = tempHTML.substring(tempHTML.indexOf(match) + match.length, tempHTML.indexOf('>', tempHTML.indexOf(match) + match.length) + 1);
  525.  
  526. if (contextBefore.includes('href=') || contextAfter.includes('</a')) {
  527. return match;
  528. }
  529.  
  530. replaced = true;
  531. processedOriginalTexts.add(originalText);
  532. return `<a href="${safeHref}" target="_blank" rel="noreferrer" style="color:#1e90ff;">${safeLinkText}</a>`;
  533. });
  534. }
  535.  
  536. if (element.innerHTML !== tempHTML) {
  537. element.innerHTML = tempHTML;
  538. }
  539.  
  540. const dlsiteLinks = element.querySelectorAll('a[href*="dlsite.com"]');
  541. dlsiteLinks.forEach(link => {
  542. if (!link.dataset._dlsite_preview_hooked) {
  543. if (dlsitePreview.isEnabled) {
  544. link.addEventListener('mouseenter', showDlsitePreview);
  545. link.addEventListener('mouseleave', hideDlsitePreview, { once: true });
  546. }
  547. link.dataset._dlsite_preview_hooked = '1';
  548. }
  549. });
  550. }
  551.  
  552.  
  553. async function chkPW(){
  554. chkp[3]=await GM.getValue('chkp[3]');
  555. isT[0]=await GM.getValue('isT[0]', true);
  556. isT[1]=await GM.getValue('isT[1]', false);
  557. dlsitePreview.isEnabled = await GM.getValue('dlsitePreviewEnabled', true);
  558. updateDown();
  559. updateTab();
  560. updateDlsitePreviewMenu();
  561.  
  562. if(host=='arca.live' || host=='kone.gg'){
  563. if(chkp[3] !=chkp[4]){
  564. const chk=prompt('국룰을 입력해주세요');
  565. if(chk?.toLowerCase()==chkp[4]) {
  566. await GM.setValue('chkp[3]', chkp[4]);
  567. } else {
  568. GM.setValue('chkp[3]', false);
  569. alert('국룰이 틀렸습니다');
  570. }
  571. }
  572. }
  573. }
  574.  
  575. async function inputPW() {
  576. let inputElem = document.querySelector(chkp[0]), btnElem = document.querySelector(chkp[1]);
  577. if (!inputElem ) {
  578. if (isT[0] === true && !document.querySelector('.files-list, #download-section')) {
  579. await new Promise(res => setTimeout(res, PageLoading[1] || 1000)).then(DBtn);
  580. }
  581. return;
  582. }
  583.  
  584. const combinedPw = [...new Set([...pw, ...npw])];
  585.  
  586. if (chkp[3] == chkp[4]) {
  587. try {
  588. for (let i = 0; i < combinedPw.length; i++) {
  589. if (!combinedPw[i]) continue;
  590. if (!inputElem) break;
  591.  
  592. inputElem.value = combinedPw[i];
  593.  
  594. if (host == 'kio.ac') {
  595. inputElem.dispatchEvent(new Event('input', { bubbles: true }));
  596. inputElem.dispatchEvent(new Event('change', { bubbles: true }));
  597. await new Promise(res => setTimeout(res, 50));
  598. if(btnElem) btnElem.click();
  599. } else {
  600. if(btnElem) btnElem.click();
  601. else {
  602. const enterEvent = new KeyboardEvent('keydown', { key: 'Enter', code: 'Enter', keyCode: 13, which: 13, bubbles: true });
  603. inputElem.dispatchEvent(enterEvent);
  604. }
  605. }
  606.  
  607. await new Promise(res => setTimeout(res, 800));
  608.  
  609. const successIndicator = document.querySelector('.files-list, #download-section, .download-link, .btn-download, .main-button-download');
  610. const errorIndicator = document.querySelector('.text-error, .text-red-500, .error-message, .incorrect-password, [class*="error"], [id*="error"]');
  611.  
  612. if (successIndicator && successIndicator.offsetParent !== null) {
  613. break;
  614. } else if (errorIndicator && errorIndicator.offsetParent !== null) {
  615. if (inputElem) inputElem.value = '';
  616. }
  617. }
  618. if (isT[0] == true) {
  619. await new Promise(res => setTimeout(res, PageLoading[1] || 1000)).then(DBtn);
  620. }
  621.  
  622. } catch (e) {
  623. if (isT[0] == true) {
  624. await new Promise(res => setTimeout(res, PageLoading[1] || 1000)).then(DBtn);
  625. }
  626. }
  627. }
  628. }
  629.  
  630. async function kioskdone(){
  631. try {
  632. await new Promise(res=> setTimeout(res, 3000));
  633. for(let i=0, jj=0; jj!=1; i++){
  634. await new Promise(res=> setTimeout(res, 1000));
  635. if(document.querySelector('.flex.flex-row.text-xs.justify-between div:nth-child(2)').innerText=='done'){
  636. await new Promise(res=> setTimeout(res, 2000)).then(() => window.close());
  637. jj++;
  638. }
  639. }
  640. } catch(e){
  641. if(isT[1]==true && isT[2]==true) window.close();
  642. }
  643. }
  644.  
  645. async function DBtn(){
  646. if (isT[0] !== true) return;
  647.  
  648. if (host === 'kiosk.ac') {
  649. try {
  650. const btns = document.querySelectorAll(chkp[2]);
  651. const clickedSet = new Set();
  652.  
  653. for (const btn of btns) {
  654. if (!btn || btn.offsetParent === null) continue;
  655. const key = btn.closest('tr')?.innerText?.trim();
  656. if (clickedSet.has(key)) continue;
  657.  
  658. let waitCount = 0;
  659. while (btn.disabled && waitCount < 10) {
  660. await new Promise(res => setTimeout(res, 200));
  661. waitCount++;
  662. }
  663.  
  664. if (btn.disabled) continue;
  665.  
  666. clickedSet.add(key);
  667. btn.click();
  668. await new Promise(res => setTimeout(res, 1800));
  669. }
  670. } catch (e) {}
  671. }
  672.  
  673. else if (host === 'mega.nz') {
  674. try {
  675. const resumeButton = document.querySelector('.mega-button.positive.resume.js-resume-download');
  676. if (resumeButton) resumeButton.click();
  677.  
  678. const standardDownloadButton = document.querySelector('.mega-button.positive.js-default-download.js-standard-download');
  679. if (standardDownloadButton) standardDownloadButton.click();
  680.  
  681. const continueDownloadButton = document.querySelector('.mega-button.large.positive.download.continue-download');
  682. if (continueDownloadButton) continueDownloadButton.click();
  683. } catch (e) {}
  684. }
  685.  
  686. else {
  687. try {
  688. const btns = document.querySelectorAll(chkp[2]);
  689. const clickedSet = new Set();
  690.  
  691. for (const btn of btns) {
  692. if (!btn || btn.offsetParent === null || btn.classList.contains('btn-disabled')) continue;
  693. const key = btn.closest('tr')?.innerText?.trim();
  694. if (!clickedSet.has(key)) {
  695. clickedSet.add(key);
  696. btn.click();
  697. await new Promise(res => setTimeout(res, 300));
  698. }
  699. }
  700. } catch (e) {}
  701. }
  702.  
  703. if (isT[1] === true && isT[2] === true) {
  704. setTimeout(() => {
  705. if (host === 'kiosk.ac') {
  706. kioskdone();
  707. } else {
  708. window.close();
  709. }
  710. }, 1500);
  711. }
  712. }
  713.  
  714. async function FindPW(){
  715. let atc;
  716. if (host === 'arca.live') {
  717. atc = document.querySelector('body div.article-body > div.fr-view.article-content');
  718. } else if (host === 'kone.gg') {
  719. atc = getKoneGGContentElement();
  720. }
  721.  
  722. if (!atc || !atc.innerHTML) return;
  723.  
  724. let tempContent = atc.innerHTML;
  725. tempContent=tempContent.replace(/ /g, ' ').replace(/( ){2,}/g, ' ');
  726. tempContent=tempContent.replace(/국룰/g, 'ㄱㄹ');
  727.  
  728. let regexx=/(대문자)/;
  729.  
  730. if(regexx.test(tempContent)) {
  731. const smpeopleUpper = atob('U01QRU9QTEU=');
  732. if (npw.indexOf(smpeopleUpper) === -1) {
  733. npw.push(smpeopleUpper);
  734. }
  735. }
  736.  
  737. function processPasswordRegex(reg){
  738. let currentLoopContent = tempContent;
  739. const processedTexts = new Set();
  740.  
  741. while(true){
  742. const matchResult = reg.exec(currentLoopContent);
  743. if (!matchResult) break;
  744.  
  745. let matchedText = matchResult[0];
  746. if (processedTexts.has(matchedText)) {
  747. currentLoopContent = currentLoopContent.replace(matchedText, `__SKIPPED_${Math.random().toString(36).substring(2, 10)}__`);
  748. continue;
  749. }
  750.  
  751. let DECed = matchedText.replace(/(ㄱㄹ)/g, '국룰');
  752. let DECedd = DECed.replace(/\s|[+]|(은|는|이|가)|(전부)|(대문자로)|(대문자)|(비밀번호)|(패스워드)|(비번)|(ㅂㅂ)|(암호)|(ㅇㅎ)|(키오스크맘)|(키오스크)|(입니다)|(이고)|(이며)|(임다)|(같다)|(처럼)|(틀리다)|(입니다요)/g, '');
  753. DECedd = DECedd.split(/[(입)(임)(이)(이)(이)(입)(임)(같)(처)(틀)]/g)[0];
  754. DECedd = DECedd.replace(/[<>]/g, '');
  755.  
  756. let dat;
  757. if (host === 'arca.live') {
  758. const dateEl = document.querySelector('.article-info .date .body');
  759. if (dateEl && typeof dateEl.innerText === 'string' && dateEl.innerText.trim() !== '') {
  760. dat = dateEl.innerText.split(' ')[0];
  761. } else {
  762. dat = undefined;
  763. }
  764. }
  765.  
  766. let regexa=/(오늘)|(날짜)|(날자)/g;
  767. if(dat && regexa.test(DECedd)){
  768. DECedd=DECedd.replace(regexa, '');
  769. const dateParts = dat.split(/\-/g);
  770. if (dateParts.length === 3) {
  771. const year = dateParts[0].slice(2);
  772. const month = dateParts[1];
  773. const day = dateParts[2];
  774. let dateFormats=[month + day, month + '-' + day, year + month + day, dat.replace(/-/g,'')];
  775. for(let k=0;k<dateFormats.length;k++){
  776. const finalPw = DECedd.replace(/국룰/g,chkp[4]) + dateFormats[k];
  777. if(finalPw.length > 2 && npw.indexOf(finalPw)=='-1') {
  778. npw.push(finalPw);
  779. }
  780. }
  781. }
  782. } else {
  783. const finalPw = DECedd.replace(/국룰/g,chkp[4]);
  784. if(finalPw && finalPw.length > 2 && npw.indexOf(finalPw)=='-1') {
  785. npw.push(finalPw);
  786. }
  787. }
  788. processedTexts.add(matchedText);
  789. currentLoopContent = currentLoopContent.replace(matchedText, `__PROCESSED_${Math.random().toString(36).substring(2, 15)}__`);
  790. }
  791. }
  792. processPasswordRegex(/[(<p>\s*)*]{0,}[ㄱ-ㅣ가-힣0-9A-Za-z\s~`!^\_+@\#$%&=]{0,}(ㄱㄹ){1,1}[ㄱ-ㅣ가-힣0-9A-Za-z\s~`!^\_+@\#$%&=]{0,}[(\s*</p>)*]{0,}/);
  793. await GM.setValue('npw', npw);
  794. }
  795.  
  796. function waitForKoneContentAndProcess() {
  797. let attempts = 0;
  798. const maxAttempts = 20;
  799. const checkInterval = setInterval(async () => {
  800. attempts++;
  801. await handleBlockingModals(host);
  802.  
  803. const atc = getKoneGGContentElement();
  804. const titleEl = [...document.querySelectorAll('h1.flex, h1.text-xl')].find(el =>
  805. el.textContent?.match(/RJ[0-9]{6,10}|VJ[0-9]{6,10}/i)
  806. );
  807.  
  808. const hasBase64 = atc && /aHR0c|YUhSMG|WVVoU|V1ZWb/.test(atc.textContent || '');
  809.  
  810. if (atc && (titleEl || hasBase64) && (atc.textContent || '').length > 10) {
  811. clearInterval(checkInterval);
  812. await FindPW();
  813. setTimeout(doDec, 200);
  814. } else if (attempts >= maxAttempts) {
  815. clearInterval(checkInterval);
  816. }
  817. }, 200);
  818. }
  819.  
  820. async function loadNpw() {
  821. const saved = await GM.getValue('npw');
  822. if (Array.isArray(saved)) {
  823. npw = [...new Set([...npw, ...saved])];
  824. }
  825. }
  826.  
  827. async function initHostSpecificSettings() {
  828. await loadNpw();
  829.  
  830. const hostConfigs = {
  831. 'kio.ac': {
  832. chkpSelectors: [
  833. '.overflow-auto.max-w-full.flex-grow.p-1 input:nth-of-type(1)',
  834. '.flex.flex-col-reverse button:nth-of-type(1)',
  835. 'td.align-middle > div.flex > button[type="button"].inline-flex'
  836. ],
  837. isT2: true,
  838. pageLoadDelay: 1500,
  839. inputPwDelay: 2000
  840. },
  841. 'kiosk.ac': {
  842. chkpSelectors: [
  843. '.input.shadow-xl.flex-grow',
  844. '.btn.btn-ghost.w-full.mt-2.rounded-md',
  845. '.dropdown.group > button'
  846. ],
  847. isT2: Down_Option === 0,
  848. pageLoadDelay: 500,
  849. inputPwDelay: 500
  850. },
  851. 'mega.nz': {
  852. chkpSelectors: [
  853. '#password-decrypt-input',
  854. '.mega-button.positive.fm-dialog-new-folder-button.decrypt-link-button',
  855. '.mega-button.positive.js-default-download.js-standard-download'
  856. ],
  857. isT2: false,
  858. pageLoadDelay: 2500,
  859. inputPwDelay: 1800
  860. },
  861. 'workupload.com': {
  862. chkpSelectors: [
  863. '#passwordprotected_file_password',
  864. '#passwordprotected_file_submit',
  865. 'a.btn.btn-prio[href*="/file/"]'
  866. ],
  867. isT2: Down_Option === 0,
  868. pageLoadDelay: 1500,
  869. inputPwDelay: 0
  870. },
  871. 'drive.google.com': {
  872. chkpSelectors: [],
  873. isT2: true,
  874. pageLoadDelay: 500,
  875. inputPwDelay: 0
  876. },
  877. 'drive.usercontent.google.com': {
  878. chkpSelectors: [
  879. null,
  880. null,
  881. 'form[method="POST"] button[type="submit"], input[type="submit"][value="다운로드"], button.jfk-button-action'
  882. ],
  883. isT2: true,
  884. pageLoadDelay: 500,
  885. inputPwDelay: 0
  886. },
  887. 'gofile.io': {
  888. chkpSelectors: [
  889. '#filesErrorPasswordInput',
  890. '#filesErrorPasswordButton',
  891. 'button.btn-download, a.btn-download, #rowFolderCenter button[data-bs-target="#filesList"] + div .btn-outline-secondary'
  892. ],
  893. isT2: true,
  894. pageLoadDelay: 1500,
  895. inputPwDelay: 0
  896. }
  897. };
  898.  
  899. const config = hostConfigs[host];
  900. if (config) {
  901. chkp[0] = config.chkpSelectors[0];
  902. chkp[1] = config.chkpSelectors[1];
  903. chkp[2] = config.chkpSelectors[2];
  904. isT[2] = config.isT2;
  905. PageLoading[1] = config.pageLoadDelay;
  906.  
  907. if (host === 'drive.google.com') {
  908. if (document.URL.includes('/file/d/')) {
  909. const fileId = document.URL.split('/d/')[1].split('/')[0];
  910. if (fileId) {
  911. window.location.href = `https://drive.usercontent.google.com/download?id=${fileId}&export=download&authuser=0`;
  912. }
  913. } else if (document.URL.includes('/drive/folders/')) {
  914. await new Promise(res => setTimeout(res, (PageLoading[0] || 1000) + 1500));
  915. if (isT[0] === true) {
  916. const downloadAllButton = document.querySelector('div[aria-label="모두 다운로드"], div[data-tooltip="모두 다운로드"]');
  917. if (downloadAllButton) {
  918. downloadAllButton.click();
  919. } else {
  920. const firstItemDownloadButton = document.querySelector('div[role="gridcell"][data-is-shared="false"] div[aria-label*="다운로드"]');
  921. if (firstItemDownloadButton) {
  922. firstItemDownloadButton.click();
  923. }
  924. }
  925. }
  926. await new Promise(res => setTimeout(res, (PageLoading[0] || 1000) + 3500)).then(() => {
  927. if (isT[0] === true) DBtn();
  928. });
  929. }
  930. } else if (host === 'drive.usercontent.google.com') {
  931. await new Promise(res => setTimeout(res, 100)).then(() => {
  932. if (isT[0] === true) DBtn();
  933. });
  934. } else {
  935. await new Promise(res => setTimeout(res, (PageLoading[0] || 1000) + config.inputPwDelay)).then(inputPW);
  936. }
  937. }
  938. }
  939.  
  940.  
  941. (async () => {
  942. await chkPW();
  943. await handleBlockingModals(host);
  944.  
  945. if (host === 'arca.live') {
  946. await FindPW();
  947. setTimeout(doDec, 200);
  948. } else if (host === 'kone.gg') {
  949. waitForKoneContentAndProcess();
  950. }
  951.  
  952. await initHostSpecificSettings();
  953. })();
  954.  
  955. (function () {
  956. if (location.host !== 'kone.gg') return;
  957.  
  958. function hookDecodeTriggerOnButton() {
  959. const buttonsToHook = [
  960. document.querySelector('div.flex.items-center.justify-between.p-4 button[data-slot="button"]'),
  961. [...document.querySelectorAll('button.flex.cursor-pointer.items-center')]
  962. .find(button => button.textContent?.trim() === '댓글 더 불러오기'),
  963. ].filter(b => b instanceof Element && b.dataset._somi_hooked !== '1');
  964.  
  965. buttonsToHook.forEach(button => {
  966. button.dataset._somi_hooked = '1';
  967. button.addEventListener('click', async () => {
  968. await handleBlockingModals(host);
  969. setTimeout(async () => {
  970. await FindPW();
  971. setTimeout(doDec, 200);
  972. }, 500);
  973. });
  974. });
  975. }
  976.  
  977. hookDecodeTriggerOnButton();
  978.  
  979. const observer = new MutationObserver(async (mutationsList) => {
  980. for (const mutation of mutationsList) {
  981. if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
  982. hookDecodeTriggerOnButton();
  983. await handleBlockingModals(host);
  984. setTimeout(async () => {
  985. await FindPW();
  986. setTimeout(doDec, 200);
  987. }, 100);
  988. } else if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
  989. await handleBlockingModals(host);
  990. setTimeout(async () => {
  991. await FindPW();
  992. setTimeout(doDec, 200);
  993. }, 100);
  994. }
  995. }
  996. await handleBlockingModals(host);
  997. });
  998. observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['class', 'style'] });
  999. })();
  1000.  
  1001.  
  1002. (function () {
  1003. if (location.host !== 'kone.gg') return;
  1004.  
  1005. let lastUrl = location.href;
  1006. let mainProcessingIntervalId = null;
  1007.  
  1008. const observer = new MutationObserver(async () => {
  1009. const currentUrl = location.href;
  1010. if (currentUrl !== lastUrl) {
  1011. lastUrl = currentUrl;
  1012. if (mainProcessingIntervalId) {
  1013. clearInterval(mainProcessingIntervalId);
  1014. }
  1015. await handleBlockingModals(host);
  1016. observeAndRunKoneFunctions();
  1017. }
  1018. });
  1019.  
  1020. observer.observe(document.body, { childList: true, subtree: true });
  1021.  
  1022. async function observeAndRunKoneFunctions() {
  1023. const start = Date.now();
  1024. const timeout = 8000;
  1025.  
  1026. if (mainProcessingIntervalId) {
  1027. clearInterval(mainProcessingIntervalId);
  1028. }
  1029.  
  1030. mainProcessingIntervalId = setInterval(async () => {
  1031. await handleBlockingModals(host);
  1032. const atc = getKoneGGContentElement();
  1033. const hasText = atc && (atc.textContent || '').length > 20;
  1034. const hasEncoded = atc && /aHR0c|YUhSMG|WVVoU|V1ZWb/.test(atc.textContent || '');
  1035. const hasDlsiteLink = atc && atc.querySelector('a[href*="dlsite.com"]');
  1036. const comments = document.querySelectorAll('p.text-sm.whitespace-pre-wrap');
  1037. let hasEncodedComments = false;
  1038. for(const comment of comments) {
  1039. if (/aHR0c|YUhSMG|WVVoU|V1ZWb/.test(comment.textContent || '')) {
  1040. hasEncodedComments = true;
  1041. break;
  1042. }
  1043. }
  1044.  
  1045.  
  1046. if (atc && (hasText && (hasEncoded || hasDlsiteLink)) || hasEncodedComments) {
  1047. clearInterval(mainProcessingIntervalId);
  1048. mainProcessingIntervalId = null;
  1049. await FindPW();
  1050. setTimeout(doDec, 200);
  1051. }
  1052.  
  1053. if (Date.now() - start > timeout) {
  1054. clearInterval(mainProcessingIntervalId);
  1055. mainProcessingIntervalId = null;
  1056. }
  1057. }, 200);
  1058. }
  1059.  
  1060. (async () => {
  1061. await handleBlockingModals(host);
  1062. observeAndRunKoneFunctions();
  1063. })();
  1064. })();

QingJ © 2025

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