🏠 Home 

FA Webcomic Auto Loader

Gives you the option to load all the subsequent comic pages on a FurAffinity comic page automatically. Even for pages without given Links

// ==UserScript==
// @name        FA Webcomic Auto Loader
// @namespace   Violentmonkey Scripts
// @match       *://*.furaffinity.net/*
// @require     https://update.greasyfork.org/scripts/525666/1549449/Furaffinity-Prototype-Extensions.js
// @require     https://update.greasyfork.org/scripts/483952/1549453/Furaffinity-Request-Helper.js
// @require     https://update.greasyfork.org/scripts/485827/1549457/Furaffinity-Match-List.js
// @require     https://update.greasyfork.org/scripts/485153/1549461/Furaffinity-Loading-Animations.js
// @require     https://update.greasyfork.org/scripts/475041/1550020/Furaffinity-Custom-Settings.js
// @grant       GM_info
// @version     2.2.2
// @author      Midori Dragon
// @description Gives you the option to load all the subsequent comic pages on a FurAffinity comic page automatically. Even for pages without given Links
// @icon        https://www.furaffinity.net/themes/beta/img/banners/fa_logo.png
// @license     MIT
// @homepageURL https://greasyfork.org/scripts/457759-fa-webcomic-auto-loader
// @supportURL  https://greasyfork.org/scripts/457759-fa-webcomic-auto-loader/feedback
// ==/UserScript==
// jshint esversion: 8
(() => {
"use strict";
var __webpack_modules__ = {
782: (module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.d(__webpack_exports__, {
A: () => __WEBPACK_DEFAULT_EXPORT__
});
var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(601), _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__), _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(314), ___CSS_LOADER_EXPORT___ = __webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__)()(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default());
___CSS_LOADER_EXPORT___.push([ module.id, ".wal-lightbox-nav {\n    position: fixed;\n    left: 50%;\n    bottom: 10px;\n    transform: translateX(-50%);\n    opacity: 0.7;\n    transition: opacity 0.2s linear;\n    z-index: 100000000;\n}\n\n.wal-lightbox-nav:hover {\n    opacity: 1;\n}\n\n.wal-no-select {\n    user-select: none;\n    -webkit-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n}", "" ]);
const __WEBPACK_DEFAULT_EXPORT__ = ___CSS_LOADER_EXPORT___;
},
314: module => {
module.exports = function(cssWithMappingToString) {
var list = [];
list.toString = function toString() {
return this.map((function(item) {
var content = "", needLayer = void 0 !== item[5];
if (item[4]) content += "@supports (".concat(item[4], ") {");
if (item[2]) content += "@media ".concat(item[2], " {");
if (needLayer) content += "@layer".concat(item[5].length > 0 ? " ".concat(item[5]) : "", " {");
content += cssWithMappingToString(item);
if (needLayer) content += "}";
if (item[2]) content += "}";
if (item[4]) content += "}";
return content;
})).join("");
};
list.i = function i(modules, media, dedupe, supports, layer) {
if ("string" == typeof modules) modules = [ [ null, modules, void 0 ] ];
var alreadyImportedModules = {};
if (dedupe) for (var k = 0; k < this.length; k++) {
var id = this[k][0];
if (null != id) alreadyImportedModules[id] = true;
}
for (var _k = 0; _k < modules.length; _k++) {
var item = [].concat(modules[_k]);
if (!dedupe || !alreadyImportedModules[item[0]]) {
if (void 0 !== layer) if (void 0 === item[5]) item[5] = layer; else {
item[1] = "@layer".concat(item[5].length > 0 ? " ".concat(item[5]) : "", " {").concat(item[1], "}");
item[5] = layer;
}
if (media) if (!item[2]) item[2] = media; else {
item[1] = "@media ".concat(item[2], " {").concat(item[1], "}");
item[2] = media;
}
if (supports) if (!item[4]) item[4] = "".concat(supports); else {
item[1] = "@supports (".concat(item[4], ") {").concat(item[1], "}");
item[4] = supports;
}
list.push(item);
}
}
};
return list;
};
},
601: module => {
module.exports = function(i) {
return i[1];
};
},
72: module => {
var stylesInDOM = [];
function getIndexByIdentifier(identifier) {
for (var r###lt = -1, i = 0; i < stylesInDOM.length; i++) if (stylesInDOM[i].identifier === identifier) {
r###lt = i;
break;
}
return r###lt;
}
function modulesToDom(list, options) {
for (var idCountMap = {}, identifiers = [], i = 0; i < list.length; i++) {
var item = list[i], id = options.base ? item[0] + options.base : item[0], count = idCountMap[id] || 0, identifier = "".concat(id, " ").concat(count);
idCountMap[id] = count + 1;
var indexByIdentifier = getIndexByIdentifier(identifier), obj = {
css: item[1],
media: item[2],
sourceMap: item[3],
supports: item[4],
layer: item[5]
};
if (-1 !== indexByIdentifier) {
stylesInDOM[indexByIdentifier].references++;
stylesInDOM[indexByIdentifier].updater(obj);
} else {
var updater = addElementStyle(obj, options);
options.byIndex = i;
stylesInDOM.splice(i, 0, {
identifier,
updater,
references: 1
});
}
identifiers.push(identifier);
}
return identifiers;
}
function addElementStyle(obj, options) {
var api = options.domAPI(options);
api.update(obj);
return function updater(newObj) {
if (newObj) {
if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap && newObj.supports === obj.supports && newObj.layer === obj.layer) return;
api.update(obj = newObj);
} else api.remove();
};
}
module.exports = function(list, options) {
var lastIdentifiers = modulesToDom(list = list || [], options = options || {});
return function update(newList) {
newList = newList || [];
for (var i = 0; i < lastIdentifiers.length; i++) {
var index = getIndexByIdentifier(lastIdentifiers[i]);
stylesInDOM[index].references--;
}
for (var newLastIdentifiers = modulesToDom(newList, options), _i = 0; _i < lastIdentifiers.length; _i++) {
var _index = getIndexByIdentifier(lastIdentifiers[_i]);
if (0 === stylesInDOM[_index].references) {
stylesInDOM[_index].updater();
stylesInDOM.splice(_index, 1);
}
}
lastIdentifiers = newLastIdentifiers;
};
};
},
659: module => {
var memo = {};
module.exports = function insertBySelector(insert, style) {
var target = function getTarget(target) {
if (void 0 === memo[target]) {
var styleTarget = document.querySelector(target);
if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) try {
styleTarget = styleTarget.contentDocument.head;
} catch (e) {
styleTarget = null;
}
memo[target] = styleTarget;
}
return memo[target];
}(insert);
if (!target) throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");
target.appendChild(style);
};
},
540: module => {
module.exports = function insertStyleElement(options) {
var element = document.createElement("style");
options.setAttributes(element, options.attributes);
options.insert(element, options.options);
return element;
};
},
56: (module, __unused_webpack_exports, __webpack_require__) => {
module.exports = function setAttributesWithoutAttributes(styleElement) {
var nonce = true ? __webpack_require__.nc : 0;
if (nonce) styleElement.setAttribute("nonce", nonce);
};
},
825: module => {
module.exports = function domAPI(options) {
if ("undefined" == typeof document) return {
update: function update() {},
remove: function remove() {}
};
var styleElement = options.insertStyleElement(options);
return {
update: function update(obj) {
!function apply(styleElement, options, obj) {
var css = "";
if (obj.supports) css += "@supports (".concat(obj.supports, ") {");
if (obj.media) css += "@media ".concat(obj.media, " {");
var needLayer = void 0 !== obj.layer;
if (needLayer) css += "@layer".concat(obj.layer.length > 0 ? " ".concat(obj.layer) : "", " {");
css += obj.css;
if (needLayer) css += "}";
if (obj.media) css += "}";
if (obj.supports) css += "}";
var sourceMap = obj.sourceMap;
if (sourceMap && "undefined" != typeof btoa) css += "\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), " */");
options.styleTagTransform(css, styleElement, options.options);
}(styleElement, options, obj);
},
remove: function remove() {
!function removeStyleElement(styleElement) {
if (null === styleElement.parentNode) return false;
styleElement.parentNode.removeChild(styleElement);
}(styleElement);
}
};
};
},
113: module => {
module.exports = function styleTagTransform(css, styleElement) {
if (styleElement.styleSheet) styleElement.styleSheet.cssText = css; else {
for (;styleElement.firstChild; ) styleElement.removeChild(styleElement.firstChild);
styleElement.appendChild(document.createTextNode(css));
}
};
}
}, __webpack_module_cache__ = {};
function __webpack_require__(moduleId) {
var cachedModule = __webpack_module_cache__[moduleId];
if (void 0 !== cachedModule) return cachedModule.exports;
var module = __webpack_module_cache__[moduleId] = {
id: moduleId,
exports: {}
};
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
return module.exports;
}
__webpack_require__.n = module => {
var getter = module && module.__esModule ? () => module.default : () => module;
__webpack_require__.d(getter, {
a: getter
});
return getter;
};
__webpack_require__.d = (exports, definition) => {
for (var key in definition) if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) Object.defineProperty(exports, key, {
enumerable: true,
get: definition[key]
});
};
__webpack_require__.o = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
__webpack_require__.nc = void 0;
var LogLevel;
__webpack_require__.d({}, {
KS: () => backwardSearchSetting,
hQ: () => customLightboxShowNavSetting,
_d: () => loadingSpinSpeedSetting,
WE: () => overwriteNavButtonsSetting,
uL: () => requestHelper,
vD: () => scriptName,
iT: () => useCustomLightboxSetting
});
!function(LogLevel) {
LogLevel[LogLevel.Error = 1] = "Error";
LogLevel[LogLevel.Warning = 2] = "Warning";
LogLevel[LogLevel.Info = 3] = "Info";
}(LogLevel || (LogLevel = {}));
class Logger {
static log(logLevel = LogLevel.Warning, ...args) {
if (null == window.__FF_GLOBAL_LOG_LEVEL__) window.__FF_GLOBAL_LOG_LEVEL__ = LogLevel.Error;
if (!(logLevel > window.__FF_GLOBAL_LOG_LEVEL__)) switch (logLevel) {
case LogLevel.Error:
console.error(...args);
break;
case LogLevel.Warning:
console.warn(...args);
break;
case LogLevel.Info:
console.log(...args);
}
}
static setLogLevel(logLevel) {
window.__FF_GLOBAL_LOG_LEVEL__ = logLevel;
}
static logError(...args) {
Logger.log(LogLevel.Error, ...args);
}
static logWarning(...args) {
Logger.log(LogLevel.Warning, ...args);
}
static logInfo(...args) {
Logger.log(LogLevel.Info, ...args);
}
}
function checkTags(element) {
var _a;
if (!("1" === document.body.getAttribute("data-user-logged-in"))) {
Logger.logWarning("User is not logged in, skipping tag check");
setBlockedState(element, false);
return;
}
const tagsHideMissingTags = "1" === document.body.getAttribute("data-tag-blocklist-hide-tagless"), tags = null === (_a = element.getAttribute("data-tags")) || void 0 === _a ? void 0 : _a.trim().split(/\s+/);
let blockReason = "";
if (null != tags && tags.length > 0 && "" !== tags[0]) {
const blockedTags = function getBannedTags(tags) {
var _a;
const blockedTags = null !== (_a = document.body.getAttribute("data-tag-blocklist")) && void 0 !== _a ? _a : "", tagsBlocklist = Array.from(blockedTags.split(" "));
let bTags = [];
if (null == tags || 0 === tags.length) return [];
for (const tag of tags) for (const blockedTag of tagsBlocklist) if (tag === blockedTag) bTags.push(blockedTag);
return [ ...new Set(bTags) ];
}(tags);
if (blockedTags.length <= 0) setBlockedState(element, false); else {
setBlockedState(element, true);
Logger.logInfo(`${element.id} blocked tags: ${blockedTags.join(", ")}`);
blockReason = "Blocked tags:\n";
for (const tag of blockedTags) blockReason += "• " + tag + "\n";
}
} else {
setBlockedState(element, tagsHideMissingTags);
if (tagsHideMissingTags) blockReason = "Content is missing tags.";
}
if ("" !== blockReason && "submissionImg" !== element.id) element.setAttribute("title", blockReason);
}
function setBlockedState(element, isBlocked) {
element.classList[isBlocked ? "add" : "remove"]("blocked-content");
}
function getDocViewSid(doc) {
let ogUrl = doc.querySelector('meta[property="og:url"]').getAttribute("content");
if (null == ogUrl) return -1;
ogUrl = ogUrl.trimEnd("/");
return parseInt(ogUrl.split("/").pop());
}
const string = class {
static isNullOrWhitespace(str) {
return null == str || "" === str.trim();
}
static isNullOrEmpty(str) {
return null == str || "" === str;
}
};
class ComicNavigation {
constructor(prevId, firstId, nextId) {
this.prevId = -1;
this.firstId = -1;
this.nextId = -1;
this.prevId = prevId;
this.firstId = firstId;
this.nextId = nextId;
}
static fromElement(elem) {
var _a;
const comicNav = new ComicNavigation(-1, -1, -1), navElems = elem.querySelectorAll('a[href*="view"]');
if (null == navElems || 0 === navElems.length) return null;
for (const navElem of Array.from(navElems)) {
const navText = null === (_a = null == navElem ? void 0 : navElem.textContent) || void 0 === _a ? void 0 : _a.toLowerCase();
if (string.isNullOrWhitespace(navText)) continue;
let idText = navElem.getAttribute("href");
if (!string.isNullOrWhitespace(idText)) {
idText = idText.trimEnd("/");
idText = idText.split("/").pop();
if (navText.includes("prev")) comicNav.prevId = parseInt(idText); else if (navText.includes("next")) comicNav.nextId = parseInt(idText); else if (navText.includes("start") || navText.includes("first")) comicNav.firstId = parseInt(idText);
}
}
return comicNav;
}
}
var __awaiter = function(thisArg, _arguments, P, generator) {
return new (P || (P = Promise))((function(resolve, reject) {
function fulfilled(value) {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
}
function rejected(value) {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
}
function step(r###lt) {
r###lt.done ? resolve(r###lt.value) : function adopt(value) {
return value instanceof P ? value : new P((function(resolve) {
resolve(value);
}));
}(r###lt.value).then(fulfilled, rejected);
}
step((generator = generator.apply(thisArg, _arguments || [])).next());
}));
};
class AutoLoaderSearch {
constructor(rootImg, rootSid, comicNav) {
this.currImgIndex = 1;
this.currSid = -1;
this.rootImg = rootImg;
this.rootSid = rootSid;
this.currComicNav = comicNav;
}
search() {
return __awaiter(this, void 0, void 0, (function*() {
var _a;
const loadedImgs = {};
loadedImgs[this.rootSid] = this.rootImg;
Logger.logInfo(`${scriptName}: starting search...`);
do {
try {
if (null == this.currComicNav) break;
const img = yield this.getPage(this.currComicNav.nextId);
if (null == img) break;
if (this.currSid in loadedImgs) break;
Logger.logInfo(`${scriptName}: found image with sid '${this.currSid}'`);
loadedImgs[this.currSid] = img;
this.currImgIndex++;
} catch (error) {
Logger.logError(error);
break;
}
} while (-1 !== (null === (_a = this.currComicNav) || void 0 === _a ? void 0 : _a.nextId));
Logger.logInfo(`${scriptName}: finished search. Found ${Object.keys(loadedImgs).length} images.`);
return loadedImgs;
}));
}
getPage(sid) {
return __awaiter(this, void 0, void 0, (function*() {
var _a;
const page = yield requestHelper.SubmissionRequests.getSubmissionPage(sid), img = page.getElementById("submissionImg");
img.setAttribute("wal-index", this.currImgIndex.toString());
img.setAttribute("wal-sid", sid.toString());
this.currSid = getDocViewSid(page);
const descriptionElem = null === (_a = page.getElementById("columnpage")) || void 0 === _a ? void 0 : _a.querySelector('div[class*="submission-description"]');
if (null != descriptionElem) this.currComicNav = ComicNavigation.fromElement(descriptionElem); else this.currComicNav = null;
return img;
}));
}
}
function isSubmissionPageInGallery(doc) {
const columnPage = doc.getElementById("columnpage"), favNav = null == columnPage ? void 0 : columnPage.querySelector('div[class*="favorite-nav"]'), mainGalleryButton = null == favNav ? void 0 : favNav.querySelector('a[title*="submissions"]');
if (null != mainGalleryButton && mainGalleryButton.href.includes("gallery")) return true; else return false;
}
function isSubmissionPageInScraps(doc) {
const columnPage = doc.getElementById("columnpage"), favNav = null == columnPage ? void 0 : columnPage.querySelector('div[class*="favorite-nav"]'), mainGalleryButton = null == favNav ? void 0 : favNav.querySelector('a[title*="submissions"]');
if (null != mainGalleryButton && mainGalleryButton.href.includes("scraps")) return true; else return false;
}
function getCurrGalleryFolder() {
const url = window.location.toString().toLowerCase();
if (!url.includes("gallery") || !url.includes("folder")) return;
const parts = url.split("/"), folderIdIndex = parts.indexOf("folder") + 1;
if (folderIdIndex >= parts.length) return;
const folderId = parts[folderIdIndex];
return parseInt(folderId);
}
function generalizeString(inputString, textToNumbers, removeCommonPhrases, removeSpecialChars, removeNumbers, removeSpaces, removeRoman) {
let outputString = inputString.toLowerCase();
if (removeCommonPhrases) {
const commonPhrases = [ "page", "part", "book", "episode" ];
outputString = outputString.replace(new RegExp(`(?:^|\\s)(${commonPhrases.join("|")})(?:\\s|$)`, "g"), "");
}
if (removeRoman) {
const roman = [ "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix", "x", "xi", "xii", "xiii", "xiv", "xv", "xvi", "xvii", "xviii", "xix", "xx" ];
outputString = outputString.replace(new RegExp(`(?:^|[^a-zA-Z])(${roman.join("|")})(?:[^a-zA-Z]|$)`, "g"), "");
}
if (textToNumbers) {
const numbers = {
zero: 0,
one: 1,
two: 2,
three: 3,
four: 4,
five: 5,
six: 6,
seven: 7,
eight: 8,
nine: 9,
ten: 10,
eleven: 11,
twelve: 12,
thirteen: 13,
fourteen: 14,
fifteen: 15,
sixteen: 16,
seventeen: 17,
eighteen: 18,
nineteen: 19,
twenty: 20,
thirty: 30,
forty: 40,
fifty: 50,
sixty: 60,
seventy: 70,
eighty: 80,
ninety: 90,
hundred: 100
};
outputString = outputString.replace(new RegExp(Object.keys(numbers).join("|"), "gi"), (match => numbers[match.toLowerCase()].toString()));
}
if (removeSpecialChars) outputString = outputString.replace(/[^a-zA-Z0-9 ]/g, "");
if (removeNumbers) outputString = outputString.replace(/[^a-zA-Z ]/g, "");
if (removeSpaces) outputString = outputString.replace(/\s/g, "");
return outputString;
}
function figureTitleIsGenerallyEqual(figure, title) {
const figCaption = figure.querySelector("figcaption"), titleElem = null == figCaption ? void 0 : figCaption.querySelector('a[href*="view"]');
if (null != titleElem) {
const figTitleGeneralized = generalizeString(titleElem.title.toLowerCase(), true, true, true, true, true, true), currTitleGeneralized = generalizeString(title, true, true, true, true, true, true);
if (string.isNullOrWhitespace(figTitleGeneralized) || string.isNullOrWhitespace(currTitleGeneralized)) return false; else return figTitleGeneralized.includes(currTitleGeneralized) || currTitleGeneralized.includes(figTitleGeneralized);
}
return false;
}
function getDocUsername(doc) {
const columnPage = doc.getElementById("columnpage"), submissionIdContainer = null == columnPage ? void 0 : columnPage.querySelector('div[class*="submission-id-container"]'), usernameContainer = null == submissionIdContainer ? void 0 : submissionIdContainer.querySelector('a[href*="user"]');
if (null != usernameContainer) {
let username = usernameContainer.href;
username = username.trimEnd("/");
username = username.split("/").pop();
return username;
}
}
var BackwardSearch_awaiter = function(thisArg, _arguments, P, generator) {
return new (P || (P = Promise))((function(resolve, reject) {
function fulfilled(value) {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
}
function rejected(value) {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
}
function step(r###lt) {
r###lt.done ? resolve(r###lt.value) : function adopt(value) {
return value instanceof P ? value : new P((function(resolve) {
resolve(value);
}));
}(r###lt.value).then(fulfilled, rejected);
}
step((generator = generator.apply(thisArg, _arguments || [])).next());
}));
};
class BackwardSearch {
constructor(currSid, amount, currSubmissionPageNo) {
this.sidToIgnore = [];
this._currSid = currSid;
this._amount = amount;
this.currSubmissionPageNo = currSubmissionPageNo;
this.sidToIgnore.push(currSid);
}
search() {
return BackwardSearch_awaiter(this, void 0, void 0, (function*() {
var _a, _b;
const isInGallery = isSubmissionPageInGallery(document), isInScraps = isSubmissionPageInScraps(document);
if (!isInGallery && !isInScraps) return {};
const columnpage = document.getElementById("columnpage"), submissionIdContainer = null == columnpage ? void 0 : columnpage.querySelector('div[class*="submission-id-container"]'), submissionTitle = null == submissionIdContainer ? void 0 : submissionIdContainer.querySelector('div[class*="submission-title"]'), currTitle = null === (_b = null === (_a = null == submissionTitle ? void 0 : submissionTitle.querySelector("h2")) || void 0 === _a ? void 0 : _a.querySelector("p")) || void 0 === _b ? void 0 : _b.textContent;
if (string.isNullOrWhitespace(currTitle)) return {};
const currUsername = getDocUsername(document), folderId = getCurrGalleryFolder();
Logger.logInfo(`${scriptName}: finding submission page...`);
if (null == this.currSubmissionPageNo || this.currSubmissionPageNo < 1) if (isInGallery) this.currSubmissionPageNo = yield requestHelper.UserRequests.GalleryRequests.Gallery.getSubmissionPageNo(currUsername, this._currSid, folderId, -1, -1); else if (isInScraps) this.currSubmissionPageNo = yield requestHelper.UserRequests.GalleryRequests.Scraps.getSubmissionPageNo(currUsername, this._currSid, -1, -1);
Logger.logInfo(`${scriptName}: found submission on page '${this.currSubmissionPageNo}'`);
Logger.logInfo(`${scriptName}: searching figures backward...`);
let figures = [];
if (isInGallery) figures = yield requestHelper.UserRequests.GalleryRequests.Gallery.getFiguresInFolderBetweenPages(currUsername, folderId, this.currSubmissionPageNo, this.currSubmissionPageNo + this._amount); else if (isInScraps) figures = yield requestHelper.UserRequests.GalleryRequests.Scraps.getFiguresBetweenPages(currUsername, this.currSubmissionPageNo, this.currSubmissionPageNo + this._amount);
let figuresFlattend = figures.flat();
figuresFlattend = figuresFlattend.filter((figure => !this.sidToIgnore.includes(parseInt(figure.id.trimStart("sid-")))));
figuresFlattend = figuresFlattend.filter((figure => figureTitleIsGenerallyEqual(figure, currTitle)));
figuresFlattend.reverse();
Logger.logInfo(`${scriptName}: searching figures backward found '${figuresFlattend.length}' figures`);
Logger.logInfo(`${scriptName}: loading submission pages...`);
const r###lt = {};
for (let i = 0; i < figuresFlattend.length; i++) {
const figureSid = figuresFlattend[i].id.trimStart("sid-"), subDoc = yield requestHelper.SubmissionRequests.getSubmissionPage(parseInt(figureSid)), img = null == subDoc ? void 0 : subDoc.getElementById("submissionImg");
if (null != img) {
img.setAttribute("wal-index", (-(figuresFlattend.length - i)).toString());
img.setAttribute("wal-sid", figureSid);
r###lt[parseInt(figureSid)] = img;
Logger.logInfo(`${scriptName}: loaded submission '${figureSid}' with index '${(-(figuresFlattend.length - i)).toString()}'`);
}
}
return r###lt;
}));
}
}
var ForwardSearch_awaiter = function(thisArg, _arguments, P, generator) {
return new (P || (P = Promise))((function(resolve, reject) {
function fulfilled(value) {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
}
function rejected(value) {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
}
function step(r###lt) {
r###lt.done ? resolve(r###lt.value) : function adopt(value) {
return value instanceof P ? value : new P((function(resolve) {
resolve(value);
}));
}(r###lt.value).then(fulfilled, rejected);
}
step((generator = generator.apply(thisArg, _arguments || [])).next());
}));
};
class ForwardSearch {
constructor(currSid, currSubmissionPageNo) {
this.sidToIgnore = [];
this._currSid = currSid;
this.currSubmissionPageNo = currSubmissionPageNo;
this.sidToIgnore.push(currSid);
}
search() {
return ForwardSearch_awaiter(this, void 0, void 0, (function*() {
var _a, _b;
const isInGallery = isSubmissionPageInGallery(document), isInScraps = isSubmissionPageInScraps(document);
if (!isInGallery && !isInScraps) return {};
const columnpage = document.getElementById("columnpage"), submissionIdContainer = null == columnpage ? void 0 : columnpage.querySelector('div[class*="submission-id-container"]'), submissionTitle = null == submissionIdContainer ? void 0 : submissionIdContainer.querySelector('div[class*="submission-title"]'), currTitle = null === (_b = null === (_a = null == submissionTitle ? void 0 : submissionTitle.querySelector("h2")) || void 0 === _a ? void 0 : _a.querySelector("p")) || void 0 === _b ? void 0 : _b.textContent;
if (string.isNullOrWhitespace(currTitle)) return {};
const currUsername = getDocUsername(document), folderId = getCurrGalleryFolder();
Logger.logInfo(`${scriptName}: finding submission page...`);
if (null == this.currSubmissionPageNo || this.currSubmissionPageNo < 1) if (isInGallery) this.currSubmissionPageNo = yield requestHelper.UserRequests.GalleryRequests.Gallery.getSubmissionPageNo(currUsername, this._currSid, folderId, -1, -1); else if (isInScraps) this.currSubmissionPageNo = yield requestHelper.UserRequests.GalleryRequests.Scraps.getSubmissionPageNo(currUsername, this._currSid, -1, -1);
Logger.logInfo(`${scriptName}: found submission on page '${this.currSubmissionPageNo}'`);
Logger.logInfo(`${scriptName}: searching figures forward...`);
let figures = [];
if (isInGallery) figures = yield requestHelper.UserRequests.GalleryRequests.Gallery.getFiguresInFolderBetweenIds(currUsername, folderId, void 0, this._currSid); else if (isInScraps) figures = yield requestHelper.UserRequests.GalleryRequests.Scraps.getFiguresBetweenIds(currUsername, void 0, this._currSid);
let figuresFlattend = figures.flat();
figuresFlattend = figuresFlattend.filter((figure => !this.sidToIgnore.includes(parseInt(figure.id.trimStart("sid-")))));
figuresFlattend = figuresFlattend.filter((figure => figureTitleIsGenerallyEqual(figure, currTitle)));
figuresFlattend.reverse();
Logger.logInfo(`${scriptName}: searching figures forward found '${figuresFlattend.length}' figures`);
Logger.logInfo(`${scriptName}: loading submission pages...`);
const r###lt = {};
for (let i = 0; i < figuresFlattend.length; i++) {
const figureSid = figuresFlattend[i].id.trimStart("sid-"), subDoc = yield requestHelper.SubmissionRequests.getSubmissionPage(parseInt(figureSid)), img = null == subDoc ? void 0 : subDoc.getElementById("submissionImg");
if (null != img) {
img.setAttribute("wal-index", (i + 1).toString());
img.setAttribute("wal-sid", figureSid);
r###lt[parseInt(figureSid)] = img;
Logger.logInfo(`${scriptName}: loaded submission '${figureSid}' with index '${(i + 1).toString()}'`);
}
}
return r###lt;
}));
}
}
var injectStylesIntoStyleTag = __webpack_require__(72), injectStylesIntoStyleTag_default = __webpack_require__.n(injectStylesIntoStyleTag), styleDomAPI = __webpack_require__(825), styleDomAPI_default = __webpack_require__.n(styleDomAPI), insertBySelector = __webpack_require__(659), insertBySelector_default = __webpack_require__.n(insertBySelector), setAttributesWithoutAttributes = __webpack_require__(56), setAttributesWithoutAttributes_default = __webpack_require__.n(setAttributesWithoutAttributes), insertStyleElement = __webpack_require__(540), insertStyleElement_default = __webpack_require__.n(insertStyleElement), styleTagTransform = __webpack_require__(113), styleTagTransform_default = __webpack_require__.n(styleTagTransform), LightboxStyle = __webpack_require__(782), options = {};
options.styleTagTransform = styleTagTransform_default();
options.setAttributes = setAttributesWithoutAttributes_default();
options.insert = insertBySelector_default().bind(null, "head");
options.domAPI = styleDomAPI_default();
options.insertStyleElement = insertStyleElement_default();
injectStylesIntoStyleTag_default()(LightboxStyle.A, options);
LightboxStyle.A && LightboxStyle.A.locals && LightboxStyle.A.locals;
class Lightbox {
constructor(orgSid, imgs) {
this.currWalIndex = 0;
this._imgCount = -1;
this._lightboxContainer = document.body.querySelector('div[class*="lightbox-submission"]');
this._imgCount = Object.keys(imgs).length;
const orgImgClone = document.getElementById("columnpage").querySelector(`img[wal-sid="${orgSid}"]`).readdToDom();
imgs[orgSid] = orgImgClone;
this.prepareOrgLightbox();
this.addSubmissionToLightbox(imgs);
if (customLightboxShowNavSetting.value) {
this._lightboxNavContainer = this.createNavigationButtons();
this._lightboxContainer.insertAfterThis(this._lightboxNavContainer);
}
this._boundHandleArrowKeys = this.handleArrowKeys.bind(this);
}
get isHidden() {
return this._lightboxContainer.classList.contains("hidden");
}
set isHidden(value) {
var _a, _b, _c;
if (this.isHidden !== value) if (value) {
window.removeEventListener("keydown", this._boundHandleArrowKeys);
this._lightboxContainer.classList.add("hidden");
null === (_a = this._lightboxNavContainer) || void 0 === _a || _a.classList.add("hidden");
for (const child of Array.from(this._lightboxContainer.children)) child.classList.add("hidden");
} else {
window.addEventListener("keydown", this._boundHandleArrowKeys);
null === (_b = this._lightboxContainer.children[this.currWalIndex]) || void 0 === _b || _b.classList.remove("hidden");
this._lightboxContainer.classList.remove("hidden");
null === (_c = this._lightboxNavContainer) || void 0 === _c || _c.classList.remove("hidden");
}
}
navigateLeft() {
if (this.currWalIndex > 0) {
Logger.logInfo(`${scriptName}: navigating left '${this.currWalIndex} -> ${this.currWalIndex - 1}'`);
const currImg = this._lightboxContainer.children[this.currWalIndex], prevImg = this._lightboxContainer.children[this.currWalIndex - 1];
if (null != currImg && null != prevImg) {
currImg.classList.add("hidden");
prevImg.classList.remove("hidden");
}
this.currWalIndex--;
}
}
navigateRight() {
if (this.currWalIndex + 1 < this._imgCount) {
Logger.logInfo(`${scriptName}: navigating right '${this.currWalIndex} -> ${this.currWalIndex + 1}'`);
const currImg = this._lightboxContainer.children[this.currWalIndex], nextImg = this._lightboxContainer.children[this.currWalIndex + 1];
if (null != currImg && null != nextImg) {
currImg.classList.add("hidden");
nextImg.classList.remove("hidden");
}
this.currWalIndex++;
}
}
handleArrowKeys(event) {
switch (event.key) {
case "ArrowLeft":
case "ArrowUp":
this.navigateLeft();
break;
case "ArrowRight":
case "ArrowDown":
this.navigateRight();
}
event.preventDefault();
}
getIndexOfClickedImage(img) {
let clickedWalIndex = img.getAttribute("wal-index");
if (!string.isNullOrWhitespace(clickedWalIndex)) {
this.currWalIndex = parseInt(clickedWalIndex);
const clickedImg = this._lightboxContainer.querySelector(`img[wal-index="${this.currWalIndex}"]`);
return null == clickedImg ? void 0 : clickedImg.getIndexOfThis();
}
}
prepareOrgLightbox() {
this._lightboxContainer.innerHTML = "";
this._lightboxContainer = this._lightboxContainer.readdToDom();
this._lightboxContainer.addEventListener("click", (() => {
this.isHidden = true;
}));
}
addSubmissionToLightbox(imgs) {
const sortedImages = Object.values(imgs).sort(((a, b) => {
var _a, _b;
return parseInt(null !== (_a = a.getAttribute("wal-index")) && void 0 !== _a ? _a : "0") - parseInt(null !== (_b = b.getAttribute("wal-index")) && void 0 !== _b ? _b : "0");
}));
for (const img of sortedImages) {
img.addEventListener("click", (() => {
var _a;
this.currWalIndex = null !== (_a = this.getIndexOfClickedImage(img)) && void 0 !== _a ? _a : 0;
this.isHidden = false;
}));
const clone = img.cloneNode(false);
clone.classList.add("hidden");
this._lightboxContainer.appendChild(clone);
}
}
createNavigationButtons() {
const container = document.createElement("div");
container.classList.add("wal-lightbox-nav", "hidden", "wal-no-select");
const leftButton = document.createElement("a");
leftButton.classList.add("button", "standard", "mobile-fix");
leftButton.textContent = "<---";
leftButton.style.marginRight = "4px";
leftButton.addEventListener("click", this.navigateLeft.bind(this));
container.appendChild(leftButton);
const closeButton = document.createElement("a");
closeButton.classList.add("button", "standard", "mobile-fix");
closeButton.textContent = "Close";
closeButton.addEventListener("click", (() => {
this.isHidden = true;
}));
container.appendChild(closeButton);
const rightButton = document.createElement("a");
rightButton.classList.add("button", "standard", "mobile-fix");
rightButton.textContent = "---\x3e";
rightButton.style.marginLeft = "4px";
rightButton.addEventListener("click", this.navigateRight.bind(this));
container.appendChild(rightButton);
return container;
}
}
var AutoLoader_awaiter = function(thisArg, _arguments, P, generator) {
return new (P || (P = Promise))((function(resolve, reject) {
function fulfilled(value) {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
}
function rejected(value) {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
}
function step(r###lt) {
r###lt.done ? resolve(r###lt.value) : function adopt(value) {
return value instanceof P ? value : new P((function(resolve) {
resolve(value);
}));
}(r###lt.value).then(fulfilled, rejected);
}
step((generator = generator.apply(thisArg, _arguments || [])).next());
}));
};
class AutoLoader {
constructor() {
var _a;
this.currComicNav = null;
this.comicNavExists = false;
this.currSid = -1;
const descriptionElem = null === (_a = document.getElementById("columnpage")) || void 0 === _a ? void 0 : _a.querySelector('div[class*="submission-description"]');
if (null != descriptionElem) {
this.currComicNav = ComicNavigation.fromElement(descriptionElem);
if (null != this.currComicNav) if (-1 !== this.currComicNav.prevId || -1 !== this.currComicNav.firstId || -1 !== this.currComicNav.nextId) {
this.comicNavExists = true;
if (overwriteNavButtonsSetting.value) this.overwriteNavButtons();
}
}
this.currSid = getDocViewSid(document);
this.submissionImg = document.getElementById("submissionImg");
this.submissionImg.setAttribute("wal-index", "0");
this.submissionImg.setAttribute("wal-sid", this.currSid.toString());
const searchButton = document.createElement("a");
searchButton.id = this.comicNavExists ? "wal-auto-load-button" : "wal-search-button";
searchButton.classList.add("wal-button", "button", "standard", "mobile-fix");
searchButton.type = "button";
searchButton.style.margin = "20px 0 10px 0";
searchButton.textContent = this.comicNavExists ? "Auto load Pages" : "Search for similar Pages";
searchButton.addEventListener("click", (() => {
if (this.comicNavExists) this.startAutoloader(); else this.startSimilarSearch();
searchButton.remove();
}));
this.submissionImg.parentNode.appendChild(document.createElement("br"));
this.submissionImg.parentNode.appendChild(searchButton);
const loadingSpinnerContainer = document.createElement("div");
loadingSpinnerContainer.classList.add("wal-loading-spinner");
loadingSpinnerContainer.style.margin = "20px 0 20px 0";
this._loadingSpinner = new window.FALoadingSpinner(loadingSpinnerContainer);
this._loadingSpinner.delay = loadingSpinSpeedSetting.value;
this._loadingSpinner.spinnerThickness = 6;
this.submissionImg.parentNode.appendChild(loadingSpinnerContainer);
}
startAutoloader() {
this.startAutoLoaderAsync();
}
startAutoLoaderAsync() {
return AutoLoader_awaiter(this, void 0, void 0, (function*() {
this._loadingSpinner.visible = true;
const autoLoader = new AutoLoaderSearch(this.submissionImg, this.currSid, this.currComicNav), submissions = yield autoLoader.search();
this.addLoadedSubmissions(submissions);
if (useCustomLightboxSetting.value) new Lightbox(this.currSid, submissions);
this._loadingSpinner.visible = false;
}));
}
startSimilarSearch() {
this.startSimilarSearchAsync();
}
startSimilarSearchAsync() {
return AutoLoader_awaiter(this, void 0, void 0, (function*() {
this._loadingSpinner.visible = true;
const forwardSearch = new ForwardSearch(this.currSid), submissionsAfter = yield forwardSearch.search(), backwardSearch = new BackwardSearch(this.currSid, backwardSearchSetting.value, forwardSearch.currSubmissionPageNo);
backwardSearch.sidToIgnore.push(...Object.keys(submissionsAfter).map(Number));
const submissionsBefore = yield backwardSearch.search();
this.addLoadedSubmissions(submissionsBefore, submissionsAfter);
if (useCustomLightboxSetting.value) new Lightbox(this.currSid, Object.assign(Object.assign({}, submissionsBefore), submissionsAfter));
this._loadingSpinner.visible = false;
}));
}
addLoadedSubmissions(...imgsArr) {
const columnpage = document.getElementById("columnpage");
for (const imgs of imgsArr) {
Logger.logInfo(`${scriptName}: adding '${Object.keys(imgs).length}' submissions...`);
let prevSid = this.currSid;
for (const sid of Object.keys(imgs).map(Number)) {
if (imgs[sid].getAttribute("wal-sid") === this.currSid.toString()) continue;
const lastImg = columnpage.querySelector(`img[wal-sid="${prevSid}"]`), lastIndex = parseInt(lastImg.getAttribute("wal-index"));
if (parseInt(imgs[sid].getAttribute("wal-index")) < lastIndex) {
lastImg.insertBeforeThis(imgs[sid]);
imgs[sid].insertAfterThis(document.createElement("br"));
imgs[sid].insertAfterThis(document.createElement("br"));
checkTags(imgs[sid]);
Logger.logInfo(`${scriptName}: added submission ${sid} before submission ${prevSid}`);
} else {
lastImg.insertAfterThis(imgs[sid]);
imgs[sid].insertBeforeThis(document.createElement("br"));
imgs[sid].insertBeforeThis(document.createElement("br"));
checkTags(imgs[sid]);
Logger.logInfo(`${scriptName}: added submission ${sid} after submission ${prevSid}`);
}
prevSid = sid;
}
}
}
overwriteNavButtons() {
var _a, _b, _c, _d, _e, _f;
if (!this.comicNavExists) return;
const columnpage = document.getElementById("columnpage"), favoriteNav = null == columnpage ? void 0 : columnpage.querySelector('div[class*="favorite-nav"]');
let prevButton = null == favoriteNav ? void 0 : favoriteNav.children[0];
if (null != prevButton && -1 !== this.currComicNav.prevId) if (null !== (_c = null === (_b = null === (_a = prevButton.textContent) || void 0 === _a ? void 0 : _a.toLowerCase()) || void 0 === _b ? void 0 : _b.includes("prev")) && void 0 !== _c ? _c : false) prevButton.href = `/view/${this.currComicNav.prevId}/`; else {
const prevButtonReal = document.createElement("a");
prevButtonReal.href = `/view/${this.currComicNav.prevId}/`;
prevButtonReal.classList.add("button", "standard", "mobile-fix");
prevButtonReal.textContent = "Prev";
prevButtonReal.style.marginRight = "4px";
prevButton.insertBeforeThis(prevButtonReal);
}
let nextButton = null == favoriteNav ? void 0 : favoriteNav.children[favoriteNav.children.length - 1];
if (null != nextButton && -1 !== this.currComicNav.nextId) if (null !== (_f = null === (_e = null === (_d = nextButton.textContent) || void 0 === _d ? void 0 : _d.toLowerCase()) || void 0 === _e ? void 0 : _e.includes("next")) && void 0 !== _f ? _f : false) nextButton.href = `/view/${this.currComicNav.nextId}/`; else {
const nextButtonReal = document.createElement("a");
nextButtonReal.href = `/view/${this.currComicNav.nextId}/`;
nextButtonReal.classList.add("button", "standard", "mobile-fix");
nextButtonReal.textContent = "Next";
nextButtonReal.style.marginLeft = "4px";
nextButton.insertAfterThis(nextButtonReal);
}
}
}
const scriptName = "FA Webcomic Auto Loader", customSettings = new window.FACustomSettings("Midori's Script Settings", `${scriptName} Settings`), showSearchButtonSetting = customSettings.newSetting(window.FASettingType.Boolean, "Similar Search Button");
showSearchButtonSetting.description = "Sets wether the search for similar Pages button is show.";
showSearchButtonSetting.defaultValue = true;
const loadingSpinSpeedSetting = customSettings.newSetting(window.FASettingType.Number, "Loading Animation");
loadingSpinSpeedSetting.description = "Sets the duration that the loading animation takes for a full rotation in milliseconds.";
loadingSpinSpeedSetting.defaultValue = 1e3;
const backwardSearchSetting = customSettings.newSetting(window.FASettingType.Number, "Backward Search Amount");
backwardSearchSetting.description = "Sets the amount of similar pages to search backward. (More Pages take longer)";
backwardSearchSetting.defaultValue = 3;
const overwriteNavButtonsSetting = customSettings.newSetting(window.FASettingType.Boolean, "Overwrite Nav Buttons");
overwriteNavButtonsSetting.description = "Sets wether the default Navigation Buttons (next/prev) are overwritten by the Auto-Loader. (Works only if comic navigation is present)";
overwriteNavButtonsSetting.defaultValue = true;
const useCustomLightboxSetting = customSettings.newSetting(window.FASettingType.Boolean, "Use Custom Lightbox");
useCustomLightboxSetting.description = "Sets wether the default Lightbox (fullscreen view) is overwritten by the Auto-Loader.";
useCustomLightboxSetting.defaultValue = true;
const customLightboxShowNavSetting = customSettings.newSetting(window.FASettingType.Boolean, "Custom Lightbox Show Nav");
customLightboxShowNavSetting.description = "Sets wether the Lightbox Navigation (next/prev) is shown in the Custom Lightbox.";
customLightboxShowNavSetting.defaultValue = true;
customSettings.loadSettings();
const requestHelper = new window.FARequestHelper(2);
if (customSettings.isFeatureEnabled) {
const matchList = new window.FAMatchList(customSettings);
matchList.matches = [ "net/view" ];
matchList.runInIFrame = false;
if (matchList.hasMatch) new AutoLoader;
}
})();