Dynasty Preloader

Preloads Dynasty Reader pages.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Dynasty Preloader
// @namespace    http://tampermonkey.net/
// @version      0.3.5.1
// @description  Preloads Dynasty Reader pages.
// @author       mcpower
// @match        http://dynasty-scans.com/chapters/*
// @grant        none
// @license      GPLv3
// ==/UserScript==

// Dynasty Preloader - a UserScript to preload pages in Dynasty Reader
// Copyright (C) 2017  mcpower
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// This preloads Dynasty Reader pages and indicates it with colours.
// Red means it's in the queue, but it hasn't preloaded it yet.
// Yellow means it's currently preloading.
// Green means it's preloaded.
//
// If you wish, you can also preload all pages by clicking on the "Load All" button
// to the right of the "Fullscreen" button.


// Change these variables if you wish.
// lookahead is the number of pages to load ahead of you.
// lookbehind
// max_concurrent is the maximum number of image requests at any one time.
// Turn this down if you get loading screens, even though the page has been preloaded.
const lookahead = 4;
const lookbehind = 2;
const max_concurrent = 5;

(function () {
	"use strict";
	let queue = []; // page objects
	let images = []; // stack/queue of Image objects to be used after they've been loaded


	const states = {
		default: -1,
		queued: 0,
		loading: 1,
		loaded: 2
	};
	const state_classes = {
		[states.default]: "",
		[states.queued]:  "queued",
		[states.loading]: "loading",
		[states.loaded]:  "loaded"
	};
	const state_list = Object.keys(states);

	const css_text = ".queued{background:#ebccd1} .loading{background:#fcf8e3} .loaded{background:#dff0d8}";



	// initialise images with the image elements
	// define the onload event so we don't have to define it later
	// just set any Image.page then Image.src and then it'll be all good
	function img_onload(event) {
		const img = event.path[0];
		const page = img.page;
		page.state = states.loaded;
		images.push(img);
		update_style(page);
		check_queue();
	}

	for (let i = 0; i < max_concurrent; i++) {
		const cur_img = new Image();
		cur_img.onload = img_onload;
		images.push(cur_img);
	}



	function update_style(page) {
		if (page.state === page.styled_state) return;
		const cl = page.element.classList;
		if (page.styled_state !== states.default) {
			cl.remove(state_classes[page.styled_state]);
		}
		cl.add(state_classes[page.state]);
		page.styled_state = page.state;
	}

	// To load stuff, chuck it onto the queue and call this function
	function check_queue() {
		while (images.length > 0 && queue.length > 0) {
			load(queue.shift());
		}
	}

	// Actually, to check stuff on the queue you should probably use this function
	// You still need to call check_queue though.
	function chuck_on_queue(page) {
		if (page.state === states.loading || page.state === states.loaded) return;

		page.state = states.queued;
		queue.push(page);
		update_style(page);
	}

	function load(page) {
		if (page.state === states.loading || page.state === states.loaded) return;

		const img = images.pop();
		page.state = states.loading;
		update_style(page);

		img.page = page;
		img.src = page.image;
	}

	// loads `lookahead` pages after the current page and `lookbehind` before.
	function load_lookahead() {
		let cur_page;
		switch (window.location.hash) {
			case "#last":
				cur_page = window.pages.length;
				break;
			case "":
				cur_page = 1;
				break;
			default:
				cur_page = parseInt(window.location.hash.substr(1));
		}
		// clamp juust in case
		cur_page = Math.min(window.pages.length, Math.max(1, cur_page));

		const cur_index = cur_page - 1;

		// Always load lookahead before lookbehind
		for (let i = cur_index; i <= cur_index + lookahead && i < window.pages.length; i++) {
			chuck_on_queue(window.pages[i]);
		}
		for (let i = cur_index - 1; i >= cur_index - lookbehind && i >= 0; i--) {
			chuck_on_queue(window.pages[i]);
		}
		check_queue();
	}

	// loads all pages
	function load_all() {
		window.pages.forEach(chuck_on_queue);
		check_queue();
		return false;
	}


	// inject the CSS we want
	const css = document.createElement("style");
	css.innerHTML = css_text;
	document.body.appendChild(css);

	// precalculate all the DOM elements
	const pages_list = document.getElementById("prev_link").parentElement;
	for (let i = 0; i < window.pages.length; i++) {
		window.pages[i].element = pages_list.children[i+1];
		window.pages[i].state = states.default;
		window.pages[i].styled_state = states.default;
	}

	// create the "Load All" button
	const load_button = document.createElement("a");
	load_button.className = "btn btn-mini";
	load_button.innerHTML = "Load All";
	load_button.href = "#";
	load_button.onclick = load_all;
	document.getElementById("fullscreen").insertAdjacentElement("afterend", load_button);

	// lookahead stuff
	window.addEventListener("hashchange", load_lookahead);
	load_lookahead();
}());