<commit_before>/* global JSZip */
// ==UserScript==
// @name         Tsumino script
// @version      0.45
// @author       HK49
// @license      MIT
// @include      /^https?://www.tsumino.com/Book/Info/.+/
// @grant        none
// @run-at       document-start
// @require      https://cdnjs.cloudflare.com/ajax/libs/jszip/3.2.0/jszip.min.js#sha256=VwkT6wiZwXUbi2b4BOR1i5hw43XMzVsP88kpesvRYfU=
// ==/UserScript==

const TIME_BETWEEN_REQUESTS = 2000/* miliseconds */;

// TODO net::ERR_SPDY_PROTOCOL_ERROR 200 over https (memory issue?)
// TODO Error Handling


/* show progress inside button while downloading */
const progress = {
  install: () => { progress.button = document.getElementById("DownloadButton"); },
  onstart: (imagesQuantity) => {
    progress.button.style = "pointer-events: none; cursor: not-allowed; opacity: 0.8;";
    const numberOfTicks = imagesQuantity * ['image load', 'image save'].length;
    progress.tick = 100 / (numberOfTicks); // 100%/above
  },
  onerror: () => {
    progress.button.style = "background-color: #c00;";
    progress.button.innerText = "\xa0\xa0:'(\xa0\xa0";
  },
  nofetch: () => {
    progress.button.style = "background-color: #ffae33;";
    progress.button.innerText = "404";
  },
  percent: 0,
  update: () => {
    progress.percent += progress.tick;
    const num = Math.floor(progress.percent);

    progress.button.innerText = `${num < 10 ? `\xa0\xa0${num}` : num}%`;
  },
  onloadend: () => {
    progress.button.style = '';
    progress.button.innerText = '\xa0\xa0\u2B73\xa0\xa0\xa0';
  },
};

// object, that stores db, manga id, array of pages urls, their total length..
const manga = {
  id: Number(window.location.pathname.match(/(?<=Info\/)\d+(?=\/)?/)),
};

// add button on page
document.addEventListener('DOMContentLoaded', (_) => {
  document
    .querySelector("#complete_form > :last-child > .book-info")
    .appendChild(Object.assign(document.createElement('button'), {
      className: "book-read-button button-stack",
      id: 'DownloadButton',
      innerText: "\xa0\xa0\u2B73\xa0\xa0\xa0", // ⭳
      onclick: (e) => {
        e.preventDefault();
        download();
      },
      title: 'Download manga',
    }));
});


// does what it says
async function download() {
  progress.install();

  cleanupDB(); // delete old entries in db

  // get array of links for images
  manga.hashes = (await mangaData().catch((e) => {
    progress.nofetch();
    throw e;
  })).reader_page_urls;

  // check if new or old, while opening connection to db
  const status = await openDB();

  // if the download of this same manga was done previously but ended abruptly
  // then preserve previously downloaded images and download only new
  if (status === 'previous') {
    manga.hashes = [];
    await new Promise(resolve => requestIDB(
      manga.db.transaction("download").objectStore("download").index("buffer").openCursor(IDBKeyRange.only(0)),
      e => cursor(e, ({ hash }) => manga.hashes.push(hash), resolve()),<commit_msg>removed bug when promise resolves instantly in cursor on downloaded pages<commit_after>/* global JSZip */
// ==UserScript==
// @name         Tsumino script
// @version      0.45
// @author       HK49
// @license      MIT
// @include      /^https?://www.tsumino.com/Book/Info/.+/
// @grant        none
// @run-at       document-start
// @require      https://cdnjs.cloudflare.com/ajax/libs/jszip/3.2.0/jszip.min.js#sha256=VwkT6wiZwXUbi2b4BOR1i5hw43XMzVsP88kpesvRYfU=
// ==/UserScript==

const TIME_BETWEEN_REQUESTS = 2000/* miliseconds */;

// TODO net::ERR_SPDY_PROTOCOL_ERROR 200 over https (memory issue?)
// TODO Error Handling


/* show progress inside button while downloading */
const progress = {
  install: () => { progress.button = document.getElementById("DownloadButton"); },
  onstart: (imagesQuantity) => {
    progress.button.style = "pointer-events: none; cursor: not-allowed; opacity: 0.8;";
    const numberOfTicks = imagesQuantity * ['image load', 'image save'].length;
    progress.tick = 100 / (numberOfTicks); // 100%/above
  },
  onerror: () => {
    progress.button.style = "background-color: #c00;";
    progress.button.innerText = "\xa0\xa0:'(\xa0\xa0";
  },
  nofetch: () => {
    progress.button.style = "background-color: #ffae33;";
    progress.button.innerText = "404";
  },
  percent: 0,
  update: () => {
    progress.percent += progress.tick;
    const num = Math.floor(progress.percent);

    progress.button.innerText = `${num < 10 ? `\xa0\xa0${num}` : num}%`;
  },
  onloadend: () => {
    progress.button.style = '';
    progress.button.innerText = '\xa0\xa0\u2B73\xa0\xa0\xa0';
  },
};

// object, that stores db, manga id, array of pages urls, their total length..
const manga = {
  id: Number(window.location.pathname.match(/(?<=Info\/)\d+(?=\/)?/)),
};

// add button on page
document.addEventListener('DOMContentLoaded', (_) => {
  document
    .querySelector("#complete_form > :last-child > .book-info")
    .appendChild(Object.assign(document.createElement('button'), {
      className: "book-read-button button-stack",
      id: 'DownloadButton',
      innerText: "\xa0\xa0\u2B73\xa0\xa0\xa0", // ⭳
      onclick: (e) => {
        e.preventDefault();
        download();
      },
      title: 'Download manga',
    }));
});


// does what it says
async function download() {
  progress.install();

  cleanupDB(); // delete old entries in db

  // get array of links for images
  manga.hashes = (await mangaData().catch((e) => {
    progress.nofetch();
    throw e;
  })).reader_page_urls;

  // check if new or old, while opening connection to db
  const status = await openDB();

  // if the download of this same manga was done previously but ended abruptly
  // then preserve previously downloaded images and download only new
  if (status === 'previous') {
    manga.hashes = [];
    await new Promise(resolve => requestIDB(
      manga.db.transaction("download").objectStore("download").index("buffer").openCursor(IDBKeyRange.only(0)),
      e => cursor(e, ({ hash }) => manga.hashes.push(hash), resolve),
{'fraction_non_alphanumeric': 0.16986120290812953, 'fraction_numerical': 0.02247191011235955, 'mean_word_length': 3.137388926862611, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 31, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 23, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4197595', 'n_tokens_mistral': 2063, 'n_tokens_neox': 1962, 'n_words': 439}