// ==UserScript== // @name 趣笔阁下载器 // @namespace http://tampermonkey.net/ // @version 0.2.0 // @description 可在趣笔阁下载小说,在小说目录页面使用,仅供交流,可能存在bug。 // @author Yearly // @match https://www.beqege.cc/*/ // @license MIT // @grant GM_registerMenuCommand // @grant GM_addStyle // @namespace https://greasyfork.org/scripts/500170 // @supportURL https://greasyfork.org/scripts/500170 // @homepageURL https://greasyfork.org/scripts/500170 // @icon https://www.beqege.cc/favicon.ico // @downloadURL none // ==/UserScript== (function() { // 添加自定义样式 GM_addStyle(` #fetchContentModal { border-radius: 10px; position: fixed; top: 40%; left: 50%; transform: translate(-50%, -50%); background: white; padding: 5px 20px 10px 20px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); z-index: 10000; width: 300px; text-align: center; } #fetchContentModal input[type="number"] { width: 30%; margin: 5px 0; text-align: center; } #fetchContentModal button { width: 100%; margin: 10px 0; } #fetchContentProgress { width: 100%; background: #f3f3f3; border: 1px solid #ccc; margin: 10px 0; } #fetchContentProgress div { width: 0; height: 20px; background: #4caf50; text-align: center; margin-left: 0; color: #960; white-space: nowrap; } `); // 创建悬浮窗 const modalHtml = ` `; document.body.insertAdjacentHTML('beforeend', modalHtml); // 获取元素 const modal = document.getElementById('fetchContentModal'); const startRangeInput = document.getElementById('_startRange'); const endRangeInput = document.getElementById('_endRange'); const fetchButton = document.getElementById('fetchContentButton'); const progressBar = document.getElementById('fetchContentProgress').firstElementChild; const downlink = document.getElementById('_downlink'); const warnInfo = document.getElementById('_warn_info'); const fetcClose = document.getElementById('fetcModalClose'); // 注册菜单命令 GM_registerMenuCommand('小说下载工具', () => { modal.style.display = 'block'; startRangeInput.max = document.querySelectorAll("#list > dl > dd > a").length; endRangeInput.max = document.querySelectorAll("#list > dl > dd > a").length; endRangeInput.value = endRangeInput.max; warnInfo.innerText=`当前小说共 ${endRangeInput.max} 章。\n设置范围后点击开始下载,并稍作等待。` }); fetcClose.addEventListener('click', async () => { modal.style.display = 'none'; }); // 下载 fetchButton.addEventListener('click', async () => { downlink.innerText = ""; downlink.href = null; downlink.download = null; const startRange = parseInt(startRangeInput.value, 10); const endRange = parseInt(endRangeInput.value, 10); const links = document.querySelectorAll("#list > dl > dd > a"); const selectedLinks = Array.from(links).slice(startRange - 1, endRange); const title = document.querySelector("#maininfo #info h1").innerText || document.title; const results = []; const totalLinks = selectedLinks.length; let completedRequests = 0; const delay = ms => new Promise(resolve => setTimeout(resolve, ms)); const fetchAndParse = async (link, index) => { await delay(index * 8); const url = link.href; try { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } const text = await response.text(); const parser = new DOMParser(); const doc = parser.parseFromString(text, 'text/html'); const contentElements = doc.querySelectorAll('div#content > :not(div#device)'); let content = ''; contentElements.forEach((element) => { content += element.innerText + '\n'; }); results[index] = { title: link.innerText, content: content.trim() }; } catch (error) { results[index] = { title: link.innerText, content: `Error fetching ${url}: ${error}` }; } finally { // 更新进度条 completedRequests++; const progress = Math.round((completedRequests / totalLinks) * 100); progressBar.style.width = `${progress}%`; progressBar.textContent = `${completedRequests} / ${totalLinks}`; } }; Promise.all(selectedLinks.map((link, index) => fetchAndParse(link, index))) .then(() => { let finalResults = document.querySelector("#maininfo #info").innerText || title || ''; finalResults += `\n\n下载章节范围:${startRange} ~ ${endRange}\n`; finalResults += "\n-----------------------\n"; results.forEach((result) => { finalResults += `\n## ${result.title}\n`; finalResults += result.content + '\n'; }); finalResults += "\n-----------------------\n"; const blob = new Blob([finalResults], { type: 'text/plain' }); downlink.innerText = "加载完成后,若未开始自动下载,点击这里"; downlink.href = URL.createObjectURL(blob); downlink.download = `${title}_${startRange}~${endRange}.txt`; downlink.click(); }) .catch((error) => { console.error('Error fetching links:', error); }); }); })();