🏠 Home 

CorocoroDownloader

Manga downloader for corocoro.jp


安装此脚本?
  1. // ==UserScript==
  2. // @name CorocoroDownloader
  3. // @namespace https://github.com/Timesient/manga-download-scripts
  4. // @version 0.6
  5. // @license GPL-3.0
  6. // @author Timesient
  7. // @description Manga downloader for corocoro.jp
  8. // @icon https://www.corocoro.jp/assets/app-icon/favicon.png
  9. // @homepageURL https://greasyfork.org/scripts/513508-corocorodownloader
  10. // @supportURL https://github.com/Timesient/manga-download-scripts/issues
  11. // @match https://www.corocoro.jp/*
  12. // @require https://unpkg.com/axios@0.27.2/dist/axios.min.js
  13. // @require https://unpkg.com/jszip@3.7.1/dist/jszip.min.js
  14. // @require https://unpkg.com/file-saver@2.0.5/dist/FileSaver.min.js
  15. // @require https://update.greasyfork.org/scripts/451810/1398192/ImageDownloaderLib.js
  16. // @grant GM_info
  17. // @grant GM_xmlhttpRequest
  18. // ==/UserScript==
  19. (async function(axios, JSZip, saveAs, ImageDownloader) {
  20. 'use strict';
  21. // reload page when enter or leave chapter
  22. const re = /https:\/\/www.corocoro\.jp\/chapter\/\d+\/viewer/;
  23. const oldHref = window.location.href;
  24. const timer = setInterval(() => {
  25. const newHref = window.location.href;
  26. if (newHref === oldHref) return;
  27. if (re.test(newHref) || re.test(oldHref)) {
  28. clearInterval(timer);
  29. window.location.reload();
  30. }
  31. }, 200);
  32. // return if not reading chapter now
  33. if (!re.test(oldHref)) return;
  34. // add info
  35. const infoElement = document.createElement('span');
  36. infoElement.innerHTML = `如果下载面板不出现,请确保阅读器处于双页模式,然后点击下一页。<br>If the download panel does not appear, please make sure the viewer is in double-page mode, then go next page.`;
  37. infoElement.style = `position: fixed; top: 12px; left: 72px; padding: 8px 10px; background-color: #000; border-radius: 4px; color: #FFF; font-family: Microsoft YaHei, PingFang SC; font-size: 12px;`;
  38. document.body.appendChild(infoElement);
  39. // try to capture data of pages
  40. let pages;
  41. const originPush = Array.prototype.push;
  42. Array.prototype.push = function() {
  43. const target = arguments[0];
  44. if (
  45. pages === undefined
  46. && target instanceof Array
  47. && target.length > 0
  48. && target.some(item => item?.side === 'center')
  49. ) {
  50. pages = this.flat().map(item => ({ src: item.src.url, crypto: item.src.crypto })).filter(item => item.src && item.crypto);
  51. }
  52. return originPush.apply(this, arguments);
  53. }
  54. // wait until data of pages being captured
  55. await new Promise(resolve => {
  56. const timer = setInterval(() => {
  57. if (pages) { infoElement.remove(); clearInterval(timer); resolve(); }
  58. }, 200);
  59. });
  60. // get title
  61. const mangaTitle = document.querySelector('div.flex.flex-col:has(p):has(h3) > p')?.textContent;
  62. const chapterTitle = document.querySelector('div.flex.flex-col:has(p):has(h3) > h3')?.textContent;
  63. const title = (mangaTitle && chapterTitle) ? `${mangaTitle} ${chapterTitle}` : document.title.split(' | ').shift();
  64. // setup ImageDownloader
  65. ImageDownloader.init({
  66. maxImageAmount: pages.length,
  67. getImagePromises,
  68. title
  69. });
  70. // collect promises of image
  71. function getImagePromises(startNum, endNum) {
  72. return pages
  73. .slice(startNum - 1, endNum)
  74. .map(page => getDecryptedImage(page)
  75. .then(ImageDownloader.fulfillHandler)
  76. .catch(ImageDownloader.rejectHandler)
  77. );
  78. }
  79. // get promise of decrypted image
  80. async function getDecryptedImage(page) {
  81. const unhex = (hexString) => new Uint8Array(hexString.match(/.{1,2}/g).map((part) => parseInt(part, 16)));
  82. const encryptedImageArrayBuffer = await axios.get(page.src, { responseType: 'arraybuffer' }).then(res => res.data);
  83. const key = await crypto.subtle.importKey('raw', unhex(page.crypto.key), 'AES-CBC', false, ['decrypt']);
  84. const decryptedImageArrayBuffer = await crypto.subtle.decrypt({ name: 'AES-CBC', iv: unhex(page.crypto.iv) }, key, encryptedImageArrayBuffer);
  85. return decryptedImageArrayBuffer;
  86. }
  87. })(axios, JSZip, saveAs, ImageDownloader);