打开SF轻小说章节页面时自动保存文章到本地, 支持##章节。
- // ==UserScript==// @name SF轻小说章节自动下载// @namespace https://github.com/NateScarlet/Scripts/tree/master/user-script// @description 打开SF轻小说章节页面时自动保存文章到本地, 支持##章节。// @grant none// @include http://book.sfacg.com/Novel/*/*/*/// @include http://book.sfacg.com/vip/c/*/// @include https://book.sfacg.com/Novel/*/*/*/// @include https://book.sfacg.com/vip/c/*/// @run-at document-idle// @version 2023.12.05+8005e7f4// ==/UserScript=="use strict";(() => {var __async = (__this, __arguments, generator) => {return new Promise((resolve, reject) => {var fulfilled = (value) => {try {step(generator.next(value));} catch (e) {reject(e);}};var rejected = (value) => {try {step(generator.throw(value));} catch (e) {reject(e);}};var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);step((generator = generator.apply(__this, __arguments)).next());});};// src/utils/urlLastPart.tsfunction urlLastPart(url) {return url.split("/").filter((i) => i).slice(-1)[0];}// src/utils/downloadFile.tsfunction downloadFile(file, filename = `${urlLastPart(location.pathname)} ${document.title}.md`) {const anchor = document.createElement("a");anchor.href = URL.createObjectURL(file);anchor.download = filename;anchor.style["display"] = "none";document.body.append(anchor);anchor.click();setTimeout(() => {document.body.removeChild(anchor);URL.revokeObjectURL(anchor.href);}, 0);}// src/utils/elementRootText.tsfunction elementRootText(element) {let ret = "";for (const i of element.childNodes) {if (i.nodeType === i.TEXT_NODE) {ret += i.nodeValue;}}return ret.trim();}// src/utils/canvasToMarkdown.tsfunction canvasToMarkdown(canvas, alt = "", title = "") {return `} "${title}")`;}// src/utils/isCanvasTainted.tsfunction isCanvasTainted(canvas) {try {canvas.getContext("2d").getImageData(0, 0, 1, 1);return false;} catch (err) {return err instanceof DOMException && err.name === "SecurityError";}}// src/utils/imageToCanvas.tsfunction imageToCanvas(_0) {return __async(this, arguments, function* (img, {background} = {}) {const canvas = document.createElement("canvas");canvas.width = img.naturalWidth;canvas.height = img.naturalHeight;const ctx = canvas.getContext("2d");if (background) {ctx.fillStyle = background;ctx.fillRect(0, 0, canvas.width, canvas.height);}ctx.drawImage(img, 0, 0);if (img.src && img.crossOrigin !== "anonymous" && isCanvasTainted(canvas)) {const corsImage = new Image();corsImage.crossOrigin = "anonymous";corsImage.src = img.src;yield corsImage.decode();return imageToCanvas(corsImage, { background });}return canvas;});}// src/utils/imageToMarkdown.tsfunction imageToMarkdown(_0) {return __async(this, arguments, function* (img, {background} = {}) {return canvasToMarkdown(yield imageToCanvas(img, { background }),img.alt,img.title);});}// src/sfacg.com/book-download.user.tsvar __name__ = "SF轻小说章节自动下载";(function() {return __async(this, null, function* () {const chapter = document.querySelector("#article .article-title").textContent;let lines = [`# ${chapter}`,`[原始页面](${location.href})`,...document.querySelector("#article .article-desc").textContent.split(/\n */).filter((i) => i),`---`];const keywords = document.querySelector("meta[name='keywords']").content.split(",").filter((i) => !["小说下载", "TXT"].includes(i)).filter((i, index, keywords2) => index === 0 || !i.startsWith(keywords2[0]));for (const i of document.querySelectorAll("img#vipImage")) {console.log(`${__name__}: 等待图片加载`);yield i.decode();console.log(`${__name__}: 图片加载完毕`);const line = yield imageToMarkdown(i, { background: "white" });lines.push(line);}for (const i of document.querySelectorAll("#ChapterBody p")) {const line = elementRootText(i);lines.push(line);for (const img of i.querySelectorAll("img")) {lines.push(yield imageToMarkdown(img));}}lines = lines.filter((i) => i.length > 0);console.log(`${__name__}: 获取到 ${lines.length} 行`);const file = new Blob([lines.join("\n\n"), "\n"], {type: "text/markdown"});downloadFile(file, `${keywords.join(" ")}.md`);});})();})();