您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Navigate to manga sites with selected numbers and bypass unsafelink popups
// ==UserScript== // @name Bypass unsafeflink // @namespace Natalie // @version 1.1 // @description Navigate to manga sites with selected numbers and bypass unsafelink popups // @match *://*/* // @grant none // @license GNU GPLv3 // ==/UserScript== (function() { 'use strict'; let menuWindow = null; let selectedNumber = ''; let showTimer = null; const hitomiSites = [ {name: 'hitomi', url: 'https://hitomi.la/doujinshi/'}, {name: 'k-hentai', url: 'https://k-hentai.org/r/'}, {name: 'litomi', url: 'https://litomi.vercel.app/manga/'} ]; const rjSites = [ {name: 'DLsite', url: 'https://www.dlsite.com/maniax/work/=/product_id/'}, {name: 'asmr.one', url: 'https://asmr.one/work/'}, {name: 'hentai-sharing', url: 'https://hentai-sharing.net/?s='}, {name: 'japaneseasmr', url: 'https://japaneseasmr.com/?s='}, {name: 'hvdb.me', url: 'hvdb'} ]; const base64Sites = [ {name: '디코딩 URL로 이동', url: ''} ]; function isValidHitomiNumber(text) { return /^\d{6,7}$/.test(text); } function isValidRJNumber(text) { return /^RJ\d{6,8}$/i.test(text); } function isBase64(text) { return /^[A-Za-z0-9+/=]+$/.test(text) && text.length % 4 === 0; } function recursiveBase64Decode(base64Text, maxDepth = 10) { if (maxDepth <= 0) return null; try { const decodedText = atob(base64Text); if (decodedText.startsWith('http://') || decodedText.startsWith('https://')) { if (decodedText.includes('unsafelink.com/')) { return decodedText.replace(/https?:\/\/unsafelink\.com\//, ''); } return decodedText; } if (isBase64(decodedText)) { const recursiveResult = recursiveBase64Decode(decodedText, maxDepth - 1); if (recursiveResult) return recursiveResult; } return null; } catch (e) { console.error('Base64 디코딩 에러:', e); return null; } } function processHvdbUrl(rjNumber) { let numberPart = rjNumber.substring(2); if (numberPart.length === 8 && numberPart.startsWith('0')) { numberPart = numberPart.replace(/^0+/, ''); } return `https://hvdb.me/Dashboard/WorkDetails/${numberPart}`; } function processUnsafelink(url) { if (url.includes('unsafelink.com/')) { return url.replace(/https?:\/\/unsafelink\.com\//, ''); } return url; } function createMenuWindow(sites) { if (menuWindow) { while (menuWindow.firstChild) { menuWindow.removeChild(menuWindow.firstChild); } } else { menuWindow = document.createElement('div'); menuWindow.style.cssText = `position:fixed;padding:5px;background:rgba(40,40,40,0.97);border:1px solid rgba(70,70,70,0.5);border-radius:5px;z-index:999999;display:none;user-select:none;pointer-events:auto;box-shadow:0 4px 8px rgba(0,0,0,0.3);left:auto;top:0;backdrop-filter:blur(3px);`; menuWindow.addEventListener('mousedown', e => e.stopPropagation()); document.body.appendChild(menuWindow); } sites.forEach(site => { const button = document.createElement('div'); button.style.cssText = `color:#e0e0e0;padding:8px 15px;margin:5px 0;cursor:pointer;border-radius:3px;font-size:14px;transition:all 0.2s;pointer-events:auto;`; button.textContent = site.name; button.addEventListener('mouseover', () => { button.style.background = 'rgba(80,80,80,0.8)'; button.style.color = '#ffffff'; }); button.addEventListener('mouseout', () => { button.style.background = 'transparent'; button.style.color = '#e0e0e0'; }); button.addEventListener('click', e => { e.preventDefault(); e.stopPropagation(); if (selectedNumber) { let url; if (sites === base64Sites) { url = recursiveBase64Decode(selectedNumber); } else if (isValidHitomiNumber(selectedNumber)) { url = site.url + selectedNumber + (site.name === 'k-hentai' ? '#1' : (site.name === 'litomi' ? '/hi' : '.html')); } else if (isValidRJNumber(selectedNumber)) { if (site.url === 'hvdb') { url = processHvdbUrl(selectedNumber); } else { url = site.url + selectedNumber + (site.name === 'DLsite' ? '.html' : ''); } } if (url) { url = processUnsafelink(url); window.open(url, '_blank'); } } hideMenu(); }); button.addEventListener('mousedown', e => { e.preventDefault(); e.stopPropagation(); }); menuWindow.appendChild(button); }); return menuWindow; } function showMenu(rect, text) { selectedNumber = text; let sitesToUse; if (isValidHitomiNumber(text)) { sitesToUse = hitomiSites; } else if (isValidRJNumber(text)) { sitesToUse = rjSites; } else if (isBase64(text) && recursiveBase64Decode(text)) { sitesToUse = base64Sites; } else { return; } const menu = createMenuWindow(sitesToUse); menu.style.display = 'block'; let finalLeft = rect.left + 35; let finalTop = rect.bottom + 5; const menuWidth = menu.offsetWidth || 100; const menuHeight = menu.offsetHeight || 100; const maxRight = document.documentElement.clientWidth - 10; if (finalLeft + menuWidth > maxRight) { finalLeft = maxRight - menuWidth; } finalLeft = Math.max(10, finalLeft); if (finalTop + menuHeight > window.innerHeight - 10) { finalTop = rect.top - menuHeight - 5; } menu.style.left = `${finalLeft}px`; menu.style.top = `${finalTop}px`; } function hideMenu() { if (menuWindow) { menuWindow.style.display = 'none'; } } document.addEventListener('selectionchange', () => { if (showTimer) { clearTimeout(showTimer); showTimer = null; } const selection = window.getSelection(); if (!selection || selection.rangeCount === 0) return; const text = selection.toString().trim(); hideMenu(); if (text && (isValidHitomiNumber(text) || isValidRJNumber(text) || (isBase64(text) && recursiveBase64Decode(text)))) { showTimer = setTimeout(() => { const range = selection.getRangeAt(0); const rect = range.getBoundingClientRect(); showMenu(rect, text); }, 500); } }); document.addEventListener('click', e => { if (menuWindow && menuWindow.style.display === 'block' && !menuWindow.contains(e.target)) { hideMenu(); } }); document.addEventListener('scroll', () => { hideMenu(); }); if (window.location.hostname.includes('unsafelink.com')) { const currentUrl = window.location.href; const originalUrl = currentUrl.replace(/https?:\/\/unsafelink\.com\//, ''); if (originalUrl !== currentUrl) { window.location.href = originalUrl; } } else { document.addEventListener('click', (e) => { if (e.target.tagName === 'A' && e.target.href && e.target.href.includes('unsafelink.com')) { e.preventDefault(); e.stopPropagation(); const originalUrl = e.target.href.replace(/https?:\/\/unsafelink\.com\//, ''); window.open(originalUrl, e.target.target || '_blank'); } }, true); if (window.location.hostname.includes('arca.live')) { const processAllLinks = () => { document.querySelectorAll('a[href*="unsafelink.com"]').forEach(link => { const originalUrl = link.href.replace(/https?:\/\/unsafelink\.com\//, ''); link.href = originalUrl; link.setAttribute('data-processed', 'true'); link.removeAttribute('onclick'); link.removeAttribute('target'); }); }; const handlePopups = () => { const popups = document.querySelectorAll('div.microModal.is-open'); popups.forEach(popup => { if (popup.textContent.includes('unsafelink.com') || popup.textContent.includes('외부 사이트로 이동합니다')) { const moveButton = popup.querySelector('button.danger'); if (moveButton) { moveButton.click(); } else { popup.remove(); } } }); }; const observer = new MutationObserver((mutations) => { let needToProcessLinks = false; let needToHandlePopups = false; mutations.forEach(mutation => { if (mutation.type === 'childList' && mutation.addedNodes.length > 0) { for (const node of mutation.addedNodes) { if (node.nodeType === 1) { if (node.tagName === 'A' || node.querySelector('a')) { needToProcessLinks = true; } if (node.classList && (node.classList.contains('microModal') || node.querySelector('.microModal'))) { needToHandlePopups = true; } } } } }); if (needToProcessLinks) { processAllLinks(); } if (needToHandlePopups) { setTimeout(handlePopups, 50); } }); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['href', 'class'] }); processAllLinks(); window.addEventListener('load', () => { setTimeout(handlePopups, 100); }); setInterval(handlePopups, 500); } } })();