Copymanga Simple Read

manga reader for copymanga, J/K for DOWN/UP, LEFT/RIGHT for previous/next chapter.

目前為 2021-09-25 提交的版本,檢視 最新版本

// ==UserScript==
// @name        Copymanga Simple Read
// @namespace   http://tampermonkey.net/
// @match       https://www.copymanga.com/comic/*/chapter/*
// @grant       none
// @version     1.12
// @author      chemPolonium
// @description manga reader for copymanga, J/K for DOWN/UP, LEFT/RIGHT for previous/next chapter.
// @run-at      document-end
// ==/UserScript==

/* jshint esversion: 6 */
/* jshint multistr: true */
(function() {
  'use strict';

  document.getElementsByClassName('header')[0].remove();

  let comicContainerFluid = document.getElementsByClassName('container-fluid comicContent')[0];
  comicContainerFluid.setAttribute('style', 'padding-right: 0px !important; padding-left: 0px !important;');

  let comicContainer = comicContainerFluid.children[0];
  comicContainer.setAttribute('style', 'max-width: 100% !important; margin-right: 0px !important; margin-left: 0px !important');

  let comicList = comicContainer.children[0];

  let comicListChildren = comicList.children;

  let currentImageIndex = 0;

  function getImage(imageIndex) {
    return comicListChildren[imageIndex].children[0];
  }

  function getCurrentImage() {
    return getImage(currentImageIndex);
  }

  function moveToCurrentImage() {
    if (currentImageIndex == 0) {
      window.scrollTo(0, 0);
    } else {
      window.scrollTo(0, getCurrentImage().offsetTop);
    }
  }

  let pageNumPerScreen = 2;

  function setPageNumPerScreen(pageNum) {
    comicList.setAttribute('style', 'padding-top: 0px !important;\
      margin-bottom: 0px !important;\
      max-width: 100% !important;\
      width: 100% !important;\
      display:grid;grid-template-columns: repeat(' + String(pageNum) + ', 1fr);\
      direction: rtl;');
    moveToCurrentImage();
    pageNumPerScreen = pageNum;
  }

  setPageNumPerScreen(2);

  let scrollEvent = new UIEvent('scroll');

  function preloadImage() {
    // simulate the scroll for preload
    // the script is like this: total client height / 3 < window scrollY then not load
    // so first scroll Y to 0
    window.scrollTo(0, 0);
    for (let i = 0; i < pageNumPerScreen; i++) {
      window.dispatchEvent(scrollEvent);
      // dispatch the scroll event for preload
    }
    // this function will scroll Y to 0
  }

  function moveImageIndex(x) {
    let newImageIndex = currentImageIndex + x;
    if (newImageIndex < comicList.children.length && newImageIndex >= 0) {
      currentImageIndex = newImageIndex;
    }
  }

  function setSingleAlign(imageIndex) {
    if (imageIndex % 2 == 0) {
      comicListChildren[imageIndex].setAttribute('style', 'text-align: left;');
    } else {
      comicListChildren[imageIndex].setAttribute('style', 'text-align: right;');
    }
  }

  function setAlign() {
    for (let imageIndex = 0; imageIndex < comicListChildren.length; imageIndex++) {
      setSingleAlign(imageIndex);
    }
  }

  function onePageDown() {
    preloadImage();
    moveImageIndex(pageNumPerScreen);
    moveToCurrentImage();
  }

  function onePageUp() {
    moveImageIndex(-pageNumPerScreen);
    moveToCurrentImage();
  }

  function createTitlePage() {
    let titlePage = document.createElement('li');
    let titlePageDiv = document.createElement('div');
    let titlePageTitle = document.createElement('p');
    titlePageTitle.appendChild(document.createTextNode(document.title));
    titlePageTitle.setAttribute('style', 'color: white;\
      font-size: xx-large;\
      max-width: 30vw;\
      margin-top: 30%;\
      margin-right: 20%;\
      white-space: normal;');
    titlePageDiv.appendChild(titlePageTitle);
    titlePage.appendChild(titlePageDiv);
    return titlePage;
  }

  let titlePage = createTitlePage();

  let parityChanged = false;

  function switchParity() {
    if (parityChanged) {
      comicListChildren[0].remove();
    } else {
      comicList.insertAdjacentElement('afterbegin', titlePage);
    }
    parityChanged = !parityChanged;
    setAlign();
    moveToCurrentImage();
  }

  let footer = document.getElementsByClassName('footer')[0];
  let footerChildren = footer.children;
  let prevChapterHref = footerChildren[1].children[0].href;
  let nextChapterHref = footerChildren[3].children[0].href;
  let chapterListHref = footerChildren[4].children[0].href;

  document.addEventListener('keydown', (event) => {
    switch (event.code) {
      case 'ArrowRight':
        window.location = nextChapterHref;
        break;
      case 'ArrowLeft':
        window.location = prevChapterHref;
        break;
      case 'KeyK':
        onePageUp();
        break;
      case 'KeyJ':
        onePageDown();
        break;
      case 'KeyL':
        window.location = chapterListHref;
        break;
      case 'Semicolon':
        switchParity();
        break;
      case 'Digit1':
        setPageNumPerScreen(1);
        break;
      case 'Digit2':
        setPageNumPerScreen(2);
        break;
      default:
        console.log('key: ' + event.key + ' code: ' + event.code);
    }
  });
  
  footer.remove();

  let firstLoad = true;
  comicList.addEventListener('DOMNodeInserted', (event) => {
    if (firstLoad && comicListChildren.length > 2) {
      firstLoad = false;
      switchParity();
    }
    setSingleAlign(comicListChildren.length - 1);
    // the set will not work if important is not added
    event.target.children[0].setAttribute('style', 'width:auto !important;\
      height:auto !important;\
      max-height: 100vh !important;\
      max-width: 100% !important;');
  });

})();