SpeedbinbDownloader

Manga downloader specific for Speedbinb reader

// ==UserScript==
// @name         SpeedbinbDownloader
// @namespace    https://github.com/Timesient/manga-download-scripts
// @version      0.9
// @license      GPL-3.0
// @author       Timesient
// @description  Manga downloader specific for Speedbinb reader
// @icon         https://gammaplus.takeshobo.co.jp/img/common/favicon.ico
// @homepageURL  https://greasyfork.org/scripts/451879-speedbinbdownloader
// @supportURL   https://github.com/Timesient/manga-download-scripts/issues
// @match        https://gammaplus.takeshobo.co.jp/_files/*
// @match        https://storia.takeshobo.co.jp/_files/*
// @match        https://webcomicgamma.takeshobo.co.jp/_files/*
// @match        https://comic-meteor.jp/ptdata/*
// @match        https://www.123hon.com/vw/*
// @match        https://www.comic-valkyrie.com/samplebook/*
// @match        https://comic-polaris.jp/ptdata/*
// @match        https://manga-mee.jp/trial_reading/*
// @match        https://digitalmargaret.jp/contents/*/*
// @match        https://televikun-super-hero-comics.com/*/*/*
// @require      https://unpkg.com/[email protected]/dist/axios.min.js
// @require      https://unpkg.com/[email protected]/dist/jszip.min.js
// @require      https://unpkg.com/[email protected]/dist/FileSaver.min.js
// @require      https://update.greasyfork.org/scripts/451810/1398192/ImageDownloaderLib.js
// @grant        GM_info
// @grant        GM_xmlhttpRequest
// ==/UserScript==

(async function (axios, JSZip, saveAs, ImageDownloader) {
  'use strict';
  
  // get base URL
  const href = window.location.href;
  const baseURL = /123hon\.com|manga-mee\.jp/.test(href) ? href.replace('index.html', '') : href;

  // get url of json files
  const html = await axios.get(window.location.href).then(res => res.data);
  const urls = html.match(/data\/\d+\.ptimg\.json/gm).map(json => baseURL + json);

  // setup ImageDownloader
  ImageDownloader.init({
    maxImageAmount: urls.length,
    getImagePromises,
  });

  // collect promises of image
  function getImagePromises(startNum, endNum) {
    return urls
      .slice(startNum - 1, endNum)
      .map(url => getDecryptedImage(url)
        .then(ImageDownloader.fulfillHandler)
        .catch(ImageDownloader.rejectHandler)
      );
  }

  function getDecryptedImage(url) {
    return new Promise(async resolve => {
      // get config of image
      const config = await axios.get(url).then(res => res.data);

      const image = document.createElement('img');
      image.src = `${baseURL}data/${config.resources.i.src}`;
      image.onload = function () {
        // create destination canvas
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');
        canvas.width = config.views[0].width;
        canvas.height = config.views[0].height;

        // get coordinates, width, height of pieces
        const coords = config.views[0].coords.map(coord => {
          const items = coord.match(/^([^:]+):(\d+),(\d+)\+(\d+),(\d+)>(\d+),(\d+)$/);
          if (!items) throw new Error("Invalid format for Image Transfer : " + coord);

          return {
            srcX: parseInt(items[2], 10),
            srcY: parseInt(items[3], 10),
            width: parseInt(items[4], 10),
            height: parseInt(items[5], 10),
            destX: parseInt(items[6], 10),
            destY: parseInt(items[7], 10)
          }
        });

        // draw pieces on correct position
        for (const { srcX, srcY, destX, destY, width, height } of coords) {
          ctx.drawImage(this, srcX, srcY, width, height, destX, destY, width, height);
        }

        canvas.toBlob(resolve);
      }
    });
  }

})(axios, JSZip, saveAs, ImageDownloader);