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; } })();