// ==UserScript== // @name 解决某垃圾小说站 // @namespace https://viayoo.com/enpza9 // @version 0.3 // @description 解决某垃圾小说站,章节截断,恶意转跳问题。 // @author Aloazny // @include http*://*/book/*/*.html // @run-at document-start // @license MIT // @grant none // ==/UserScript== (function() { 'use strict'; const spoofPlatform = (p = 'Mac') => { const s = new Proxy(navigator, { get(t, k) { if (k === 'platform') return p; let v = Reflect.get(t, k); return typeof v === 'function' ? v.bind(t) : v; }, getOwnPropertyDescriptor: (t, k) => k === 'platform' ? { value: p, writable: false, configurable: true, enumerable: true } : Object.getOwnPropertyDescriptor(t, k) }); const f = () => { try { if (Object.getOwnPropertyDescriptor(navigator, 'platform')) { navigator.__defineGetter__('platform', () => p); } else { Object.defineProperty(navigator, 'platform', { get: () => p, configurable: true, enumerable: true }); } Object.defineProperty(window, 'navigator', { value: s, writable: false, configurable: true }); Object.defineProperty(Navigator.prototype, 'platform', { get: () => p, configurable: true, enumerable: true }); Object.freeze(window.navigator); } catch (e) {} }; const i = String.prototype.indexOf; String.prototype.indexOf = function(v) { if (this === p) { if (['Win', 'Linux', 'X11'].includes(v)) return -1; if (v === p) return 0; } return i.apply(this, arguments); }; f(); }; spoofPlatform('Mac'); const DEFAULT_KEYWORDS = [ 'htmlAds', '_ffc1();', '_ffc2();', '_ffc3();', '_ffc4();', '_ffp();', 'kbbaidu1();', 'kbbaidu2();', 'kbbaidu3();', 'html5player.checkVideoAds', 'ads_codes', '{return void 0!==b[a]?b[a]:a}).join("")}', '${scripts[randomIndex]}', '${scripts[Math.random()', '"https://"+Date.parse(new Date())+', '"https://"+(new Date().getDate())+', 'https://hongosi.xn--', 'https://{randomstr}.', 'new Function(t)()', 'new Function(b)()', 'new Function(c)()', 'new Function(t);', 'new Function(b);', 'new Function(c);', 'new Function(\'d\',e)', 'new Function(document[', 'new Function(function(p,a,c,k,e,d)', 'function a(a){', 'function b(b){', 'function c(c){', 'function updateCarousel()', 'Math.floor(2147483648 * Math.random());', 'Math.floor(Math.random()*url.length)', 'Math.floor(Math.random() * urls.length)', 'new Date()[\'getTime\']()', 'newDate=new window', 'Math.floor(((new Date()).getTime()', '&&navigator[', '=navigator;', 'navigator.platform){setTimeout(function', 'disableDebugger', 'blockDeveloperTools', '["Date"]())[\'getTime\']()', '\');', '<\\/\'+\'s\'+\'c\'+\'ri\'+\'pt\'+\'>\');', 'class=\\"zdhf\\"', '(\'#htmlContenthtml\').html', 'D.createElement(\'span\');', 'class=\\"app_tj\\"', 'window.$m(', 'jsjiami.com.v4', 'histats.com', 'hm.baidu.com', 'adbyunion', '{win:false,mac:false,xll:false}', 'mainCell:".bd",effect:"leftLoop"', '/invoke.js">', 'function|getDate', 'parseInt(Math[\'random\']', 'pc.stgowan.com' ]; const regexes = DEFAULT_KEYWORDS.map(k => { try { let pattern = k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') .replace(/\\ /g, '[\\s\\n\\r]*') .replace(/ /g, '[\\s\\n\\r]*') .replace(/\\\)\\\{/g, '\\s*\\)\\s*\\{') .replace(/\\\)\\\;/g, '\\s*\\)\\s*\\;'); return new RegExp(pattern); } catch (e) { return { test: () => false }; } }); function isAdScriptContent(content) { if (!content) return false; return regexes.some(reg => reg.test(content)); } function removeMatchedScripts() { document.querySelectorAll('script').forEach(script => { const content = script.innerHTML || script.textContent; if (content && isAdScriptContent(content)) { script.type = 'text/prevented'; script.textContent = ''; script.remove(); } }); } const observer = new MutationObserver(mutations => { mutations.forEach(m => { m.addedNodes.forEach(node => { if (node.nodeName === 'SCRIPT') { const content = node.innerHTML || node.textContent; if (content && isAdScriptContent(content)) { node.type = 'text/prevented'; node.textContent = ''; node.remove(); } else { const obs = new MutationObserver(() => { const laterContent = node.innerHTML || node.textContent; if (laterContent && isAdScriptContent(laterContent)) { node.type = 'text/prevented'; node.textContent = ''; node.remove(); obs.disconnect(); } }); obs.observe(node, { childList: true, characterData: true, subtree: true }); setTimeout(() => obs.disconnect(), 5000); } } }); }); }); observer.observe(document.documentElement, { childList: true, subtree: true }); removeMatchedScripts(); function tryDecrypt() { let decryptFn = window.php_decrypt_js; let encrypted = window.c; if (typeof decryptFn !== 'function') { for (let key in window) { if (key.toLowerCase().includes('decrypt') && typeof window[key] === 'function') { decryptFn = window[key]; break; } } } if (typeof encrypted !== 'string' || encrypted.length < 50) { const scripts = document.querySelectorAll('script:not([src])'); for (let s of scripts) { const match = s.textContent.match(/var\s+[a-zA-Z_$][\w$]*\s*=\s*"([A-Za-z0-9+/=]{100,})"/); if (match) { encrypted = match[1]; break; } } } if (typeof decryptFn !== 'function' || typeof encrypted !== 'string') { setTimeout(tryDecrypt, 500); return; } try { const selectors = ['#chaptercontent', '#content', '.content', '.read-content', '.chapter-content', '.post-content', '#booktxt', '#htmlContent', '.article-content']; let contentDiv = null; for (let sel of selectors) { contentDiv = document.querySelector(sel); if (contentDiv) break; } if (!contentDiv) return; const currentHtml = contentDiv.innerHTML; const decryptedHtml = decryptFn(encrypted); const currentText = contentDiv.innerText.substring(0, 100).trim(); let finalHtml = decryptedHtml.includes(currentText) ? decryptedHtml : currentHtml + decryptedHtml; contentDiv.innerHTML = finalHtml; const moreContent = contentDiv.querySelector('#morecontent'); if (moreContent) moreContent.remove(); const keywords = [ '小说推荐:', '看后求收藏', '退出阅读模式即可', '更多内容加载中', '本站只支持手机浏览器访问', '若您看到此段落,代表章节内容加载失败' ]; const paragraphs = contentDiv.querySelectorAll('p'); paragraphs.forEach(p => { const text = p.innerText; if (keywords.some(keyword => text.includes(keyword))) { p.remove(); } }); const errorMsg = document.querySelector('p[style*="color:red"]'); if (errorMsg && errorMsg !== contentDiv) errorMsg.remove(); } catch (e) { console.error('[解密脚本] 运行异常:', e); setTimeout(tryDecrypt, 2000); } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', tryDecrypt); } else { tryDecrypt(); } })();