🏠 返回首頁 

Greasy Fork is available in English.

刺猬猫章节自动下载

打开刺猬猫章节页面时自动保存文章到本地, 支持##章节。

  1. // ==UserScript==
  2. // @name 刺猬猫章节自动下载
  3. // @namespace https://github.com/NateScarlet/Scripts/tree/master/user-script
  4. // @description 打开刺猬猫章节页面时自动保存文章到本地, 支持##章节。
  5. // @grant none
  6. // @include https://www.ciweimao.com/chapter/*
  7. // @run-at document-idle
  8. // @version 2023.12.05+fbf1a78c
  9. // ==/UserScript==
  10. "use strict";
  11. (() => {
  12. var __async = (__this, __arguments, generator) => {
  13. return new Promise((resolve, reject) => {
  14. var fulfilled = (value) => {
  15. try {
  16. step(generator.next(value));
  17. } catch (e) {
  18. reject(e);
  19. }
  20. };
  21. var rejected = (value) => {
  22. try {
  23. step(generator.throw(value));
  24. } catch (e) {
  25. reject(e);
  26. }
  27. };
  28. var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
  29. step((generator = generator.apply(__this, __arguments)).next());
  30. });
  31. };
  32. // src/utils/elementRootText.ts
  33. function elementRootText(element) {
  34. let ret = "";
  35. for (const i of element.childNodes) {
  36. if (i.nodeType === i.TEXT_NODE) {
  37. ret += i.nodeValue;
  38. }
  39. }
  40. return ret.trim();
  41. }
  42. // src/utils/canvasToMarkdown.ts
  43. function canvasToMarkdown(canvas, alt = "", title = "") {
  44. return `![${alt}](${canvas.toDataURL()} "${title}")`;
  45. }
  46. // src/utils/isCanvasTainted.ts
  47. function isCanvasTainted(canvas) {
  48. try {
  49. canvas.getContext("2d").getImageData(0, 0, 1, 1);
  50. return false;
  51. } catch (err) {
  52. return err instanceof DOMException && err.name === "SecurityError";
  53. }
  54. }
  55. // src/utils/imageToCanvas.ts
  56. function imageToCanvas(_0) {
  57. return __async(this, arguments, function* (img, {
  58. background
  59. } = {}) {
  60. const canvas = document.createElement("canvas");
  61. canvas.width = img.naturalWidth;
  62. canvas.height = img.naturalHeight;
  63. const ctx = canvas.getContext("2d");
  64. if (background) {
  65. ctx.fillStyle = background;
  66. ctx.fillRect(0, 0, canvas.width, canvas.height);
  67. }
  68. ctx.drawImage(img, 0, 0);
  69. if (img.src && img.crossOrigin !== "anonymous" && isCanvasTainted(canvas)) {
  70. const corsImage = new Image();
  71. corsImage.crossOrigin = "anonymous";
  72. corsImage.src = img.src;
  73. yield corsImage.decode();
  74. return imageToCanvas(corsImage, { background });
  75. }
  76. return canvas;
  77. });
  78. }
  79. // src/utils/imageToMarkdown.ts
  80. function imageToMarkdown(_0) {
  81. return __async(this, arguments, function* (img, {
  82. background
  83. } = {}) {
  84. return canvasToMarkdown(
  85. yield imageToCanvas(img, { background }),
  86. img.alt,
  87. img.title
  88. );
  89. });
  90. }
  91. // src/utils/loadImage.ts
  92. function loadImage(url) {
  93. return __async(this, null, function* () {
  94. const img = new Image();
  95. img.src = url;
  96. img.alt = url;
  97. yield img.decode();
  98. return img;
  99. });
  100. }
  101. // src/utils/sleep.ts
  102. function sleep(duration) {
  103. return __async(this, null, function* () {
  104. return new Promise((resolve) => {
  105. setTimeout(resolve, duration);
  106. });
  107. });
  108. }
  109. // src/ciweimao.com/download.user.ts
  110. var __name__ = "刺猬猫章节自动下载";
  111. (function() {
  112. return __async(this, null, function* () {
  113. const chapter = document.querySelector("#J_BookCnt .chapter").firstChild.textContent;
  114. let lines = [];
  115. let startTime = Date.now();
  116. while (lines.length === 0 && Date.now() - startTime < 6e4) {
  117. yield sleep(1e3);
  118. for (const i of document.querySelectorAll("#J_BookImage")) {
  119. const url = i.style["background-image"].match(
  120. /(?:url\(")?(.+)(?:"\))?/
  121. )[1];
  122. const line = yield imageToMarkdown(yield loadImage(url));
  123. lines.push(line);
  124. }
  125. for (const i of document.querySelectorAll("#J_BookRead p.chapter")) {
  126. const line = elementRootText(i);
  127. lines.push(line);
  128. for (const img of i.querySelectorAll("img")) {
  129. yield img.decode();
  130. lines.push(yield imageToMarkdown(img));
  131. }
  132. }
  133. for (const i of document.querySelectorAll("p.author_say")) {
  134. const line = elementRootText(i);
  135. lines.push(` ${line}`);
  136. for (const img of i.querySelectorAll("img")) {
  137. yield img.decode();
  138. lines.push(yield imageToMarkdown(img));
  139. }
  140. }
  141. lines = lines.filter((i) => i.length > 0);
  142. }
  143. console.log(`${__name__}: 获取到 ${lines.length} 行`);
  144. const file = new Blob([`# ${chapter}
  145. `, lines.join("\n\n") + "\n"], {
  146. type: "text/markdown"
  147. });
  148. const anchor = document.createElement("a");
  149. anchor.href = URL.createObjectURL(file);
  150. anchor.download = `${location.pathname.split("/").slice(-1)[0]} ${document.title}.md`;
  151. anchor.style["display"] = "none";
  152. document.body.append(anchor);
  153. anchor.click();
  154. setTimeout(() => {
  155. document.body.removeChild(anchor);
  156. URL.revokeObjectURL(anchor.href);
  157. }, 0);
  158. });
  159. })();
  160. })();