// ==UserScript==
// @name 圖片全載Next
// @name:en Full Picture Load
// @name:zh-CN 图片全载Next
// @name:zh-TW 圖片全載Next
// @version 2025.9.6
// @description 支持寫真、H漫、漫畫的網站1000+,圖片全量加載,簡易的看圖功能,漫畫無限滾動閱讀模式,下載壓縮打包,如有下一頁元素可自動化下載。
// @description:en supports 1,000+ websites for photos, h-comics, and comics, fully load all images, simple image viewing function, comic infinite scroll read mode, and compressed and packaged downloads.
// @description:zh-CN 支持写真、H漫、漫画的网站1000+,图片全量加载,简易的看图功能,漫画无限滚动阅读模式,下载压缩打包,如有下一页元素可自动化下载。
// @description:zh-TW 支持寫真、H漫、漫畫的網站1000+,圖片全量加載,簡易的看圖功能,漫畫無限滾動閱讀模式,下載壓縮打包,如有下一頁元素可自動化下載。
// @author 德克斯DEX
// @match *://*/*
// @connect *
// @exclude *.youtube.com*
// @exclude *docs.google.com*
// @exclude *google*/maps/*
// @exclude *mail.google.com*
// @exclude *accounts.google.com*
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAtFBMVEVEREAAAABEREBEREAuuaIzqpkvr58yiHgzhnY6kYM7mYI4kog4s6A2tpo0r544ooo2nY40sJw0sp00rZg1sJw0sZ0zsp01sZw0sZw0rZk1sJw1sZw1rZk0sp00rpk1sp01sZs1rpk1rpk0sp01spw1sJ00rZo1rZk1rpo0r5k0sJw0sZ01r5o0sZw0rpk0sp01sZ01sJw1spw1r5k1sp01sZw0sZ01sZw1rpk1sp01sZw1r5pUzpTcAAAAOXRSTlMAAAUGCw8QERIUFxgbHB0hIieqq6yvtLa3vb/AwMHCxMXFxsfIyc3Oz+zt7vDx8fL4+Pn5+vr7/v7AEFI4AAABR0lEQVR42qWT11bDMAxApbhsmm5KKVD2KiUQwpD1///FkZcSmh4e8FOsex3LsgymPy6ISkRyA4FlWMRXomIyQOg/SbyKAmSOE2Ip02UOYxf/DILNjOOEWLnAEAqio0MMAzJjTAZh1p0SrYCIuu0cMZc9JbENXLa1NWGdI1nWeQuXGPzBTdzC8ws52UI5MwchrA/VTOuTEP9fFyTG7E+R9q8JLsbW1UHzU8HHrCuU1fyToDlB43xRqMUgfc+/KA77fZrWSH/47zPlzOcpJxG8u32r/OEg5SRCqO/WTeT3+5oTuP4LxrXnd5F7waZ+wM5c+NVeujMRrDYMYueE+VK5E5r3uzOb7TbvHH7f/1pP/L8nU9u38Nwyy8OZdjfwY+ZnmPinp28y3mglNeERDJYy/9A3GYVS+GMPMB+uyL67/qO68Mb8MurBD7foVTtvIbtnAAAAAElFTkSuQmCC
// @license MIT
// @namespace https://greasyfork.org/users/20361
// @grant GM_xmlhttpRequest
// @grant GM.xmlHttpRequest
// @grant GM_registerMenuCommand
// @grant GM.registerMenuCommand
// @grant GM_unregisterMenuCommand
// @grant GM.unregisterMenuCommand
// @grant GM_openInTab
// @grant GM.openInTab
// @grant GM_getValue
// @grant GM.getValue
// @grant GM_setValue
// @grant GM.setValue
// @grant GM_listValues
// @grant GM.listValues
// @grant GM_deleteValue
// @grant GM.deleteValue
// @grant GM_getResourceText
// @grant GM.getResourceText
// @grant GM_addElement
// @grant GM.addElement
// @grant unsafeWindow
// @grant window.close
// @grant window.onurlchange
// @run-at document-end
// @noframes
// @require https://update.greasyfork.org/scripts/473358/1237031/JSZip.js
// @require https://unpkg.com/[email protected]/dist/axios.min.js
// @resource ajaxHookerJS https://scriptcat.org/lib/637/1.4.8/ajaxHooker.js#sha256=dTF50feumqJW36kBpbf6+LguSLAtLr7CEs3oPmyfbiM=
// @resource CryptoJS_code https://unpkg.com/[email protected]/crypto-js.js
// @resource JqueryJS https://unpkg.com/[email protected]/dist/jquery.min.js
// @resource FancyboxV5JS https://unpkg.com/@fancyapps/[email protected]/dist/fancybox/fancybox.umd.js
// @resource FancyboxV5Css https://unpkg.com/@fancyapps/[email protected]/dist/fancybox/fancybox.css
// @resource FancyboxV3JS https://unpkg.com/@fancyapps/[email protected]/dist/jquery.fancybox.min.js
// @resource FancyboxV3Css https://unpkg.com/@fancyapps/[email protected]/dist/jquery.fancybox.min.css
// @resource ViewerJs https://unpkg.com/[email protected]/dist/viewer.min.js
// @resource ViewerJsCss https://unpkg.com/[email protected]/dist/viewer.min.css
// ==/UserScript==
(async (axios, JSZip) => {
"use strict";
//await wait(() => !!document.body && document.readyState !== "loading");
//await wait(() => !!document.body && document?.body?.childNodes?.length > 0);
//限制在最上層頁框執行
if (window.self !== window.top) {
console.error("Full Picture Load 檢測到在非最上層頁框執行");
return;
}
if ((ge("body.no-js:not(.has-preloader,.single-post,.archive)") && !ge("#layout-default")) || ge(".captcha-area") && !ge("#layout-default")) {
debug("Cloudflare驗證中不執行腳本。");
return;
}
if (document.title.startsWith("DDoS-Guard")) {
debug("DDoS-Guard驗證中不執行腳本。");
return;
}
//火狐Firefox使用open("about:blank", "_blank")打開空白頁,空白頁的location.href會變成父視窗的location.href,導致載入腳本,必須排除。
if (["分頁畫廊:", "标签画廊:", "TabView:"].some(t => document.title.startsWith(t))) {
return;
}
//await delay(600);
const defaultOptions = {
icon: 1, //是否顯示左下圖示,1:顯示、0:不顯示
threading: 8, //最大下載線程數
zip: 1, //1:圖片下載後壓縮打包,0:批量下載圖片,無法全自動下載
autoInsert: 1, //頁面容器自動聚圖,1:自動、0:手動
autoDownload: 0, //!!!維持0不要改!!!建議透過UI選項設定來開啟,需要customData也有autoDownload
autoDownloadCountdown: 5, //有NEXT時自動下載的倒數秒數
comic: 0, //1,忽視漫畫站點開關選項,啟用漫畫規則
zoom: 0, //1 ~ 10 腳本插入的圖片縮放比例,10 = 100%,9 = 90%,0 = auto
column: 4, //圖片並排顯示的數量 2 ~ 6
//viewMode: 0, //0:置中、1:並排
fancybox: 1, //Fancybox圖片燈箱展示功能,1:開啟、0:關閉
shadowGallery: 0, //自動進入影子畫廊,1:自動、0:手動
mobileGallery: 0, //自動進入手機畫廊,1:自動、0:手動
autoExport: 0 //自動匯出網址,1:自動、0:手動
};
const FullPictureLoadShowEye = localStorage.getItem("FullPictureLoadShowEye") ?? 1;
const FullPictureLoadCustomDownloadVideo = localStorage.getItem("FullPictureLoadCustomDownloadVideo") ?? 1;
let options = defaultOptions;
const _unsafeWindow = unsafeWindow ?? window;
let language = GM_getValue("language", null) || _unsafeWindow.navigator.language;
if (language == "UI") {
language = _unsafeWindow.navigator.language;
}
let siteUrl = _unsafeWindow.location.href.replace(_unsafeWindow.location.hash, "");
let currentURL = document.URL;
let lastValidPageURL = document.URL;
let frameWindow = _unsafeWindow;
let siteData = {};
let _this = {};
let tempData = {};
let siteJson = {};
let DL = {};
let globalImgArray = [];
let captureSrcArray = [];
let captureTotal = 0;
let isCaptureMode = false;
let thumbnailSrcArray = [];
let videoSrcArray = [];
let fileUrlArray = [];
let promiseBlobArray = [];
let captureLinksArray = [];
let setArray = new Set();
let setVideoArray = new Set();
let customTitle = null;
let apiCustomTitle = null;
let isEsc = false;
let isDownloading = false;
let isStopDownload = false;
let isCountdowning = false;
let isFetching = false;
let isXhrHeadRequest = false;
let isGetAll = false;
let isAutoScrolling = false;
let isValidPage = true;
let isSimpleMode = false;
let isAddKeyEvent = false;
let isAddFullPictureLoadButton = false;
let isAddFullPictureLoadFixedMenu = false;
let isAddNewTabViewButton = false;
let isAddAjaxHooker = false;
let isOpenOptionsUI = false;
let isOpenMenu = false;
let isOpenGallery = false;
let isOpenFilter = false;
let isGoToNext = false;
let isGoToPrev = false;
let isChangeNum = false;
let fetchErrorArray = [];
let fastDownloadSwitch = false;
let combineDownloadSwitch = false;
let currentDownloadThread = 0;
let downloadNum = 0;
let getImgFnProcessRecord = "";
let doc = document;
const fragment = new DocumentFragment();
let autoPagerSwitch = true;
let httpFetchError = false;
let currentPageNum = 0;
let nextLink = null;
let prevLink = null;
let nextElement = null;
let tempNextLink = null;
let tempEles = [];
const PC_UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0";
const Mobile_UA = "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Mobile Safari/537.36 EdgA/139.0.0.0";
let loading_bak = "data:image/webp;base64,UklGRuoYAABXRUJQVlA4IN4YAADwrACdASpYAlgCPjEYiEQiJIkMMCQBglpbvgkzDGFnFrLKt/7KVpN6xSb/u36x+EL+A/sviH49/Jnsr+7v13YP+t/xm9yv5L9d/sX9u/b7+7/t/+BP7T/d+I/p09Qj8Z/jX9w/MX/DfuPyye0eYR7B/Y/9v/iv3j/yXxCfaedH2c9gL+S/07/W8mNQG/VHoK/8f+Z/MD3K/Qv/P/zX+g/Y77C/51/YP+D/h/3u/xnzzeyb90vZ+ClXZIdok82wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsCNopTEwLsdkHgHL+gZIdok82wMUJHTa/xi+zoZ90mTTlYCoNLyTES32y/2i+ukN6myIOO0c0Rv32jCjb5OU96NGSFfhpXzSZpaE5ChI6bYGKCjn7iW0/5Dezoa0ZnLSFRQjUROFOa1AibrCfHplF9wMRcKDy4rTu1dMV23loZ+8D2I0DFLslZg1NuPf2K3qqbWlIEVtk+mLpoZMx6FxWdrRPNsDFCRyvjzY1bEVWfbY0H/yrYEWG0F0GHAPygTleFT+w1zmu+G8E1JXb8+i8pAB16KxHWGU3PWCOT8FN8I1FzkQJD1qdIlGyinHJXoi1Bq//hKHTJVMtyBq4xQkdNsDFCM9M2/uGv7YTwQLxMeYKLS+6fRyLbd+Oyw1MXRjB340D7lick4EXwQM3fPMZMcZyCw1JrjWfAfKSCath7p8JTmPmnFIkNAfNx6lFCM9GBihI6bYGKEjptgYoSODWLpZlEGvLfaE5ChI6bYGKEjptgYoSOm2BihI6bYGKBfklJi8sFQCwCK93gFIi96YO43MxHplyjrE6wDbGQp1gGw6OnG5tNKf3o5d4BuHI19URSxfrNTV/I448rlQKTdtX0NCo9PeBdlGKjnEMoHUvaQmGhJJPuGrnIEFDBDM2OA+DPBzlqE4yilUzwx7vnnC+EokraPL4/m14XqOHRrBMQQSJfeV5Xb6LGyuQ+hVUK9PVnQZoyavUy//Mi6OLAinzTnU4jJDU0CqEL5whPtNksOOu7FlSYYPU91j2g/KbZ9dEVLpCjEOM/OuxEWclHnbcVeHpeqykBKTDsV8dYjOTOFlIPDttkki2B2cLOQ1KMOY4TWeFX0UT9zmWrTEytUwglcm+rEyi4wHsQtl+K4gQSgPHo/b7vO6sP9nt50/BPxERwlICIGMsX+PIgFeFRHaznei1aUpfJfoGBPZt2kopFQDZVTWx65udMAOpr4gpsGyqmvh82wbKqa/GKj094FrZBXxAdt/tE82wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFCR02wMUJHTbAxQkdNsDFAAAA/v/iWAAAAAAAAAAAAAAAAAGV13KpZXh6l/xrK8gblq7/n2oKDnYvjNK9OOq947NMQRgd9mQggHYCI1202LjqhMg7C1YBBLuOE40fa2I7hPUNML+PKywy3y55I5N4K0A2HZqM6Ogxil6nQlGTIQL3r88o2qGvoB6uIkW62QiUDP+9Et5rdlXS2c/OcBq4p47jWKUHW97/cczdOdYgVDB2eP244A3IopxnPGCDfC6yar7iFxJ/xucC2LbEsqaUt04V0KOJjxHI+QCJCKHsuQniWYYKytDOXMFtZnEkzN8ahzZd+lmKx+FttpzJThx2PCIo08OMtdPEtf9oow5zRDMFT4tFwnPIp0KTCWqbHvG5H0FnoVJt3hSc3ONGlWm3O5PhjbHSkIo/MDWzHOQsFGA2+sAxtRfetRwTCp11dMUn/zDS1RKuvWM41ky9iasIV7Cb4ZEjdjEEQLxolpvfujVmQkrrpVL+uS8iEYskMDf3EEmdBEZZGC5DOSw8OysaWJCsLO7DVCyS0YEfwuAlYZFd3SeowJaQZ29XsOlWNHio86b4khxd14+S4BZpRVSOgEnajYLesLIHDdms8Jp7h2f1/4AfEJloxNaT94YkpRaBYewIJ3EIu24yqnA4mGUl2BQ1Xl+vML9JmQzLVseZPGP5mW8F4OkW5MdlR5WE70H9/schTVK6KU7dPaDJRfW5+9/o3gTPkhMYiMcgsQXXWBUaJ723gC+XrkdpI9EB28jyzMF+7taQobDEJfpDvHMaOxJsOpm/Mv2aUTk6YTC9jisZAvABXMOpgyL+Sh++FLzUhBdsC8BXfOqdqxd/VLjStcn6XVj6f4f0HotHL5ozUEdCTsQhG5enVc2hxhkIKL/U8xylbMFqAwlLsXT5XN4jZMgU/opqYirEH3X1LiH12kdeooaDACtqfeBJ8P0Y3nbDxa3KK2H11pRumsJmR49YVESQYN2dok7i44mwLSw7T47gO6YjqQNMavo9gc0bJpdz6ykFBvFW4mK4vOa3jbK2Kcdk9wAFj3tCUEn8itoropCg7yuWwpg+zaml+mT0E5p7Cpa6m9EWiW4dCQ/UEb/PkDgb6aZBKQaGnjQC4xzyvkle5AAuGBkUStb+moEd5EHeE0QXwZXOcvI2SpxHfuiVdQzwvrbsLhvpNMQ3sWASWtnPn7+VoAnjeDEXlAif5QSDStUzQZyzhBlydPQVIU/VY16UM+cwR8bUZut9d3xFFWCWOROrQ2yb35uKIF1PNg0oCsIzvntJKLmfQfIIlWw+7L9WMfQozAfWToVkIgghq2Xuvu8t+po3Vl44f6zz6PQyGsf2riaMZaBF04AZzzJktPxs+tF0SsI9XPTDUJZF29Vpy60WBLyVKU1GYUYmakanCAW2g2VH/sRN7sT5hKjbVcPN8/tCEbBKAxvOK71J3x+zlHhdgRh2X4zlBbwr+8mVX1YDywaQ4H/yHbYCNLI7x43cuM6KlFPXPTkJVCeMy8bP1MPqAbxBz9bbJi23Ie12Ek+5EhG1hGzHc4+qD0y+dtPyIlnU+g6eTLUVRrP/NxMD1q43k1c3TWqrrjLscbeMfSuNPA1viUxgfpWqubUfsj1i3UlOy3/uQflsUaUQMkoo3wXFGTh7wXLpV4VMIKnQ5PmEHnwLGQqHL6TbfB00ghA1mJGtI5nd3i5EfAo+dVDfuaiTAi5H4EdkRKmsq0IYgQ68mSXKgoGTSsJbOLwwpFJX67q2uSNjhuvFGQWeRE2l/rm+W+od3ywdzVgmU5bzj3w454OXelcd4EL2oV/syPjL+vvU7+8RRd0a2GGFuhSWgZMbvtw734ZBcP0sMbHYulWvEJiRYQBTtFox9vPOPZsUdh+YzV/eGnQLwI5Ka1ZmvHmDoKo4h8ULxPBDCf3aea9xVK2h3Bl8pJYfNXTuzjbQoHzFcIv5y4K7lw0gg7ZCx59D7GerhGKZtD1EBXZi+j/V8QQfL3zP2ZIw/tTeO0T+fqUbOHjFEgb1QKJ3nHHQA8bSZ8USXBjKYy7f72CM4/ERS58MLle7awoVucJTPdupJdnawqkCZPysKYn/RKmTQtsTuCwbVUpgH+mO9WWjx3/xxmXRgz3HnnelqkqI7Rg42bzyvQFwqnH9YJcuStMwFNfdlBe/FHc1QOGRHyOCr3MKW502fiszPwSJlYnYxuefUMhtxSpr5JVJ46rV98RBcxF1AjlOX//FlYUMAuew/XACaZs4uXvSpMnn0UpJOsln8mnj44ejUAbJh1/ncioiNaeWGb+FNXG+9ZMTq0wQLmekxfLvc2peS2oaa9IazXZH1DzndIyFWFi7bJikQvkHUqRdV4fYQDASfblv/boSp8T/MoAlGPGgChtZg2mZVeQrI60Mw18R+Mu59ZgZhc24730pnLxFe9WZkfhTv19dXiZ072Y/NZn5JJJUKd0I0E6C6vvHHNTQ48/acg7mbXi0j0R7KNErxhYmTFAXv8BCwfRm6bqKt39z1wH+vH6a8m5BG7nUongsIXlrGfffgiY8sqj56oAEhDqdCfbxVgCQZcKLReZqCPavtebASRJpLs+G2WfDMuCiNU2EQyKHpi/M/KZ3dxa5M4BiviXRC+5PMv+YF7E1ceJXW45Kd+ayJLA0QaoFIy66wt5iV0QIfKDyf3AdC/qZ5oJwD2di1ToTpRcXL7Vk33AFWQdaa5cYrzVEJzlHb/gZrws9omwxIIodUvzuj21PzSqw/TWGXMdOG6mzRdzsfo7AP+yC6bTkZTia+3BoKwG+tvW30b+i2zhxuhL+mcpuYcnl6f1H6i9m51of6/WJIxlWLLbGVaKve3xiDZV807/OtFArIn8iIB0W5GZEYiK6LYC3c4mnqfxEcSuABe+0fXNQxq5kEOBELL3QTBYvRfVrfoKuulAjcCTIix8A+orvbkUlgt7iPTP7e/u1rUYHd7D6UrUbTjC/v03cL9X9lckW4g2/r+53r7wlhvkmw6NTFS+NBC1PPr+Ll40TiVVnO//+1qc+BIWP77dfKHMIJntzmgOIdvCYXexw8gSdTWRPBMx+9RqY7hdt2rTniHKnTiosnJVaA4QjDvZW9pZXuYKNJThyEXXVF/4WVXzTQg80cnG47/VIaRzJEW4TdaVgVAAvLNOK0gpxWeLj9CRqGkQpmKU5avHT/nj9VJQ+K0OfVdSCeoQsbBUX3QYtIEX6nj/vlVLdUjbweauPx+q+zrRUs/s6KMony1AUESbNrf67MuSBX+4H7LwlKRNZOThcmZeKCP5m+gAYCo+aoZt5bTdrYA465blwgP7oBIQtl5AuDtYnbRsWv/ITD2I7jL56fryyPvUbzWFXJDc2nDfFkJ8p6kwrtgT6roUzJ4L5tmcgAAUhvsFlA4LtZ3peMFszb/ERT5KXw3TOgWux901dL/w+oBgGuP38tWY8bML54JLrPG9GowErJbLzfH3GOR3h7wO7N4zZ8ZE+GrXz1h6iGNQ/XM/+gODp0yLQFlhqenfwtTefpwFn0d8prD+YYiraO0fORaRjkCWkJafIkwY6LEmW/vuAWqxOC/Sn2dleqwlLdL/r+r1VFQclLmhIFV17vRhBaf20KGZr5CE5lrK26L4FstljLf/r5x/7sj85g29+lQMoLbPqRRg4I/SGS23Ijvi8kdSwS3/6st3VGm7xH7fCQDJYpKGoGnIR/r9axNkG6xt4PQEXoiis9S5gpo6GD+vpxHftr8BnSq8jmFC6OZ989Zj9+Ot6LioqrKNM2bHHVgxN1jgqWq55V9OCPAAYwbjEtiCfJfZC19y6WbeXvqOzFiPCx1mLx4eJwif12JfotYD3YmlxzSAR2v9O3cMhVZE6E4X2fp5h1jSx5IlzrF7awEAAsID0LEu1vbwZsKSDl4MSaa5cphN2DiZVErUubDSTqHt50YpVA9wU8rOSHFfvhtgehE0e14gVy1hlO/9gNd2XSeaoVGyzeusBuzoWpAITBBXRaAX8l2Chtw/Rx3b9GYfDSwLY/b2/njjBc3+4YKrngf+2ARHQz8u6q0qiN4hG7ynqKo3bRACj4rAOEKn7sHZbySrGFwzq4KOaJ4xxV54/ASBqNeyjlgAE6/bQ2gj+ufx4qocejwHjpay18wXrP/DyZcaeOnTxMaQuRiQrGsZ99v4NcDCi+RCYxl4pjvLb4qXh1JiXQhdOi+heL+7QtUXl8K/L8SfRAmRQTR0PwreQkilmCgOpzmm7NgIkK6T2sSiDe4qbzC+eFydGFjJUUgH9eB7g6UqTQnXw/AI3FHmRN+JJagUFn/ruXQqxGEbLmc18AaWIlmqRlOAE+N5YY/uuCciOb1Kj7KSzyQfikrNMoofxnEKD2z1uPijgCnixzPJFP7q96cDWHb/930CyAPweyWJyMBH20mldtsWbAo7Ffw9ufZyXA8HkN0AHb9Y26usPRAZq/7dBKjg0BuqBCDl/t0BfDF+/iXDZGYkO8clEeq1CeJOUNr/iOQCT+wDDeaZvgD2TWB1OmcKq+C2DTQhhQll9ztCUJggCXHdTPKqxO2Zh45kOIVHqOlYhktn6Wuc7Vc6WZicCwkTW9a1YeqwOz3rEpo1jKcMCcJ7ySsW2lk5BxUO1WK4WbcBdze7KZzEHuVJp+Zh4LHTjMnco+J+pW4BaqRKk6B6aHVjXy7PCFHO/WVHlg0eKuwtagbFpHrv1ky0hRr/TFY+SJHbygb9LAkjPB67fMdXq+ua3v3Xc8hI/s7h3PyvAKEaLnTuQ+lu83iDeEu4nd7l64w+5ISqE7EH5iKMoC48jCMfhriRsWCyhDmOKukD9s9vBUa5zRmLt3owfC8LbCR/N1iD5H07Pela2iM0uRrAgy9ShGfd6NR88PeWwXo2uBw4uuM3Q37aVJMzwUK7hj3ZmnwqJjA0dYp5PtHHFwI2VqI6N28a9MTbxhOuTpGmrgP7qI7hELUIYMmCuSmOFwJv2q/xOXAVPRH0qXWQYNbrbv/ewYIoRn96SUNqYF2jkEeLLDUVpjG2HyVyfGJRm/l8HHItuNbAQ+sgzwKcxakIkvmV5ZjLpESfZ81LPM5BbH83+b25nXdFJBski6FtbuBsmdofAaEzCXX+Jgza2f59vCvNypfvhHP/UO9H+CQrR8pj76QJFyZfuLo21x2xkuDDyhjRVGlW8FifrS4VGP4o3IiKHITVw8VvizAF311lRvAHYdfC4zew/ytDj825Y3c/ggAWB9fVh6jFLkS83xC7pWeOdbQ/yZJBH6ScPbYJRmAsQorleR7l+ABSmMv+QnAnnH9ZL+VfvPmLzMotObhxW91pPPreIEO2G9RmsV3d8Ffk1LDiC0YYtG6ZobgAuI8nQVWnp2PNSQVH+ctVWzNU/E9xHF8MrhQokoFx68v0n2AR2rRL+YrRDX9aIngbO1FSAJ+CA5yJ5dwtVbzdZpNdeet2UTAzgUqEygR/xvw52ZW2KjDLQMjt8eeNxeTL/LKlmJDnO8lshzy/sJVKGOxTAYMC5MQJKx1nwacuD3EX+WerpkB80gmBFjNtow3GSVOHVj1NQsTRZ1Ien9M2t9IjY7oc2HTxNUD8mr0FDSPOkNOKvoUMKeEZBatq55CeQw8ig2nW9idEGL3UGSmVD/uJmqsefPvno174XBjaRO1Ayw553bDRWcPxY3/EEewRtVZyPMZY7LYmBoVlo4L2KOkFvrnq+gjjWQGkuU9idkzu+mvfj2J9xFzlhLHWwgQq75erd1wx3EzC4QfI3R8dxbj1Jrcmrb0GuxdaHyxEHRgrGB3DMBXaAnymNeOnNKZxvXmjSrPDpH2757leEQ5HOuFFQI9W/4CvrrI+w1q0XB5cQ56GiQkSGYVjHRRTbkleYxXHtqcKw8wQ5gHikNPFAgZ8BzZ8HqrXb/KL47uq+bP0PMvTmSYzIV5PATkg3fCwaBag+PncZ3VvbL3D/vLfc/Qm+jpfjppZgbjYbQg3hmYY407iBvK7I8333yxNhMWxO88qvrp0+QBJy3byFFrq9yKC5lDexaJZeSQ0KjRqzNA3fqcMiuLcjZIN3whD1l0dPE3It1WnsX2AZbeJwDjNqUrTRJeoKMx57vgzLqe09u7TRq+wslu3UzN6i3a1Sy9E6+i44jxkn8HYht7nzbVu4TGnOp86llThvZ/KzM2k5Y54tWHw8Bf5C5KxvYJzpvoNwnxdLeFcOTUiPvu5xWH8LdHOAKMZ2wNocEXTiY5TTSYP86w7x7A48l9Ufh3J+MERmPTHOrlP1kF3+S28cLJQhHjVqhCbTf7ILUolaap05Ba/qMdB2s80r7Dtevn23jvlQP7VA/DZ9ot0vfOYQ4FuMfXWFIJWZgEvWbQg5BMpnZhP7CVk26Ba1n1wWm0Uhy5gd1LfzF1YHf/ux9G+12QQAJ1Pep8G91Cw+pn318xJrx2nIARfCjcGH2LNR+FSpOOqz1iI987FuNzFwgMzDymYCT4XI6rFCC4NfP/Ved8JGZ13CEL6t2aXzu7osPdWuxbeYNIDwVaMsvi3kzDMjZTcieBkaGB1G58JqWWjKDJ65ZAQoa7G+v0txE+t3Kzb6FDztS3l6kr713GgqknebyF5oNIVGXUVref+b8iU2GWBWlP1YB2ET9pJULQSFFGARJ8h9viuyf8LBaY4AAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
let autoPagerLoading_gif = "data:image/webp;base64,UklGRh42AABXRUJQVlA4WAoAAAASAAAA7wAA7wAAQU5JTQYAAAAAAAD/AABBTk1GlA0AAAIAAAIAAOcAAOYAAEYAAAJBTFBIiwMAAAEPMP8REYJua1u5rWdhApzhAizRhiPjwixBaZRCCYQEiBWw2Zt7v88/YUT/JwDfOwt2etZZsBlebaE86hQY3uxLedJ4oX8xFenFVpQHjQp621BF21JlG1U0NYO3DEO0LEO2bEMxVBrodM3kdcMUddOUdNtUdDRRVR84TX8QNONB1MwHSbMeZA0fUFGfuFt74m/1ibvhCZT7QdGsB1kzHyTNeBC/5C/0BwG/SB3tgUeQhqsPXI0XjwdolxmwTQU9SStimTJGlnbGlNItYRWJBUPIALYQsXkhuuABdCGAUiVdOzLOffhKuqORvh5RGIdrpD86GXA4oR7oZLhEbLJA3mTBuAwyYZHpMsmMScZjkhmT9JdOJiwyXQoG6S6VjNiXRRKdBffNAJL52CRdY1JM+kqy3HxlVAy6diPJAHpFIzpJAqhHxHaKWjAOd0lY0GbMSzsy/lD9jnX4S8Fvql+xL/0grDzDzRnqbQje0IR4C4Z+m0I0DCHdkmHelpANS8i39GoL0TCFcguG8Zl+o+if8OYM7VIlGKvkvqJYcGmPtuCl/JlkWlJ/NIUgxe8auvBqfCRK3tR/oCZNwT1Kr6oOP8R6BCEL5aeyNfnH2B8pz9bXpH+O+XOIPyH8D7pJMj4YPH+g8mxq0r+s/GB9w/pI/obyYP8c+IDC/Ej6CmeqXzG+wZuaEL8imLrUPxKkaBpflExTah/xUjYtXTFtqX7ESTTxKyA5Q5Vw8YZ220IwdKF8STSM2xKSYQr5lg3rNoVkmEK6RcO4DSEYuhBv3tBuXXCGKoQbrLd2FPym+hX78JeMP1S/Y13qkfC36k/Mw10itlPUgnHBEUCvaEQ/AGCT9JVB0ekayXJzjUkx6ettkURnViwGkMzHJAsGqSAjNpkuGZP0l0YmrMsgExYZL4PMmGQ8OhmxyXxZZMEgwyWAJC8kiX5ppK9HEPrhGumPSrp2JGEevpLuAIl+0AGoPAMUBUNIAKYQsQlxZ0yBAZ1iwirSilhSwZYyZpZmwDYVjCQND5qIdnP1gatR6mgPPIL0F/qDgF8kYDyIUH5oPkia9SBr9oOi4QMq6hN3a0/8rT5xNzyBcj3ImvkgacaDqOkPgqY+cBo8gHqbim6akm6Yoq6ZvK6anA7bUGBchmwZhmhpBm+BAealyrahiram8jZsRcHDqUgvmsK/wL4UPO2X8AZbKHjchfAKs2AnqAEAVlA4IOgJAAAwRgCdASroAOcAPpFCnUklpCMhKNKbCLASCWlu9T+X8skDz9OEuGAYAARO/Nd+jfzD+s/jj+onlT/lvyI6NPuZ+wDAPdZ2kexGUsDm5IMpzkYbYtQP9a+p/+9fsAfsp//zfr6+4P35wr3Gt3MW3ZQtfG6bgjCFW+L2ad29cd/TPOvsewDWBN2Qtglu0V1H/DCXBlfKtLaP29TvLLZUwmQ+CnL7tQ6d3ltaHEHmLX/1CZH5yusHOERz9LJ7rQsr3aPRRZ1bvASU51kumM+vlAOd0aTUeHzLAAMjLizr0PrYNv/McSN7Cr7NP4VI4e35Y4RLW6VZEAjIwEpDT7Rv2cnkNMdf+Y4+M2rgC8wQg1mZcpdppYLourjyH4ucNkScy3tLfSDewaTB8F7+Gk2U7x6zkXUyYFP6NK/u/FTbsx76mGaE00za6y/Qqqfm8dKzIWxxLnjesf2ItJrN+HnDY9sh3aJ+lgLAXSxUirmd4uJAm2edCb0w3HFLSrigPpnIC6Sp/PCk0Nbaya7jVOu1gqt2L4X9XsjdCwMgZxV5aGzC0sPiJEIYuFPJeW6PSWBjqzKLNAd35tpAkJ1ZECtok3q//6MvZFuyt5xLAdjbRu6sUFyK/MsZqc8OHP3laquLv0VnKDx+xpF7apkFRXUaVrLFfxHN5G6SuUhqBtdabYXggZ/sXMvaml34DhiqY7Lz9gZt3R17CakF8Kbw78KRPZnyfZBT0kOtXNlLMrgm9noXbRwD07gLLaswDAAA/ttF8cjPOyhJWnjVdS6KXPFSmrTFTo641daDcH/ahYK+1uvz2T06eTcmHjHfLEEH2BcuuvOcylyb2tQfdpgAZ5dNZZ21DwkYDrEfUsqtJ9C1/Oq+R4NTgRm+ev+b0NrmAx6Op39N039DrHrQnMv7cog504gPZp9kbVPJoazf1lVPKWMKWwB8GAqydRRIQcDXcO7vnS11pYQCFP1l9Dxr+dzT55zY1/hN0rBRgVC0eBLBGTAkicVBTAZOJsVcL1SQsu6RperHYuIKL5oSfJ/WX+cbDK+zW5OI20IlQfgDyzAvQBeFHPYNIL7Cm68uuBWbxVgTrDYa7nLrmCynHkViD02+nYgZtMOQLrcgspOMK3tgitHEtN+vtdYkYERa1WJeI2JTfnx8Jkj6j2r7VhhD3Ll6qz3oH3X8xiavOkb6rtr8+9TTBcUPIGVXYo13pEcoaeVLZz1J1mUGkbv5ePyCYXQODRig01N2ADX5cYtY3WuynxCWI/VlXMrrALW8j2IPQo5VfxDTtkr50IVsv/75yR4wrJHkB4OEfFPfgYskIAnOhwuNDdkiC7qdQAPYNzl8apzcNXF6jXH2pn8ep087H6dfqTsLy5m0a1rwAmIzB4mnTzvaevHp+DU8qJwrLYXZI/ZSQ5viX8vwbkO7cebcSBcEt18SR/z9wG3j8ZfTFIkigpFyKzWYqyPEQ0uvm/xuRDMl4TI8ACMIFsxuPMDCBVGcADZ4PGEJz3Y8bAePhl9dq0Xr9vF7UYTh9G0NUGFbDOu4bTBIvV6sXYfSwgPAf1vwmhMx9BSDcWHOJC6af7SpTtLyB8AkHd0o3LnqZ8yZgXE8biFAJqraprjK3W45uGxDEzPCPWDhHFh/Rfwj8Zo+ZX+A5pvPp/V8m2EB9Wu4mIGmy7/sndyjksNMcRfzPc0stUaBTtyysM5hC7RLqCRfIV8gJqdcB19kpo1/Oza3/cWm/sidyeSTfiPdvqtQ+cyrCPXg7BT/Oe4QIb2WoNQVyQYIjJZ99WFmICB3w1qCVEc+pnpbhv2JJBjpD8jQB/6G85nLSKui8Au2OT7mEXh3+PSIDK01oCogocAMMn9jZgqV4bV/nJvllf6lZ3SMy2g1/fYbJ4nGYIL7unRCrVQu4BUemuvxJhtPSdmi75NoFmee7Rq9xONP7P34Uy1IbnOmUR8dDy8TKnvJDLLHXhPn+XWDqsqvJV/d0EUGbepxe5SfWuDB4MuUJI+BgVE8+YBhwv56SIdd/jU7yd62jDA3WjTEn2hxdnV4smFDJsO+8tp8LLqyMrutqqIK/mJmOWZUc+s7gHRQoLgwl3En595PP6bLhrj1sUrfQjUOmXxPJ771x+6ZQzPanGvpkxWiI2bmad/EFTPe5aUPXXFTe5vOpwpKrNeFPeECIh3um5Gcsf35eSDP7iP+NouZpsh6f8gACS2GExXah1pLfIcobG44W8/Fy1/+2qOg96xk0kJ4cF/mNQCvAest5HOjFDLl0ntsUAn7sszBWUdl/68kCju6Q862xOuojX/fObp18EK/gaTnPRkEE7qhC1jdSNTFw5FvC4uQRTxjm836jX/FpPzpFGCl/WDcW6vJPfO7yGRn0G/Zhjmp4MZY9/8Yod3ruKvxdXbZNvEYA4CTrCt9r73AQS8G1YSdkPg7vgVY8/4Go41uEcq0C0ULLUSC8v5g0lx3NHWxupS/hklViGR1faTZn+jb7yQzlLbnJCgIAP1gffvSOTvdofCs0aQLWV28EmfdWZ+e1+iNDDlgNiS8FFn5lmbRR7LcQOTi7W8XwcSGBdWCLNdvSScSsou32TcJ0lwkAlGn8c2w8K3D/7d/rCzgayzueX6A3eH2k0fwzC1rL9Mc8+KnOZVVvrQZWaT+8/+8PsGfZiybs0x9dmTE/bj/RGFQH4Id0KHZ4iQBkp0PH7r5PwQ9Cqk7eumTXOhBYf0X8I/FXVTiZaaAMLWLDpOtmpxRV2vkcvinciIZ1Ou+oU3o276JumKNCWe1b2s1tta5+QnC+N5u2VKNB1fbwwNjJd4BVUs9QEHQEDOOUxt4PDgL50v56JmQVw1SoILZshiHVBwtkEcxogL7qUgqDt2LDy5Lh8lUcPazXf+WogdleZpJp8gzkC187N9+1H0Q40B2y/Gi74YHtWU2s+btvuVQfS+XW9TKVWhxrrRdcJ6JQTwRC+tARDTzY5PORzUI0obafcyFxcU8pdLJgnTivT+bNmwD6L7Fat7VqTpd6fPEVuxN9i056rxbYGZELEC22RMjF6XPGl9RONpPlXqwcRdGyYj7AtAgaPj0AT5gKs/7vNqxZmFEhBkVtK8Uq9Ij/+lh/+NF//9O5K6vYRJoXtZlGQ9m112WFPPVXU2rGqq1lZjjHPMt9xqZ0oYQtNsznMOixUrB1VWxxkqJ4cNGXU6jdK1iaA/IzTI2MicV413hcIM5Yb3qF/xDaa0c+McmwT6HrwKjXbTjSHiJnSRQdzDrQMsG9h+fmpVs2AkQkaWvNTvrduFOzN5If+AnR9QaeaF2OCE3V7wWwXsGshF7+IYqIzmbq7unCdJhySny5nDt7grI0MYa8R6gCxxZ/CXx/95IzsxoKBShCNaUJ+Vtu9vElzJSp4Ggff0wAAAAQU5NRlwEAAA+AAA+AABvAABvAABGAAACQUxQSAgBAAABDzD/ERECciTZdZuFSQq+IQFXIRMjNCA0hIIQcNQHxT3g4T39Aojo/wTgyZ0k8+ddv8R4XXrW+TGc45PKG4RFfUl7il/0l1yfsi3GS07BLfiKIkGuhibkJ3XDVUiLYbgKcdENTQiLaiiCX0D3i3PapD8M1T+ukxNKRtdUok0QG10lmaUrt6IZ9CCZJDLgJKNQyYix6mTClQzCIDM66QWSRFu0yVVym67TVkgHoHD2IAHgKgScU6MYMTKAU0roSZPRooaoQeWKboNXefyoAuZVNKSXZAMtzrAZnAG6bIiGYPCGzQBdNkRDMGwGp8vQJUMwbAbokiEYNl2GLho2XYbOG6Dzugj1BXpWUDggNAMAAPAUAJ0BKnAAcAA+kUCdSiWjoyGqcQowsBIJaQAV5t/Ue1H++8qZ64aLuyCt11AXy/iI0gWYfxtfpr/xe4L/GP6/1aPQT/R7/6G6BMGjpE15yv3ziTH08lUQoKBxOp4m1wWXiWzsJcnprMZAD6FPWJhAXK7+4TGtjeC6uC1MxH83LJWx/vdpUOfvnzQ1l+48YKGP5NYZJl2hMTG5za8MoVOgsT+Hnnn+2QbyxSpN0ysAAP77QEFdVKORYcPKyB1nGIruEzxjevlkqAYmKHMsMVK2seLswKa/zrstBK+kdOKX0u+i2QBpdBTGcM/Ff1jd5Y8DwDa/0gOLoFSRwCaHdWVsBkoD6cMC4BbFuXM854R1DaFChsQ6ujw4N7356ZTh5ukCwdNijseQzzrvbV8iehHykoGdbxFokhI70ynZWpr36GrErajkccOKHtrNJn66UsxU2csZYxmh6b7D4kqtkRj2E+IZN50UcmKbdu9U0osNc0dpGsHOcxu6He3OMdNmBFBpBzx2Mol1xURgenQICuuvBJlV6lAklrueGVrcBKrEceIh5VgqjvUtDal4+tQ50G72N19VBCjsd8RWUCi/tfIon88rp0PuAYeztGR/ZQCGVcvK5PD1wOK+dF0p1jLCiN9cta7Is2c8MS4MHDIA9vdgLaDzEW5xBnqsntqVxvQVzUydYVxqp2KOq8u3k0H2dS1Gs5cAVaK8ZImm7yMvgPYD9rjFb2M4KoavWdTRnZBiOQrGln3zfuF/vlQ3yyekyY+M9lTCVNvDHcZT4yC/XNH5SWh+iM5uSUfcpuQBjr+xL+NuK8QCs7L1r/GLGDyT/MK2/4u9vGxeca0HjQ4paXcHAvOJaXWCGetTNNaK6l//ZjffE+NHk3GqIgV3Ye+6J/uqm5uo36vhRbhdK9ilP3Im/jCjzgWxgIjhSgo+9n/UD4KM4SPVWbVrcO9iLOdRDO60hW7mSIwnExRPBhTCKRVimIuigDum7VapuUo+Bm7nYF5/pbmuwOcmVMQV1Z2cg54GntCu2yrDiWvOt0kDNMHiHXYPri+U/Rjx5+beXw/42c+YhScsxCrip3PkRWyZEbr0AABBTk1GqAQAABUAAFcAAJsAAD0AAEYAAAJBTFBIHwEAAAEPMP8REQJSbVuRncP6XfongTghkuIApCEFCQwZsOoOigIkRPR/AiT3x+wvTSZRpv6pMkWqm2kUmQLtNXO4LJOn24xuSSbj8BNJL2R6oThRZBymW5LcVZWnm1yWblddgWaiSHYlRapFqhQusiSKBZqkiyrJZfN0SbdRl3RLZhyS/CBJ0gt7ofOgnIyfWxq8TsfJ8+XyQEDROfBGGQWShhGoI7k2EtDWHPS1GxxrL9CakTZ48oZA2VI3xC2i7XB9x+3Y8dIOO3a8+o5b20HZEMkbAmmDhw0v6Gs3aGsOylIE8lIAWLLTsfI6tRV3qiuc80IYsGCjPncb1TnGeSpcMGVXbcZdlYnI5ITNtCs3ky48033k5tLAs1jkWmQ5OSYBAFZQOCBoAwAAMBcAnQEqnAA+AD6FOJNHpSOhoTf1WmigEIlpABXnH9y/ADt7/j1cOzgI6fcUxMfhFXSvVv/f9wP+L/1/9avaZ9bXoUfqkHZsYRGvOotxlAr7WriWi75aEJzHEniDT8NUcsw15Lz2PX/Ik2hcMMI/JxNKz9MjWcC5XkawXu+imRKR6zitFLce5X2xLcgcAXZ4MQ8jNxxmCKTTFvbIk4ufh/o5AZt/JxeM75epER0hmzxkxI14bGzJYkGLfyUrCy12yMAA6l6gCd8bwD26HDNM+4HHuXS8cWf47OvmIsSjxThQxzpAKN81P9y59iCJLgJXRBBS31eMvxb4yPCcRPwjJm9viR+r7WHzJfaS7Gc2NNZPvnH/vO3zB4JN0QQ7J2kTn5RVTo79VpkLNywRRMHrZeIDKpl0ny+x/xDfMUq7QMzwr7OkJt2+d9qb3fnzKgw3fZsFb5YxPuBEZxyKzT8ko1d94qiwBEUeIXBqGqGPh4DeuNb1HdQSKYXcHVJFv1BGMNw7CJI2pi+iR8AjpntOclci8BY69z9yeDV4Rbu6H+iWqnv/HB/KySOFMULX/f1rUjj17Rm/hBa0GHQUXC4y/DoVcbFOrj/aVKdAuvihMGEkXh/9OwWNq63h/oruip6pInE2kxtDWYn8VL/sfpaXhgUSaUd039r7/m88L9j4cH5jhEwPUZyn5XkVz8TQuwLBMeGXg+/OhpzDbO1JmZyd1MMtBMxOkpm4mA4fq7bIMDt/xOua4hik4Hs39kOutE35LrTbAc7X5qm7R9pg197Ct1IUSMGVyDPu1ZjgeQEA8F8l97tzmjb2l1pTo0i1IJIvj1x8AS/L8+JytvLrK6ublj3jjQ5CHnMTKhfBKgw+kFj/+t3k+glgY3REr1ndTWc5Ii9HVpGhzNM7IcTY64H7BHPgztsuO8oUVPm8XjiSsUd3Olm1f4/zPYuPhI48XzM/odXsxM7I+F+Lgm8ZX80bGcIf1z56NP4StE3obWbooKO506RkHFy4/CROQHzyTjxkwIqwtrRyKoT2lun5uJ5louixfd8F8KxO4aeWajXPP6qptNpK5UCvJfBERMGq7opsiAgQr4LrKsQGJAflRRhOk8ENywKPahEvx33GUbF64kjtTwaHhSkNB/+5K+h8bkFAX/Yn/E8AAABBTk1GSAQAAAIAAD4AAG4AAG8AAEYAAAJBTFBIBAEAAAEPMP8REQJya1u1m4PshCHpgDYyI4VFepRGKZTA0B/EGXDh+FdARP8nACLn8KjxiPiR0mv0Rxxvw9XlBdxTTov2An5RHxKeEhflIUk4FvkhVJyFx5wWw/BCeFA3opAWFyMKYdEML5wW1XAClmU68LOV8GvlKeJ/K2A4A5MHT9Ygecr0O64wWp0kKpN1IQ80ciPhQp6MRkZ0MhiVDBhkWnmQpFHIU578lElXprhAnegAgAeaEaeRcDHoAfSIbh0ALgFj6wTuNJe3KsrWH+oW0J5yEbowBO5loQhZgNKFi9CEKmQByhAuQhOKkAUMoQtNKAKULjShCBjCRSgChlAFDKEKuAgAVlA4ICQDAABQFQCdASpvAHAAPpFAm0ilpCKhLHG6qLASCWkAE+P/jMe71FNPlgaQKaD4xPqD2Av5T/V/SA9bXoFfriM66iKZrjk1eLpNNTNK+0r3T5hgtnoOhygoW6d/BDz2T9l1yMpYtuo+MIieiqsMpqkvxHSNnWOyO7OD68/gHJTv/n5WQeG7TFW2cMsrF+ddQ3ZgHyMZ2Re9gd8hhlKVkFVJzZHeTj0ky1Nmeqg9nv1MGtHMqPbFQAD+76z4F+zBIBdxsknUUkIIyTCbZzXAlgX64UNWIHzf/sOhuTeYj8xl210j/5pxHj4oMfZZqWa860O0uGXmFA9HPx3/x4+PTwTGfkkr4GPD+/9Nqb+8NTrBvf/zJ8h/44Py9GMCb4oz/L46l7fKP/Fjm8GK/vf9sxUj1a5CFs9uWX1GLWqaRW3Jw/lV93QzWj6NCBJb3JjZmPfd7boaOzik9kUJkbI9KPS+Dnsj1xCaGpYoEaoH05T43+OewsD5sO6f+FE7gXeIc6RVcQoNainwhmg+nfrjQeP7uE+12J9E89sUNG7Newy/38Q0W3wPiqlpzYMB6t7YMjuMxuVrGMJ3al+MybJeKauoXJ3RGr+8mfmGNqLqj5VRdj4/EkdkRP9A6r1Bk+jHZIizaDdvt4mNLXs1ODbUTJ7s1tNkW1co4JLipXn/Pmg0/r5LV/HM9Yfcfj4zfQP8gSKGqNy10QgKSg+NGdkjWukFHnc7joQb7vosZMlyj+g+PGFqobYSobgAz2ldIoaJ59Bpwrv+EtgoFwW/31T4ltv9Lv3rnHHK77UX3knkfEjmlcG/VxeaZnaj/i/tVtfIevHjXI53+8QB4SNlbzpKEf6XWT1OnGCMKQ/XFAf/NSVCW0hBS7dz4mRSTXzgSS5chLpwLqUb6nXmaZNfcEBN6ncGWvGjBl6ARv/fTYFQSRtqCNOdQgIzbiUSK/MJOC8Z2TFEXz1h2V9f0F/4HgCkP5v12NcFrGwzqpdbrB8aGTIXw/MUxK1O+tzjcbd8YZSiuCG/AnNo49Mrp2n8wO3VoztiP/Q2l7FR2FpcVrnuQxQM3hCO9ll8AABBTk1GIg0AAAAAAAAAAO8AAO8AAEYAAAJBTFBIhAMAAAEPMP8REYJubO3Ytu0w3hnZqwRfJ1r6OqA0pShBKDCOAOd5Ptf3G0b0fwLwL7gydDq7fRSzzoPBat+KUeeNwWa9sknli86iS4LFkmQLSmjQZF43ZFG3ZFlHGVVN4zVdEzRTkzRLkzXUUFF1TtZ1QTZ0UTZ1SbZ1RUYdRdXCSZqFlwyLKJkWSbIssmRaJMmwiJJuESTNwkuqhZPAAp/5ha0r+OP1G0uX8ecrYeoS5qNmDF3EehFdF7DdrdE1nQf9rdPXh3u5xnAbDLh5oN/QGW+TEfvIALCPgiFJWIc/+pExmW6LGfPA9UhYzLfNgkEy3SbJiM3yIjrJcOskA/gi6RpJd6skfSV5qSR9JTOem3SNpHsFkOk1SfRXIxmxGV6dBYOkPzrJhEX3qsyYJMMrYxJCJqzXIFkwsmRFbJLxmCSJniQzgCSTwLUoGb4K1uGrlzTXjiwIcJKKLthHhHIcRZA0U8Aza9ZBQdHsV71Qw6sTOFkVtJuXtZsXOKt+g7zeghVURbNf45Jt4itp1mvazEt6xR8KmvFaNv2SX/5b7bUvTlMv5YVvQVHs+BO027JsVq2WLFk5s/mlaNasxsV/I3ytf8mb9Z8JZu3vw/291L+/8QmY4X/VztOCZ/j7c1+r/w68rn2j/Yz/RtD1v49oVq3GxX0j6eY38DO4Zd36UtHtx/6J8qCOn3Ka+lo/kV9e0zTBbNr0S3pFzfjKuCTNvMRX1qxXvxTNvoSvUMNXuzlZvXmBlzVBvTlZvTkBlAJcimZf8MqaJdhH0syjCKJmCNYR4CQV/cgCX72kuSaYh2tB0n09kgA9SWaAYJAsGFmyIjbJeHSSGbNIdsIiGV4Ji+5VmTFfjWTEpn81FgyS/qgkA8j4GiQ6SffylcyvRbr2AknXSL5I+koS102ik/S3RjKALK+CQTLeBsmI/VrMmCTLbZNMWMy3yYRFku6oJJkxmW6DEftIxzwKBuMrgFcHVF7RX52+3gqwb64x3BrRbgyddw/6Wy3ouoDtbsgYuoiFZ8LUJczXbyxdxp+vX9i6gj9eAHWE+IeqhZM0Cy/pFkEyLKJkWiTJssiSaZEkwyJKmoWXVAsngQXEW1dkU5dkQxdlXRdkVedk0EG5NFkzNUnTNUHTNF4DDdRLlnVDFnVN5nWQwXBJskWXBIsqcRZYrwzT/go22LcC434LVthHgXk9nN2/SVZQOCB+CQAA8EQAnQEq8ADwAD6RRJ1Ipb+jISu0ifPwEglpbtOAaavF54Ha38gPhT6A8gHHUcScQPyAzWLwB+t0DJ/DP9QNQl+gCCAf278AL3TPz9O/7x+OP62eW/+l/HD8OvkXjOfqr9gDzhb97C5Q4OtkRqgkx3/B/7zluagn669Tv0AP1oOYdgGzLwCf8J0NLuvxok72Kwup+1mI3DLPdVO+dkoGKXYMN6cDuINdtV7oZOGfUBHWYMC6zTs4HXP/yGdxLVp9jzKzKefQKeUscWGmDXIvWs4euHFsr7SRVDjT4uuAdP0LWr2jHhvii19gqEfcIm/63Bw3hnuqBTth8yd1gh0SUwDszCEwRY6va3ViBV0eg97IkDgOLF/q1tuJplFssKi61pvHCzKS7u5A9MHC52w7gxI2cmLkarXIeFQjLJAnK8EaTX7Yi9QYxO/d7AdmYzlJ7Cf/ci2s/NEefdYOHgOzMkAeMEen8XWCbTbXtkvsBCHuj9Sz2DcGu9gh5kSKb3ValA1/St9C1TDGhaZGfHhtVv2oLw+6ATpigP/VOklH3AkFBIo4Z7+ACTmDI6x6LGLYp4GuN8EKeIaQ0C9qifq4nyqPBICJ4rnjeq4rbuMLnVbd8REKzQc/tn2vMAsaycS7zWhgAQ5DiNm2IFdW82EGcye0WhoMXpvigbWbEOuj6sihHKQ1f321QDnrwrco4maPSK4hES9bFeUNk+n6nVARiyZ43fVv61svFwT0dre2KUAA/sERa6H2Q75/qK6rgpJ5+yRkRHMGRHEWY/kxNkka2cD8ZoYJh3/TwTVM5nxLXGYreWqFkvbf7326VkKh0CIOJv5/OBB2UKfBzHAY+HFpdUrkE/s6XM40P7cV1F7pYnUvuLa5X8RGB9LYvgQdpQY/9ACywx3RZz0zmY7xQgGjouw3ILaHhyGgbihPA7w26yNV98woDrWuGg3/RkTrCZTk2n9NJDH8FBnlS/HQsnZb+UkAFNuiWyiRgMZ+oPPzuEU0eoXodi0fTsEOxr/Cc9aD/VIcQal7DFjRpsISJTYCzC8H/c+j+7eRCm48SWSd/066Up/TP98E7AgrPL6u6IYAaYboK+MbqT3A4jQW2drujHo8THeWTHjVGPVVee2X/GscTf3pqutUW8KPxxm8yAxx4rMZW8nTdtqFT/6N6vViicIb/O4p3Uw1/Gei9p9CvtLyNI4XWen4jI4TI8Vm8VDYB09VfmPxQMu3n7M/sZRq1Jjt0vBqIK4gRzWvzBDl6d7Z+74Pys8UpHmVkkllsc/qdPo+MeZorgtc0ECDVi+oQ8mm3idQ+YyGhn+cCRDtPRgQSWYX1Xmg/PK/iT48bidgmTeiydHYqwwHpJSet9E/a9/JI7ZkcY/y7b/GUbLkjuMBbOfECFawG/h4FqFAYafGqogysZ43qmpCcgsdLMQcmb5dyqR89I4iqXnP5F2JVEf4vF/1aRlLMU3iBL3uPwBNdf4fXJdzEC1D3RPOU63TIMN8gX27ueT/kbyp5AU+n2teWS64G8mkcG6BC4DoOaVLS9hrt1QQ4kKF6b9vO9C/U2rH3/18im0+X3y9CffX8nru6KOfzMFzGPgeoqj8B1NYAr52GejYC0u+oAROhOvM2XDLKSDuZbkOvxRkpzDwY+byKMUddl5hxc/HYUQHEOVnFU1PMbK4trlHi33Ca2FMSyOZAPMiBf9zTczv+fD46aj+gOLo39YHNYe0fWZaNLZKdtj9xWABHk2Qm896x4U77+9rhAMG4NhNZm/MXX5IVKm1jrDhJeHx+Vb+5hqUo9xkLDHlbAIhlivTI48c3eSbF6G5H7Y+s3WvXNL7vS0wPlRnw4YSQOe0sJTu663bqwx7ygOmcsn8K4f8lfHmOmBOZDDp+DwCypLhaUXspZLwsmROx5WoVebFnP6XPUd9pFBxnJp3cnJosIbTGHi58VRGXzXe7eYoev6+Dgbx23jJf4GrcGw/Mddmy+mySD1P/HDh+r6RcoiX/izSz75iocRTIuN4X0r/yoBvgdC37WO+UQtiU1y3FtT9MS/GsK0bN3+XwLFKS1b1NLWBPzuP2acn98x+wzAHFqx3n/bz8uyoc6j1CDT2FYozNqN9yFdV0U0Dvm6FQeraAz2AdDNlUTGHRURJ1LPDEAdm0Dljh6YKgu9PpOAjngE4COjIj1DL9MAjnXNDAWrNtUX/uL7dDxCOOmHMO7cUH7JSwd4yCZmCmm0PjQjBcNvPccduIH1iIRrB0B4hlBicn4HGxpb4OEbB/90OWG4Cyqa5ZU8jiKm2h8Z/JPWtf5ItBSaSIsPbUPS2vHmgmwn75QMWwQSzej85WNZeTOQvVzCejLXe3uvqFr2X1LpjehqPNhHc4Cl9NeDff5riECAjKA2epwZX9D0WKf9wGbi6C/lfjOkjZAZ43t8rpw00x0wfpmHfARSc5cB3gaTqoJb4VufzFBt6KWkn9gulwlo2KZU3u//+9p8YowphsiIDADAMLHlZj/S9FHXI9gH58KEyskjws39h1WEP1VKJz8qUAszMaCbfpspyStkWYBw6dCzfZmlnae87Rv0TB14GECZWYXwhujZkh3RWcBepuw4O2R5SAPb4JhYkJuDU9KEr8XU6uBzs366h+wSCmflZS+6WS7OE4UuC0m8oBQxZDHKqOuSdqiOLQ/lp0pWD1PCUNbLWJP78BydTtSeS3xtnjjtFPtc9ylMXClQsV24+BR9ung0w+zFLBvItvT+icCQ1WAP7l0RY2uyqAXQOmHxG17hGDKh9EgFtnfXaBKEeYOltA8sPtaVio1BFEYVDAZo54+nzhfcHw2580r5on8rSXxYc7F0cAMON9g9U+d+Zo6BFYpJn2WLlxn7gnYgzEUtN+JcGvQrv+FXs/Qs6zMQKdJJ8PN3jkcdZB+eNi4QRdwViD7W29k79Md8nNAXZTIP//TPS/Mo6zSFEJugneDGdWb4E+dsofsknsMYPYBpYWFaGVhnZrDPFhwXVZgvaCdJepLZjQBIz2cLgr+pUBNcJtRA5+BVHCBXG77vmXZt8cAS6h+D8LEixPlsBgAEIYpVeWUGW/McHFAGatLhzI5bP32K4stowrp3Q+Q5eDNHCEY4QWcQ5oKVKNXufjyD+bQmA5tYzsoBVDTsDJHreFJa8PAuFZGu29uYXVo+52Sj9PnbLwCh6IT/yoyvd0o6qCT8gFmA6U5cUHJv06gCHYsHO2Jf3J7Qus/MPveOAM8efdE/JwMqEt/wjAAAAQU5NRowEAAACAAACAAB5AABuAABGAAACQUxQSAgBAAABDzD/ERECUm3bdZurpq2HKgPR6MyFUiYSNEERBA3z0dId+Ond/ABE9H8C4P+HeM74cDUqVJo0lUrlLE2lUunSkKhUqUtDmkqhUqUunaUpUalSk7p0lqZEpUhVKhK0KY2HnaUu/KEJDVXooSgnCOcN0zcihm/uOFs7jszoRoZFNONkFDLUQ4ZZyVM5RKuRGw7BETHJDLuTCYNMizO540xunoxOhsUgicaM5SQZKpPvVBhXJLmBp0U5RMzgSxhY1sOOXyHjZ9UOhNMKjm6cpM1xNqKUHMPYpeSYRpS2B9A8SWFVLDwqO+qddik52p3iwzZHv9Ppic5GeBgeMO6Tn25/xHyN9PbiMwFWUDggZAMAAPAVAJ0BKnoAbwA+kUKcSSWkIyEpsttIsBIJaQhysCqOv5t2xf5eRA7VPGX+k40OCS8IQyX/reTX6Y9gP+Q/17qu+g5+pB4pwGA8aCvUX2Kv/wsg7anQL/okqWYXMyrfpnz5PXqpsV7NW40pVlOeeu9cXhGUYybmFlbFYaLlpS3WqmQTmWwqRRUNvE7gHmV4A47f/yrPxhyCBxJ8icxqxMDaDETnTmDFZhCTSS8lFjfXFo+quJnaZNAA/s0JZm5L7QV2SxwL3aPTceiccvc0gb2PMXKrOJVAkc9u4FBQfuNS4o30glKv+Ka7ZWb/m/mTvvQRYWWE7JeXwUBmV6lf2eb33dSkkbipHdL4iA/iairg2IAc4CQHmA1C9L5r72CSaTDcY9fd87UuoBML/EHzeCWga9zVpL9//6/SMCHAZRN18h64vMYFZu/XF9//8y1CX+ur+1e15S45cQMk7mOicbjnXFy3WC/k5xco8LjsG/35JMP7WpDHFnMVcMrWeOxzCZD5t4s1m1uh3M5A2lCbhcoM2H3JduptorNDQbyFyaKLfux3AzpRn+n/LsKHIaAYj56QIBCv/ERRm9A8Pw7Xvik0D2dfzK0UTFwIJuig2XBl3xXm1I8rL9KXLyQQLfozcPoMalo82k2bHQ+qraMtzAzyd8c1YwR8uy/yA9tQUdVAD0iyE1QVvl6m5srk24iO7E+JzZj3GIQ8zjtvxl7/SaGX9pNCsykfgC8/7qY7nX1BBbx4bW6f6WHVTCzi7tWvR2JR8CoJQKPFhXSfTxLl6ys1WaVLjfhiKMDcF5jGkxDBYsvhfVxO/5mWRYCcV2TUo+TAU+BT5zu8mUsfV+EUptNXhsF4NX9py3Wjw49pqhwcxZrQXXGX7DuSgft/GMoDc1JqPxgigImOsBjVnZ9/5DKn4HugbrLoReH54ML8Im7PF1UBmIpOyrYdz1PAJkAHkOJcEn/OQKbns1oylfoFfd5RasiwDwTFF9MH6tszsZRACQmSaOOepazQ3ILBRGwnF4XCxwONKu8cU0QjUdZqWbYOuCgkwe1IK+2jID/ObJwAXw60aEj38QjBUFv0ECel2u6brYVwNlZLvRIwOeL3Uv4CfQir7qlCGcyBoZc78thtGfNfTiZFjtNUOcP4tRH/SPAAAABBTk1GzAQAABUAAAIAAJsAAD0AAEYAAAJBTFBIIQEAAAEPMP8REQJubVtxncP6g2e/1JncCS7JHUBplEIJhAQs3UBMJUT0fwKY/GE5y9WwEiVXdSzUjm5TUb1jqg7kZjSyiTwRJuqE3EgzNkhTflCmNGhzt57mrJMWfKcsqFNX3OVcebloxYC05IG8FIC6JAdt7QbnmhG1dpA2ePKGQNkg13bczh0v2mHnjpe241Z3uLKDvCVtCFs8ccMBGwzOtRdoazeoaw7KGpB7gUEAl3pA7Xheb7FjQOocfL7Q4douxrdxSvKddHnBDpqklw6XWzRPleR6TZJLFihSoF8kkU1kyQZRChSTS9LLgFOearpFyY2qDprpBQXGRcZpMk4/kfSCTAfNJqJuUSZPfZngdEmmQLnNNLJMIjP7T7m4v6lfqgwAVlA4IIoDAAAQFwCdASqcAD4APo06l0elI6IhM/M7MKARiWkAFeof3Pth/yuOxkM3FexGV7wM0kc0rxlfUP/e9wT+Sf2b0gPVP+3nsW/qisJqKVz/wopGcG5GnNrj6iOTyBwleWeZR1m/OKU/9MdBAuGYsgJ+xHklGE1tgkLiblB9QB21Z2WOWaDJc/TU/Ot82pHKJqvLY5qQkwxxGK6I7fN6vHYa+hgeiDjwhnK4Ux4fJsBZf8csDh4ne8AnHCFp0xbIi9Pr6+wAAP78rTr+g4sFbUkWcMPTTA6msapWMjhqV7Ys+IL/eoJjo+5KS9hBvHVYupdYXnEChCNjqfd3j0msYKcMmekQO++IexHHym/ctJcxj/S910DxUmF/5Vw0Tvkgpt4uqY4RPs1Hb6HPMmQ8St4b7DjSEFR22xN7uQWEkdo/m/rUk+Oe3d33v0u8tt7tFqYei+jDs8q2DzaN62vdzY/S79ObrfZgAwacvuns3aDMQU+dwyOUO59kXTx5+zy/KGG51r7w17x7xGlwM4rMtqsvbGCqV7/arWiL/n0FKjLbunPf1ZrYrX3Bnaqro0PljYUNomw9rxN4RGOAGRaFR7gQBjD2z9aXAUq+wIS+T0bwbhMbD4SQzlcgZ0uLfrEW/57DytCU/pjrgD3rA1vyvdnJzBxpMJ+2szpalsJg3CgpkKK0h/9DY04AqWk+vfMnW8mUzY38P+sgajl8bk/uAxcmUBTPo9yY8iF0zGn3s1byA0d2j8R3kpiOyiMlISkNeWVcsva3e72e2caEP4t2lpc6p570aWnYvCUsfifHbQzvoUqfEDql52U5wi++LhMI8aEpWQtJjap4F8MWqLGoQ6SwPHel7Q4NsK6aignARryF3ltZLWR61j2J6Y2gg3q/NDU2hKV4xfY2w8Br0A3bO4Y2ey0oLOZWhksLAFV+1jjMnPQKx0H62qTd4Vl83Ta2BvKyNaPGGkdCfYRHxfMTSBJBgUf/qlkaL/HK0yTwZxPnDz/+t55QoE5kuXGfbDbXT0/PhzN/4nvJ3VEG/+xNbMwMvj9Ljj/4gRijs/XiCUfZymxqzEBaHg3B/ETDdsnJglqex58tm5qc89ZqQKl5xm03Ln2jaqWo9fed/1Bfb8trDhxjW9CNjwRVekr9SL+S+dXkhKHp2KPI15Q0+ziRKFUpxeu8eDIOm29RX702+ZYvRysDNQHguOIRAd4AAABBTk1GYAQAAD4AAAIAAG8AAG4AAEYAAAJBTFBI/gAAAAEPMP8REQJubVuxm4s14IwGvBalUBqURimUQCjJf3EDHlxNBUT0fwIgjijQC1mgF7LAkxCFLPAkBCEJVE5CEJKQBTrhJAQhClmg4gQvBCEKSaDihJPgBOxlIQlRCC/x+Nk6wW+5ErZQ405G30q4pZ2IIwPAMAIGp2Z4kA4AxnQqiz65Sp6mMqGRfsIgM/rqRibcyGA0MuIgo1HIgLHCoAfJZN14KiSz1enqTiUaSVolo0/OQMJt6w/HdLJ+MbYAzn5RhGqERRO6ERc34TDSk25GXnShPYWLKhTLPQfKME5POoSb4Z/U3yAs2kuqEZ9U3ghGeo/xbnl1fInbZ1EBVlA4IEIDAAAQFwCdASpwAG8APpFAm0ilpCKhLRJqeLASCWkIcAAqTPs+/1XOwgxjHrUZaneA4X2FJ9s3yQ5r3p32B/5P/WfRA9dP7gewl+r45HLFRRFN3stJcfVY3jXVE7KFwvktT5n7wOdIBzNltXWek8oTQVeYxLK/cxPIaN89/41zIWCnY0K37+iOj16Qr7+eaacbS9ELhAGeJjfYqv9oPyB5eJ9Fq2J8FJEePohyB07lAXi9DVMT28QSZ1Mn7aIW/q608ktwAP5of6/E4i9hk7f/tVly+PKgvhpk94BB7NkAggutY61eM30xe4FK78zuML33uZzTcjWJYtzOx0A7F2ipCK7iKqDCCEDo+kC0+hoHLhEtyToRUxvlbAoBwGxp0T1GW6K10CZrT9IOCDzrLqIkJBWTZs/quhQXBZzRP5VB0A40VrP4TnE9ZA8u3lQe3zksR9uQ6VUblETAsisiKE7fgkejJIgdka/+qRjzZ0iVQg49ku14HYiQaXykvpx31Gm+1vPSC85aRtEomaDfIYsIZlif6pwlbQPsEA3ZGHF5mfHnkyY58/3luNhRGViVzNZoVBBuCTvbxbFx5D+eTaZ6tIEB1fmW+bGSGA3fiIi0ZT1cQOL67ij5FU/M2jwAR6JsAUyqOnQ3N/ORYr88bBY5/ArBgPCt9M3PNrZGmMW3F78ptwGLg7izi+0j5LrtGGhqvimrgMK0fGHzBkhU+FzwQSz+U/9iRlvkuKqo9hYOAl56mVCUrVhqAHp1dRuwcKlW40G6KLO5iVdWsz/ji1OnAjN8OzxbpcpRwnT9FdJvBr6o/T0cKWFY4Qv1aMZjXsbcvCXf6wiB3AAtTgsVUw3SlFNWdqOiYG6/Q9cnRu1f4HLaDXFM9rcOtuvrWIAD2Xej3EBJ1xLh8+mz2F4Rjo/+NWhmPl+rooKry+1maagZdbvaypM/XPMYtADLtiSFQIMGBAm1D8XU2TUAWrcd1cxG7k77IH/wMEeOqE4JGj3ZuPFv+8+YOZ5sfTZ44ehz0UkCJ8J9Lhqdg3arnPRXSaGh8Cwefeqs60yb1zbb+T0UnUuiTt1+TcgadI9qTvHqF8GMfIEcFCLTXb9WOlV3ISBwq3gAAAA=";
const MutationObserverConfig = {
childList: true,
subtree: true
};
const smoothOptions = {
behavior: "smooth",
block: "center",
inline: "center"
};
const instantOptions = {
behavior: "instant",
block: "center",
inline: "center"
};
//自定義站點規則
const customData = [{
name: "BEAUTYLEG 腿模",
link: "http://www.beautyleg.com/photo/show.php?no=1",
url: {
h: "beautyleg.com",
p: "/photo/show",
s: "no="
},
box: [".table_all", 2, 1054],
imgs: "a[href*='/album/']",
thumbs: "a[href*='/album/'] img",
button: [4],
insertImg: ["box", 2],
insertImgAF: () => fn.hideEle(".table_all"),
next: () => `?no=${Number(fn.getUSP("no")) + 1}`,
prev: () => `?no=${Number(fn.getUSP("no")) - 1}`,
customTitle: () => {
let [no, date] = fn.gae("tr span").map(e => fn.gt(e));
no = no.padStart(3, "0");
date = date.replace(/\d+$/, "").trim();
return `BEAUTYLEG 腿模(免費下載) No.${no} ${date}`;
},
category: "photo"
}, {
name: "KAI-YOU(カイユウ)",
url: {
h: "kai-you.net",
p: "/article/",
e: ".m-article-eyecatch-content-link,.m-article-images-main"
},
imgs: () => fn.clp("/images/") ? fn.gae(".m-article-images-main-swiper-slide-img") : fn.getImgA(".m-article-images-main-swiper-slide-img", [fn.gu(".m-article-eyecatch-content-link")]),
capture: () => _this.imgs(),
videos: () => fn.gae("div.youtube[data-video]").map(e => e.dataset.video),
customTitle: ".m-article-header-title,.m-article-image-title",
category: "photo"
}, {
name: "cureco beta",
url: {
h: ["cureco.jp"],
p: "/view/"
},
imgs: () => fn.getNP(".article_tweet:has(.triangle-border)", "#pager_box .next a", null, "#pager_box").then(() => fn.gae(".attach_image")),
capture: () => _this.imgs(),
customTitle: ".article_title",
category: "photo"
}, {
name: "豆瓣相册",
url: {
h: ["www.douban.com", "douban.com"],
p: "/album/",
d: "pc"
},
imgs: async () => {
let links;
let pages = fn.ge(".paginator .next");
if (pages) {
let max = fn.gt(".paginator .next", 2);
links = fn.arr(max, (v, i) => i == 0 ? fn.lp : fn.lp + `?m_start=${i * 18}`);
await fn.getEle(links, ".photolst a").then(eles => {
//links = eles.map(a => a.href);
thumbnailSrcArray = eles.map(a => fn.src("img", a));
});
} else {
//links = fn.gau(".photolst a");
thumbnailSrcArray = fn.getImgSrcArr(".photolst a img");
}
//return fn.getImgA(".image-show img", links);
return thumbnailSrcArray.map(e => e.replace("/s/", "/l/"));
},
category: "photo"
}, {
name: "豆瓣相册M",
url: {
h: ["www.douban.com", "douban.com"],
p: "/album/",
d: "m"
},
init: async () => {
await fn.wait(() => {
let button = fn.ge(".getmore-btn");
if (!!button) {
EClick(button);
}
return !button;
});
},
imgs: () => {
let links = fn.gau("ul.grid a");
thumbnailSrcArray = fn.getImgSrcArr("ul.grid a img");
return thumbnailSrcArray.map(e => e.replace("/s/", "/l/"));
},
customTitle: ".photo-info>h1",
category: "photo"
}, {
name: "百度 NewsPage",
reg: [
/^https?:\/\/baijiahao\.baidu\.com\/s\?id=\d+$/,
/^https?:\/\/mbd\.baidu\.com\/newspage\/data\/landingsuper\?context=/
],
init: () => fn.waitEle(["div[data-testid=article] img", "#header div"]),
imgs: "div[data-testid=article] img",
customTitle: "#header div",
category: "photo"
}, {
name: "交通部觀光署 桌布下載",
url: {
h: "www.taiwan.net.tw",
p: "m1.aspx",
s: "sNo=0012076"
},
imgs: ".media-download>a:last-child",
category: "photo"
}, {
name: "免費圖庫相片",
url: {
h: "www.pexels.com"
},
SPA: true,
init: async () => {
addNewTabViewButton();
const get = async () => {
let imgs = fn.gae("article[class^=MediaCard_card] img[srcset]:not(.get)");
if (imgs.length > 0) {
imgs.forEach(img => img.classList.add("get"));
fn.getImgSrcArr(imgs).forEach(src => {
if (!src.includes("/free") && !src.includes("/lib/avatars/")) {
src = src.replace(/\?.+$/, '');
setArray.add(src);
}
});
}
let videos = fn.gae("video[class^=VideoTag_video]:not(.get)");
if (videos.length > 0) {
videos.forEach(video => {
video.classList.add("get");
let src = video.src;
setVideoArray.add(src);
});
videoSrcArray = [...setVideoArray];
}
if (captureTotal != setArray.size) {
captureTotal = setArray.size;
await captureSrcB();
}
};
await get();
fn.addMutationObserver(async () => {
if (captureExclude()) return;
await get();
});
},
imgs: () => setArray,
capture: () => _this.imgs(),
infiniteCapture: 1,
downloadVideo: true,
category: "photo"
}, {
name: "wallhaven",
url: {
h: ["wallhaven.cc"],
e: "figure[data-wallpaper-id]"
},
SPA: true,
init: async () => {
addNewTabViewButton();
const get = async () => {
let figures = fn.gae("figure[data-wallpaper-id]:not(.get)");
if (figures.length > 0) {
figures.forEach(figure => {
figure.classList.add("get");
const id = figure.dataset.wallpaperId;
const isPng = !!fn.ge(".thumb-info .png", figure);
const ex = isPng ? "png" : "jpg";
const src = `https://w.wallhaven.cc/full/${id.substring(0, 2)}/wallhaven-${id}.${ex}`;
setArray.add(src);
});
}
if (captureTotal != setArray.size) {
captureTotal = setArray.size;
await captureSrcB();
}
};
await get();
fn.addMutationObserver(async () => {
if (captureExclude()) return;
await get();
});
},
imgs: () => setArray,
capture: () => _this.imgs(),
infiniteCapture: 1,
category: "photo"
}, {
name: "Behance",
url: {
h: "www.behance.net"
},
page: () => fn.clp("/gallery/"),
SPA: () => _this.page(),
observeURL: "head",
init: () => _this.page() ? fn.waitEle([
"div[class^='UniversalPopup-navigationLayer'],#primary-project-content",
"h1[class^='Project-title']",
".grid__item-image[srcset],picture source[srcset],.ImageElement-image-SRv"
]) : void 0,
imgs: () => {
if (!_this.page()) return [];
videoSrcArray = fn.gae(".Preview__project--topMargin iframe[src*='.vimeo.']").map(e => e.src);
return fn.getImgSrcset(".grid__item-image[srcset],#primary-project-content source[data-ut='project-module-source-original'],.ImageElement-image-SRv");
},
capture: () => _this.imgs(),
customTitle: () => _this.page() ? fn.waitEle("h1[class^='Project-title']").then(e => fn.gt(e)) : null,
category: "photo"
}, {
name: "kpopping",
url: {
h: "kpopping.com",
p: "/kpics/"
},
box: [".justified-gallery", 2],
imgs: ".justified-gallery a[data-fancybox]",
thums: ".justified-gallery a[data-fancybox] img",
button: [4],
insertImg: [
["box", 0, ".justified-gallery"], 2
],
customTitle: ".container h1",
fancybox: {
v: 3,
css: false
},
category: "photo"
}, {
name: "Irancartoon",
url: {
h: "www.irancartoon.com",
p: "/gallery/"
},
imgs: "#galls a",
thums: "#galls a img",
customTitle: ".post_title",
category: "photo"
}, {
name: "小黃書/8色人體攝影",
url: {
h: [
/xchina(-cn)?\./,
/^(tw\.)?8se\.me$/
],
p: /^\/(photo|amateur)\/id-\w+\.html$/,
e: ".photo-detail .item:has(>.icon>.fa-image)"
},
init: () => {
fn.run("$(document).off('keydown')");
const params = new URLSearchParams({
action: "getComments",
page: 1,
pageSize: 1000,
dataMode: "object",
"dataObject[mode]": "photo",
"dataObject[id]": location.pathname.split("/").at(-1).slice(3, -5),
withReplies: false
}).toString();
fetch("/ajax.php", {
"headers": {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8"
},
"body": params,
"method": "POST"
}).then(res => res.json()).then((json) => console.log("評論", json.data));
},
loop: () => {
document.body.removeAttribute("class");
document.body.removeAttribute("style");
},
imgs: async () => {
const {
videos,
domain
} = _unsafeWindow;
if (videos && domain) {
videoSrcArray = videos.map(e => domain + e.url);
}
const [, album_id] = /id-([^.]+)/.exec(fn.lp);
let [numP] = fn.gt(".photo-detail .item:has(>.icon>.fa-image)").match(/\d+/);
numP = Number(numP);
const [thumb_src] = fn.getImgSrcArr(".photo-items div.img,.amateur-items div.img");
const srcArrFn = (total, photoUrl = "https://img.xchina.io/photos/", mode = 1) => {
let suffix = ".jpg";
if (fn.lp.includes("/amateur/")) {
suffix = ".webp";
} else if (mode === 2) {
suffix = "_600x0.webp";
}
return fn.arr(total, (v, i) => photoUrl + album_id + "/" + String(i + 1).padStart(4, "0") + suffix);
};
if (!!thumb_src) {
const OOOI = thumb_src.endsWith("/0001_600x0.webp") || thumb_src.endsWith("/0001.webp");
const [photoUrl] = /^https?:\/\/[^\/]+\/[^\/]+\//.exec(thumb_src);
if (OOOI) {
thumbnailSrcArray = srcArrFn(numP, photoUrl, 2);
return srcArrFn(numP, photoUrl);
} else {
let max;
try {
let pageUrls = fn.gau(".pager a[href]");
let lastUrl = pageUrls.at(-1);
let [, lastNum] = lastUrl.match(/\/(\d+)\.html$/);
max = Number(lastNum);
} catch {
max = 1;
}
if (max > 1) {
await fn.getNP(".photo-items .item", ".pager span.current+a:not(.pager-next)", null, ".pager", 1500);
}
thumbnailSrcArray = fn.getImgSrcArr(".photo-items div.img");
if (numP != thumbnailSrcArray.length) {
setTimeout(() => {
fn.hideMsg();
fn.showMsg(DL.xchina_picnum_error, 5000);
}, 1500)
}
if (fn.lp.includes("amateur")) {
return thumbnailSrcArray;
} else {
return thumbnailSrcArray.map(e => e.replace("_600x0", "").replace(".webp", ".jpg"));
}
}
} else {
const srcArr = srcArrFn(numP);
const [first] = srcArr;
const check1 = await fn.checkImgStatus(first);
if (check1.ok) {
return srcArr;
} else {
const test_src = first.replace("/photos/", "/photos2/");
const check2 = await fn.checkImgStatus(test_src);
if (check2.ok) {
return srcArr.map(src => src.replace("/photos/", "/photos2/"));
} else {
return [];
}
}
}
},
button: [4],
insertImg: [".content-box:has([class*=items])", 2],
insertImgAF: () => fn.hideEle(".btn-group:has(.nav-prev,.nav-next)"),
customTitle: () => {
try {
let text = "";
let texts = [
".photo-detail .item:has(.fa-video-camera) a",
".photo-detail .item:has(.fa-video-camera) .joiner+a",
".photo-detail .item:has(.fa-calendar-days)",
".photo-detail .item:has(.fa-file)",
".photo-detail .model-avatar-container,.photo-detail .item:has(.fa-circle-user)",
".photo-detail .item:has(.fa-address-card)"
].map(s => document.querySelector(s)?.innerText);
// 大分類、小分類、日期、編號、模特名、寫真名
let [sort_a, sort_b, days, serial, model, album_title] = texts;
texts.forEach((t, i, a) => {
if (a.length - 1 == i && !!model) {
if (t.includes(model)) {
// 寫真名含模特名則刪掉模特名
text = text.replace(model, "");
}
}
if (!!t && t?.length > 0) {
text += " " + t;
}
if (i == 0 && !!sort_a) {
text += " -";
}
});
if (location.pathname.includes("/amateur/")) {
// 補上業餘自拍
text = document.querySelector(".fa-angles-right+a").innerText + " -" + text;
}
if (text.includes("秀人")) {
text = text.replace("Vol. ", "NO.");
} else {
text = text.replace("Vol. ", "Vol.");
}
text = text.replace(/(\d+)-(\d+)-(\d+)/, "$1.$2.$3");
text = text.replace(" 秀人网 ", " [Xiuren秀人网] ").replace(" 秀人網 ", " [Xiuren秀人網] ")
.replace("各国其他套图 -", "").replace("各國其他套圖 -", "")
.replace("其他地区套图", "").replace("其他地區套圖", "")
.replace("其他套图 -", "").replace("其他套圖 -", "")
.trim();
if (text.includes("其他中国工作室") || text.includes("其他中國工作室")) {
let t = document.querySelector(".photo-detail .item:has(.fa-filter)")?.innerText;
if (!!t && t?.length > 0) {
// 換成工作室名稱
text = text.replace(/其他中国工作室|其他中國工作室/, t);
}
}
if (text.includes("Graphis")) {
let t = document.querySelector(".photo-detail .item:has(.fa-filter)")?.innerText;
if (!!t && t?.length > 0) {
// 加上Graphis的子機構
text = text.replace("Graphis", "Graphis " + t);
}
}
return fn.dt({
t: text
});
} catch (e) {
return fn.dt({
t: document.title
});
}
},
hide: ".push-top-container,div[class*='backdrop-show'],.modal-overlay,.content-box:has([class^='static-container']),div[clickmode],.item:has([clickmode],[class*=exoclick],.a-media,iframe)",
downloadVideo: true,
category: "nsfw2"
}, {
name: "小黃書/8色人體攝影 AD",
url: {
h: [
/xchina\./,
/^(tw\.)?8se\.me$/
]
},
init: () => fn.addMutationObserver(() => fn.remove("[class*='exoclick']")),
loop: () => {
document.body.removeAttribute("class");
document.body.removeAttribute("style");
},
hide: ".push-top-container,div[class*='backdrop-show'],.modal-overlay,.content-box:has([class^='static-container']),div[clickmode],.item:has([clickmode],[class*=exoclick],.a-media,iframe)",
category: "ad"
}, {
name: "绅士会所",
host: ["www.hentaiclub.net"],
url: {
t: "绅士会所",
p: "/r"
},
imgs: "div[data-fancybox]",
button: [4],
insertImg: [
["#masonry", 2, "#masonry"], 2
],
customTitle: ".post-info-text",
fancybox: {
v: 3,
css: false
},
hide: ".banner-top",
category: "nsfw2"
}, {
name: "NLegs/HoneyLeg/Lady Lap/Nuyet/LegBabe", //需搭配專用腳本 https://greasyfork.org/scripts/463123
host: ["www.nlegs.com", "www.honeyleg.com", "www.ladylap.com", "www.nuyet.com", "www.legbabe.com"],
reg: [
/^https?:\/\/www\.nlegs\.com\/girls\/\d+\/\d+\/\d+\/\d+\.html$/,
/^https?:\/\/www\.honeyleg\.com\/article\/\d+\/\d+\/\d+\/\d+\.html$/,
/^https?:\/\/www\.ladylap\.com\/show\//,
/^https?:\/\/www\.nuyet\.com\/gallery\//,
/^https?:\/\/www\.legbabe\.com\/hot\/[^\.]+\.html$/
],
imgs: ".col-md-12.col-xs-12 img[src^=blob],.col-md-12.col-lg-12 img[src^=blob]",
repeat: 1,
button: [4],
insertImg: ["//div[img[starts-with(@src,'blob')]]", 0],
customTitle: "[class^=container] p",
category: "nsfw2"
}, {
name: "雅拉伊", //免VIP僅支援PC版和圖片命名是簡單數字遞增的。
url: {
h: ["www.yalayi.com"],
p: "/gallery/"
},
imgs: async () => {
await fn.waitEle(".bigimg>img");
let [max] = fn.gt(".tishiwenzi-box").match(/\d+/);
let img = fn.ge(".bigimg>img");
let dir = fn.dir(img.dataset.original);
let testArr = [dir + "1.jpg", dir + "01.jpg", dir + "001.jpg", dir + "0001.jpg"];
let ok = false;
let pad = 1;
for (let [i, test] of testArr.entries()) {
let obj = await fn.checkImgStatus(test);
console.log(`確認圖片[${i}]`, obj);
if (obj.ok) {
ok = true;
pad = i + 1;
break;
}
}
if (ok) {
return [img.src, ...fn.arr(max, (v, i) => dir + String(i + 1).padStart(pad, "0") + ".jpg")];
} else {
return [];
}
},
button: [4, "24%", 4],
insertImg: [".bigimg", 2],
customTitle: () => fn.title(" - ", 3),
category: "nsfw1"
}, {
name: "JKF",
host: ["www.jkforum.net"],
reg: /^https?:\/\/www\.jkforum\.net\/(p\/)?thread/,
init: () => fn.waitEle("img[id^=aimg]"),
imgs: () => isM ? fn.gae("img[id^=aimg]:not([style])") : fn.gae("img[id^=aimg][zoomfile]"),
capture: () => _this.imgs(),
customTitle: ".title-hd h1,.post-title",
category: "nsfw2"
}, {
name: "草榴社區",
host: ["www.t66y.com", "cl.6962x.xyz"],
url: {
e: ["//div[@id='header']//b[text()='草榴社區' or text()='草榴社区']", "img[ess-data]"],
p: /^\/htm_data\/\d+\/\d+\/\d+\.html$/
},
imgs: () => fn.fetchDoc(fn.url).then(dom => fn.gae("img[ess-data]", dom)),
capture: () => _this.imgs(),
customTitle: "h4.f16",
category: "nsfw2"
}, {
name: "24FA",
host: ["www.24fa.com"],
link: "https://www.24fa.com/c49.aspx",
url: {
t: "24FA",
p: ".aspx",
e: ["#content img", ".pager"]
},
init: "document.onkeydown=null",
imgs: () => fn.getImgA("#content img", ".pager a:not([title])"),
button: [4],
insertImg: ["#content", 2],
autoDownload: [0],
next: ".prevNews>a",
prev: ".nextNews>a",
customTitle: "h1",
hide: "body>ins",
category: "nsfw2"
}, {
name: "Depvailon格式",
host: [
"www.depvailon.com",
"nungvl.net",
"www.kaizty.com",
"lootiu.com",
"thismore.fun",
"cosxuxi.club",
"nutrientchoices.com",
"baobua.com"
],
reg: [
/^https?:\/\/www\.depvailon\.com\/[^\.]+\.html/,
/^https?:\/\/cosxuxi\.club\/[^\.]+\.html/,
/^https?:\/\/nutrientchoices\.com\/[^\.]+\.html/,
/^https?:\/\/www\.kaizty\.com\/photos\//,
/^https?:\/\/nungvl\.net\/gallerys\//,
/^https?:\/\/lootiu\.com\/gallery\//,
/^https?:\/\/thismore\.fun\/view\//,
/^https?:\/\/baobua\.com\/post\//
],
clearEvent: true,
init: async () => {
await fn.waitVar("jQuery");
fn.run("jQuery(document).off() && jQuery('body').off()");
fn.remove(".mobiletop");
},
box: [".contentme,.contentme2", 2],
imgs: async () => {
let max;
try {
let text = fn.gt("h1,h2");
if (text?.includes("|")) {
[max] = text.match(/\d+$/);
} else {
max = 1;
}
} catch {
max = 1;
}
return /\?m=1/.test(siteUrl) ? await fn.getImg(".contentme img,.contentme2 img", max, "8") : await fn.getImg(".contentme img,.contentme2 img", max);
},
button: [4],
insertImg: [
["box", 0, ".contentme,.contentme2"], 2
],
endColor: "white",
customTitle: () => fn.dt({
t: document.title.split("|")[0],
d: [
/^[a-z-\s\.]+:/i,
"NứngVL.net:",
/Nude Chinese Model Uncensored Gallery[\s\d–]+/,
" – Chinese Beauties",
" – DVL"
]
}),
category: "nsfw2"
}, {
name: "Hit-x-Hot格式",
url: {
h: ["www.hitxhot.org", "www.dongojyousan.com"],
p: ["/gallerys/", "/articles/"]
},
clearEvent: true,
imgs: () => fn.getImgA(".VKSUBTSWA img", "div[id^=post] a"),
button: [4],
insertImg: [".VKSUBTSWA", 2],
insertImgAF: () => fn.remove(".pagination,h3+.HCRIN"),
customTitle: () => fn.title(/^[a-z-\s\.I]+:/i).split("|")[0].trim(),
category: "nsfw2"
}, {
name: "RedSeats.Org格式",
url: {
h: ["redseats.org", "cn.looives.com"],
p: ["/gallery/", "/view/"]
},
imgs: async () => {
let links = fn.gau("div[id^=post] a");
links.unshift(fn.url);
fn.showMsg(DL.str_14, 0);
let loop = true;
let pn = 13;
let fetchNum = 1;
const getNext = () => {
return fn.fetchDoc(fn.lp + "?page=" + pn).then(dom => {
fn.showMsg(`${DL.str_14} (Page${fetchNum += 1})`, 0);
if (fn.ge("div[id^=post]", dom)) {
links = [...links, ...fn.gau("div[id^=post] a", dom)];
} else {
loop = false;
}
});
};
while (loop) {
await getNext();
pn += 12;
}
return fn.getImgA(".VKSUBTSWA img", links);
},
button: [4],
insertImg: [".VKSUBTSWA", 2],
insertImgAF: () => fn.remove("h3+.HCRIN"),
customTitle: () => fn.dt({
t: fn.title(/^[a-z-\s\.I]+:/i).split("|")[0].trim(),
d: " - 1.jpg"
}),
category: "nsfw2"
}, {
name: "TGStat Show more",
reg: /^https?:\/\/([a-z]{2}\.)?tgstat\.com\//,
observerClick: "//button[contains(text(),'Show more')]",
category: "autoPager"
}, {
name: "Telegram Web",
url: {
h: ["telegra.ph"]
},
imgs: () => fn.showMsg(DL.str_01, 0).then(() => fn.fetchDoc(fn.url).then(dom => fn.gae(".tl_article img", dom))),
capture: () => _this.imgs(),
customTitle: "h1",
category: "nsfw2"
}, {
name: "Rentry.co",
url: {
h: ["rentry.co"]
},
imgs: "img",
customTitle: "h1",
category: "nsfw2"
}, {
name: "新闻吧/新闻屋/新娱乐在线/新娱乐网/福建热线/山东热线/广西热线/武汉热线/天津热线/云南热线/甘肃热线",
link: "https://www.xinwenba.net/web/meinv/",
url: {
h: [
/\.xinwenba\.net$/,
/\.xwbar\.com$/,
/\.dv67\.com$/,
/\.xinent\.net$/,
/\.fjrx\.org$/,
/\.sdrx\.org$/,
/\.gxrx\.org$/,
/\.whrx\.org$/,
/\.tjrx\.org$/,
/\.ynrx\.org$/,
/\.gsrx\.org$/,
/\.xwwu\.net$/
],
p: /^\/web\/info\/\d+-\d+\.html$/,
e: ".main img"
},
box: [".main", 1],
imgs: () => {
let [max] = fn.gt(".page-link").match(/\d+/);
return fn.getImg(".main img", max, "5");
},
button: [4],
insertImg: [
["box", 0, ".view_img .main"], 2
],
insertImgAF: (p, b) => {
let text = fn.ge(".main .txt,.info_imgs>.txt");
if (text) {
insertBefore(b, text);
}
fn.remove(".info_imgs>.main,.info_imgs>.page-item");
},
autoDownload: [0],
next: "//li[text()='上篇:']/a",
prev: "//li[text()='下篇:']/a",
customTitle: ".title>h1",
hide: "div.web",
category: "nsfw1"
}, {
name: "四海资讯/娱乐吧/娱乐屋/娱乐宝/新闻宝",
link: "https://www.shzx.org/b/12-0.html",
url: {
h: [
/\.shzx\.org$/,
/\.yuleba\.org$/,
/\.entba\.net$/,
/\.entwu\.com$/,
/\.xwbzx\.com$/,
/\.entbao\.com$/
],
p: [/\/web\/info\/[\d-]+\.html$/, /\/a\/[\d-]+\.html$/],
e: ".main img"
},
imgs: () => {
let [max] = fn.gt(".paging>a").match(/\d+/);
let url = fn.lp.replace(/-\d+\.html$/, "");
let links = fn.arr(max, (v, i) => url + `-${i}.html`);
return fn.getImgA(".main img", links);
},
button: [4],
insertImg: [".main", 2],
insertImgAF: (p, b) => {
let text = fn.ge(".info_imgs>.txt");
if (text) {
insertBefore(b, text);
}
fn.remove(".paging");
},
autoDownload: [0],
next: "//li[text()='上一篇:']/a",
prev: "//li[text()='下一篇:']/a",
customTitle: ".title>h1",
hide: "div.web",
category: "nsfw1"
}, {
name: "留园酷",
host: ["www.cool18.com", "wap.cool18.com"],
reg: [
/^https?:\/\/www\.cool18\.com\/bbs\d*\/index\.php\?app=forum&act=threadview&tid=\d+/,
/^https?:\/\/wap\.cool18\.com\/index\.php\?app=index&act=view&cid=\d+/
],
imgs: "img[mydatasrc],#shownewsc img,.show_content img,img[data-fancybox]",
customTitle: ".main-title,.show_content b,h1.article-tit",
gallery: 1,
hide: ".img_ad_list",
category: "nsfw2"
}, {
name: "我为人人",
host: ["2048.info", "2048.cc"],
url: {
e: "link[rel][title$='人人']",
p: "/read.php",
s: "tid=",
},
imgs: "#read_tpc img",
customTitle: "#subject_tpc",
category: "nsfw2"
}, {
name: "4096社区",
host: ["www.4096bbs.com", "4096bbs.com"],
url: {
e: ".wp a[title^='4096社区'],meta[content*='4096社区']",
p: "/thread"
},
imgs: "td[id^='postmessage'] img,.view_tit+div[id^=pid] img",
customTitle: "#thread_subject,.view_tit",
category: "nsfw2"
}, {
name: "梦想岛",
host: ["www.mmxxdd.com", "www.mmdd.cc"],
link: "https://www.mmxxdd.com/website.html",
url: () => {
let ca = fn.checkUrl({
e: [".logo img[alt=梦想岛],.logo img[alt=夢想島]", ".gallerypic img"],
p: "/gallery/"
});
let cb = fn.checkUrl({
t: ["梦想岛", "夢想島"],
p: "/gallery/"
});
let cc = false;
if (fn.clp(/^\/gallery\/\d+\.html$/)) {
cc = !!document?.documentElement?.innerHTML?.includes("梦想岛");
}
return ca || cb || cc;
},
init: () => fn.waitEle(".gallerypic img"),
test: async (max) => {
let [src] = fn.getImgSrcArr(".gallerypic img").sort();
let dir = fn.dir(src);
let f = src.split("/").at(-1);
let ex = f.split(".").at(-1);
ex = "." + ex;
let [num] = f.match(/\d+/);
num = Number(num);
let srcs = [];
let successNum = 0;
let testNum = 0;
let testSrc;
let loop = true;
while (loop) {
fn.showMsg(`test:${num} | success:${successNum}/${max}`, 0);
testSrc = dir + num + ex;
let status = await fn.xhrHEAD(testSrc).then(res => res.status);
if (status == 200) {
srcs.push(testSrc);
successNum += 1;
if (testNum > 500 || successNum >= max) {
loop = false;
}
}
testNum += 1;
num += 1;
}
return srcs;
},
imgs: async () => {
let src = fn.src(".gallerypic img");
if (!src) return [];
let dir = fn.dir(src);
let f = src.split("/").at(-1);
let [num] = f.match(/\d+/);
let ex = ".jpg";
let [max] = fn.gt(".gallery_img label").match(/\d+/);
if (num?.length == 1 && num == 0) {
return fn.arr(max, (v, i) => dir + i + ex);
} else if (num?.length == 3 && Number(num) == 1) {
return fn.arr(max, (v, i) => dir + String(i + 1).padStart(3, "0") + ex);
} else if (isNumber(Number(num))) {
let tfs = fn.getImgSrcArr(".gallerypic img").map(e => e.split("/").at(-1));
let mode = prompt("thums:" + String(tfs) + "\nMode:\n1. [0.jpg]\n2. [1.jpg]\n3. [001.jpg]\n4. [test()]", 1);
if (mode == 1) {
return fn.arr(max, (v, i) => dir + i + ex);
} else if (mode == 2) {
return fn.arr(max, (v, i) => dir + (i + 1) + ex);
} else if (mode == 3) {
return fn.arr(max, (v, i) => dir + String(i + 1).padStart(3, "0") + ex);
} else if (mode == 4) {
return _this.test(max);
} else {
return fn.gae(".gallerypic img");
}
} else {
return fn.gae(".gallerypic img");
}
},
capture: () => _this.imgs(),
customTitle: () => fn.title(" - 梦想岛"),
category: "nsfw1"
}, {
name: "魅影画廊",
host: ["www.wc1.es", "wc1.es", "www.jb9.es", "jb9.es"],
url: {
t: "魅影画廊"
},
box: [".gallery", 2],
imgs: () => fn.gau(".gallery .gallery-item a").map(u => u.replace("-scaled", "")),
thums: ".gallery .gallery-item img",
button: [4],
insertImg: [
["box", 0, ".gallery"], 2
],
customTitle: () => {
let text = fn.gt(".article-title");
let m = text.match(/(\d+)/);
if (m) {
text = fn.dt({
t: text
});
let [num] = m[0].match(/\d+/);
return text + " No." + num;
} else {
return text;
}
},
hide: ".modown-ad",
fancybox: {
v: 3,
css: false
},
category: "nsfw1"
}, {
name: "MOMO图库",
host: ["mo8.org"],
url: {
t: "MOMO图库"
},
srcset: ".entry-content img[srcset]",
button: [4],
insertImg: [".entry-content", 2],
autoDownload: [0],
next: ".nav-previous a",
prev: ".nav-next a",
customTitle: ".entry-title",
category: "nsfw1"
}, {
name: "写真门",
host: ["xzm2048.com"],
url: {
t: "写真门",
e: [".logo a[title$=写真门]", ".article-content img[src*='/cover.jpg'],.article-content img[src*='/0001.jpg']"]
},
imgs: () => {
let g_num = prompt("请输入图片总数", 100);
let src = fn.src(".article-content img");
let dir = fn.dir(src);
let srcs = src.includes("/cover.jpg") ? [src] : [];
for (let i = 1; i <= Number(g_num); i++) {
src = dir + String(i).padStart(4, "0") + ".jpg";
srcs.push(src);
}
return srcs;
},
repeat: 1,
customTitle: "h1.article-title",
category: "nsfw1"
}, {
name: "御女控",
url: {
h: "www.yunvkong.com",
p: ".html",
e: ".ptm"
},
init: () => tempEles.push(fn.ge(".ptm .cl")),
imgs: () => fn.getNP(".ptm .cl:has(a>img)", ".ptm a[href$=html]").then(() => fn.gae("#showimages .ptm img")),
button: [4],
insertImg: [".ptm", 1],
insertImgAF: (_, bar) => bar.before(...tempEles),
autoDownload: [0],
next: "a.imgpage-left[href$=html]",
prev: "a.imgpage-right[href$=html]",
customTitle: "#showimages h2",
hide: ".ptm .cl[style]",
category: "nsfw1"
}, {
name: "御女控",
host: ["www.yunvkong.com"],
url: {
h: "www.yunvkong.com",
p: ".html",
e: [".showtitle .mlw", "#showimgXFL img"]
},
box: ["#showimgXFL p,#showimgXFL>img", 1],
imgs: () => {
let max = Number(fn.gt(".showtitle .mlw").match(/\d+/g).at(-1));
return (max > 1) ? fn.getImg("#showimgXFL img", max, 9) : fn.gae("#showimgXFL img");
},
button: [4],
insertImg: [
["box", 0, "#showimgXFL p,#showimgXFL>img,#pageNum"], 2
],
autoDownload: [0],
next: "a.imgpage-left[href$=html]",
prev: "a.imgpage-right[href$=html]",
customTitle: ".showtitle h2",
hide: ".pcad_1_w",
category: "nsfw1"
}, {
name: "御女控M",
host: ["m.yunvkong.com"],
url: {
h: "m.yunvkong.com",
p: ".html",
e: ".contimgw"
},
imgs: () => fn.getNP(".contimgw>*", ".contimgw a[href$=html]").then(() => fn.gae(".contimgw img")),
button: [4],
insertImg: [".contimgw", 1],
autoDownload: [0],
next: "//a[contains(text(),'上一组图')][starts-with(@href,'/')]",
prev: "//a[contains(text(),'下一组图')][starts-with(@href,'/')]",
customTitle: ".imgTitle-name",
category: "nsfw1"
}, {
name: "御女控M",
host: ["m.yunvkong.com"],
url: {
h: "m.yunvkong.com",
p: ".html"
},
box: [".img-box", 1],
button: [4],
imgs: () => {
let pages = fn.ge("a[title=Page]");
if (pages) {
let [, max] = fn.gt(pages).match(/\d+/g);
max = Number(max);
return fn.getImg(".img-box img", max, 9);
}
return fn.gae(".img-box img");
},
insertImg: [
["box", 0, ".img-box,a[title=Page],a[title=Page]~a,a[title=Page]~b"], 2
],
autoDownload: [0],
next: "//a[contains(text(),'上一组图')][starts-with(@href,'/')]",
prev: "//a[contains(text(),'下一组图')][starts-with(@href,'/')]",
customTitle: ".imgTitle-name",
category: "nsfw1"
}, {
name: "秀人集",
host: ["25.xy09.my"],
url: {
e: "//div[@class='item_info']//a[text()='秀人集']",
p: /\/\w+\/\d+\.html$/
},
init: () => {
let pag = fn.gae(".page");
if (pag.length > 0) pag[0].remove();
},
imgs: () => fn.getImg(".content>p img[alt]", fn.gt(".page a:last-child", 2), 3, null, 100),
button: [4],
insertImg: ["//div[p[img[@alt]]]", 2],
autoDownload: [0],
next: "//span[contains(text(),'下一篇')]/a[contains(@href,'html')]",
prev: "//span[contains(text(),'上一篇')]/a[contains(@href,'html')]",
customTitle: ".item_title>h1",
hide: ".content br",
category: "nsfw1"
}, {
name: "秀人美女網",
host: ["www.xiu01.top"],
url: {
e: "//div[@class='single-cat']/a[text()='秀人美女网']",
p: /\/\w+\/\d+\/\d+\.html$/
},
imgs: () => fn.getImg(".content p img[alt]", fn.gt(".page a:last-child", 2), 3, null, 100),
button: [4],
insertImg: ["//div[p[img[@alt]]]", 2],
autoDownload: [0],
next: "//span[contains(text(),'下一篇')]/a[contains(@href,'html')]",
prev: "//span[contains(text(),'上一篇')]/a[contains(@href,'html')]",
customTitle: ".item_title>h1",
hide: ".item_info>a,p[align='center']:has(>img),.item_title>div[id],.item_title>a,.content br,.bottom_fixed,.update_area_lists>div[id]",
category: "nsfw1"
}, {
name: "极品性感美女",
host: ["www.xinggan5.top", "尤物网.Com"],
url: {
e: "//div[@class='toptip']/a[text()='极品性感美女']",
p: /\/\w+\/\w+\.html$/
},
init: () => {
let pag = fn.gae(".pagination");
if (pag.length > 0) pag[0].remove();
let p = fn.gae("//article/p[not(img)]");
if (p.length > 0) {
let te = fn.ge(".article-content");
p.forEach(e => insertBefore(te, e));
}
},
imgs: () => fn.getImg(".article-content img[alt]", fn.gt("a.current~*:last-child", 2), 3, null, 100),
button: [4],
insertImg: [
["//div[@class='pagination'][last()]", 1, "//p[img[@alt]]"], 2
],
autoDownload: [0],
next: ".article-nav-next>a[href$=html]",
prev: ".article-nav-prev>a[href$=html]",
customTitle: ".article-title",
hide: ".article-header>div[id],.article-header>a,.article-content br,img[src*='zz1.gif'],.bottom_fixed,.article-content~a,#bottom-banner,.content>div[id]",
category: "nsfw1"
}, {
name: "性感美女",
host: ["www.5201025.xyz"],
url: {
e: "//h1[@class='logo']/a[@title='性感美女尤物']",
p: /\/\w+\/\w+\.html$/
},
init: () => {
let pag = fn.gae(".pagination");
if (pag.length > 0) pag[0].remove();
let p = fn.gae("//article/p[not(img)]");
if (p.length > 0) {
let te = fn.ge(".article-content");
p.forEach(e => insertBefore(te, e));
}
},
imgs: () => fn.getImg(".article-content img[alt]", fn.gt("a.current~*:last-child", 2), 6),
button: [4],
insertImg: [
["//div[@class='pagination'][last()]", 1, "//p[img[@alt]]"], 2
],
autoDownload: [0],
next: ".article-nav-next>a[href$=html]",
prev: ".article-nav-prev>a[href$=html]",
customTitle: ".article-title",
hide: "center.x-abc",
category: "nsfw1"
}, {
name: "爱美女网",
host: ["a1.imn1.vip"],
url: {
e: "//section[@class='container']//a[text()='爱美女网']",
p: /\/\w+\/\w+\.html$/
},
imgs: () => fn.getImg(".imgwebp p img[alt]", fn.gt(".page a:last-child", 2), 3, null, 100),
button: [4],
insertImg: ["//div[p[img[@alt]]]", 2],
autoDownload: [0],
next: "//span/b[contains(text(),'下一篇')]/a[contains(@href,'html')]",
prev: "//span/b[contains(text(),'上一篇')]/a[contains(@href,'html')]",
customTitle: ".focusbox h1+div",
hide: ".imgwebp br,img[src*='zz2.gif'],p:has(>a[title][alt]>img)",
category: "nsfw1"
}, {
name: "爱看美女网",
host: ["www.ik009.top"],
url: {
e: ["//i[@class='iconfont icon-shouye']/following-sibling::a[text()='爱看美女网']", ".info-pagebar>a"],
p: /^\/\w+\/\d+\.html$/
},
init: () => {
let pag = fn.gae(".pagebar");
if (pag.length > 0) pag[0].remove();
},
imgs: () => fn.getImg(".info-imtg-box img[alt]", fn.gt(".pagebar>*:last-child", 2), 3, null, 100),
button: [4],
insertImg: ["//p[img[@alt]]", 2],
autoDownload: [0],
next: ".info-next li:last-child a",
prev: ".info-next li:first-child a",
customTitle: "h1",
category: "nsfw1"
}, {
name: "美人图",
url: {
h: "meirentu",
p: /\/pic\/\d+\.html$/
},
imgs: () => fn.getImg(".content_left img[alt]", fn.gt(".page a:last-child", 2), 5),
button: [4],
insertImg: [".content_left", 2],
autoDownload: [0],
next: "//span[contains(text(),'下一篇')]/a[contains(@href,'html')]",
prev: "//span[contains(text(),'上一篇')]/a[contains(@href,'html')]",
customTitle: ".item_title>h1",
hide: "img[alt]~br",
category: "nsfw1"
}, {
name: "卡卡美女网",
url: {
h: "kaka234",
p: /^\/HTM\/\w+\/(\w+\/)?\d+\/\d+\/\d+\.html$/
},
init: () => {
let ele = fn.ge(".PsBox");
if (ele) {
let te = ele.parentNode;
insertBefore(te, ele);
}
},
imgs: () => {
let max = Number(fn.gt(".dede_pages li>a,.article_page li>a")?.match(/\d+/)) || 1;
return fn.getImg(".content img,.ArticleImageBox img", max, 9);
},
button: [4],
insertImg: ["//div[@class='content'] | //div[div[@class='ArticleImageBox']]", 2],
autoDownload: [0],
next: () => {
let next = fn.ge("//li[contains(text(),'上一篇')]/a");
return next ? next.href : null;
},
prev: 1,
customTitle: ".Title>h1,.PsBox",
hide: ".m_adv",
category: "nsfw1"
}, {
name: "高清图片吧",
host: ["www.pic881.cc"],
reg: /^https?:\/\/www\.pic\d+\.cc\/\w+\/\d+\/\d+\.html$/,
imgs: () => {
let max = fn.gt(".page>*:last-child");
return fn.getImg(".content img,.ArticleImageBox img", max, 9);
},
button: [4],
insertImg: [".content", 2],
customTitle: "//div[@class='Title111']/h3[not(a)]",
hide: ".center:has(>.dibu1),.center:has(>.dibu2)",
category: "nsfw1"
}, {
name: "高清图片吧M/美女写真网M/美女图片网M/聚图美女网M",
host: ["m.pic881.cc", "m.ku138.cc", "m.tu99663.cc", "m.jutu1232.cc"],
reg: [
/^https?:\/\/m\.pic\d+\.cc\/\w+\/\d+\/\d+\.html$/,
/^https?:\/\/m\.ku\d+\.cc\/\w+\/\d+\/\d+\.html$/,
/^https?:\/\/m\.tu\d+\.cc\/\w+\/\d+\/\d+\.html$/,
/^https?:\/\/m\.jutu\d+\.cc\/\w+\/\w+\/\d+\.html$/
],
box: [".PsBox", 2],
imgs: ".ArticleImageBox>img",
button: [4],
insertImg: [
["box", 0, ".ArticleImageBox,.m_adv,.m_kanp"], 2
],
customTitle: ".PsBox",
hide: ".m_adv,.m_kanp",
category: "nsfw1"
}, {
name: "美女写真网",
host: ["www.ku138.cc"],
reg: /^https?:\/\/www\.ku\d+\.cc\/\w+\/\d+\/\d+\.html$/,
imgs: () => fn.getImgA(".content img", ".page>a[href]"),
button: [4],
insertImg: [".content", 2],
customTitle: () => fn.ge("meta[name=keywords]").content,
hide: ".center:has(>.dibu1),.center:has(>.dibu2)",
category: "nsfw1"
}, {
name: "美女图片网",
host: ["www.tu99663.cc"],
url: {
t: "tu963.com",
p: "/y/"
},
imgs: () => {
let max = Number(fn.gt(".articleV4Page a")?.match(/\d+/)) || 1;
return fn.getImg(".content img", max, 9);
},
button: [4],
insertImg: [".content", 2],
customTitle: ".articleV4Tit",
hide: ".dibu1,.dibu2",
category: "nsfw1"
}, {
name: "聚图美女网",
host: ["www.jutu1232.cc"],
url: {
t: "jutu123.com",
p: /^\/huhu\/soso\d+\/\d+\.html$/
},
imgs: () => {
let max = Number(fn.gt(".pages>a")?.match(/\d+/)) || 1;
return fn.getImg(".content img", max, 9);
},
button: [4],
insertImg: [".content", 2],
customTitle: "//div[@class='content']/preceding-sibling::div[1]/h9",
hide: ".link2",
category: "nsfw1"
}, {
name: "美女目录网 列表模式",
url: {
h: ["www.girldir.com"],
p: "_list/"
},
imgs: async () => {
await fn.getNP(".list-page-box>.item", ".pagination a.active+a", null, ".pagination", 2000);
thumbnailSrcArray = fn.getImgSrcArr(".list-page-box img");
return thumbnailSrcArray.map(e => e.replace(".medium.", ".big."));
},
button: [4],
insertImg: [".list-page-box", 2],
customTitle: () => fn.dt({
d: " - 美女目录网"
}),
category: "nsfw1"
}, {
name: "美眉村",
host: ["meimeicun.top", "www.meimeicun.top", "193.123.238.234"],
url: {
t: "美眉村",
p: "/articles/"
},
imgs: ".images-list img",
autoDownload: [0],
next: "//div[contains(text(),'上一篇')]/a",
prev: "//div[contains(text(),'下一篇')]/a",
customTitle: ".title",
category: "nsfw1"
}, {
name: "ROSI写真",
host: ["www.rosipic.com", "rosipic.com"],
reg: /^https?:\/\/(www\.)?rosipic\.com\/rosi\/\d+\.html$/i,
imgs: () => fn.gau("a.spotlight").map(u => u.replace("https://wsrv.nl/?url=", "").replace(/&blur=\d+/, "")),
button: [4],
insertImg: [
["#waterfall-container", 2], 2
],
category: "nsfw1"
}, {
name: "ROSI美女写真",
host: ["www.rosixz.cc", "www.rosixiezhen.cc", "rosixiezhen.cc", "www.rosi985.com", "www.rosi365.cc", "www.rosi360.cc", "www.2meinv.cc", "www.silk-necktie.com"],
url: {
h: [
/^(www\.)?rosixz\.\w+$/,
/^(www\.)?rosixiezhen\.\w+$/,
/^(www\.)?rosi\d{3}\.\w+$/,
/^(www\.)?\dmeinv\.cc$/,
/^www\.silk-necktie\.com$/
],
p: /^\/\w+\/\w+\.html$/,
ee: "//span/a[text()='ROSI视频']"
},
init: () => {
let pag = fn.gae(".pagination2");
if (pag.length > 0) pag[0].remove();
fn.remove(".content>b,.content>br,.asst");
},
imgs: () => {
let max = Number(fn.gt("//a[contains(text(),'共')]")?.match(/\d+/)) || 1;
return fn.getImg(".article-content img", max, 9);
},
button: [4],
insertImg: [".article-content", 2],
autoDownload: [0],
next: ".article-nav-prev>a",
prev: ".article-nav-next>.a",
customTitle: ".article-title",
category: "nsfw1"
}, {
name: "ROSI小莉最新写真",
host: ["www.rosimm.top"],
url: {
t: "ROSI小莉写真官网",
p: /^\/html\/\d+$/
},
imgs: () => fn.getImgA("article img", ".page-links a"),
button: [4],
insertImg: ["article.post", 2],
autoDownload: [0],
next: ".nav-previous>a",
prev: ".nav-next>a",
customTitle: "h1.entry-title",
category: "nsfw1"
}, {
name: "闺秀网",
url: {
h: ["www.guixiu.org", "guixiu.org"],
p: "/post/"
},
imgs: () => fn.getImgA("#lightgallery img", "#ipage a[href*=ipage]"),
button: [4],
insertImg: ["#lightgallery", 2],
customTitle: ".focusbox-title",
category: "nsfw1"
}, {
name: "素拾网",
url: {
h: "sushixz.net",
e: ".m-list-content"
},
imgs: () => {
let pages = fn.ge(".link_pages");
if (pages) {
let max = fn.gt(".link_pages>a[title=Page]").match(/\d+/g).at(-1);
let links = fn.arr(max, (v, i) => i == 0 ? fn.url : fn.url + `_${i + 1}`);
return fn.getImgA(".m-list-content img", links);
} else {
return fn.gae(".m-list-content img");
}
},
button: [4],
insertImg: [".m-list-content", 2],
autoDownload: [0],
next: ".sxpage_l a",
prev: ".sxpage_r a",
customTitle: ".article h2",
category: "nsfw1"
}, {
name: "悄悄的看2019",
url: {
h: ["qqdk2019.net"]
},
box: [".blog-details-text>p:has(>img)", 1],
imgs: ".blog-details-text>p>img",
button: [4],
insertImg: [
["box", 0, ".blog-details-text>p:has(>img)"], 2
],
customTitle: "h2.blog-details-headline",
category: "nsfw1"
}, {
name: "秀人网",
url: {
h: "www.xiurenpic.com",
p: "/article/"
},
box: ["#gallery", 1],
imgs: "#gallery img",
button: [4],
insertImg: [
["box", 0, "#gallery"], 2
],
customTitle: ".filename",
category: "nsfw2"
}, {
name: "福利图",
url: {
h: ["fulitu.me"],
p: "/pic/"
},
imgs: () => fn.getImg(".content_left img", fn.gt("//a[text()='下页']", 2), 5),
button: [4],
insertImg: [".content_left", 2],
autoDownload: [0],
next: "//span[contains(text(),'下一篇')]/a",
prev: "//span[contains(text(),'上一篇')]/a",
customTitle: ".item_title>h1",
hide: ".content br",
category: "nsfw1"
}, {
name: "爱图门",
url: {
h: ["aitu.men"],
p: ".html",
e: ".context img"
},
imgs: () => fn.getNP(".context img", ".pagelist span+a", null, ".pagelist", 0, null).then(() => fn.gae(".context img")),
button: [4],
insertImg: [".context", 1],
autoDownload: [0],
next: ".post-previous a",
prev: ".post-next a",
customTitle: "#content h1",
category: "nsfw1"
}, {
name: "K55",
link: "https://k55.net/arttype/2.html",
url: {
h: ["k55.net"],
p: "/artdetail-",
e: ".photo_box",
},
imgs: () => fn.gae(".photo_box img").map(e => e.src).sort((a, b) => a.match(/(\d+)\.\w+$/)[1] - b.match(/(\d+)\.\w+$/)[1]),
button: [4],
insertImg: [".photo_box", 2],
autoDownload: [0],
next: ".item_prev_next>.item_right>a",
prev: ".item_prev_next>.item_left>a",
customTitle: () => fn.dt({
s: ".title-box>.h3-md.mb-1",
d: /\[\d+P\].+$/i
}),
fancybox: {
v: 3,
css: false
},
category: "nsfw1"
}, {
name: "Hotgirl.biz",
url: {
h: ["hotgirl.biz"]
},
imgs: ".entry-content img",
button: [4],
insertImg: [".entry-content", 2],
customTitle: ".entry-title",
category: "nsfw1"
}, {
name: "XLUST.ORG",
url: {
h: ["xlust.org"]
},
imgs: ".rl-gallery-item a",
button: [4],
insertImg: [
[".entry-content", 0, ".rl-gallery-container"], 2
],
customTitle: ".entry-title",
fancybox: {
blacklist: 1
},
category: "nsfw1"
}, {
name: "秀人网",
url: {
h: ["xiurenwang.me"],
p: "photo.php",
s: "id="
},
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr(".intro>img");
return thumbnailSrcArray.map(e => e.replace("_600x0", "").replace(".webp", ".jpg"));
},
button: [4],
insertImg: [".intro", 2],
customTitle: "h1",
mcss: ".paragraph .intro img{width:100%!important}",
hide: ".article:has(>div>.media),.banner,.banner_ad,.push-top,.push-bottom,.banner-sexgps",
category: "nsfw1"
}, {
name: "秀人网 AD",
reg: /^https?:\/\/xiurenwang\.me/,
hide: ".article:has(>div>.media),.banner,.banner_ad,.push-top,.push-bottom,.banner-sexgps",
category: "ad"
}, {
name: "秀人图",
host: ["xiurentu.xyz", "www.xiurentu.com", "www.xiurenst.com", "aituxiuren.com", "www.aixiurentus.com"],
url: {
e: ".site .logo-wrapper img.logo.tap-logo[alt^='秀人']",
p: /^\/\d+\.html/,
ee: "//button[contains(text(),'登录购买')]"
},
imgs: () => fn.getImgA("a[data-fancybox],.entry-content img", ".fenye a"),
button: [4],
insertImg: [".entry-content", 2],
autoDownload: [0],
next: ".article-nav-prev a",
prev: ".article-nav-next a",
customTitle: ".entry-title",
fancybox: {
v: 3,
css: false
},
observerClick: [".swal2-close", ".ht-n-close-toggle"],
css: ".navbar .nav-list>.menu-item>a{line-height:20px;margin:0 6px}",
category: "nsfw1"
}, {
name: "秀人网图集",
url: {
e: ".site .logo-wrapper img.logo.tap-logo[alt^='秀人']",
},
observerClick: [".swal2-close", ".ht-n-close-toggle"],
css: ".navbar .nav-list>.menu-item>a{line-height:20px;margin:0 6px}",
category: "ad"
}, {
name: "牛C網",
url: {
//h: ["rulel.com"],
t: "NIUC.NET",
p: /^\/\d+\.html$/,
e: "//i[@class='czs-folder-l']/following-sibling::a[1][text()='美女写真' or text()='美女寫真' or text()='Beauty photo' or text()='뷰티포토' or text()='美容写真' or text()='Cosplay' or text()='JAV.PHOTO']"
},
imgs: () => fn.gae(".content-warp img").filter(e => !e.closest("a[href$='app.html'],a[href*='/t.me/']")),
button: [4],
insertImgBF: () => fn.showMsg(DL.str_04, 0).then(() => fn.waitEle("a.core-next-img").then(() => fn.hideMsg())),
insertImg: [".content-warp", 2],
autoDownload: [0],
next: "//a[div[text()='<<上一篇']]",
prev: "//a[div[text()='下一篇>>']]",
customTitle: ".post-title",
mcss: ".post-warp .content-warp{padding:0px}",
category: "nsfw2"
}, {
name: "牛C網 自動翻頁",
url: {
//h: ["rulel.com"],
t: "NIUC.NET",
e: [".post-list", ".list-footer"]
},
init: () => fn.waitEle(".el-pager .active").then(e => (currentPageNum = Number(fn.gt(e)))),
autoPager: {
ele: ".post-list",
observer: ".post-list>.post-item",
next: () => {
let lastNum = _unsafeWindow.core_next.total_page;
lastNum = Number(lastNum);
if (currentPageNum < lastNum) {
let url = fn.dlp().replace(/\/page\/\d+/, "");
if (url === "/") {
url = "";
}
if (fn.dls() !== "") {
return url + "/page/" + (currentPageNum += 1) + fn.dls();
}
return url + "/page/" + (currentPageNum += 1);
} else {
return null;
}
},
pageNum: () => currentPageNum,
lazySrc: "img[data-src]"
},
category: "autoPager"
}, {
name: "8E资源站",
url: {
h: ["8ezy.com"],
e: ".entry-header>h1"
},
imgs: ".entry-content img",
videos: "video>source",
button: [4],
insertImg: [".entry-content", 2],
customTitle: () => fn.dt({
s: ".entry-header>h1",
d: [
"【在线观看】-",
/\d+p(\d+v)?$|\(\d+[\w\s\.\+-]+\)|\[\d+[\w\s\.\+-]+\]|“\d+ photos.*/i
]
}),
fancybox: {
v: 3,
insertLibrarys: 1
},
downloadVideo: true,
hide: ".single-top-html,.single-bottom-html",
category: "nsfw2"
}, {
name: "8E资源站 歸檔自動翻頁",
link: "https://8ezy.com/uncategorized/",
url: {
h: ["8ezy.com"],
p: ["/uncategorized/", "/acgn/", "/%e7%be%8e%e5%9b%be/", "/video/"],
e: [".post-list-item", ".post-nav[data-max]"]
},
init: async () => {
await fn.waitEle("button.selected,a.button.selected[href^=http]");
let code = fn.gst("b2_cat");
let obj = fn.TextToObject(code, '"opt"', 1);
siteJson = obj;
currentPageNum = Number(obj.post_paged);
},
autoPager: {
mode: "json",
fetchOptions: () => {
let body = {
"post_type": "post-1",
"post_order": "new",
"post_row_count": "4",
"post_count": "24",
"post_thumb_ratio": "1/0.618",
"post_open_type": "1",
"post_meta[0]": "user",
"post_meta[1]": "date",
"post_meta[2]": "views",
"post_meta[3]": "like",
"post_meta[4]": "cats",
"post_meta[5]": "des",
"post_paged": currentPageNum,
"post_load_more": "0",
"post_cat[0]": Number(siteJson.post_cat),
"show_sidebar": "",
"width": "1100",
"no_rows": "false",
"paged": currentPageNum
};
return {
"headers": {
"accept": "application/json, text/plain, */*",
"accept-language": "zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-CN;q=0.6",
"cache-control": "no-cache",
"content-type": "application/x-www-form-urlencoded",
"pragma": "no-cache"
},
"body": new URLSearchParams(body).toString(),
"method": "POST"
}
},
ele: (json) => [fn.html(json.data)],
pos: [".b2_gap", 0],
observer: ".archive-row .post-list-item",
next: () => {
let lastNum = fn.ge(".post-nav[data-max]").dataset.max;
lastNum = Number(lastNum);
if (currentPageNum < lastNum) {
currentPageNum += 1;
return "/wp-json/b2/v1/getPostList";
} else {
return null;
}
},
aF: () => {
[...document.querySelectorAll(".post-list-item .picture:has(source)")].forEach(e => {
fn.ge("source", e)?.remove();
let img = fn.ge("img", e);
img.src = img.dataset.src;
img.classList.add("entered");
img.classList.add("loaded");
});
},
pageNum: () => currentPageNum,
showTitle: 0,
history: 0
},
openInNewTab: ".post-list-item a:not([target=_blank])",
topButton: true,
category: "autoPager"
}, {
name: "8E资源站 搜索自動翻頁",
reg: [
/^https?:\/\/8ezy\.com\/\?s=/,
/^https?:\/\/8ezy\.com\/page\/\d+\/\?s=/
],
init: async () => {
await fn.waitEle("button.selected,a.button.selected[href^=http]");
currentPageNum = Number(fn.gt("button.selected,a.button.selected[href^=http]"));
},
autoPager: {
ele: ".archive-row",
observer: ".archive-row .post-list-item",
next: () => {
let lastNum = fn.ge(".post-nav[data-max]").dataset.max;
lastNum = Number(lastNum);
if (currentPageNum < lastNum) {
let url = fn.dlp().replace(/page\/\d+\/?/, "");
if (fn.dls() !== "") {
return url + "page/" + (currentPageNum += 1) + "/" + fn.dls();
}
return url + "page/" + (currentPageNum += 1);
} else {
return null;
}
},
bF: (dom) => {
[...dom.querySelectorAll(".post-list-item .picture")].forEach(e => {
fn.ge("source", e)?.remove();
let img = fn.ge("img", e);
img.src = img.dataset.src;
img.classList.add("entered");
img.classList.add("loaded");
});
},
pageNum: () => currentPageNum
},
openInNewTab: ".post-list-item a:not([target=_blank])",
topButton: true,
category: "autoPager"
}, {
name: "夜社资源",
url: {
h: ["yeshezy.com"],
p: "/play/",
d: "pc"
},
imgs: ".picslist img",
button: [4],
insertImg: [".picslist", 2],
next: ".nextbtn a",
prev: 1,
customTitle: () => fn.getText([".picslist .name", ".breadcrumbs li:last-child"]),
category: "nsfw2"
}, {
name: "夜社资源",
url: {
h: ["yeshezy.com"],
p: "/detail/",
e: ".videolist a.link[onclick*='img.yesheimg.com']",
d: "pc"
},
imgs: () => fn.gae(".videolist a.link[onclick*='img.yesheimg.com']").map(e => {
let code = e.getAttribute("onclick");
let [, src] = code.split("'");
return src;
}),
button: [4],
insertImg: [".contbox:has(.videolist)", 2],
customTitle: ".breadcrumbs li:last-child",
category: "nsfw2"
}, {
name: "6图",
url: {
h: ["www.6tu.com"],
p: "/t/"
},
box: [".container .box", 2],
imgs: ".swiper-box img",
button: [4],
insertImg: ["box", 2],
autoDownload: [0],
next: "//a[text()='下一篇']",
prev: "//a[text()='下一篇']",
customTitle: ".box h1",
category: "nsfw1"
}, {
name: "牛牛美图",
url: {
h: ["www.uyn8.cn"],
p: "/archives/"
},
init: "fn.clearAllTimer()",
imgs: ".entry-content img",
button: [4],
insertImg: [".entry-content", 2],
customTitle: ".entry-title",
fancybox: {
v: 3,
css: false
},
referer: "",
category: "nsfw1"
}, {
name: "优美图录",
url: {
h: ["www.umei.net", "umei.net"],
p: ".html",
e: ".image_div img"
},
imgs: () => fn.getImgO(".image_div img", fn.gt(".item_info span"), 9, null, 200, ".nav-links"),
button: [4],
insertImg: [".image_div", 2],
customTitle: ".item_title>h1",
css: ".content_left img,.image_div a img{cursor:unset}",
hide: ".affs,.xg_content>li:nth-child(n+1):nth-child(-n+2)",
category: "nsfw1"
}, {
name: "Xiutaku/Kiutaku",
url: {
h: ["xiutaku.com", "kiutaku.com"],
p: /^\/\d+$/
},
init: () => fn.remove(".search-form~*,.blog~*:not([class]),.pagination~*:not([class]):not(hr),.article.content~*:not([class]):not(hr),.bottom-articles~*"),
imgs: () => fn.getImg(".article-fulltext img", fn.gt(".pagination-list>span:last-child")),
button: [4],
insertImg: [".article-fulltext", 2],
customTitle: () => fn.dt({
s: ".article-header>h1",
d: /([\s-]+)?.Mitaku.*/i
}),
category: "nsfw1"
}, {
name: "MissBby.cc",
host: ["missbby.cc"],
reg: /^https?:\/\/missbby\.cc\/[^\/]+$/,
include: "//div[strong[contains(text(),'Album Name')]]",
imgs: () => fn.getImgA(".items-center.min-h-screen img", "a[class*=bg-pink-500][href*='page=']"),
button: [4],
insertImg: [".items-center.min-h-screen", 2],
insertImgAF: () => fn.remove("//div[iframe]|//*[span[text()='Sponsored ads']]"),
customTitle: () => fn.dt({
s: "//div[strong[contains(text(),'Album Name')]]",
d: "Album Name: "
}),
css: ".md\:px-16,.xl\:px-20{padding:unset!important}.max-w-3xl{max-width:100%!important}",
category: "nsfw2"
}, {
name: "MissBby.cc 分類自動翻頁",
reg: /^https?:\/\/missbby\.cc\//,
autoPager: {
mode: 1,
waitEle: "//div[@class='flex py-4 justify-center md:justify-between mt-4']/preceding-sibling::div[@class='grid grid-cols-1 md:grid-cols-3 gap-y-6 gap-x-4 xl:grid-cols-4']//img",
ele: "//div[@class='flex py-4 justify-center md:justify-between mt-4']/preceding-sibling::div[@class='grid grid-cols-1 md:grid-cols-3 gap-y-6 gap-x-4 xl:grid-cols-4']",
pos: ["//div[@class='flex py-4 justify-center md:justify-between mt-4']", 1],
next: "//a[text()='Next']",
re: "//div[@class='flex py-4 justify-center md:justify-between mt-4']",
pageNum: () => nextLink.match(/\d+$/)[0],
bottom: screen.height * 2
},
openInNewTab: ".grid a:not([target=_blank])",
category: "autoPager"
}, {
name: "BingMM",
url: {
h: ["bingmm.com"]
},
page: () => fn.clp(/^\/\w+\/\d+\.html$/),
data: () => fn.waitEle(".entry-content img").then(() => fn.showMsg(DL.str_05, 0).then(() => fn.fetchDoc(fn.clp()).then(dom => (doc = dom) && fn.hideMsg()))),
SPA: () => _this.page(),
observeURL: "nav",
init: () => _this.page() ? _this.data() : void 0,
imgs: () => _this.page() ? fn.gae(".entry-content img", doc) : [],
capture: () => _this.imgs(),
autoDownload: [0],
next: () => {
if (!_this.page()) return null;
let next = fn.ge("//a[div[span[text()='Previous']]][@href]", doc, doc);
return next ? next.pathname : null;
},
prev: 1,
customTitle: () => {
if (!_this.page()) return null;
return fn.gt("#post-title", 1, doc);
},
category: "nsfw1"
}, {
name: "图库库",
url: {
h: ["tukuku.cc"],
p: ".html"
},
imgs: ".entry-content img[decoding]",
button: [4],
insertImg: [".entry-content", 2],
autoDownload: [0],
next: ".nav-previous>a",
prev: ".nav-next>a",
customTitle: () => fn.title(" - 图库库"),
hide: "[id].widget_text,.gridmode-post-thumbnail-single,.gridbit-thumbnail-alignwide",
category: "nsfw1"
}, {
name: "Cup2D",
url: {
h: ["cup2d.com"],
p: /^\/[^\/]+\/$/
},
imgs: () => fn.showMsg(DL.str_05, 0).then(() => fn.fetchDoc(fn.url).then(dom => {
thumbnailSrcArray = fn.getImgSrcArr(".entry-content>div:not(.separator,.c)>a img[data-lazy-src]", dom);
return fn.gae(".entry-content>div:not(.separator,.c)>a", dom);
})),
button: [4],
insertImg: [".entry-content>div", 2],
autoDownload: [0],
next: ".nav-previous>a",
prev: ".nav-next>a",
customTitle: ".post-title.entry-title",
category: "nsfw2"
}, {
name: "COSERMM",
url: {
h: ["cosermm.blog.2nt.com"],
p: "/blog-entry-"
},
imgs: "#inner-contents img",
button: [4],
insertImg: ["#inner-contents", 2],
autoDownload: [0],
next: "a.next-a",
prev: "a.prev-a",
customTitle: "#entry-title",
category: "nsfw1"
}, {
name: "COSERMM 自動翻頁",
reg: /^https?:\/\/cosermm\.blog\.2nt\.com\/(page-\d+\.html)?$/i,
autoPager: {
mode: 1,
waitEle: "#pagination>li",
ele: "#grid-container",
observer: "#grid-container>.grid-items",
next: "li:has(>span#current)+li>a",
re: "#pagination",
pageNum: "li:has(>span#current)"
},
openInNewTab: ".grid-items a:not([target=_blank])",
category: "autoPager"
}, {
name: "美图网",
host: ["www.meitu8.cc", "meitu8.cc", "www.meitu8.org", "meitu8.org"],
url: {
t: "meitu8.cc",
p: ".html",
e: [".logo img[alt=美图网]", "#lightgallery img"]
},
imgs: () => {
let [max] = fn.gt(".pagelist>b").match(/\d+$/);
return fn.getImg("#lightgallery img", max, 9);
},
button: [4],
insertImg: ["#lightgallery", 2],
autoDownload: [0],
next: ".prev>a",
prev: ".next>a",
customTitle: ".focusbox-title",
category: "nsfw1"
}, {
name: "美图社/花瓣美女",
host: ["www.928r.com", "www.060k.com"],
url: {
t: ["美图社", "花瓣美女"],
p: /^\/post\/\d+\.html$/
},
imgs: () => {
fn.showMsg(DL.str_05, 0);
let url = fn.gu("//a[text()='显示全文']");
return fn.fetchDoc(url).then(dom => fn.gae("#lightgallery img", dom));
},
button: [4],
insertImg: ["#lightgallery", 2],
autoDownload: [0],
next: ".prev>a",
prev: ".next>a",
customTitle: ".focusbox-title",
category: "nsfw1"
}, {
name: "大美姐",
url: {
h: "www.dmjie.com",
p: "/v/"
},
init: () => {
fn.clearAllTimer(3);
if ("detectDevTools" in _unsafeWindow) {
_unsafeWindow.showWarning = null;
_unsafeWindow.detectDevTools = null;
_unsafeWindow.onresize = null;
}
},
imgs: () => {
let as = "//a[text()='显示全文']";
let is = "#lightgallery img";
if (fn.ge(as)) {
let url = fn.gu(as);
return fn.getImgA(is, [url]);
}
return fn.gae(is);
},
button: [4],
insertImg: ["#lightgallery", 2],
autoDownload: [0],
next: ".prev>a",
prev: ".next>a",
customTitle: ".focusbox-title",
category: "nsfw1"
}, {
name: "美女写真馆",
host: ["www.photo13.com"],
url: {
t: "美女写真馆",
p: "/m/"
},
init: () => {
if ("detectDevTools" in _unsafeWindow) {
_unsafeWindow.showWarning = null;
_unsafeWindow.detectDevTools = null;
_unsafeWindow.onresize = null;
}
tempEles = fn.gae(".post-content>blockquote");
},
imgs: ".post-content img",
button: [4],
insertImg: [".post-content", 2],
insertImgAF: (_, bar) => bar.before(...tempEles),
customTitle: "h1.post-title",
category: "nsfw1"
}, {
name: "找套图/Xiuno BBS",
host: ["www.zhaotaotu.cc", "kantaotu.cc", "taotu.uk"],
url: {
t: "Xiuno BBS",
u: ["/thread", "/?thread"],
e: ".card-user-info"
},
imgs: ".message>img:not(:first-of-type)",
button: [4],
insertImg: [".message", 2],
customTitle: ".media-body>h4",
category: "nsfw1"
}, {
name: "尤美图库/M5MM",
host: ["www.umeitu.com", "www.m5mm.com"],
url: {
h: /umeitu\.com$|m5mm\.com$/,
p: ["/img/", "/photo/"]
},
imgs: () => fn.getImg(".vipimglist img", fn.gt(".stitle>h1>span").match(/\d+/)[0], 9),
button: [4],
insertImg: [".vipimglist", 2],
customTitle: () => fn.dt({
d: [
" - 尤美图库",
" - M5MM"
]
}),
css: ".vipimglist img{min-height:unset!important;}",
hide: "union[id],.sb.list2>li:nth-child(n+2):nth-child(-n+3)",
category: "nsfw1"
}, {
name: "秀套图吧/91性感美女",
url: {
h: ["www.taotu8.cc", "www.913wen.com", "913wen.com"],
p: ["/mm/", "/p/"]
},
imgs: () => {
let max = Number(fn.gu(".page_navi a:last-child")?.split("_")[1]?.match(/\d+/)) || 1;
return fn.getImg(".sg_img img", max, 9);
},
button: [4],
insertImg: [".sg_img", 2],
customTitle: "h1",
css: ".sg_img img{min-height:unset!important}",
hide: "#divpsg,.tujia",
category: "nsfw1"
}, {
name: "Xiuren 秀人网",
url: {
h: "www.xiuren.org"
},
imgs: "a[rel='gallery']:not([href*='html']",
button: [4],
insertImg: [
[".post p>a:not([title])", 2, ".post p>a[title],.post p>span"], 2
],
customTitle: "#title>h1",
css: "#post .post img{max-width:100% !important}",
category: "nsfw2"
}, {
name: "Xiuren 秀人网",
url: {
h: "xiuren.download",
s: "token"
},
box: [".photo-show"],
imgs: ".photo-show a:has(img)",
button: [4],
insertImg: [
["box", 0, ".photo-show>a"], 2
],
customTitle: ".photo-show blockquote",
category: "nsfw2"
}, {
name: "微密猫",
host: [
"www.",
"weme[245679].com",
"wemecat8.com",
"wemimao1.vip",
"wemao.xyz",
"weiminew.com",
"maobao.xyz",
"maobao.vip",
"mvxzsp.com",
"stxlmt.com",
"amstt.com",
"xiuren-wang.com",
"xiurentaotu.com",
"xiuren-tu.com",
"xiurenmote.com",
"xiurenxiezhen.com",
"xiurenwxz.cc",
"hywsg.com",
"jvidmtpj.com",
"panssphw.com",
"pansspzp.com",
"yuhuajie.net",
"rtxzw.net",
"www.xiuren-wang.com",
"qnxz.top",
"wmqxz.net",
"fenseqingrenr.net",
"net-weimi.com",
"laohucaicai.net",
"tik.oumeisetut.com",
"oumeitp.cc",
"taotuw.cc",
"setu.bar"
],
url: {
//t: ["微密猫", "秀人"],
e: [
".scrollbar-thumb-match-color.scrollbar-track-sub-color",
"#nuxt-ui-colors",
".van-back-top",
"#__nuxt",
"#teleports"
]
},
page: () => fn.clp("/archives/"),
SPA: () => _this.page(),
observeURL: "head",
init: () => _this.page() ? fn.fetchDoc(fn.clp()).then(() => fn.waitEle(".grid>div>div>div.fetch-image img,main .text-lg img")) : void 0,
imgs: async () => {
if (!_this.page()) return [];
let more = fn.ge("//div[span[starts-with(text(),'点击展开')]]");
if (more) {
EClick(more);
}
await fn.aotoScrollEles({
ele: ".grid>div>div>div.fetch-image",
cb: (ele) => isEle(fn.ge("img[src]", ele)),
top: "#page-main"
});
return fn.gae(".grid>div>div>div.fetch-image img,main .text-lg img");
},
capture: () => _this.imgs(),
customTitle: () => _this.page() ? fn.dt({
s: "main h1"
}) : null,
loopClick: {
s: ".van-icon-close",
t: 60000
},
hide: ".my-2.grid.grid-cols-1,.lg\\:grid-cols-10,div:not([id],[class]):has(>div img[alt^='约炮首选']),div:has(>div.block span.text-match-color),.lg\\:grid-cols-2:has(.overflow-hidden img.inline-block)",
category: "nsfw2"
}, {
name: "微密猫",
host: [
"www.me-quan.com",
"www.tie-fen.com"
],
url: {
t: "微密猫",
e: ".wp-singular",
p: "/archives/"
},
imgs: ".article-content img",
button: [4],
insertImg: [".article-content", 2],
autoDownload: [0],
next: ".article-nav-prev a",
prev: ".article-nav-next a",
customTitle: ".article-title",
fancybox: {
v: 3,
css: false
},
category: "nsfw2"
}, {
name: "微圖坊",
url: () => fn.checkUrl({
h: ["www.v2ph.com", "www.v2ph.net", "www.v2ph.ru", "www.v2ph.ovh"],
p: "/album/",
e: ".photos-list"
}) && !fn.cls("page="),
imgs: async () => {
let [picTotalNum] = fn.gt("dd:last-child").match(/\d+/);
let pagePicNum = fn.gae(".album-photo img[alt]").length;
let max = Math.ceil(picTotalNum / pagePicNum);
let links = fn.arr(max, (v, i) => siteUrl.replace(/\?hl=.+|\?page=\d+/, "") + `?page=${(i + 1)}`);
let srcArr = [];
let status = 200;
let vip = false;
let fetchNum = 0;
fn.showMsg(DL.str_01, 0);
for (let [page, link] of links.entries()) {
await fetch(link).then(res => {
if (res.status == 403) status = 403;
fn.showMsg(`${DL.str_02}${fetchNum+=1}/${links.length}`, 0);
return res.arrayBuffer();
}).then(buffer => {
const decoder = new TextDecoder(document.characterSet || document.charset || document.inputEncoding);
const htmlText = decoder.decode(buffer);
const dom = fn.doc(htmlText);
debug(`\n${link}\n`, dom);
let vipEle = fn.ge(".lead", dom);
if (vipEle) vip = true;
let imgs = fn.gae(".album-photo img[alt]", dom);
imgs.length == 0 ? debug(`\n${link}\n沒有任何圖片`) : debug(`\n${link}\n此頁圖片`, imgs);
let tE = fn.gae("div.album-photo").at(-1);
imgs.forEach(img => {
img.dataset.src ? srcArr.push(img.dataset.src) : srcArr.push(img.src);
if (page != 0) insertAfter(tE, img.parentNode.cloneNode(true));
});
if (page != 0 && !vipEle && fn.ge(".pagination", dom)) fn.ge(".pagination").outerHTML = fn.ge(".pagination", dom).outerHTML;
});
if (status == 403) {
setTimeout(() => {
fn.showMsg("403請先登錄網站!", 0);
}, 1200);
return srcArr;
}
if (vip) {
setTimeout(() => {
fn.showMsg("VIP限定專輯圖片!", 5000);
}, 1200);
return srcArr;
}
await delay(600);
}
if (picTotalNum != srcArr.length && !vip) {
setTimeout(() => {
fn.hideMsg();
fn.showMsg("圖片有缺,請看主控台訊息", 5000);
}, 1300)
}
return srcArr;
},
button: [4],
insertImg: [".photos-list", 2],
customTitle: "h1",
css: ".albums-list img,.photos-list img{opacity:1!important}",
category: "nsfw2"
}, {
name: "柠檬皮",
url: {
h: "www.emonl.com",
p: ".html"
},
imgs: async () => {
await fn.getNP(".single-content>*", ".page-links span.current+a:has(.next-page)", null, ".page-links").then(() => fn.hideEle(".page-links"));
return fn.gae(".single-content img");
},
capture: () => _this.imgs(),
customTitle: "h1.entry-title",
fancybox: {
v: 3,
css: false
},
category: "nsfw1"
}, {
name: "美图乐",
host: ["www.meitule.net", "www.meitule.com", "www.meitulu.cc", "www.meitu001.cc"],
url: {
t: "美图乐",
p: "/photo/",
e: ".content img"
},
imgs: () => {
let max = Number(fn.gu(".page>li:last-child>a")?.split("_")[1]?.match(/\d+/)) || 1;
return fn.getImgO(".content img", max, 9);
},
button: [4],
insertImg: [".content", 2],
customTitle: "h1.h5",
hide: "#dtag>center,#divpsg,.tujia,.list-album>li:nth-child(n+1):nth-child(-n+2)",
category: "nsfw1"
}, {
name: "绝美网",
link: "https://www.juemei.com/mm/l.html",
url: {
h: "juemei.com",
p: ".html"
},
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr(".album_wrap img");
return thumbnailSrcArray.map(e => e.replace("_s.", "."));
},
button: [4],
insertImg: [".album .wrap", 2],
autoDownload: [0],
next: "//a[text()='上一篇']",
prev: 1,
customTitle: ".album h1",
hide: ".asd,.album_list,.page>em,.page>.next,.page>.num,.page>.end,.page>.current",
category: "nsfw1"
}, {
name: "美女私房菜",
host: ["ozv.me"],
url: {
t: "美女私房菜",
p: ".html"
},
init: () => fn.clearAllTimer(3),
imgs: "img.swiper-lazy",
customTitle: () => fn.title(" - 美女私房菜"),
category: "nsfw1"
}, {
name: "Elysium",
url: {
h: "www.elysium.pro",
p: "/albums/",
e: "a[data-thumbnail]:not([data-video])"
},
box: [".list-group", 1],
imgs: async () => {
let eles = fn.gae(_this.url.e);
let pages = fn.ge(".pagination.flex-wrap li.page-item.active+li>a:not([aria-label=Next])");
if (pages) {
let links = fn.gau(".pagination.flex-wrap>.page-item:not(.disabled)>a");
eles = await fn.getEle(links, _this.url.e);
}
thumbnailSrcArray = eles.map(e => e.dataset.thumbnail);
return eles;
},
button: [4],
insertImg: ["box", 2],
customTitle: () => fn.gt(".text-muted+a") + " - " + fn.gt(".btn-toolbar>h4"),
category: "nsfw1"
}, {
name: "美桌",
link: "http://www.win4000.com/meitu.html",
url: {
h: "www.win4000.com",
p: /^\/meinv\d+\.html$/
},
imgs: () => fn.getImgA(".pic-large", "#scroll>li:not(.current)>a", 200),
button: [4],
insertImg: ["#pic-meinv,.pic-meinv", 2],
autoDownload: [0],
next: ".group-next>a",
prev: ".group-prev>a",
customTitle: ".ptitle>h1",
category: "nsfw1"
}, {
name: "MM1311",
url: {
h: ["www.mm1311.net", "m.mm1311.net"],
p: /^\/\w+\/\d+\.html$/
},
imgs: () => {
let max;
fn.ge(".page-ch") ? [max] = fn.gt(".page-ch").match(/\d+/) : [, max] = fn.gt(".fenye>.rw").match(/\d+\/(\d+)/);
return fn.getImg(".content-pic img,.post-content img", max, 9);
},
button: [4],
insertImg: [".content-pic,.post-content", 2],
autoDownload: [0],
next: ".updown_r",
prev: ".updown_l",
customTitle: ".content>h5,.mm-title",
hide: "union",
category: "nsfw1"
}, {
name: "656G精品套图/秀人妹子图",
url: {
h: ["www.656g.com", "m.656g.com", "www.mmww.cc"],
p: "/tid/"
},
imgs: () => {
let [max] = fn.gt(".i1").match(/\d+/);
return fn.getImgO(".imgg img", max, 9);
},
button: [4],
insertImg: [".imgg", 2],
customTitle: ".c-tt>h1",
category: "nsfw1"
}, {
name: "青年美圖",
host: ["jrants.com"],
reg: [
/^https?:\/\/(\w+\.)?jrants\.com\/\d+\.html$/,
/^https:\/\/\w+\.jrants\.com\/[^\/]+\/$/
],
imgs: () => fn.ge(".page-links") ? fn.getImg(".entry-content img", fn.gt(".page-links>a:last-child"), 7) : fn.gae(".entry-content img"),
button: [4],
insertImg: [".entry-content", 1],
autoDownload: [0],
next: "span.prev>a",
prev: "span.next>a",
customTitle: ".entry-title",
hide: ".code-block",
category: "nsfw2"
}, {
name: "CosBlay/風流雜誌/虹圖",
host: ["cosblay.com", "trendszine.com", "www.hongimg.com"],
reg: [
/^https?:\/\/(cosblay\.com|trendszine\.com|www\.tiplogo\.com)\/\d+\.html/i,
/^https?:\/\/[a-z]{2}\.cosblay\.com\/\d+\/[^\.]+\.html$/,
/^https?:\/\/[a-z]{2,3}\.hongimg.com\/\d+\/[^\.]+\.html$/
],
imgs: () => fn.getImg(".entry-content img", fn.gt(".pgntn-page-pagination-block>*:last-child", 2) || 1, 7),
button: [4],
insertImg: [".entry-content", 2],
autoDownload: [0],
next: "span.prev>a",
prev: "span.next>a",
customTitle: ".entry-title",
mcss: ".separate-containers .inside-article,.separate-containers .comments-area,.separate-containers .page-header,.separate-containers .paging-navigation,.one-container .site-content,.inside-page-header{padding:2px}.entry-content:not(:first-child),.entry-summary:not(:first-child),.page-content:not(:first-child){margin-top:2px}",
hide: ".code-block",
category: "nsfw2"
}, {
name: "888美女网",
url: {
h: "www.888meinv.com",
e: [".suoyou", ".pannel img"]
},
imgs: () => {
let [, max] = fn.gt(".suoyou").match(/\/(\d+)/);
let links = fn.arr(max, (v, i) => siteUrl + "/" + (i + 1));
return fn.getImgA(".pannel img", links);
},
button: [4],
insertImg: [".pannel", 2],
autoDownload: [0],
next: ".pre_pageload>a",
prev: ".next_pageload>a",
customTitle: "h1",
css: ".nr .tupianqu img{margin-top:0px !important}",
mcss: ".nr .tupianqu,.nr .tupianqu .pannel{padding:0px !important}",
hide: "union",
category: "nsfw1"
}, {
name: "淑女爱",
host: ["www.shunvi.com", "www.shunvai.com"],
url: {
h: /^www\.shunva?i\.com$/,
e: "#allnum",
},
imgs: async () => {
let max = fn.gt("#allnum");
let links = fn.arr(max, (v, i) => i == 0 ? siteUrl : siteUrl.replace(".html", "") + "_" + (i + 1) + ".html");
let all = fn.ge("//a[text()='多图显示']");
if (all) {
let ok = await fetch(all).then(res => res.ok);
if (ok) {
links = [all.href];
}
}
return fn.getImgA(".picsbox img", links, 2).then(srcs => srcs.filter(e => fn.isImage(e) && !e.includes("/logo/") && !e.includes("onerror")));
},
button: [4],
insertImg: [".picsbox>center", 2],
customTitle: ".picmainer>h1",
hide: ".picpege",
category: "nsfw1"
}, {
name: "淑女爱M",
host: ["m.shunvi.com", "m.shunvai.com"],
url: {
h: /^m\.shunva?i\.com$/,
p: "/photo/",
e: ["#thenum", ".swiper-slide img"]
},
imgs: () => {
let [max] = fn.gt("//span[b[@id='thenum']]").match(/\d+$/);
let links = fn.arr(max, (v, i) => i == 0 ? siteUrl : siteUrl.replace(".html", "") + "_" + (i + 1) + ".html");
return fn.getImgA(".swiper-slide img", links, 200).then(srcs => srcs.filter(e => fn.isImage(e) && !e.includes("/logo/") && !e.includes("onerror")));
},
button: [4],
insertImg: ["#slider", 2],
customTitle: () => fn.dt({
s: ".infoline",
d: /\d+\s\/\s\d+\n/
}),
hide: "union,#pic_list li:has(img:not([src*=shunvi]))",
category: "nsfw1"
}, {
name: "TWOIMG",
link: "https://www.twoimgs.com/people",
url: {
h: [/twoimg/, /lovemmtu/],
p: /^\/\d+\.html$/
},
imgs: ".gallery a",
thums: ".gallery img",
button: [4],
insertImg: [
[".article-content", 0, ".gallery"], 2
],
autoDownload: [0],
next: ".article-nav-prev a",
prev: ".article-nav-next a",
customTitle: ".article-title,.focusbox-title",
category: "nsfw1"
}, {
name: "mn52图库",
host: ["www.mn52.com", "wap.mn52.com"],
link: "https://www.mn52.com/xingganmeinv/",
url: {
h: ".mn52.com",
p: ".html"
},
imgs: "#originalpic img,.w100 img,#piclist img",
button: [4],
insertImg: ["#originalpic,.w100", 2],
autoDownload: [0],
next: "//a[span[text()='上一个图集']]|//li[contains(text(),'上一篇')]/a",
prev: "//a[span[text()='下一个图集']]|//li[contains(text(),'下一篇')]/a",
customTitle: ".title>h1,.general-title>h4",
css: ".general-title{padding:unset!important}",
category: "nsfw1"
}, {
name: "三千图片网",
link: "https://www.win3000.com/tags/xingganmeinv/",
url: {
h: "www.win3000.com",
p: ".html",
e: ".pic-cont img"
},
imgs: () => {
let [max] = fn.gt(".title>span").match(/\d+$/);
let links = fn.arr(max, (v, i) => siteUrl.replace(".html", "") + "_" + (i + 1) + ".html");
return fn.getImgA(".pic-cont img", links, 2);
},
button: [4],
insertImg: [".pic-cont", 2],
autoDownload: [0],
next: "a.other-group.fr",
prev: "a.other-group.fl",
customTitle: ".title>h1",
category: "nsfw1"
}, {
name: "三千图片网M",
link: "https://m.win3000.com/tags/xingganmeinv/",
url: {
h: "m.win3000.com",
p: ".html",
e: [".show-page>i", ".pic-showbox .imgbox img"]
},
imgs: () => {
let max = fn.gt(".show-page>i");
let links = fn.arr(max, (v, i) => siteUrl.replace(".html", "") + "_" + (i + 1) + ".html");
return fn.getImgA(".pic-showbox .imgbox img", links, 2);
},
button: [4],
insertImg: [".pic-showbox", 2],
autoDownload: [0],
next: "a.page-next",
prev: "a.page-prev",
customTitle: ".pic-infobox h1",
css: "#app{font-size:14px!important}",
category: "nsfw1"
}, {
name: "3G 壁纸",
host: ["www.3gbizhi.com", "m.3gbizhi.com"],
link: "https://www.3gbizhi.com/meinv",
reg: /^https?:\/\/(www|m|desk)\.3gbizhi\.com\/meinv\/(\w+\/)?\w+\.html$/,
imgs: () => {
let links = fn.gae(".showImglistw a").map(a => a.pathname);
return fn.getImgA("#contpic,#mobile_c_img>img", links);
},
thums: ".showImglistw img",
button: [4],
insertImg: ["#showimg", 1],
endColor: "white",
autoDownload: [0],
next: "a.next-page[href$=html]",
prev: "a.prev-page[href$=html]",
customTitle: "h2.title,.titlew>h2",
hide: "[class^=ad_id]",
category: "nsfw1"
}, {
name: "亿图全景图库",
host: ["www.yeitu.com", "m.yeitu.com"],
link: "https://www.yeitu.com/meinv/",
reg: /^https?:\/\/(www|m)\.yeitu\.com\/\w+\/\w+\/\w+\.html$/,
init: () => {
let a = fn.ge(".article-body>a,.gallery-item>a");
if (a) a.outerHTML = a.innerHTML;
},
imgs: () => {
let [, max] = fn.gt(".imageset-sum,span.num").match(/\/\s?(\d+)/);
let links = fn.arr(max, (v, i) => i == 0 ? siteUrl : siteUrl.replace(".html", "") + "_" + (i + 1) + ".html");
return fn.getImgA(".img_box img[alt],.gallery-item img[alt],.article-show img", links, 2);
},
button: [4],
insertImg: [".img_box,.gallery-item,.article-show", 2],
customTitle: "#title>h1,h1.article-title,.article-info>h1",
hide: ".appbox,.uk-page~section,.yt-pages+.mssp",
category: "nsfw1"
}, {
name: "优美图库",
host: ["www.umei.cc"],
link: "https://www.umei.cc/meinvtupian/",
reg: /^https?:\/\/www\.umei\.cc\/meinvtupian\/\w+\/\d+\.htm$/i,
imgs: () => {
let url = fn.gu(".pages li:last-child>a");
let [, max] = url.match(/_(\d+).htm/);
return fn.getImg(".big-pic img", max, 17);
},
button: [4],
insertImg: [".big-pic", 1],
autoDownload: [0],
next: ".preandnext:not(.connext)>a",
prev: ".preandnext.connext>a[href$=htm]",
customTitle: "#photos>h1",
css: ".photo img {max-width:100% !important}",
category: "nsfw1"
}, {
name: "优美图库M",
host: ["wap.umei.cc"],
reg: /^https?:\/\/wap\.umei\.cc\/meinvtupian\/\w+\/\d+\.htm$/,
include: "//a[text()='尾页']",
imgs: () => {
let [, max] = fn.gu("//a[text()='尾页']").match(/_(\d+).htm/);
return fn.getImg("#maincont img", max, 17);
},
button: [4],
insertImg: ["#maincont", 1],
autoDownload: [0],
next: () => {
let next = fn.ge("a.f-r.l3");
return next ? next.href : null;
},
prev: 1,
customTitle: ".title>h1",
hide: "#maincont>div:not(#FullPictureLoadImgBox),dl:nth-child(n+1):nth-child(-n+2)",
category: "nsfw1"
}, {
name: "MEITU131",
host: ["www.meitu131.com", "m.meitu131.com"],
link: "https://www.meitu131.com/nvshen/,https://www.meitu131.com/jigou/",
reg: /^https?:\/\/(www|m)\.meitu131\.(com|net)\/(\w+\/)?meinv\/\d+\//,
imgs: () => {
let [, max] = fn.gt("a[title],.uk-page>span").match(/\/(\d+)/);
return fn.getImgO(".work-content img,.uk-article-bd img", max, 15);
},
button: [4],
insertImg: [".work-content>p,.uk-article-bd", 1],
customTitle: ".contitle-box>h1,h1.uk-article-title",
css: ".work-content img{max-width:100%!important}",
hide: ".appbox,.uk-page~section",
category: "nsfw1"
}, {
name: "爱套图",
url: {
h: ["www.aitaotu.cc", "aitaotu.cc", "www.2taotu.cc", "2taotu.cc"],
p: "/photo/"
},
box: [".uk-inline", 2],
imgs: () => {
let [, max] = fn.gu("//a[text()='尾页']").match(/_(\d+).htm/);
return fn.getImg(".uk-article img", max, 9);
},
button: [4],
insertImg: [
["box", 0, "figure.uk-inline"], 2
],
next: ".m-prevnext a",
customTitle: ".uk-article-title",
hide: "union[id]",
category: "nsfw1"
}, {
name: "和邪社",
url: {
h: "www.hexieshe.com",
p: /^\/\d+\/$/
},
init: () => fn.getNP("#content-innerText>p", "span.current+a", null, ".post-links"),
imgs: "#content-innerText img",
customTitle: () => fn.dt({
s: ".entry-title",
d: "为您朗读"
}),
setFancybox: true,
category: "nsfw1"
}, {
name: "天极图片",
url: {
h: "pic.yesky.com",
p: ".shtml"
},
box: [".bigPic", 1],
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr(".previewPic img");
return thumbnailSrcArray.map(e => e.replace(/d-|\/180x320/g, ""));
},
button: [4],
insertImg: [
["box", 0, ".bigPic"], 2
],
customTitle: "h1",
css: ".atlasSwiper .floatR,.atlasSwiper .floatR .previewPic{width:unset!important}",
category: "nsfw1"
}, {
name: "天极图片M",
link: "https://wap.yesky.com/pic/",
url: {
h: "wap.yesky.com",
p: ".shtml"
},
box: [".swiper-container", 1],
imgs: "[data-imgid] img",
button: [4],
insertImg: [
["box", 0, ".swiper-container"], 2
],
customTitle: ".atlas_introduce h1",
hide: ".swiper-sum,[class^=ad]",
category: "nsfw1"
}, {
name: "爱美女",
url: {
h: "www.92meinv.com",
p: "/article-",
e: ".pp.hh img[alt],#image_div img"
},
imgs: () => {
let [, max] = fn.gt(".des>h1,.post_title_topimg").match(/\/\s?(\d+)/);
let links = fn.arr(max, (v, i) => siteUrl.replace(/\.html$/, "") + "-" + (i + 1) + ".html");
return fn.getImgA(".pp.hh img[alt],#image_div img", links, 200);
},
button: [4],
insertImg: [".pp.hh,.content", 2],
autoDownload: [0],
next: "//a[@class='active' and contains(text(),'下一篇')] | //a[@class='active' and contains(text(),'下一组')]",
prev: "//a[@class='active' and contains(text(),'上一篇')] | //a[@class='active' and contains(text(),'上一组')]",
css: ".pp img{max-width:100%!important}",
customTitle: () => fn.title("_", 1),
category: "nsfw1"
}, {
name: "爱美女M",
url: {
h: "m.92meinv.com",
p: "/article-",
e: ".arcmain img,#image_div img"
},
imgs: () => {
let max = fn.gt(".article-page>*:last-child", 2);
let links = fn.arr(max, (v, i) => siteUrl.replace(/\.html$/, "") + "-" + (i + 1) + ".html");
return fn.getImgA(".arcmain img,#image_div img", links, 200);
},
button: [4],
insertImg: [".clearfix.arcmain,.content", 1],
autoDownload: [0],
next: "a.f-r.l3",
prev: "a.f-l.l2",
hide: "body>a",
customTitle: () => fn.title("_", 1),
category: "nsfw1"
}, {
name: "HuaLin",
host: ["hualin.san.tc"],
url: {
h: "hualin",
p: ".html",
e: ["a[title=HuaLin]", ".single-content"]
},
init: () => (tempEles = fn.gae(".abstract,.down-form")),
imgs: () => {
let pages = fn.ge(".page-links");
if (pages) {
let max = fn.gt(".page-links a:has(.be-arrowright)", 2);
return fn.getImg(".single-content img", max, 7);
} else {
return fn.gae(".single-content img");
}
},
button: [4],
insertImg: [".single-content", 2],
insertImgAF: (_, bar) => bar.before(...tempEles),
autoDownload: [0],
next: "a[rel=prev]",
prev: "a[rel=next]",
customTitle: "h1.entry-title",
category: "nsfw1"
}, {
name: "52XiuRen",
url: {
h: "52xiuren.cc"
},
imgs: ".entry-content a[data-fancybox]",
button: [4],
insertImg: [".entry-content", 2],
autoDownload: [0],
next: () => fn.attr(".post-autoload", "data-url"),
prev: 1,
customTitle: ".jeg_post_title",
fancybox: {
v: 3,
css: false
},
category: "nsfw2"
}, {
name: "美女图册",
host: ["www.mntuce01.com"],
url: {
t: "美女图册",
p: /^\/\d+\/\.html$/
},
imgs: async () => {
let post_id = Number(fn.lp.match(/\d+/));
let page = 1;
let html = "";
let loop = true;
const getData = async () => {
let params = new URLSearchParams({
action: "load_more_post_page",
post_id,
page_num: page
}).toString();
try {
let res = await fetch("/wp-admin/admin-ajax.php", {
"headers": {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-requested-with": "XMLHttpRequest"
},
"body": params,
"method": "POST"
});
let json = await res.json();
fn.showMsg(`${DL.str_06}${page}/???`, 0);
html += json?.data?.content;
if (!json?.data?.next_page) {
loop = false;
return;
}
page++;
} catch {
loop = false;
return;
}
};
while (loop) {
await getData();
}
return [...fn.doc(html).images];
},
button: [4],
insertImg: [".wp-posts-content", 2],
customTitle: ".article-title",
fancybox: {
blacklist: 1
},
category: "nsfw1"
}, {
name: "秀人集",
url: {
h: "www.xiuren7.com",
p: ".html",
ee: ".pay-flexbox"
},
init: () => {
let ps = fn.gae(".wp-posts-content p");
ps.forEach(p => {
if (p?.firstChild?.nodeName === "#text") {
tempEles.push(p.firstChild.textContent);
}
});
},
imgs: ".wp-posts-content img",
button: [4],
insertImg: [".wp-posts-content", 2],
insertImgAF: (_, bar) => {
tempEles.forEach(t => {
let p = document.createElement("p");
p.innerText = t;
fragment.append(p);
});
bar.before(fragment);
},
autoDownload: [0],
next: "//a[p[text()='上一篇']]",
prev: "//a[p[text()='下一篇']]",
customTitle: "h1.article-title",
fancybox: {
blacklist: 1
},
css: "div[data-nav=posts][style]{max-height:unset!important}",
category: "nsfw1"
}, {
name: "男人之家",
host: ["nanrenhome.cc", "nanrenhome.com"],
url: {
h: /nanrenhome\./,
p: ".html",
e: "//a[@rel='category tag'][text()='福利美图']"
},
imgs: () => {
let pages = fn.ge(".article-paging a[href]");
return pages ? fn.getImgA(".article-content img", ".article-paging a[href]") : fn.gae(".article-content img");
},
button: [4],
insertImg: [
["//article/p[img]", 2, "//article/p[img] | //div[@class='article-paging']"], 2
],
customTitle: ".article-title",
category: "nsfw1"
}, {
name: "网红跟我俩",
host: "www.2wh.net",
reg: /^https?:\/\/www\.2wh\.net\/\d+\.html$/,
include: "//div[@class='breadcrumbs']/a[2][text()='美女写真机构']",
init: () => {
fn.gae(".article-content>p").forEach(p => {
if (!fn.ge("img", p)) {
tempEles.push(p);
}
});
},
imgs: () => {
let pag = fn.ge(".article-paging a[href]");
return pag ? fn.getImgA(".article-content img", ".article-paging a[href]") : fn.gae(".article-content img");
},
button: [4],
insertImg: [".article-content", 2],
insertImgAF: (_, bar) => bar.before(...tempEles),
autoDownload: [0],
next: ".article-nav-prev a",
prev: ".article-nav-next a",
customTitle: () => fn.dt({
s: ".article-title",
d: "无删减私房写真流出"
}),
category: "nsfw1"
}, {
name: "网红跟我俩",
reg: /^https?:\/\/www\.2wh\.net\/\d+\.html$/,
imgs: ".article-content img",
autoDownload: [0],
next: ".article-nav-prev a",
prev: ".article-nav-next a",
customTitle: () => fn.dt({
s: ".article-title",
d: "无删减私房写真流出"
}),
setFancybox: true,
category: "nsfw1"
}, {
name: "PixiBB",
url: {
h: "sexy.pixibb.com",
e: [".entry-content img", ".post h2"]
},
imgs: () => fn.getImgA(".entry-content img", ".page-links a"),
button: [4],
insertImg: [".entry-content", 2],
autoDownload: [0],
next: ".left-post a",
prev: ".right-post a",
customTitle: () => fn.dt({
s: ".post h2",
d: [
/Sexy Cosplay.*$/,
/Maid Raiden Cosplay.*$/
]
}),
hide: ".row:has(>a>img[alt^=Watch]),#custom_html-3",
category: "nsfw1"
}, {
name: "PutMega 分類自動翻頁",
reg: /^https?:\/\/(www\.)?putmega\.com\/explore\//,
autoPager: {
ele: "#list-recent-albums>.pad-content-listing,#list-recent-images>.pad-content-listing",
observer: "#list-recent-albums>.pad-content-listing>div,#list-recent-images>.pad-content-listing>div",
next: ".pagination-next>a[href]",
re: ".content-listing-pagination"
},
category: "autoPager"
}, {
name: "PutMega/ImgBB/JPG6/NF Host",
links: [
"https://www.putmega.com/explore/recent/?list=albums&sort=date_desc&page=1",
"https://shiki17chen.imgbb.com/albums",
"https://2920215920.imgbb.com/albums",
"https://ozpin.imgbb.com/albums",
"https://afc123.imgbb.com/albums",
"https://jpg6.su/xelszy/albums",
"https://jpg6.su/rainbowsmile/albums",
"https://nfhost.me/insta_girls/albums"
],
url: {
h: [/putmega\.com$/, "ibb.co", /jpg\d\.su/, "nfhost.me"],
p: ["/album/", "/a/"],
st: "PF.obj.config.auth_token"
},
imgs: () => {
fn.showMsg(DL.str_05, 0);
let id;
if (fn.lh === "ibb.co") {
[, , id] = fn.lp.split("/");
} else {
id = fn.lp.split(".").at(-1);
}
let code = fn.gst("PF.obj.config.auth_token");
let [, auth_token] = code.match(/PF\.obj\.config\.auth_token[\s="]+(\w+)/);
let params = new URLSearchParams({
auth_token,
pathname: fn.lp,
action: "get-album-contents",
albumid: id
}).toString();
return fetch("/json", {
"headers": {
"accept": "application/json, text/javascript, */*; q=0.01",
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-requested-with": "XMLHttpRequest"
},
"body": params,
"method": "POST"
}).then(res => res.json()).then(json => {
customTitle = fn.dt({
t: json.album.name
});
thumbnailSrcArray = json.contents.map(e => e.thumb.url);
return json.contents.map(e => e.url);
});
},
capture: () => _this.imgs(),
button: [4],
insertImg: ["#content-listing-tabs", 3],
category: "nsfw2"
}, {
name: "anh.im/Lensdump",
links: [
"https://anh.im/bigradish/albums",
"https://lensdump.com/marcusagrippa777",
"https://lensdump.com/saucyspazgurl"
],
url: {
h: ["anh.im", "lensdump.com"],
p: ["/album/", "/a/"],
e: "#content-listing-tabs"
},
imgs: async () => {
await fn.getNP("#list-most-recent>.pad-content-listing", ".pagination-next>a[href]");
thumbnailSrcArray = fn.getImgSrcArr(".list-item-image img").reverse();
return thumbnailSrcArray.map(e => e.replace(".md.", "."));
},
button: [4],
insertImg: ["#content-listing-tabs", 3],
customTitle: () => fn.dt({
d: ["— anh.im"]
}),
hide: ".ad-banner",
category: "nsfw2"
}, {
name: "Luscious",
url: {
h: "luscious.net"
},
page: () => fn.clp("/albums/"),
SPA: () => _this.page() ? fn.waitEle(["a[href*='/read/'],.album-heading a", ".album-heading:not(.o-padding-sides),.album-heading.o-padding-sides a"]) : false,
observeURL: "head",
imgs: async () => {
if (!_this.page()) return [];
fn.showMsg(DL.str_05, 0);
const getApiUrl = (id, page) => {
let searchParams = new URLSearchParams({
operationName: "PictureListInsideAlbum",
query: " query PictureListInsideAlbum($input: PictureListInput!) { picture { list(input: $input) { info { ...FacetCollectionInfo } items { __typename id title description created like_status number_of_comments number_of_favorites moderation_status width height resolution aspect_ratio url_to_original url_to_video is_animated position permissions url tags { category text url } thumbnails { width height size url } } } } } fragment FacetCollectionInfo on FacetCollectionInfo { page has_next_page has_previous_page total_items total_pages items_per_page url_complete } ",
variables: `{"input":{"filters":[{"name":"album_id","value":"${id}"}],"display":"date_newest","items_per_page":50,"page":${page}}}`
});
return `https://apicdn.luscious.net/graphql/nobatch/?${searchParams}`;
};
let id = Number(new URL(fn.gu("a[href*='/read/'],.album-heading a")).pathname.split("/")[2].match(/\d+$/)[0]);
let max = await fetch(getApiUrl(id, 1)).then(res => res.json()).then(json => json.data.picture.list.info.total_pages);
let fetchNum = 0;
let resArr = fn.arr(max, (v, i) => {
let url = getApiUrl(id, (i + 1));
return fetch(url).then(res => {
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${max}`, 0);
return res.json();
}).then(json => json.data.picture.list.items.map(e => {
return e.url_to_video ? {
video: e.url_to_video
} : {
original: e.url_to_original,
thumbnail: e.thumbnails.at(-1).url
}
}));
});
return Promise.all(resArr).then(data => {
videoSrcArray = data.flat().filter(item => item.video).map(e => e.video);
thumbnailSrcArray = data.flat().filter(item => item.thumbnail).map(e => e.thumbnail);
return data.flat().filter(item => item.original).map(e => e.original);
});
},
capture: () => _this.imgs(),
button: [4],
insertImg: ["article.o-padding-top-bottom,.picture-frame-wrapper", 3],
downloadVideo: true,
customTitle: () => _this.page() ? fn.gt(".album-heading:not(.o-padding-sides),.album-heading.o-padding-sides a") : null,
css: "body.o-modal-no-scroll{overflow:unset!important}",
hide: "#modal-root",
category: "hcomic"
}, {
name: "次元岛",
url: {
h: ["ciyuandao.com"],
p: "/photo/show/"
},
imgs: ".talk_pic img",
button: [4],
insertImg: [".talk_pic", 2],
customTitle: "h1",
category: "nsfw1"
}, {
name: "萌次元",
host: ["www.mtutuu.com"],
reg: /^https?:\/\/www\.mtutuu\.com\/\d+\.html$/,
exclude: ".content-cap",
imgs: ".entry-content img",
button: [4],
insertImg: [
["//div[@class='entry-content']/p[img]", 2, "//div[@class='entry-content']/p[img]"], 2
],
customTitle: ".post-style-3-title",
category: "nsfw1"
}, {
name: "次元小镇",
host: ["dimtown.com"],
reg: /^https?:\/\/dimtown\.com\/\d+\.html$/,
exclude: ".down-login",
imgs: "#content img",
button: [4],
insertImg: [
["p:has(>img),p:has(a>img)", 2, "p:has(>img),p:has(a>img)"], 2
],
autoDownload: [0],
next: ".post-pre a",
prev: ".post-next a",
customTitle: "h1",
category: "nsfw1"
}, {
name: "米卡插画",
host: ["mikagogo.com"],
reg: /^https?:\/\/mikagogo\.com\/\d+/,
imgs: "#content img",
autoDownload: [0],
next: ".post-pre a",
prev: ".post-next a",
customTitle: "h1:not([class])",
setFancybox: true,
category: "nsfw1"
}, {
name: "LA站",
url: {
h: "cosplayla.com",
p: "/picture-"
},
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr(".pic_list img,.picturelist img");
return thumbnailSrcArray.map(e => e.replace("_750.", "."));
},
capture: () => _this.imgs(),
customTitle: () => {
if (fn.lh.startsWith("cos.")) {
return fn.gt(".top_border a").trim() + " - " + fn.gt(".picture_info .title").trim();
}
return document.title.replace("之", " - ");
},
category: "nsfw1"
}, {
name: "推次元",
host: ["www.a2cy.com", "a2cy.com"],
url: {
h: "a2cy.com",
p: ".html"
},
imgs: () => fn.gae(".imgBox img,.w:not(.box-shadow) img").filter(e => !e.closest(".cy_tyoum,.cy_ranking,.yalayi_box")),
capture: () => _this.imgs(),
customTitle: "h1",
category: "nsfw1"
}, {
name: "Nu-Cosplay",
url: {
h: ["nu-cosplay.com"],
p: /^\/[^\/]+\/$/
},
srcset: ".gallery-item img",
button: [4],
insertImg: [".entry-content", 2],
autoDownload: [0],
next: ".nav-previous>a",
prev: ".nav-nextv>a",
customTitle: "h1.entry-title",
category: "nsfw1"
}, {
name: "Cosplay Porn",
link: "https://cosplayporn.online/category/cosplay/",
url: {
h: ["cosplayporn.online"],
p: /^\/\w+\/[^\/]+\/$/,
ee: ".responsive-player"
},
imgs: ".video-description img",
button: [4],
insertImg: [".video-description", 2],
customTitle: ".entry-title",
observerClick: "#wpdp-close",
category: "nsfw1"
}, {
name: "Cosplay Porn",
reg: /^https?:\/\/cosplayporn\.online\//,
observerClick: "#wpdp-close",
category: "ad"
}, {
name: "小丁 (Fantasy Factory) Patreon Cosplay Leaks",
url: {
h: "www.fantasyfactory.xyz"
},
SPA: true,
observeURL: "body",
init: () => fn.waitEle("#crumbbar"),
imgs: () => {
let urls = fn.gau(".item.file>a");
videoSrcArray = urls.filter(url => url.includes(".mp4"));
return urls.filter(url => !/\.md$|\.mp4$/.test(url));
},
repeat: 1,
capture: () => _this.imgs(),
customTitle: () => fn.delay(500, 0).then(() => fn.waitEle("#crumbbar")).then(e => fn.gt(e)?.replace("www.fantasyfactory.xyz", "小丁 (Fantasy Factory)")),
category: "nsfw1"
}, {
name: "Tokar浵卡 Cosplay",
url: {
h: "tokar.fantasyfactory.xyz"
},
box: [".container", 2],
button: [4],
imgs: async () => {
fn.showMsg(DL.str_05, 0);
let video = fn.ge("a[href^='/video/']");
if (video) {
let url = fn.gu("a[href^='/video/']");
videoSrcArray = await fn.fetchDoc(url).then(dom => fn.gae("video>source", dom).map(e => e.src));
}
let viewUrl = fn.gu("//a[text()='View Photos']");
return fn.iframeVar(viewUrl, "list").then(w => w.list.flat());
},
insertImg: ["box", 2],
customTitle: "h2.text-center",
downloadVideo: true,
category: "nsfw1"
}, {
name: "蠢沫沫",
link: "https://yanxiangrong.github.io/chunmomo/",
reg: /^https?:\/\/yanxiangrong\.github\.io\/chunmomo\/[^\/]+\//,
imgs: "p img[alt]",
customTitle: "h1[id]",
setFancybox: true,
category: "nsfw1"
}, {
name: "HaneAme",
url: {
h: "haneame.net",
p: "/album-"
},
imgs: () => fn.getImgA(".entry-content img", ".pagelinks a"),
button: [4],
insertImg: [".entry-content", 2],
autoDownload: [0],
next: "a.g1-teaser-prev",
prev: "a.g1-teaser-next",
customTitle: () => fn.dt({
s: "h1.entry-title",
d: "Album –"
}),
category: "nsfw1"
}, {
name: "蠢沫沫",
url: {
h: "chunmomo.net",
p: "/album-"
},
imgs: async () => {
let srcs;
let pages = fn.ge(".all-page");
if (pages) {
let [max] = pages.textContent.match(/\d+/);
srcs = await fn.getImg(".s-post-content img", max, 4);
} else {
srcs = fn.getImgSrcArr(".s-post-content img");
}
return srcs.filter(e => !e.includes("rehanman") && !e.includes("thumbnail"));
},
button: [4],
insertImg: [".s-post-content", 2],
autoDownload: [0],
next: ".next-page a.pg-arrow",
prev: ".prev-page a.pg-arrow",
customTitle: () => fn.dt({
s: "h1.entry-title",
d: "Album –"
}),
hide: "[id^='quads-ad'],[id^=block]",
category: "nsfw1"
}, {
name: "Byoru",
url: {
h: "byoru.net",
p: /^\/[^\/]+\/$/,
e: "h1.entry-title"
},
init: () => {
let eles = fn.gae("//p[contains(text(),'Download')] | //p[contains(text(),'Password')]");
if (eles.length > 0) {
let x = fn.ge(".s-post-content");
for (let e of eles) {
insertBefore(x, e);
}
}
},
imgs: () => {
let pages = fn.ge(".all-page");
if (pages) {
let [max] = pages.textContent.match(/\d+/);
return fn.getImg(".s-post-content img", max, 4);
} else if (fn.ge(".msacwl-slide>a")) {
return fn.gae(".msacwl-slide>a").map(a => a.dataset.mfpSrc).sort((a, b) => a.match(/(\d+)\.\w+$/)[1] - b.match(/(\d+)\.\w+$/)[1]);
} else if (fn.ge("figure.wp-block-image img[data-src]")) {
return fn.gae("figure.wp-block-image img[data-src]").map(e => e.dataset.src.replace(/-\d+x\d+(\.\w+)/, "$1")).sort((a, b) => {
try {
return a.match(/(\d+)\.\w+$/)[1] - b.match(/(\d+)\.\w+$/)[1];
} catch {
try {
return a.match(/\((\d+)\)\.\w+$/)[1] - b.match(/\((\d+)\)\.\w+$/)[1];
} catch {
return a;
}
}
});
} else if (fn.ge(".galeria_img>img")) {
return fn.gae(".galeria_img>img");
} else if (fn.ge(".s-post-content img[title][data-lazyloaded]")) {
return fn.gae(".s-post-content img[title][data-lazyloaded]").map(e => e.src);
} else if (fn.ge(".s-post-content img")) {
return fn.gae(".s-post-content img");
} else {
return [];
}
},
capture: () => _this.imgs(),
autoDownload: [0],
next: "a.next-page-link",
prev: "a.prev-page-link",
customTitle: () => fn.dt({
s: "h1.entry-title",
d: /Byoru – | \(Cosplay\)/g
}),
category: "nsfw1"
}, {
name: "4K Beautyful Cosplay Girl",
host: ["oo4k.com"],
url: () => fn.checkUrl({
e: [
"meta[property='og:title'][content$='4K Beautyful Cosplay Girl']",
"link[title=JSON]"
],
p: "/album/",
}) && !fn.lp.includes("/category/"),
init: () => {
fn.waitEle("._buttons,.post-nav-links").then(() => _unsafeWindow?.jQuery(document)?.off());
},
imgs: () => {
let json_url = fn.gu("link[title=JSON]");
fn.showMsg(DL.str_05, 0);
return fetch(json_url).then(res => res.json()).then(json => {
let dom = fn.doc(json.content.rendered);
return fn.getImgSrcArr([...dom.images]).filter(e => !e.includes("thumbnail"));
});
},
capture: () => _this.imgs(),
customTitle: () => fn.title(" - 4K Beautyful Cosplay Girl"),
hide: "._title>._helper",
category: "nsfw2"
}, {
name: "女神社",
url: {
h: ["nshens.com", "inewgirl.com", "lovens.shop"]
},
page: () => fn.clp(/^\/web\/\d+\/\d+\/\d+\/[^\/]+$/),
SPA: () => _this.page(),
observeURL: "nav",
imgs: () => {
if (!_this.page()) return [];
fn.showMsg(DL.str_05, 0);
return fn.fetchDoc(fn.clp()).then(async dom => {
let code = fn.gst("__NUXT__", dom);
let data = fn.parseCode(code);
apiCustomTitle = data.data[0].postData.title;
let url = "/web" + data.routePath;
let pageTotal = data.data[0].pageTotal;
if (!isNumber(pageTotal) || pageTotal == 0) {
pageTotal = 1;
}
let links = fn.arr(pageTotal, (v, i) => i == 0 ? url : url + "/" + (i + 1));
let fetchNum = 0;
let resArr = links.map((url, i, arr) => fn.fetchDoc(url).then(dom => {
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${arr.length}`, 0);
let code = fn.gst("photoList", dom);
if (i == 0) {
let is_v = ["videoid", "videourl"].every(k => code.includes(k));
if (is_v) {
console.log("有影片");
let a = code.indexOf("videoid");
let b = code.indexOf("}", a);
let str = code.slice(a - 1, b + 1);
str = str.replace(/like:[\s\w]+,/i, "")
let obj = fn.run(str);
console.log(obj);
videoSrcArray = [obj.videourl];
}
}
return fn.TextToArray(code, "photoList");
}));
let photourl = await Promise.all(resArr).then(data => data.flat().map(e => e.photourl));
if (photourl.length > [...new Set(photourl)].length) setTimeout(() => fn.showMsg("VIP套圖需升級為VIP", 5000), 1200);
return photourl;
});
},
button: [4],
insertImg: ["//div[a[div[@class='v-image v-responsive theme--light']]] | //div[@postid]/div[@style]", 2],
downloadVideo: true,
category: "nsfw2"
}, {
name: "Chottie", //很多都需要VIP,不然只會重複抓到第一頁的圖片
url: {
h: ["chottie.com", "chottie.org", "chinesehottie.com", "www.chinesehottie.com"]
},
page: () => fn.clp(/^\/blog\/(\w{2}\/)?archives\/\d+$/),
SPA: () => _this.page(),
observeURL: "nav",
imgs: () => {
if (!_this.page()) return [];
fn.showMsg(DL.str_05, 0);
return fn.fetchDoc(fn.clp()).then(async dom => {
let code = fn.gst("__NUXT__", dom);
let data = fn.parseCode(code);
apiCustomTitle = data.data[0].postData.title;
let url = "/blog" + data.routePath;
let pageTotal = data.data[0].pageTotal;
if (!pageTotal || !isNumber(pageTotal) || pageTotal == 0) {
pageTotal = 1;
}
console.log("pageTotal", pageTotal);
let links = fn.arr(pageTotal, (v, i) => i == 0 ? url : url + "/" + (i + 1));
let fetchNum = 0;
let resArr = links.map((url, i, arr) => {
return fn.fetchDoc(url).then(dom => {
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${arr.length}`, 0);
if (i == 0) {
let code = fn.gst("__NUXT__", dom);
let is_v = ["video", "poster"].every(k => code.includes(k));
if (is_v) {
console.log("有影片");
let a = code.indexOf("video");
let b = code.indexOf("{", a);
let c = code.indexOf("}", b);
let str = code.slice(b, c + 1);
let obj = fn.run(str);
console.log(obj);
videoSrcArray = [obj.link];
}
}
let code, imgs = [];
try {
code = fn.gst("imgList", dom);
imgs = fn.TextToArray(code, "imgList");
} catch {
try {
code = fn.gst("snapshotList", dom);
imgs = fn.TextToArray(code, "snapshotList");
} catch {}
}
return imgs;
});
});
let imgList = await Promise.all(resArr).then(data => data.flat());
if (imgList.length > [...new Set(imgList)].length) setTimeout(() => fn.showMsg("VIP套圖需升級為VIP", 5000), 1200);
return imgList;
});
},
button: [4],
insertImg: ["//div[a[div[@class='v-image v-responsive theme--light']]] | //div[@style][div/video[@poster]]", 2],
downloadVideo: true,
category: "nsfw2"
}, {
name: "街角ijjiao",
url: {
h: ["ijjiao.com", "api.ijjiao.com"]
},
page: () => fn.clp("/album"),
SPA: () => _this.page(),
observeURL: "nav",
imgs: () => {
if (!_this.page()) return [];
fn.showMsg(DL.str_05, 0);
return fn.fetchDoc(fn.clp()).then(dom => {
let code = fn.gst("__NUXT__", dom);
let data = fn.parseCode(code);
let url = data.routePath.replace(/\/\d+$/, "");
let pageTotal = data.data[0].pageTotal;
apiCustomTitle = data.data[0].postData.title;
let links = fn.arr(pageTotal, (v, i) => i == 0 ? url : `${url}/${i + 1}`);
return fn.getEle(links, "//script[contains(text(),'__NUXT__')]").then(scripts => {
let images = scripts.map(script => {
let data = _this.parseCode(script.textContent);
return data.data[0].postData.photoList;
}).flat();
thumbnailSrcArray = images.map(e => e.thumbnail);
return images.map(e => e.photourl);
});
});
},
category: "nsfw1"
}, {
name: "tu928美女写真网",
url: {
h: ["tu928.com"],
p: ".html"
},
box: [".gallery-description,.gallery-full-images", 1],
imgs: ".wp-block-image img,.gallery-full-images img",
button: [4],
insertImg: [
["box", 0, ".gallery-description,.gallery-full-images"], 2
],
customTitle: ".gallery-title",
hide: "body>div[style]:has(>a>img)",
category: "nsfw1"
}, {
name: "图集网",
url: {
h: ["www.aiavr.uk", "aiavr.uk", "m.aiavr.uk", "www.ialbum.uk", "ialbum.uk"],
p: /^\/(systemAlbum\/)?detail/,
s: "aid="
},
init: () => fn.showMsg(DL.str_05, 0).then(() => fetch("/api/album/info?id=" + fn.getUSP("aid")).then(res => res.json()).then(json => (siteJson = json.data) && fn.hideMsg())),
imgs: () => siteJson.imageList.map(({
url,
sourceWeb,
sourceUrl
}) => {
if (sourceWeb?.startsWith("http") && sourceUrl?.startsWith("/")) {
return sourceWeb + sourceUrl;
} else if (sourceUrl?.startsWith("http")) {
return sourceUrl;
} else if (url?.startsWith("http")) {
return url;
} else {
return null;
}
}),
capture: () => _this.imgs(),
autoDownload: [0],
next: () => {
let id = Number(siteJson?.pre?.id);
return id ? "/systemAlbum/detail?aid=" + id : null;
},
prev: 1,
customTitle: () => siteJson.title,
category: "nsfw1"
}, {
name: "爱死美女图片站",
host: ["www.24tupian.org", "m.24tupian.org"],
url: {
h: "24tupian.org",
p: /^\/\w+\/\d+\/\d+\/\d+\.html$/,
e: "img[data-original*='imgs.diercun.com']"
},
imgs: () => {
let pid = fn.gt("#pid");
let num;
let is_m = fn.lh.startsWith("m.");
if (is_m) {
num = Number(fn.gt(".ser").match(/(\d+)张/)[1]);
} else {
num = Number(fn.gt(".mores>a").match(/\d+/)[0]);
}
let max = Math.ceil(num / 21);
fn.showMsg(DL.str_05, 0);
let fetchNum = 0;
let links = fn.arr(max, (v, i) => `/ajax${is_m ? "" : "s"}.aspx?fun=${is_m ? "getmorett" : "getmore"}&id=${pid}&p=${i * 21}`);
let resArr = links.map(u => fetch(u).then(res => {
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${max}`, 0);
return res.text();
}));
return Promise.all(resArr).then(data => {
let html = data.join("");
let dom = fn.doc(html);
let datas = fn.gae("img[data]", dom).map(e => e.getAttribute("data"));
thumbnailSrcArray = datas.map(data => "https://imgs.diercun.com" + data);
return datas.map(data => "https://big.diercun.com" + _unsafeWindow.getbig(data));
});
},
button: [4],
insertImg: [
[".mores,.kshow", 2], 2
],
topButton: true,
customTitle: ".gtitle1>h1,.ser h1",
hide: "body>.mask",
category: "nsfw1"
}, {
name: "爱死美女图片鏡像站?",
url: {
h: "www.aisimm.com",
p: ".html",
e: [".gtps", "#hgg3"]
},
imgs: async () => {
let imgs = fn.gae(".gtps img");
if (fn.ge("//a[text()='尾页']")) {
let [, max] = fn.gu("//a[text()='尾页']").match(/_(\d+)\.html$/);
max = Number(max) + 1;
let links = fn.arr(max, (v, i) => i == 0 ? fn.url : fn.url.replace(".html", "") + `_${i}.html`);
imgs = await fn.getEle(links, ".gtps img");
}
thumbnailSrcArray = fn.getImgSrcArr(imgs);
return thumbnailSrcArray.map(url => {
let i = url.lastIndexOf("/");
let murl = url.substring(i + 1);
url = url.replace(murl, murl.substring(1));
url = url.replace(/imgs?\./, "big.");
return url;
});
},
button: [4],
insertImg: [
["#hgg3", 1], 2
],
topButton: true,
customTitle: ".gtitle1>h1",
category: "nsfw1"
}, {
name: "爱死美女图片M鏡像站?",
url: {
h: "m.aisimm.com",
p: ".html",
e: [".center1"]
},
imgs: async () => {
let imgs = fn.gae(".center1 img");
if (fn.ge(".page a[href$=html]")) {
let url = fn.gau(".page a[href$=html]").at(-1);
let [, max] = url.match(/_(\d+)\.html$/);
max = Number(max) + 1;
let links = fn.arr(max, (v, i) => i == 0 ? fn.url : fn.url.replace(".html", "") + `_${i}.html`);
imgs = await fn.getEle(links, ".center1 img");
}
thumbnailSrcArray = fn.getImgSrcArr(imgs);
return thumbnailSrcArray.map(url => {
let i = url.lastIndexOf("/");
let murl = url.substring(i + 1);
url = url.replace(murl, murl.substring(1));
url = url.replace(/imgs?\./, "big.");
return url;
});
},
button: [4],
insertImg: [
[".center1", 2], 2
],
topButton: true,
customTitle: ".ser h1",
category: "nsfw1"
}, {
name: "爱死cos美女图片站",
url: {
h: ["www.24cos.org", "24cos.org", "www.lovecos.net"],
p: /^\/\w+\/\d+\.html$/
},
imgs: async () => {
let pages = fn.gau(".page>a");
let liImgs = fn.gae(".mtp>li");
if (pages.length > 0 && liImgs.length < 21) {
await fn.getEle(pages, ".mtp>li", [".mtp", 0]);
}
thumbnailSrcArray = fn.gae(".mtp img").map(e => decodeURIComponent(e.src));
return thumbnailSrcArray.map(url => {
let i = url.lastIndexOf("/");
let murl = url.substring(i + 1);
url = url.replace(murl, murl.substring(1));
return url;
});
},
button: [4],
insertImg: [
[".mtp", 2, ".mtp"], 2
],
topButton: true,
customTitle: ".tmsg>h1",
css: ".tpmh img{filter:unset!important;}",
category: "nsfw1"
}, {
name: "Huamao wallpaper 花猫壁纸",
host: ["huamaobizhi.com", "ja.huamaobizhi.com", "en.huamaobizhi.com"],
url: {
h: "huamaobizhi.com",
p: "/mix/",
e: ".images-card"
},
init: async () => {
let load = fn.ge(".load-more-photos");
if (load) load.remove();
await fn.getNP(".images-card", "li.active+li>a", null, ".pagination");
fn.gae(".thumb-nsfw").forEach(e => e.classList.remove("thumb-nsfw"));
},
imgs: async () => {
thumbnailSrcArray = fn.gae(".images-card img").map(e => e.dataset.src ?? e.src);
fn.clearAllTimer(2);
fn.showMsg(DL.str_05, 0);
let fetchNum = 0;
const resBlobUrl = (id, max) => {
return fetch("/normal-download/", {
"headers": {
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"content-type": "application/x-www-form-urlencoded"
},
"body": `wallpaperId=${id}`,
"method": "POST"
}).then(res => res.blob()).then(blob => {
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${max}`, 0);
return URL.createObjectURL(blob);
});
};
let IDs = fn.gae("span[data-imgid]").map(e => e.dataset.imgid);
let bigImgsArr = [];
for (let id of IDs) {
bigImgsArr.push(await resBlobUrl(id, IDs.length));
//await delay(1500);
}
return bigImgsArr;
},
button: [4],
insertImg: [
["#main", 2], 0
],
customTitle: ".title>h1",
ex: "jpg",
category: "nsfw1"
}, {
name: "Huamao wallpaper 花猫壁纸 en.huamaobizhi.com 分類自動翻頁",
host: ["ja.huamaobizhi.com", "en.huamaobizhi.com"],
url: {
h: "huamaobizhi.com",
p: /^\/(mixs|tags|artists|people-tags)\/\?/
},
autoPager: {
ele: "//div[@class='row'][div[div[@class='mixs-card']]] | //div[@class='table-responsive table-sm-no-border'] | //div[div[div[@class='thumbnail']]] | //div[@class='tags-wrap']",
next: ".pagination li.active+li>a",
re: ".pagination",
pageNum: ".pagination li.active",
bF: (dom) => {
fn.gae(".mixs-card-img:not(.lock)", dom).forEach(e => {
let url = e.attributes[1].value.replaceAll("'", "");
e.outerHTML = `<div class="mixs-card-img" data-src="${url}" lazy="loaded" style="background-image: url('${url}');"></div>`;
});
fn.gae(".thumbnail .img-circle[v-lazy]", dom).forEach(e => {
let url = e.getAttribute("v-lazy").replaceAll("'", "");
e.outerHTML = `<img src="${url}" alt="${e.alt}" class="img-circle" data-src="${url}" lazy="loaded">`;
});
fn.gae(".tags-item img[v-lazy]", dom).forEach(e => {
let url = e.getAttribute("v-lazy").replaceAll("'", "");
e.outerHTML = `<img src="${url}" alt="${e.alt}" data-src="${url}" lazy="loaded">`;
});
}
},
openInNewTab: ".mixs-card-content>a:not([target=_blank])",
category: "autoPager"
}, {
name: "次元LSP/猫猫网盘/云边网盘/小易の云盘/ooo.pqdh.com",
url: {
h: ["cylsp.org", "pan.catcat.blog", "qinzhi.top", "alist.xiaoyiblog.fun", "yun.pqdh.com"]
},
SPA: true,
observeURL: "body",
imgs: () => fn.getAList(),
customTitle: () => fn.dt({
d: [" | 次元LSP", " | 猫猫网盘", " | 云边网盘", " | 小易の云盘", " | ooo.pqdh.com"]
}),
downloadVideo: true,
category: "nsfw1"
}, {
name: "柚子肉 微博Coser",
link: "https://youzirou.org/weibo/users",
url: {
h: ["youzirou.org"]
},
page: () => fn.clp(/^\/weibo\/user\/\d+(\/pics)?$/),
SPA: () => _this.page(),
observeURL: "nav",
init: () => _this.page() ? fn.fetchDoc(fn.clp()).then(dom => (doc = dom)) : void 0,
imgs: () => {
if (!_this.page()) return [];
fn.showMsg(DL.str_05, 0);
let id = fn.clp().split("/").at(3);
id = Number(id);
let p = [...doc.querySelectorAll("main p")].find(p => p.innerText == "微博数").previousElementSibling;
let postNum = Number(p.innerText);
let body = {
"operationName": "WeiboTweets",
"variables": {
"pagination": {
"page": 1,
"pageSize": postNum
},
"query": {
"userId": id
}
},
"query": "query WeiboTweets($pagination: Pagination!, $query: WeiboTweetsFilterQuery) {\n weiboTweets(pagination: $pagination, query: $query) {\n data {\n ...WeiboTweetFragment\n __typename\n }\n pager {\n page\n pageSize\n total\n __typename\n }\n __typename\n }\n}\n\nfragment WeiboTweetFragment on WeiboTweet {\n id\n content\n isChoice\n isLiked\n tweetCreateAt\n pics {\n ...WeiboPicFragment\n __typename\n }\n user {\n ...WeiboUserFragment\n __typename\n }\n __typename\n}\n\nfragment WeiboPicFragment on WeiboPic {\n id\n name\n ossKey\n imageInfo {\n ...WeiboImageInfoFragment\n __typename\n }\n __typename\n}\n\nfragment WeiboImageInfoFragment on WeiboPicImageInfo {\n width\n height\n __typename\n}\n\nfragment WeiboUserFragment on WeiboUser {\n id\n name\n info\n followersCount\n creatorId\n __typename\n}"
};
return fetch("/graphql", {
"headers": {
"content-type": "application/json"
},
"body": JSON.stringify(body),
"method": "POST"
}).then(res => res.json()).then(json => json.data.weiboTweets.data.map(e => e.pics).flat().map(e => "https://youzirou.org/cdn/weibo/large/" + e.name));
},
capture: () => _this.imgs(),
customTitle: () => _this.page() ? "微博" + fn.dt({
t: fn.gt("main p", 1, doc)
}) : null,
category: "nsfw1"
}, {
name: "𝐇𝐨𝐬𝐭𝐞𝐠𝐠",
url: {
h: "egg.heip.eu.org"
},
box: ["body"],
imgs: () => {
let urls = fn.gau(".file a");
videoSrcArray = urls.filter(url => fn.isVideo(url));
fileUrlArray = urls.filter(url => fn.isZip(url));
return urls.filter(url => fn.isImage(url));
},
button: [4],
insertImg: ["box", 3],
customTitle: () => fn.dt({
s: "h1>a:last-child"
}),
category: "nsfw2"
}, {
name: "新美图录/臺灣美腿女郎",
url: {
h: ["www.xinmeitulu.com", "www.twlegs.com"],
p: "/photo/"
},
imgs: "img[data-original]",
button: [4],
insertImg: [".text-center", 2],
customTitle: "h1.h3",
category: "nsfw1"
}, {
name: "美图录",
url: {
h: ["meitulu.me"],
p: "/item/",
e: ".mb-4>img[alt]"
},
imgs: () => fn.getImg(".mb-4>img[alt]", fn.gt(".pagination>li:last-child", 2), 9),
button: [4],
insertImg: [".mb-4", 1],
customTitle: ".top-title",
category: "nsfw1"
}, {
name: "秀窝/RMM吧/赞MM格式",
url: {
e: ["#showimg img", "//p[contains(text(),'图片数量') or contains(text(),'圖片數量')]"],
p: ".html"
},
init: () => fn.clearAllTimer(),
imgs: () => fn.getImgO("#showimg img", fn.gt("//p[contains(text(),'图片数量') or contains(text(),'圖片數量')]").match(/\d+/)[0], 9),
button: [4],
insertImg: ["#showimg", 2],
customTitle: ".weizhi h1",
referer: "",
mcss: ".content img{max-width:100%!important}",
category: "nsfw1"
}, {
name: "妹妹图",
url: {
h: ["mm.tvv.tw"],
p: "/archives/"
},
imgs: ".img-responsive",
button: [4],
insertImg: ["//p[img]", 2],
customTitle: ".blog-details-headline",
category: "nsfw1"
}, {
name: "Mei101",
host: ["www.mei101.com", "m.mei101.com", "www.mei101.net", "m.mei101.net"],
url: {
st: "var yaomei",
e: "#image_div",
p: ".html",
},
imgs: async () => {
let {
PID,
post_url,
max_page
} = _unsafeWindow.yaomei;
let data = new URLSearchParams({
action: "mei_imageall",
type: "all",
lazy: "false",
post_id: PID,
post_url
}).toString();
fn.showMsg(DL.str_05, 0);
let images = await fn.fetchDoc("/wp-admin/admin-ajax.php", {
"headers": {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-requested-with": "XMLHttpRequest"
},
"body": data,
"method": "POST"
}).then(dom => [...dom.images]);
if (images.length) {
return images;
} else {
let url = post_url.replace(".html", "");
let links = fn.arr(max_page, (v, i) => i == 0 ? post_url : `${url}/${i + 1}.html`);
return fn.getImgA("#image_div img", links);
}
},
button: [4],
insertImg: ["#content", 2],
customTitle: ".item_title>h1",
hide: ".single-views,.ad_xiangguan_up,.ad_dixuan",
category: "nsfw1"
}, {
name: "小姐姐么/妹妹图集",
url: {
h: ["xiaojiejie.me", "www.mmtuji.com"],
st: "chenxing"
},
init: () => {
if (fn.lh.includes("mmtuji")) {
_unsafeWindow.fuckyou = null;
_unsafeWindow.ck = null;
_unsafeWindow.hehe = null;
_unsafeWindow.comprehensiveCheck = null;
_unsafeWindow.onWindowSizeChange = null;
_unsafeWindow.onresize = null;
fn.clearAllTimer(3);
}
},
imgs: () => {
fn.showMsg(DL.str_05, 0);
let code = fn.gst("chenxing");
let chenxing = fn.TextToObject(code, "chenxing", 2);
return fn.fetchDoc("/wp-admin/admin-ajax.php", {
"headers": {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-requested-with": "XMLHttpRequest"
},
"body": `action=chenxing_imageall&type=all&post_id=${chenxing.PID}`,
"method": "POST",
}).then(dom => {
tempEles = [...dom.getElementsByTagName("p")];
return [...dom.images];
});
},
button: [4],
insertImg: ["#content", 2],
insertImgAF: (_, bar) => {
bar.before(...tempEles);
fn.gm_run("$(document).off()");
},
customTitle: () => fn.dt({
d: [
/ – 小姐姐| - 妹妹图集/,
/(\d+月\d+打赏群(自购)?资源)/
]
}),
css: ".content_left>p{margin:0}",
hide: ".affs",
category: "nsfw1"
}, {
name: "图片吧",
host: ["www.tp8.org"],
url: {
t: "图片吧",
p: /^\/\d+\.html$/,
e: "#image_div",
ee: "//a[@rel='category tag'][text()='演出视频']"
},
imgs: () => {
let max = fn.gt("//a[@class='page-numbers prev'][@title='下一页']//preceding-sibling::a[1]");
return fn.getImg("#image_div img", max, 9, [/\?x-oss-process.+$/, ""]);
},
button: [4],
insertImg: ["#content", 2],
insertImgAF: () => fn.run("$(document).off()"),
customTitle: () => fn.title(" – 图片吧"),
category: "nsfw1"
}, {
name: "美图吧",
url: {
h: "meituba.cc",
p: "/gallery/",
e: "#image_div"
},
imgs: () => {
let max = fn.gt("//a[@class='page-numbers prev'][@title='下一页']//preceding-sibling::a[1]");
return fn.getImg("#image_div img", max, "4");
},
button: [4],
insertImg: ["#content", 2],
customTitle: ".item_title",
category: "nsfw1"
}, {
name: "秀人图吧",
url: {
h: "www.502x.com",
p: /^\/\w+\/\d+\.html/
},
imgs: () => fn.getImgA("#content img", [fn.gu(".post_au>a")]),
button: [4],
insertImg: ["#image_div", 2],
customTitle: ".item_title>h1",
css: ".image_div a img{cursor:unset}",
hide: ".affs",
category: "nsfw1"
}, {
name: "FoamGirl",
url: {
h: "foamgirl.net",
p: ".html",
e: "a.imageclick-imgbox"
},
imgs: () => {
let max = Number(fn.gt(".mbx-nav-right")?.match(/\d+/g)?.at(-1)) || 1;
return fn.getImg("a.imageclick-imgbox", max, 9);
},
button: [4],
insertImg: [
["#image_div>*:last-child", 1, "#image_div br,a.imageclick-imgbox"], 2
],
customTitle: () => fn.dt({
s: ".item_title>h1",
d: /\n/g
}),
hide: ".affs",
category: "nsfw2"
}, {
name: "COSPLAY Girl 18+",
host: ["cosplay.girl18.net", "xiuren.girl18.net", "bobosocks.girl18.net", "imiss.girl18.net", "cosplay.girl18.net"],
url: {
h: ".girl18.net"
},
imgs: "#image_div img",
button: [4],
insertImg: ["#image_div", 2],
customTitle: ".item_title",
hide: ".item_images_info",
category: "nsfw2"
}, {
name: "Girl 18+/Bikini Girl",
host: ["girl18.net", "bikiniz.net"],
url: {
h: /girl18|bikiniz/
},
imgs: "#content img",
button: [4],
insertImg: ["#content", 2],
customTitle: ".item_title",
hide: ".item_images_info",
category: "nsfw1"
}, {
name: "18成人貼圖",
host: ["www.sexphotos.cc"],
reg: /^https?:\/\/www\.sexphotos\.cc\/\w+\/\d+\.html$/,
init: () => fn.waitEle(".article-body>img").then(e => fn.createImgBox(e, 1)),
imgs: ".article-body>img",
button: [4],
insertImg: [
["box", 0, ".article-body>img"], 2
],
autoDownload: [0],
next: "a.entry-page-prev[href$=html]",
prev: "a.entry-page-next[href$=html]",
customTitle: ".detail-title",
category: "nsfw2"
}, {
name: "九天美图",
host: ["meitu9.com", "jiutianmeitu.com", "www.2kl.net", "www.74p.net", "www.79011.net", "www.59669.net"],
url: {
e: ["#body-header-top", ".logo-pc", ".logo-moible"],
p: "/meitu/",
st: "chenxing"
},
box: ["#image_div", 1],
imgs: () => {
fn.showMsg(DL.str_05, 0);
return fn.fetchDoc("/ajax/", {
"headers": {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-requested-with": "XMLHttpRequest"
},
"body": `type=all&id=${_unsafeWindow.chenxing.PID}`,
"method": "POST",
}).then(dom => {
tempEles = [...dom.getElementsByTagName("p")];
return [...dom.images];
});
},
button: [4],
insertImg: ["box", 2],
insertImgAF: (_, bar) => {
bar.before(...tempEles);
fn.hideEle("#image_div,#image_div_all");
},
customTitle: ".item_title>h1",
hide: ".img-box,#installContainer",
category: "nsfw1"
}, {
name: "九天美图",
host: ["meitu9.com", "jiutianmeitu.com", "www.2kl.net", "www.74p.net", "www.79011.net", "www.59669.net"],
url: {
e: ["#body-header-top", ".logo-pc", ".logo-moible"],
p: "/chapter/"
},
imgs: ".image-stack img",
button: [4],
insertImg: [".image-stack", 2],
autoDownload: [0],
next: ".nav-links .current+a",
prev: "//div[@class='nav-links page_imges']/span[@class='page-numbers current']/preceding-sibling::a[1]",
customTitle: ".item_title>h1",
hide: "#installContainer",
category: "hcomic"
}, {
name: "Coser Lab",
url: {
h: ["coserlab.io"],
p: "/archives/",
ee: ".card-body .error-empty,.post-hide-content"
},
imgs: () => {
fn.showMsg("fn.xhrHEA(check)...", 0);
let xhrNum = 0;
return fn.gau("a.glightbox").map(u => u.replace("-scaled", "")).map(async (src, i, arr) => {
await delay(100 * i);
let res = await fn.xhrHEAD(src);
fn.showMsg(`fn.xhrHEAD(${xhrNum+=1}/${arr.length})`, 0);
let status = res.status;
return status == 404 ? src.replace(/(\.[a-z]+)$/i, "-scaled$1") : src;
});
},
thums: "a.glightbox img",
button: [4],
insertImg: [
[".masonry-list", 2, ".masonry-list"], 2
],
customTitle: "span.current,.card-body h1",
category: "nsfw2"
}, {
name: "Mega Gallery",
url: {
h: "ecy8.com"
},
imgs: ".wp-block-gallery img",
button: [4],
insertImg: [".wp-block-gallery", 2],
autoDownload: [0],
next: "a[rel=prev]",
prev: "a[rel=next]",
customTitle: ".wp-block-post-title",
category: "nsfw1"
}, {
name: "二刺猿地帶",
url: {
h: "cosplay-nextjs.vercel.app"
},
page: () => fn.clp("/albums/"),
data: () => fn.showMsg(DL.str_05, 0).then(() => fn.fetchDoc(fn.clp()).then(dom => (doc = dom) && fn.hideMsg())),
SPA: () => _this.page(),
observeURL: "nav",
loop: () => {
document.body.removeAttribute("data-scroll-locked");
document.body.removeAttribute("style");
},
init: () => _this.page() ? _this.data() : void 0,
imgs: () => {
if (_this.page()) {
let text = fn.__next_f(doc);
return fn.TextToArray(text, '"images":');
}
return [];
},
//capture: () => _this.imgs(),
insertImgBF: () => fn.waitEle("main div [aria-roledescription=carousel]+.grid img[itemprop=image]").then(() => fn.createImgBox(".shadow:has(h1)", 2)),
button: [4],
insertImg: ["box", 2],
customTitle: () => {
if (!_this.page()) return null;
let h = fn.gt(".bg-card h1", 1, doc);
let g = fn.gt(".bg-card p", 1, doc);
let text;
if (h.includes(g)) {
text = h;
} else {
text = g + " - " + h;
}
return fn.dt({
t: text
});
},
referer: "",
hide: "div[data-state=open]",
category: "nsfw1"
}, {
name: "AIHGAME",
url: {
h: ["aihgirl.com"],
p: ["/manga/detail/", "/gallery/detail/"]
},
imgs: ".gallery-images img,.manga-images img",
button: [4],
insertImg: [".gallery-images,.manga-images", 2],
customTitle: ".gallery-title,.manga-title",
category: "hcomic"
}, {
name: "美图坊",
host: ["www.yalatu.com", "m2ph.xyz", "www.m2ph.xyz", "110.40.75.172:39000"],
url: () => ["flutter.password", "flutter.account"].every(k => k in localStorage) && isM,
SPA: true,
init: () => {
if ("gallery_json" in localStorage) {
siteJson = JSON.parse(localStorage.getItem("gallery_json"));
}
_unsafeWindow.addEventListener("message", async event => {
if (["response", "change"].some(m => event.data === m)) {
await captureSrcB();
//debug(`\n自定義標題:${customTitle}`);
//debug("\n此圖集JSON資料\n", siteJson);
}
});
const ajaxHooker = addAjaxHookerLibrary();
ajaxHooker.filter([{
method: "POST",
type: "xhr",
url: "/ServerInfo",
}, {
method: "POST",
type: "xhr",
url: "/ServerConfig",
}, {
method: "POST",
type: "xhr",
url: "/Image/ImageUrl",
}]);
ajaxHooker.hook(request => {
//debug("API請求", request);
request.response = res => {
if (request.url.includes("/ServerConfig") || request.url.includes("/ServerInfo")) {
//debug("(ServerConfig_API || ServerInfo_API) 回應", res);
let text = new TextDecoder().decode(res.response);
let json = JSON.parse(text);
//debug("(ServerConfig_API || ServerInfo_API) 回應JSON", json);
if ("ipv4" in json.data) {
siteJson.big_image_base_url = Object.values(Object.fromEntries(Object.entries(json.data.ipv4).filter(([k, v]) => k.startsWith("big_image_base_url") && !!v)))[0];
} else if ("image_server_list" in json.data) {
//siteJson.big_image_base_url = json.data.image_server_list[Math.round(Math.random())].image_big_base;
siteJson.big_image_base_url = json.data.image_server_list[0].image_big_base;
} else {
Reflect.deleteProperty(siteJson, "big_image_base_url");
}
//debug("big_image_base_url", siteJson.big_image_base_url);
}
if (request.url.includes("/Image/ImageUrl")) {
//debug("ImageUrl_API回應", res);
let text = new TextDecoder().decode(res.response);
let json = JSON.parse(text);
//debug("ImageUrl_API回應JSON", json);
siteJson = Object.assign(siteJson, json);
siteJson.title = fn.dt({
t: siteJson.title
});
customTitle = siteJson.title;
localStorage.setItem("gallery_json", JSON.stringify(siteJson));
_unsafeWindow.postMessage("response", fn.lo);
}
};
});
},
imgs: () => {
if (!siteJson?.big_image_base_url && !siteJson?.data) return [];
let paths = JSON.parse(siteJson.data);
let base = siteJson.big_image_base_url;
let srcs = paths.map(p => base + p);
return srcs;
},
capture: () => _this.imgs(),
infiniteCapture: 1,
customTitle: () => siteJson?.title,
category: "nsfw1"
}, {
name: "孔雀海/洛丽网/ladymao图库/懒人看图",
host: ["www.kongquehai.top", "www.lolili.net", "www.ladymao.net", "www.lazymanpic.net"],
reg: [
/^https?:\/\/((www\.)?kongquehai\.top|(www\.)?lolili\.net)\/\w+\/\w+\/\w+\.html(\?btwaf=\d+)?$/i,
/^https?:\/\/(www\.)?ladymao\.net\/[a-z]{2,3}\/\w+(\?btwaf=\d+)?$/,
/^https?:\/\/(www\.)?lazymanpic\.net\/[a-z]{2,3}\/\w+(\?btwaf=\d+)?$/
],
imgs: async () => {
await fn.getNP(".m-list-content img", "//a[text()='下一页'][@class='next']", null, ".link_pages");
return fn.gae(".m-list-content img");
},
button: [4],
insertImg: [".m-list-content", 2],
autoDownload: [0],
next: ".sxpage_r>a",
prev: ".sxpage_l>a",
customTitle: () => fn.dt({
s: ".m-list-tools>h2",
d: [
/\(\d\)/,
/\[\d+[\s\.\+\w-\/]+\].*/,
/全网首发|免费下载|无损图包下载|未删减版|无删减图包/g
]
}),
category: "nsfw1"
}, {
name: "尤物秀",
host: ["www.youwushow.net"],
reg: /^https?:\/\/(www\.)?youwushow\.net\/pic\/\w+\.html(\?btwaf=\d+)?$/,
imgs: async () => {
await fn.getNP(".entry-content>*:not(.page-links)", "span.current+a", null, ".page-links");
return fn.gae(".entry-content img");
},
button: [4],
insertImg: [".entry-content", 2],
autoDownload: [0],
next: "a.prev-link",
prev: "a.next-link",
customTitle: () => fn.dt({
s: ".entry-title",
d: [
/\(\d\)/,
/\[\d+[\s\.\+\w-\/]+\].*/,
/全网首发|免费下载|无损图包下载|未删减版|无删减图包/g
]
}),
category: "nsfw1"
}, {
name: "iLegs时光印象网",
url: {
h: ["legskr.com"],
p: "/album/detail/"
},
imgs: "#lightgallery div.col-6[data-src]",
thums: "#lightgallery .img-fluid[data-src]",
button: [4],
insertImg: ["#lightgallery", 2],
customTitle: () => fn.dt({
s: ".title",
d: "Album name:"
}),
category: "nsfw1"
}, {
name: "比思在線圖庫",
host: ["bisipic.xyz", "bisipic.online"],
url: {
h: /bisipic\./,
p: "/thread-",
e: "img[zoomfile]"
},
imgs: () => fn.gae("img[zoomfile]").map(e => fn.lo + "/" + fn.attr(e, "zoomfile")),
button: [4, "24%", 2],
insertImg: ["[id^=postmessage]", 2],
customTitle: () => fn.dt({
t: fn.ge("meta[name=keywords]").content,
d: /【\d+P】.*$/
}),
category: "nsfw1"
}, {
name: "洛秀网/维秘秀",
host: ["www.loxiu.com", "www.xiunvw.com"],
url: {
t: ["洛秀网", "维秘秀"],
p: "/post/"
},
imgs: () => fn.getImg(".info-imtg-box>img[alt]", fn.gt(".pagebar>*:last-child", 3)),
button: [4],
insertImg: ["div:has(>.info-imtg-box)", 2],
autoDownload: [0],
next: "//a[p[text()='上一篇']]",
prev: "//a[p[text()='下一篇']]",
customTitle: ".info-title>h1",
category: "nsfw1"
}, {
name: "遛无写真格式",
url: {
h: [
"www.096d.com",
"www.0niz.com",
"www.1nlm.com",
"www.1plq.com",
"www.1tu5.com",
"www.1vtr.com",
"www.3pxa.com",
"www.3tck.com",
"www.4tck.com",
"www.54k5.com",
"www.5njs.com",
"www.5pwc.com",
"www.6evu.com",
"www.6kpo.com",
"www.6tck.com",
"www.6vtr.com",
"www.7k1a.com",
"www.7mqk.com",
"www.7tck.com",
"www.7u8t.com",
"www.09kt.com",
"www.c0h.net",
"www.df10.net",
"www.eshh.net",
"www.game1313.net",
"www.te2zn.com",
"www.tmm123.vip",
"www.wangblog.net",
"www.wjstbs.net",
"www.wsqap.com",
"www.wxytw.com",
"www.zhaixiaonan.com",
"www.vansankan.net",
"d2nx.com"
],
p: /^\/\d+\.html$/,
e: "#post_content img,.article-content img,.entry-content img",
ee: "//a[@rel='category tag'][contains(text(),'人物简历') or contains(text(),'宅男科技') or contains(text(),'时尚玩酷') or contains(text(),'身边事') or contains(text(),'追星一族') or contains(text(),'网红头条') or contains(text(),'大众娱乐') or contains(text(),'生活热点') or contains(text(),'影评剧透') or contains(text(),'娱乐时尚') or contains(text(),'吃喝玩乐') or contains(text(),'体育') or contains(text(),'亲子宠物') or contains(text(),'番号大全') or contains(text(),'番号推荐') or contains(text(),'最新番号') or contains(text(),'素人番号')]"
},
imgs: () => fn.getImgA("#post_content img,.article-content img,.entry-content img", ".pagelist a,.pagination a,.article-paging a"),
button: [4],
insertImg: ["#post_content,.article-content,.entry-content", 2],
autoDownload: [0],
next: "a[rel=prev],.article-nav-prev a",
prev: "a[rel=next],.article-nav-next a",
customTitle: () => fn.dt({
s: "h1",
d: [
/无圣光.+$/,
/无水印.+$/,
/无删减.+$/,
/高品质.+$/,
/超高清.+$/,
]
}),
css: ".article_container{padding:10px 0px!important}#post_content{padding:0px!important}",
mcss: ".container{max-width:100% !important}",
category: "nsfw1"
}, {
name: "原创妹子图/尤物私房图/极品美女图/免费私房图/私房网红图/尤物妹妹图",
//所有域名在環境變數urltz
host: ["www.ycmzt.com", "www.ywsft.com", "www.jpmnt.com", "www.mfsft.com", "www.sfwht.com", "www.ywmmt.com"],
url: {
e: [".b", "#picg", ".pagelist"],
p: /^\/[a-z]+\/[a-z]+\/\d+\/\d+\.html$/
},
init: () => {
fn.gae(".b a").forEach(a => a.removeAttribute("target"));
fn.gae("#picg a").forEach(a => (a.outerHTML = a.innerHTML));
fn.remove("iframe", 2000);
},
imgs: async () => {
fn.showMsg(DL.str_01, 0);
let max = fn.gt(".pagelist font~*:last-child", 2);
let url = siteUrl.replace(/(_\d+)?\.html$/, "");
let links = fn.arr(max, (v, i) => i == 0 ? url + ".html" : url + `_${i + 1}.html`);
let imgsArr = [];
for (let [page, link] of links.entries()) {
let dom = await new Promise(async resolve => {
for (let check = 1; check <= 100; check++) {
let res = await fetch(link);
if (res.status == 304 || res.status == 200) {
fn.showMsg(`${DL.str_02}${page + 1}/${Number(links.length)}`, 0);
let buffer = await res.arrayBuffer();
let decoder = new TextDecoder(document.characterSet || document.charset || document.inputEncoding);
let htmlText = decoder.decode(buffer);
let dom = fn.doc(htmlText);
resolve(dom);
break;
} else {
fn.showMsg(`第${page + 1}頁${res.status}重試第${check}次`, 2900);
await delay(3000);
}
}
});
let imgs = fn.gae("#picg img[alt]", dom);
let te = fn.gae("#picg img[alt]").at(-1);
imgs.forEach(e => {
imgsArr.push(e.cloneNode(true));
if (page != 0) insertAfter(te, e.cloneNode(true));
});
if (page != 0) {
let ce = fn.gae("h1,.page .pagelist");
let re = fn.gae("h1,.page .pagelist", dom);
if (ce.length == re.length) {
ce.forEach((e, i) => (e.outerHTML = re[i].outerHTML));
}
}
await delay(200);
}
return imgsArr;
},
button: [4],
insertImg: ["#picg", 2],
autoDownload: [0],
next: "//div[@class='b' and contains(text(),'上一')]/a",
prev: "//div[@class='b' and contains(text(),'下一')]/a",
customTitle: () => fn.dt({
s: "h1",
d: [
/第\d+页|^- /g,
/[\s-]+P\.\d/g,
/:/g
]
}),
topButton: true,
fancybox: {
v: 3,
insertLibrarys: 1
},
css: "#imgc img{margin:0px auto !important}#picg{max-width:1110px !important;margin:0 auto}#picg img:hover{transform:none !important}#picg img{filter:blur(0px) !important}",
hide: "body>br,#apic,#bzs7,.interestline+center,center+#pic,#qpai,#d4a,#divone,#xzpap1,#divpsgx,#bdivpx,#divfts,#divftsp,#app+div,#xzappsq,div.bg-text,#divpsg,#divStayTopright2,#bdssy,#qrcode2>.erweima-text,#qrcode2>center,#qrcode2>center+div,#d5tig,#pcapicb,#google_translate_element,#d5a>*:not([id]):not([class]),.slide>a+div,.slide>img+div,#xtjpp,#divftst,.interestline+.nav~span,.interestline+.nav~br",
category: "nsfw2"
}, {
name: "美女私房照/看妹图",
host: ["www.sfjpg.com", "www.sfmm.cc", "www.kmeitu.cc", "kanmeitu.net"],
url: {
t: ["美女私房照", "看妹图", "看妹圖"],
p: /^\/\w+\/\d+\.html$/,
e: "#picg img"
},
init: () => {
fn.gae(".b a").forEach(a => a.removeAttribute("target"));
fn.gae("#picg a").forEach(a => (a.outerHTML = a.innerHTML));
},
imgs: () => {
let [, max] = fn.gt(".pagelist span,.pagelist a[title=Page]").match(/\/(\d+)/);
return fn.getImgO("#picg img", max, 9, null, 0, ".page .pagelist");
},
button: [4],
insertImg: ["#picg", 2],
autoDownload: [0],
next: "//div[@class='b' and contains(text(),'上一')]/a",
prev: "//div[@class='b' and contains(text(),'下一')]/a",
customTitle: "h1",
topButton: true,
fancybox: {
v: 3,
insertLibrarys: 1
},
css: "#imgc img{margin:0px auto !important}#picg{max-width:1110px !important;margin:0 auto}#picg img:hover{transform:none !important}#picg img{filter:blur(0px) !important}",
hide: "body>br,.interestline+center,center+#pic,#xzpap1,#divpsgx,#bdivpx,#divfts,#divftsp,#app+div,#xzappsq,div.bg-text,#divpsg,#divStayTopright2,#bdssy,#qrcode2>center,#d5tig,#pcapicb,#pcapic,#google_translate_element,#d5a>*:not([id]):not([class]),union[id]",
category: "nsfw2"
}, {
name: "六色美图",
url: {
h: "www.06se.com",
p: /^\/\d+\.html/
},
imgs: ".article-content img",
button: [4],
insertImg: [
[".wp-posts-content", 2, ".wp-posts-content"], 2
],
autoDownload: [0],
next: "//a[p[text()='上一篇']]",
prev: "//a[p[text()='下一篇']]",
customTitle: ".article-title",
css: ".modal-open{overflow:unset!important;}",
hide: "#modal-system-notice,.container.fluid-widget,#zibpay_modal,#mini-imgbox,.modal-backdrop",
category: "nsfw1"
}, {
name: "秀图湾",
url: {
h: ["www.okxx.de", "okxx.de", "www.xiusz.de", "xiusz.de", "www.xiusz.com", "xiusz.com", "www.aiyes.de", "aiyes.de", "xy.aiyes.de"],
},
box: [".pic-group", 1],
imgs: () => {
let pages = fn.ge(".pagination");
if (pages) {
let [max] = fn.gt(".pagination li:last-child", 2).match(/\d+/);
let link = fn.gu(".pagination a");
let url = link.replace(/-\d\.htm$/, "-");
let links = fn.arr(max, (v, i) => url + `${i + 1}.htm`);
return fn.getImgA(".pic-group img", links);
} else {
return fn.gae(".pic-group img");
}
},
button: [4],
insertImg: [
["box", 0, ".pic-group,.pagination"], 2
],
customTitle: ".media-body h4",
category: "nsfw1"
}, {
name: "女神部落",
url: {
h: "girlsteam.club"
},
imgs: "#content img",
button: [4],
insertImg: ["#content", 2],
customTitle: ".item_title>h1",
category: "nsfw1"
}, {
name: "丝袜客",
url: {
h: "siwake.cc",
p: "/post/"
},
init: () => (tempEles = fn.gae(".Content>.newfujian")),
imgs: ".Content>a",
button: [4],
insertImg: [".Content", 2],
endColor: "white",
insertImgAF: (_, bar) => bar.before(...tempEles),
autoDownload: [0],
next: "a.fas",
prev: "a.next.fas",
customTitle: ".title",
category: "nsfw1"
}, {
name: "丝袜客 分類自動翻頁",
reg: /^https?:\/\/siwake\.cc\//,
autoPager: {
ele: "#main.gallery",
observer: "#main.gallery>.thumb",
next: "a.next.fas",
re: ".pagelist"
},
openInNewTab: "#main.gallery a:not([target=_blank])",
category: "autoPager"
}, {
name: "爱妹子",
url: {
h: ["xx.knit.bid"],
p: /^\/([\w-]+\/)?article\/\d+\//i,
e: ".item-image img"
},
box: [".image-container"],
imgs: () => {
if (fn.ge("li.next-page")) {
let max = fn.gt("li.next-page", 2);
let links = fn.arr(max, (v, i) => i == 0 ? fn.lp : fn.lp + `page/${i + 1}/`);
return fn.getImgA(".item-image img", links);
} else {
return fn.gae(".item-image img");
}
},
button: [4],
insertImg: [
["box", 0, ".item-image,.loading-indicator,.pagination-nav"], 2
],
insertImgAF: () => setTimeout(() => fn.clearAllTimer(2), 1500),
customTitle: ".focusbox-title",
css: "a{white-space:unset!important}",
hide: ".clickadu-container",
category: "nsfw1"
}, {
name: "爱妹子",
url: {
h: ["mm.187187.xyz", "999888.best"],
p: /^\/([\w-]+\/)?article\/\d+\//i,
e: "#img-box img"
},
imgs: "#img-box img",
button: [4],
insertImg: ["#img-box", 2],
customTitle: ".focusbox-title",
css: "a{white-space:unset!important}",
category: "nsfw1"
}, {
name: "爱妹子 反反廣告提示",
url: {
h: ["xx.knit.bid", "mm.187187.xyz", "999888.best"]
},
init: () => setTimeout(() => fn.clearAllTimer(2), 1000),
openInNewTab: ".excerpts-wrapper a:not([target=_blank])",
category: "ad"
}, {
name: "美女写真",
url: {
h: "portrait.knit.bid",
p: /^\/\w+\/\d+$/,
e: ".container>.container>img"
},
imgs: async () => {
let max = fn.gt("//li[a[text()='下页']]", 2);
let links = fn.arr(max, (v, i) => siteUrl + "?page=" + (i + 1));
return fn.getImgA(".container>.container>img", links, 300);
},
button: [4],
insertImg: [
[".container>.container>nav", 2, "nav[aria-label=pagination],.img-fluid"], 2
],
customTitle: ".container h1",
category: "nsfw1"
}, {
name: "美图网",
url: {
h: "meitu.knit.bid",
p: /^\/(beauty|handsome)\/[^\/]+$/,
e: ".details_item>img"
},
imgs: async () => {
let [max] = fn.gau("a[href*=gotoPage]").at(-2).match(/\d+/);
let links = fn.arr(max, (v, i) => siteUrl + "?page=" + (i + 1));
return fn.getImgA(".details_item>img", links, 300);
},
button: [4],
insertImg: [".details_item", 2],
customTitle: () => fn.gt(".text-center>h1").replace("|", "-"),
category: "nsfw1"
}, {
name: "美图网",
url: {
h: "meitu.knit.bid",
p: /^\/(news|street)\/\d+$/
},
imgs: ".news-body img",
customTitle: () => fn.gt(".text-center>h1").replace("|", "-"),
category: "nsfw1"
}, {
name: "福利兔",
url: {
h: "www.fulitu.cc",
p: ".html"
},
imgs: "div[data-fancybox]",
button: [4],
insertImg: [
["#masonry", 2, "#masonry"], 2
],
customTitle: ".post-info h2",
fancybox: {
v: 3,
css: false
},
category: "nsfw1"
}, {
name: "猎美社",
url: {
h: "liemeishe.com"
},
imgs: ".entry-content a[data-fancybox]",
button: [4],
insertImg: [".entry-content", 2],
customTitle: ".single-article h1",
fancybox: {
v: 3,
insertLibrarys: 1
},
category: "nsfw1"
}, {
name: "萌图社",
url: {
h: ["www.446m.com", "446m.com"],
p: /^\/index\.php\/\w+\/\d+\.html$/
},
imgs: "span.post-item",
button: [4],
insertImg: [".post-content", 2],
customTitle: () => fn.title(" - 萌图社"),
fancybox: {
v: 3,
css: false
},
category: "nsfw1"
}, {
name: "萌萝社",
url: {
h: ["www.042l.com", "042l.com"],
e: "//a[text()='显示全文']"
},
init: () => tempEles.push(fn.ge(".tags")),
imgs: () => {
let url = fn.gu("//a[text()='显示全文']");
return fn.fetchDoc(url).then(dom => fn.gae("#lightgallery .boximg", dom));
},
button: [4],
insertImg: ["#lightgallery", 2],
insertImgAF: (parent) => parent.append(...tempEles),
autoDownload: [0],
next: "//a[text()='上一篇']",
prev: "//a[text()='下一篇']",
customTitle: ".focusbox-title",
category: "nsfw1"
}, {
name: "日式JK旧版",
url: {
h: "v2.jk.rs",
p: ".html"
},
imgs: "div[data-fancybox]",
button: [4],
insertImg: ["#masonry", 2],
insertImgAF: () => fn.css("#masonry{position:unset!important;height:unset!important}"),
customTitle: () => fn.title(" - 日式JK"),
fancybox: {
v: 3,
css: false
},
referer: "",
category: "nsfw1"
}, {
name: "日式JK新版",
url: {
h: "www.jk.rs",
p: ".html",
ee: ".post-hide-content"
},
imgs: "a.glightbox",
button: [4],
insertImg: [
[".masonry-list", 2, ".masonry-list"], 2
],
insertImgAF: () => fn.css("#masonry{position:unset!important;height:unset!important}"),
customTitle: () => fn.title(" – 日式JK"),
referer: "",
category: "nsfw1"
}, {
name: "汉服网",
url: {
h: "hanfu.in",
e: ".mdui-chip-title"
},
imgs: "a[data-fancybox=gallery]",
customTitle: () => fn.dt({
s: ".mdui-chip-title",
d: "标题:"
}),
referer: "",
fancybox: {
blacklist: 1
},
category: "nsfw1"
}, {
name: "妹妹美",
host: ["mmm.red"],
reg: /^https?:\/\/(www\.)?mmm\.red\/art\/\d+$/,
exclude: ".login-tip",
imgs: "div[data-fancybox][data-src]",
autoDownload: [0],
next: "//div[text()='上一篇']/following-sibling::a",
prev: "//div[text()='下一篇']/following-sibling::a",
customTitle: ".post-info-text",
category: "nsfw1"
}, {
name: "胴体的诱惑/美图吧",
host: ["dongti.blog.2nt.com", "meituba.blog.2nt.com"],
reg: [
/^https?:\/\/dongti\.blog\.2nt\.com\/blog-entry-\d+.html$/,
/^https?:\/\/meituba\.blog\.2nt\.com\/blog-entry-\d+.html$/
],
imgs: ".inner-contents img",
button: [4],
insertImg: [".inner-contents", 2],
autoDownload: [0],
next: "//a[div[@class='pager_entry-box next-justify']]",
prev: "//a[div[@class='pager_entry-image-prev']]",
customTitle: "#entry-title",
category: "nsfw1"
}, {
name: "秀色女神",
url: {
h: ["www.xsnvshen.co", "www.xsnvshen.com"],
p: "/album/"
},
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr("img[id^='imglist'][data-original]");
return thumbnailSrcArray.map(e => e.replace("thumb_600x900/", ""));
},
button: [4],
insertImg: ["//li[img[@id='bigImg']]", 2],
customTitle: "h1",
css: ".workShow li img{max-width:100%!important}",
referer: "url",
category: "nsfw1"
}, {
name: "秀色女神M",
url: {
h: ["m.xsnvshen.co", "m.xsnvshen.com"],
p: "/album/"
},
imgs: async () => {
let [max] = fn.gt(".pg_current").match(/\d+$/);
thumbnailSrcArray = await fn.getImg("#arcbox img.lazy", max, 6);
return thumbnailSrcArray.map(e => e.replace("thumb_600x900/", ""));
},
button: [4],
insertImg: [
["#arcbox", 0, "//div[@id='arcbox']/p[img]"], 2
],
customTitle: "h1>a",
css: "#arcbox img{margin:unset;min-width:unset}",
referer: "url",
category: "nsfw1"
}, {
name: "秀色女神news",
url: {
h: ["www.xsnvshen.co", "www.xsnvshen.com", "m.xsnvshen.co", "m.xsnvshen.com"],
p: "/news/"
},
imgs: "#arcbox img",
button: [4],
insertImg: [
["#arcbox>*:first-child", 1, "//p[img]"], 2
],
customTitle: "h1",
css: "#arcbox img{margin:unset;min-width:unset}",
referer: "url",
category: "nsfw1"
}, {
name: "秀色女神OORPG",
url: {
h: "oorpg.com",
e: ["#masonry img", "h1.post-title"]
},
imgs: () => {
let getNum = src => Number(src.split("/").at(-1).match(/\d+/));
return fn.getImgSrcArr("#masonry img").filter(e => !e.includes("logo_girl.png")).sort((a, b) => getNum(a) - getNum(b));
},
button: [4],
insertImg: ["#masonry", 2],
customTitle: () => fn.dt({
s: "h1.post-title",
d: "-[秀人套图]"
}),
fancybox: {
v: 3,
css: false
},
category: "nsfw1"
}, {
name: "优图坊",
url: {
h: "www.anfn.cc",
p: /^\/\d+\.html$/
},
imgs: "img[bigimg]",
button: [4],
insertImg: [".picshow", 2],
customTitle: ".piccontext h2",
category: "nsfw1"
}, {
name: "Secret Home",
url: {
h: ["poiblog.com"]
},
page: () => fn.clp("/archives/"),
SPA: () => _this.page(),
observeURL: "loop",
init: () => _this.page() ? fn.waitEle([".post-content img", ".post-title"]) : void 0,
imgs: ".post-content img",
customTitle: ".post-title",
category: "nsfw1"
}, {
name: "HotAsiaGirl分頁模式",
url: {
h: "hotgirl.asia"
},
box: [".galeria_img", 1],
imgs: () => fn.getImgA(".galeria_img>img", ".pagination a[href]"),
button: [4],
insertImg: [
["box", 0, ".galeria_img,#pagination"], 2
],
customTitle: ".mvic-desc h3",
category: "nsfw2"
}, {
name: "HotAsiaGirl幻燈片模式",
url: {
h: "hotgirl.asia"
},
box: ["#carouselImageIndicators", 2],
imgs: "#carouselImageIndicators img",
button: [4],
insertImg: ["box", 2],
customTitle: ".mvic-desc h3",
category: "nsfw2"
}, {
name: "HotGirl World",
url: {
h: ["www.hotgirl2024.com", "hotgirl.world"],
P: "/g/"
},
init: () => fn.gae(".blur-image").forEach(e => e.classList.remove("blur-image")),
imgs: () => fn.getImg(".article__image-list img", fn.gt(".pagination__total") || 1),
button: [4],
insertImg: [".article__image-list", 2],
customTitle: ".article-header__title",
fancybox: {
v: 3,
css: false
},
category: "nsfw1"
}, {
name: "HotGirl World 分類自動翻頁",
reg: [
/^https?:\/\/(www\.hotgirl2024\.com|hotgirl\.world)\/(\?page=\d+)?$/,
/^https?:\/\/(www\.hotgirl2024\.com|hotgirl\.world)\/(category|agency|tag)\/\d+\.html\/(\?page=\d+)?$/,
/^https?:\/\/(www\.hotgirl2024\.com|hotgirl\.world)\/search\.html\/\?(page=\d+&)?q=/
],
init: () => fn.gae(".blur-image").forEach(e => e.classList.remove("blur-image")),
autoPager: {
ele: ".articles-grid",
next: ".pagination__item--active+a",
re: ".pagination",
lazySrc: "img[data-src]",
pageNum: ".pagination__item--active",
aF: () => _this.init(),
bottom: screen.height * 2
},
openInNewTab: ".articles-grid a:not([target=_blank])",
category: "autoPager"
}, {
name: "爱秀网",
url: {
h: "ixiu.one",
},
imgs: ".gallery-item img",
customTitle: "h1.post-title",
category: "nsfw1"
}, {
name: "MaoJiuJiu/SkyBird/TightImg/SexCity",
url: {
h: ["www.maojiujiu.com", "www.skybirdx.com", "www.tightimg.com", "www.sexscity.com"],
p: "/album/",
e: "#item_list img"
},
imgs: () => fn.getImgA("#item_list img", ".pager>a:not(.current)"),
capture: () => _this.imgs(),
customTitle: "h1.title",
setFancybox: "#item_list a:has(>img)",
category: "nsfw1"
}, {
name: "Photos XTAPO",
url: {
h: "photos.xtapo.org",
p: /^\/[^\/]+\/$/
},
box: [".dynamic-entry-content .code-block", 1],
imgs: ".dynamic-entry-content img",
button: [4],
insertImg: [
["box", 0, ".dynamic-entry-content .code-block,.dynamic-entry-content .code-block~*"], 2
],
customTitle: "article h2",
category: "nsfw1"
}, {
name: "Pibys",
url: {
h: "pibys.win",
e: ".page-links"
},
box: [".entry-content img", 1],
imgs: () => fn.getImgA(".entry-content img", ".page-links a"),
button: [4],
insertImg: [
["box", 0, "#FullPictureLoadMainImgBox~*"], 2
],
customTitle: ".entry-title",
category: "nsfw1"
}, {
name: "Pibys",
url: {
h: "pibys.com",
p: "/threads/"
},
box: [".btnSummary", 1],
imgs: ".divSummary img",
button: [4],
insertImg: [
["box", 0, ".btnSummary,.divSummary,.w3-row-padding:has(>div>.w3-margin-bottom),.w3-container:has(>.pagination)"], 2
],
customTitle: "#posttitle",
category: "nsfw1"
}, {
name: "TGG",
url: {
h: ["thegg.net"],
e: "#header img,#body img"
},
imgs: () => fn.getImgSrcset("#header img:not([alt*='author']),#body img:not([alt*='author'])").filter(src => !src.includes("banner")),
capture: () => _this.imgs(),
autoDownload: [0],
next: "//a[text()='Next post']",
prev: "//a[text()='Previous post']",
customTitle: ".info h2",
category: "nsfw1"
}, {
name: "LUVBP",
url: {
h: "luvbp.com",
ee: ".c-post-upgrade-cta"
},
imgs: ".kg-image-card img",
customTitle: ".c-post-hero__title",
category: "nsfw2"
}, {
name: "1Y Beauties",
url: {
h: "www.1y.is",
p: /^\/[\w-]+\/[^\.]+\.html$/i
},
imgs: () => fn.getImgA(".entry-content img", ".page-links a"),
capture: () => _this.imgs(),
customTitle: ".entry-title",
category: "nsfw1"
}, {
name: "BeautyLeg",
url: {
h: "www.beautyleg6.com",
p: /^\/\w+\/\d+\/\d+\.html/i
},
imgs: () => {
let max = Number(fn.gt(".page a")?.match(/\d+/)) || 1;
return fn.getImg(".contents img[alt]", max, 9);
},
button: [4],
insertImg: [".contents", 2],
autoDownload: [0],
next: ".pre>a",
prev: ".next>a",
customTitle: ".content>h1",
css: ".content .contents img{max-width:100%!important}",
category: "nsfw1"
}, {
name: "BeautyLegM",
url: {
h: "m.beautyleg6.com",
p: "view.php",
s: "aid="
},
imgs: () => {
let links = fn.arr(_unsafeWindow.totalpage, (v, i) => i == 0 ? siteUrl : siteUrl + "&pageno=" + (i + 1));
return fn.getImgA("#bigImg", links);
},
button: [4],
insertImg: [".show-simg", 2],
autoDownload: [0],
next: () => {
let next = fn.ge("a.f-r.l3");
return next ? next.href : null;
},
prev: 1,
customTitle: ".showcontbt>h1",
category: "nsfw1"
}, {
name: "Asianude4u",
host: ["www.asianude4u.net"],
reg: /^https?:\/\/www\.asianude4u\.net\/.+\/.+\/(#small-1)?$/,
exclude: "//a[@rel='category tag' and text()='Videos'] | //a[@rel='category tag' and text()='Madonna-AV']",
imgs: () => fn.ge(".wp-block-image a[href*=attachment_id]") ? fn.gae(".wp-block-image img[data-id]") : fn.gae(".wp-block-image>a,.mgl-img-container>a,.gallery a").map(e => e.href),
button: [4],
//insertImg: ["//li[img[@id='bigImg']]", 1],
insertImg: [
["div.entry>*:last-child", 2], 2
],
customTitle: "h1.entry-title",
css: "button.rmp_menu_trigger{z-index:100 !important}",
mcss: ".entry{width:100% !important}",
hide: ".single-box,.entry-img-300",
category: "nsfw1"
}, {
name: "Nudegirls4u",
url: {
h: ["nudegirls4u.com"]
},
imgs: ".rgg-imagegrid>a",
button: [4],
insertImg: [".rgg-container", 2],
customTitle: ".entry-title",
css: ".rgg-imagegrid{height:auto!important}",
category: "nsfw1"
}, {
name: "看美女",
url: {
h: "eyecoser.com"
},
imgs: ".entry-content img:not([data-src$='1616334013075.jpg'],[data-src$='AD1.jpg'])",
button: [4],
insertImg: [".entry-content", 2],
autoDownload: [0],
next: "a[rel=prev]",
prev: "a[rel=next]",
customTitle: "h1.entry-title",
category: "nsfw1"
}, {
name: "爱看 INS",
host: ["www.ikanins.com"],
reg: /^https?:\/\/www\.ikanins\.com\/[\w-]+\//,
imgs: "img[srcset]",
button: [4],
insertImg: [
[".entry-content", 0, "//p[img]"], 2
],
autoDownload: [0],
next: "a[rel=prev]",
prev: "a[rel=next]",
customTitle: ".entry-title",
category: "nsfw1"
}, {
name: "Jablehk",
host: ["jablehk.com"],
url: {
h: "jablehk.com"
},
imgs: ".gallery-strips-lightbox-link>img[data-src]",
thums: "figure.gallery-strips-item",
button: [4],
insertImg: [
[".gallery-strips-wrapper", 2, ".gallery-strips-wrapper"], 2, 2000
],
autoDownload: [0],
next: ".item-pagination-link--next",
prev: ".item-pagination-link--prev",
customTitle: "h1>strong",
category: "nsfw1"
}, {
name: "True Pic",
url: {
h: ["truepic.net"],
p: /^\/[\w-]+\/$/,
e: "//div[@class='entry-content']//p[img]"
},
box: ["//p[img]", 1],
imgs: () => fn.getImgA("//p/img", ".pagination_split_post a"),
button: [4],
insertImg: [
["box", 0, "//p[img]"], 2
],
customTitle: ".entry-content h2",
category: "nsfw1"
}, {
name: "TangMoc",
host: ["tangmoc.com"],
reg: /^https?:\/\/tangmoc\.com\/blog\/show\/\w+\/.+/,
init: () => fn.remove("//span[@id='install-pwa-box'] | //div[@class='row mt-3'] | //div[ins[@class='adsbygoogle']] | //div[@class='mt-3'][@id] | //div[@class='row my-5'] | //iframe[@id]"),
imgs: () => fn.ge(".btn-warning+.btn-secondary") ? fn.getImgA("a[href*=media]>.media-preview", "a.btn-secondary") : fn.gae("a[href*=media]>.media-preview"),
button: [4],
insertImg: ["//media[article]", 2],
customTitle: () => fn.dt({
s: "h1",
d: [
"View - ",
/[\s-]+$/
]
}),
category: "nsfw1"
}, {
name: "TangMoc去廣告",
host: ["tangmoc.com"],
reg: /^https?:\/\/tangmoc\.com\//,
init: () => fn.addMutationObserver(() => fn.remove("//span[@id='install-pwa-box'] | //div[@class='row mt-3'] | //div[ins[@class='adsbygoogle']] | //div[@class='mt-3'][@id] | //div[@class='row my-5'] | //iframe[@id]")),
category: "ad"
}, {
name: "Fapeza",
url: {
h: "fapeza.com",
e: ".profile-avatar-wrapper"
},
init: () => (siteJson.max = fn.ge("#load_more")?.dataset?.max || 1),
imgs: () => {
let [, avatar] = fn.lp.split("/");
let links = fn.arr(siteJson.max, (v, i) => `/ajax/model/${avatar}/page-${i + 1}/`);
return fn.getEle(links, ".image-row img").then(eles => {
let images = [];
let videos = [];
let thumbs = [];
eles.forEach(e => {
if (e.nextElementSibling) {
videos.push(e.src.replace("_400px.jpg", ".mp4"));
} else {
thumbs.push(e.src);
images.push(e.src.replace("_400px", ""));
}
});
videoSrcArray = videos.reverse();
thumbnailSrcArray = thumbs.reverse();
return images.reverse();
});
},
capture: () => _this.imgs(),
button: [4],
insertImg: [".image-grid-wrap", 3],
insertImgAF: () => fn.run("jQuery(window).off()"),
customTitle: () => fn.dt({
s: ".profile-wrapper h4"
}),
observerClick: ".superberb_b",
css: ".feed-profile-wrapper{padding-top: 58px}",
downloadVideo: true,
category: "nsfw2"
}, {
name: "Picazor",
url: {
h: ["picazor.com"],
},
page: () => fn.clp(/^\/[a-z]{2}\/[\w-]+$/) && !fn.clp("/tags"),
SPA: () => _this.page(),
observeURL: "gm",
init: () => _this.page() ? fn.fetchDoc(fn.clp()).then(() => fn.waitEle(".grid a")) : void 0,
imgs: async () => {
let [, , u] = fn.clp().split("/");
let max = Math.ceil(Number(fn.gu(".grid a").split("/").at(-1) / 12));
let links = fn.arr(max, (v, i) => i == 0 ? "/en/" + u : "/en/" + u + "/page/" + (i + 1));
let eles = await fn.getEle(links, ".grid a img");
let srcs = fn.getImgSrcArr(eles).reverse();
let urls = srcs.map(e => fn.getUSP("url", e));
let videos = [];
let thumbs = [];
let images = [];
urls.forEach((e, i) => {
if (e.includes(".mp4.")) {
let src = e.replace(".mp4.jpg", ".mp4");
if (src.startsWith("http")) {
videos.push(e);
} else {
videos.push(fn.lo + e);
}
} else {
thumbs.push(srcs[i]);
if (e.startsWith("http")) {
images.push(e);
} else {
images.push(fn.lo + e);
}
}
});
thumbnailSrcArray = thumbs;
videoSrcArray = videos;
return images;
},
downloadVideo: true,
category: "nsfw2"
}, {
name: "Fapello",
url: {
h: ["fapello.com", "pt.fapello.com"],
p: /^\/[^\/]+\/$/
},
init: () => {
let ele = fn.ge("#showmore");
let max = ele?.dataset?.max || 1;
siteJson.max = max;
},
imgs: async () => {
let eles;
if (siteJson.max > 1) {
let links = fn.arr(siteJson.max, (v, i) => i == 0 ? siteUrl : siteUrl + `page-${i + 1}/`);
eles = await fn.getEle(links, "#content>div");
} else {
eles = fn.gae("#content>div");
}
let imgSrcs = eles.map(node => {
if (fn.ge("img[src*='icon-play.svg']", node)) {
let videoSrc = fn.ge("img", node).src.replace("https://fapello.com/", "https://cdn.fapello.com/").replace("_300px", "").replace(/\.jpg$/i, ".mp4");
videoSrcArray.push(videoSrc);
return null;
} else {
thumbnailSrcArray.push(fn.ge("img", node).src);
let imgSrc = fn.ge("img", node).src.replace("_300px", "");
return imgSrc;
}
}).filter(Boolean).sort();
thumbnailSrcArray.sort();
videoSrcArray.sort();
return imgSrcs;
},
button: [4],
insertImg: ["#content", 3],
insertImgAF: () => {
fn.run("jQuery(window).off()");
fn.remove("#showmore,#next_page");
},
customTitle: () => fn.dt({
t: fn.title("/", 1),
d: " - Fapello"
}),
downloadVideo: true,
category: "nsfw2"
}, {
name: "Fapello",
url: {
h: ["fapello.pics", "xapello.com"],
e: "link[title=JSON]"
},
init: () => {
let ele = fn.ge("#showmore");
let max = ele?.dataset?.max || 1;
siteJson.max = max;
},
imgs: () => {
fn.showMsg(DL.str_05, 0);
let fetchNum = 0;
let id = fn.gu("link[title=JSON]").split("/").at(-1);
let url = "/wp-admin/admin-ajax.php?action=get_post_datac&post_id=" + id;
let urls = fn.arr(siteJson.max, (v, i) => i == 0 ? url : url + `&page=${i}`);
let resArr = urls.map(u => fetch(u).then(res => {
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${siteJson.max}`, 0);
return res.text();
}));
return Promise.all(resArr).then(data => {
let html = data.join("");
let dom = fn.doc(html);
let as = fn.gae("a[data-thumb]", dom);
thumbnailSrcArray = as.map(a => a.dataset.thumb).sort();
return as.map(a => a.href).sort();
});
},
button: [4],
insertImg: ["#mainbb,#first-contents", 3],
insertImgAF: () => {
fn.run("jQuery(window).off()");
fn.remove("#showmore");
},
customTitle: ".entry-content h2",
fancybox: {
blacklist: 1
},
category: "nsfw2"
}, {
name: "Fapello.su",
host: ["fapello.su"],
reg: /^https?:\/\/(www\.)?fapello\.su\/[^\/]+\/$/,
init: () => {
let ele = fn.ge("#showmore");
let max = ele?.dataset?.max || 1;
siteJson.max = max;
},
imgs: async () => {
let total = Number(fn.gt("//div[strong[text()='Media']]").match(/\d+/)[0]); //媒體總數
console.log("媒體總數", total);
const model_bid = fn.lp.replaceAll("/", "");
fn.showMsg(DL.str_05, 0);
let ajaxNum = 0;
let links = fn.arr(siteJson.max, (v, i) => `/ajax/model_new/${model_bid}/page-${i + 1}/photos`);
let resArr = [];
for (let url of links) {
let res = await fetch(url).then(res => {
fn.showMsg(`${DL.str_06}${ajaxNum+=1}/${siteJson.max}`, 0);
return res.text();
});
resArr.push(res);
await fn.delay(1000, 0);
}
let tempDom1;
let picNum;
await Promise.all(resArr).then(async arr => {
ajaxNum = 0;
let html = arr.join("");
tempDom1 = fn.doc(html);
picNum = [...tempDom1.images].length; //圖片數量
console.log("圖片數量", picNum);
thumbnailSrcArray = [...tempDom1.images].map(e => e.dataset.src);
console.log("縮圖地址", thumbnailSrcArray);
});
let videoNum = total - picNum;
let videoPages = Math.ceil(videoNum / 16);
fn.showMsg(DL.str_05, 0);
let links2 = fn.arr(videoPages, (v, i) => `/ajax/model_new/${model_bid}/page-${i + 1}/videos`);
let resArr2 = [];
for (let url of links2) {
let res = await fetch(url).then(res => {
fn.showMsg(`${DL.str_06}${ajaxNum+=1}/${videoPages}`, 0);
return res.text();
});
resArr2.push(res);
await fn.delay(1000, 0);
}
let tempDom2;
await Promise.all(resArr2).then(async arr => {
await delay(1000);
ajaxNum = 0;
let html = arr.join("");
tempDom2 = fn.doc(html);
let videoUrls = fn.gae("iframe.saint-iframe", tempDom2).map(e => e.src);
console.log("iframeVideoUrls", videoUrls);
fn.showMsg(DL.str_05, 0);
let getVideoUrlsArr = videoUrls.map((url, i, arr) => {
return fn.xhrDoc(url).then(dom => {
fn.showMsg(`${DL.str_06}${ajaxNum+=1}/${arr.length}`, 0);
return fn.src("source[type]", dom) || null;
});
});
await Promise.all(getVideoUrlsArr).then(async mp4Arr => {
await delay(1000);
mp4Arr = mp4Arr.filter(Boolean);
console.log("MP4地址", mp4Arr);
videoSrcArray = mp4Arr;
});
});
return thumbnailSrcArray.map(e => e.replace(".md.", "."));
},
button: [4],
insertImg: ["#content", 3],
insertImgAF: () => {
fn.run("scrollMore=()=>{}");
fn.remove("#showmore,#next_page,.content-action-buttons");
},
downloadVideo: true,
customTitle: ".container h2",
category: "nsfw2"
}, {
name: "Fapachi",
host: ["fapachi.com"],
reg: /^https?:\/\/fapachi\.com\/[^\/]+$/,
init: () => {
let medias = Number(fn.gt("//p[contains(text(),'Media')]").match(/\d+/)[0]);
siteJson.medias = medias;
},
imgs: async () => {
if (siteJson.medias > 24) {
let max = Math.ceil(siteJson.medias / 24);
let links = fn.arr(max, (v, i) => siteUrl + "/page/" + (i + 1));
thumbnailSrcArray = await fn.getImgA(".model-media-prew img", links).then(arr => arr.filter(src => src.includes("/models/")).sort());
return thumbnailSrcArray.map(e => e.replace("/300px/", "/full/").replace("_300px", ""));
} else {
thumbnailSrcArray = fn.getImgSrcArr(".model-media-prew img").filter(src => src.includes("/models/")).sort();
return thumbnailSrcArray.map(e => e.replace("/300px/", "/full/").replace("_300px", ""));
}
},
button: [4],
insertImg: ["//div[div[contains(@class,'model-media-prew')]]", 3],
customTitle: "h1",
category: "nsfw2"
}, {
name: "Faponic/Fapellas",
host: ["faponic.com", "fapellas.com"],
reg: /^https?:\/\/(faponic\.com|fapellas\.com)\/[^\/]+\/$/,
include: ".author-content",
init: () => {
let ele = fn.ge("#showmore");
let max = ele?.dataset?.max || 1;
siteJson.max = max;
},
imgs: () => {
let links = fn.arr(siteJson.max, (v, i) => i == 0 ? siteUrl : siteUrl + `page-${i + 1}/`);
return fn.getEle(links, ".photo-item>img");
},
button: [4],
insertImg: ["#content", 3],
insertImgAF: () => {
fn.run("scrollMore=()=>{}");
fn.remove("#showmore,#next_page");
},
customTitle: ".author-content>a",
category: "nsfw2"
}, {
name: "Fapullo",
host: ["fapullo.com"],
reg: /^https?:\/\/fapullo\.com\/[^\/]+\/$/,
init: () => {
let ele = fn.ge("#load_more");
let max = ele?.dataset?.max || 1;
siteJson.max = max;
},
imgs: () => {
let links = fn.arr(siteJson.max, (v, i) => i == 0 ? siteUrl : siteUrl + `page-${i + 1}/`);
return fn.getEle(links, ".thumb_img").then(eles => {
thumbnailSrcArray = fn.getImgSrcArr(eles).sort();
return thumbnailSrcArray.map(e => e.replace("_400px", ""));
});
},
button: [4],
insertImg: ["#media", 3],
insertImgAF: () => {
fn.run("scrollMore=()=>{}");
fn.remove("#load_more");
},
customTitle: () => fn.title("/", 1),
category: "nsfw2"
}, {
name: "Fapodrop/Fapsan",
url: {
h: ["fapodrop.com", "fapsan.com"],
e: ".one-pack img[src*=thumbnail]"
},
imgs: async () => {
await fn.getNP(".one-pack>a", "//a[text()='Next page']", null, ".row:has(>div>.page-btn)")
thumbnailSrcArray = fn.getImgSrcArr(".one-pack img[src*=thumbnail]");
thumbnailSrcArray = thumbnailSrcArray.reverse();
return thumbnailSrcArray.map(e => e.replace("/thumbnails/", "/photo/").replace("_thumbnail", ""));
},
button: [4],
insertImg: [".one-pack", 3],
customTitle: "h1.h3",
category: "nsfw2"
}, {
name: "Onlytreon/FapMenu",
url: {
h: ["onlytreon.com", "fapmenu.com"],
e: ".model-media-prew"
},
box: [".row:has(>.model-media-prew),.grig-model-media", 1],
imgs: () => {
let max = Math.ceil(Number(fn.gt("//p[contains(text(),'Media:')]").match(/\d+/g).at(-1)) / 24);
let links = fn.arr(max, (v, i) => i == 0 ? fn.lp : fn.lp + `/page/${i + 1}`);
return fn.getEle(links, ".model-media-prew a").then(as => {
let ts = as.map(a => a.firstElementChild);
thumbnailSrcArray = fn.getImgSrcArr(ts).sort();
links = as.map(a => a.href);
return fn.getImgA(".container .media-img", links).then(srcs => srcs.sort());
});
},
button: [4],
insertImg: [
["box", 0, ".row:has(>.model-media-prew),.grig-model-media"], 3
],
customTitle: ".container h1",
category: "nsfw2"
}, {
name: "WildSkirts",
url: {
h: "wildskirts.su",
st: "window['cid']"
},
imgs: () => {
let id = fn.ge(".like-btn").dataset.celeb;
fn.showMsg(DL.str_05, 0);
return fetch("https://api.wildskirts.su/api/media/" + id).then(res => res.json()).then(json => {
let srcs = [];
Object.values(json.media.items).forEach(e => {
if (e.t == "video") {
videoSrcArray.push(e.u);
} else if (e.t == "photo") {
thumbnailSrcArray.push(e.p);
srcs.push(e.u);
}
});
return srcs;
});
},
customTitle: ".profile-info .font-semibold",
downloadVideo: true,
fetch: 1,
category: "nsfw2"
}, {
name: "#TheFappening",
url: {
h: "fap.thefappening.one",
p: /^\/[^\/]+\/$/,
e: ".entry-title"
},
imgs: () => {
let a = fn.ge(".gallery-item a[target]");
if (a) {
return fn.gae(".gallery-item a[target]");
}
return fn.gae(".gallery-item img");
},
capture: () => _this.imgs(),
customTitle: () => fn.gt(".entry-title").replaceAll("/", "-"),
category: "nsfw2"
}, {
name: "The Fappening Plus",
host: ["thefappening.plus"],
reg: /^https?:\/\/thefappening\.plus\/[^\/]+\/$/,
imgs: async () => {
await fn.getNP(".gallery__item", "//a[text()='Next']", null, ".fusion-meta-info");
thumbnailSrcArray = fn.gae(".gallery_thumb").map(e => e.src).reverse();
return thumbnailSrcArray.map(e => e.replace(/_s(\.\w+)$/, "$1"));
},
button: [4],
insertImg: [".post-content", 2],
customTitle: () => fn.gt(".entry-title").replaceAll("/", "-"),
category: "nsfw2"
}, {
name: "TheFappening",
host: ["thefappeningblog.com"],
reg: /^https?:\/\/thefappeningblog\.com\/[^\/]+\/(#more-\d+)?$/,
include: "//a[noscript][not(@class)]",
imgs: "//a[noscript]",
button: [4],
insertImg: [
["//a[noscript]", 2, "//a[noscript]"], 2
],
customTitle: ".entry-title",
category: "nsfw2"
}, {
name: "TheFappening",
url: {
h: ["thefappeningblog.com"],
p: "/gallery/"
},
imgs: async () => {
await fn.getNP(".item_content", ".nav-next>a", null, ".nav-single");
thumbnailSrcArray = fn.gae(".item_img>img").map(e => e.src).reverse();
return thumbnailSrcArray.map(e => e.replace(/_\d+px(\.\w+)$/, "$1"));
},
button: [4],
insertImg: [".entry-content", 2],
customTitle: () => fn.gt(".entry-title").replaceAll("/", "-"),
category: "nsfw2"
}, {
name: "The Fappening",
url: {
h: "fap.thefappeningnew.com"
},
imgs: ".entry-content img",
customTitle: "h1.entry-title",
category: "nsfw2"
}, {
name: "The Fappening",
url: {
h: "thefappening2015.com"
},
srcset: ".lazy-gallery img,.entry-content .wp-image",
button: [4],
insertImg: [".entry-content", 2],
autoDownload: [0],
next: ".nav-previous a[rel=prev]",
prev: ".nav-previous a[rel=next]",
customTitle: "h1.entry-title",
hide: ".header-banner",
category: "nsfw2"
}, {
name: "AllPornImages",
url: {
h: ["allpornimages.com"]
},
imgs: ".entry-content img",
customTitle: ".entry-title",
category: "nsfw2"
}, {
name: "30Galleries",
url: {
h: "30galleries.com"
},
imgs: ".ngg-gallery-thumbnail>a",
thumb: ".ngg-gallery-thumbnail img",
customTitle: "h1.entry-title",
category: "nsfw2"
}, {
name: "Desi Porn Photo",
url: {
h: "desipornphoto.com"
},
imgs: ".gallery-item a",
thums: ".gallery-item img",
customTitle: "h1.entry-title",
category: "nsfw2"
}, {
name: "Fapomania",
host: ["fapomania.com"],
reg: /^https?:\/\/(\w+\.)?fapomania\.com\/[^\/]+\/$/,
box: [".previzakosblo", 2],
imgs: async () => {
const last = (dom) => !fn.ge(".leftocontar .previzako", dom);
await fn.getNP(".leftocontar .previzako", "//a[contains(text(),'Next')]", last, ".morebutaro");
thumbnailSrcArray = fn.gae(".leftocontar .previzakoimag>img:not([src$='leaks.png'])").map(e => e.src).reverse();
return thumbnailSrcArray.map(e => e.replace(/_\d+px(\.\w+)$/, "$1"));
},
button: [4],
insertImg: [
["box", 0, ".leftocontar .previzakosblo,.morebutaro"], 2
],
customTitle: () => fn.gt(".leftocontar>h1").replaceAll("/", "-"),
fancybox: {
v: 3,
insertLibrarys: 1
},
category: "nsfw2"
}, {
name: "Shemale Leaks",
url: {
h: ["shemaleleaks.com"],
p: /^\/[^\/]+\/$/
},
box: [".site-main", 2],
imgs: async () => {
const next = (dom) => {
let n = fn.ge(".nav-next>a", dom);
if (isEle(n)) {
let num = n.href.match(/\d+/).at(-1);
return fn.lp + "?page=" + num;
} else {
return null;
}
};
await fn.getNP("#main>article", next, null, ".post-navigation");
thumbnailSrcArray = fn.getImgSrcArr("#main>article img").reverse();
return thumbnailSrcArray.map(e => e.replace("_thumb.", "."));
},
button: [4],
insertImg: [
["box", 0, ".site-main"], 2
],
customTitle: "h1.page-title",
category: "nsfw2"
}, {
name: "NudoStar.TV",
host: ["nudostar.tv"],
reg: /^https?:\/\/nudostar\.tv\/models\/[^\/]+\/$/,
imgs: async () => {
await fn.getNP("#list_videos_common_videos_list_items>.item", ".next>a", null, "#list_models_models_list_pagination");
thumbnailSrcArray = fn.gae("#list_videos_common_videos_list img.thumb").map(e => e.src).reverse();
return thumbnailSrcArray.map(e => e.replace(/_\d+px(\.\w+)$/, "$1"));
},
button: [4],
insertImg: [".list-videos", 2],
customTitle: () => fn.gt(".headline>h1").replaceAll("/", "-"),
hide: ".zkido_div",
category: "nsfw2"
}, {
name: "NudoStar",
url: {
h: "nudostar.com",
p: /^\/[^\/]+\//
},
box: [".pagination-single", 1],
imgs: "//p/a[img]",
vioeos: "video.wp-video-shortcode>source",
button: [4],
insertImg: [
["box", 0, "//p[a[img]] | //div[@class='wp-video']"], 2
],
autoDownload: [0],
next: "a.previous-post",
prev: "a.next-post",
customTitle: "h1.entry-title",
category: "nsfw2"
}, {
name: "NudoStar",
url: {
h: "nudostar.com",
p: /^\/model\/[^\/]+\/$/
},
imgs: async () => {
await fn.getNP(".entry-content div:has(.item_content)", "a.next-post", null, ".pagination-single");
thumbnailSrcArray = fn.getImgSrcset(".entry-content img").reverse();
return thumbnailSrcArray.map(e => e.replace("_340", ""));
},
button: [4],
insertImg: [".entry-content", 2],
customTitle: "h1.entry-title",
category: "nsfw2"
}, {
name: "Fapopedia",
url: {
h: ["fapopedia.net", "fapopedia-net.theporn.how"],
p: /^\/[^\/]+\/$/,
e: "a[name='photos']"
},
box: [".shrt-blk", 2],
imgs: async () => {
await fn.getNP("//h2[i]/following-sibling::div[1][@class='shrt-blk']/div", "//a[text()='Next ']", null, ".nv-blk");
thumbnailSrcArray = fn.gae("//h2[i]/following-sibling::div[1][@class='shrt-blk']//img").map(e => e.src).sort();
let links = fn.gau("//h2[i]/following-sibling::div[1][@class='shrt-blk']//a");
return fn.getImgA(".lrg-pc>a", links).then(arr => arr.sort());
},
button: [4],
insertImg: [
["box", 0, "//h2[i]/following-sibling::div[1][@class='shrt-blk']|//div[@class='nv-blk']"], 2
],
customTitle: "h1",
category: "nsfw2"
}, {
name: "Nudogram",
host: ["nudogram.com", "dvir.ru"],
reg: [
/^https?:\/\/nudogram\.com\/models\/[^\/]+\/$/,
/^https?:\/\/dvir\.ru\/kingdesi\/models\/[^\/]+\/$/
],
imgs: async () => {
await fn.getNP("#list_videos_common_videos_list_items>.item", "//li[span]/following-sibling::li[1]/a", null, ".pagination");
thumbnailSrcArray = fn.gae("#list_videos_common_videos_list div.img>img").map(e => e.src).reverse();
return thumbnailSrcArray.map(e => e.replace(/_\d+(\.\w+)$/, "$1"));
},
button: [4],
insertImg: [".list-videos", 2],
customTitle: () => fn.gt(".headline>h2").replaceAll("/", "-"),
category: "nsfw2"
}, {
name: "Fappening Book",
host: ["fappeningbook.com"],
reg: /^https?:\/\/fappeningbook\.com\/[^\/]+\/$/,
include: ".model-thumbs-dv",
imgs: async () => {
await fn.getNP(".my-gallery>*", ".pages-dv a:has(.fa-angle-right)", null, ".pages-dv");
thumbnailSrcArray = fn.getImgSrcArr(".my-gallery li:not(.wp_xsize_class) img").reverse();
return fn.gae(".my-gallery li:not(.wp_xsize_class) a[data-orig]").reverse();
},
button: [4],
insertImg: [".model-thumbs-dv", 2],
customTitle: () => fn.ge("h1").textContent,
category: "nsfw2"
}, {
name: "HentaiDude TV",
host: ["hentaidude.tv"],
link: "https://hentaidude.tv/category/cosplay/",
reg: /^https?:\/\/hentaidude\.tv\/[\w-]+\/[^\/]+\/$/,
include: "h1.entry-title",
imgs: () => fn.getImgSrcArr(".post-thumb img,.entry-content a.swipebox").map(e => e.replace("198.16.76.146", "hentaidude.tv")),
capture: () => _this.imgs(),
customTitle: ".entry-title",
hide: "#cboxOverlay,#colorbox",
category: "nsfw2"
}, {
name: "Hotleaks/Thotsbay/Hotleak/Leakedzone/BestThots/Thotporn",
host: ["hotleaks.tv", "thotsbay.tv", "hotleak.vip", "leakedzone.com", "bestthots.com", "thotporn.tv"],
reg: () => /^https?:\/\/(hotleaks\.tv|thotsbay\.tv|hotleak\.vip|leakedzone\.com|bestthots\.com|thotporn\.tv)\/[\w\.-]+(\/photo)?$/i.test(fn.url) && !/^\/home/.test(fn.lp),
init: () => {
if (location.href.split("/").length === 4 && !fn.lh.includes("bestthots")) {
location.href = location.href + "/photo";
} else {
EClick("#photos-tab");
}
},
imgs: async () => {
if (/\/photo/.test(location.href)) fn.clearAllTimer();
let ptext = fn.gt("#photos-tab");
let num;
try {
let [, m] = ptext.match(/\(([\d\.K]+)\)/);
if (/\./.test(m) && /K/.test(m)) {
num = (Number(m.replace(/\.|K/g, "")) + 1) * 100;
} else if (/K/.test(m)) {
num = Number(m.replace(/K/g, "")) * 1000 + 100;
} else {
num = Number(m);
}
} catch {
num = Number(ptext.match(/\d+/g).join(""));
}
let pages = Math.ceil(num / 48);
let actorName = siteUrl.split("/")[3];
let imgsSrcArr = [];
let fetchNum = 0;
fn.showMsg(DL.str_05, 0);
for (let i = 1; i <= pages; i++) {
let json = await fetch(`/${actorName}?page=${i}&type=photos&order=0`, {
"headers": {
"x-requested-with": "XMLHttpRequest"
}
}).then(res => {
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${pages}`, 0);
return res.json();
});
if (json.length == 0) break;
let images;
if (fn.lh == "leakedzone.com") {
images = json.map(e => e.thumbnail.replace("_300.", "."));
} else if (fn.lh == "bestthots.com") {
images = json.map(e => e.image);
} else {
images = json.map(e => e.player);
}
let thumbnails = json.map(e => e.thumbnail);
imgsSrcArr = imgsSrcArr.concat(images);
thumbnailSrcArray = thumbnailSrcArray.concat(thumbnails);
if (json.length < 48) break;
}
return imgsSrcArr;
},
button: [4],
insertImg: ["#photos", 3],
customTitle: ".actor-name>h1,.actor-title-port",
category: "nsfw2"
}, {
name: "Hot Girl Pix",
url: {
h: "www.hotgirlpix.com",
p: "/p/"
},
imgs: () => fn.getImgA("article img", "#singlePostPagination a", 300),
button: [4],
insertImg: ["article", 2],
customTitle: "#singlePostTitle",
hide: "#modalAdblock,.alignCenter,.gcseSearchPlaceHolder",
category: "nsfw1"
}, {
name: "Hot Girl Pix AD",
host: ["www.hotgirlpix.com"],
reg: /^https?:\/\/www\.hotgirlpix\.com\//,
hide: "#modalAdblock",
category: "ad"
}, {
name: "套圖TAOTU.ORG",
url: {
h: "taotu.org"
},
box: [".piclist", 2],
imgs: "a[data-fancybox=gallery]",
thums: "a[data-fancybox=gallery] img",
button: [4],
insertImg: [
["box", 0, ".piclist"], 2
],
autoDownload: [0],
next: ".next a",
prev: ".prev a",
customTitle: ".suit_title>h1",
hide: "#right-bottom,#ad,.ad",
fancybox: {
v: 3,
css: false
},
category: "nsfw2"
}, {
name: "Taotuxp.com/www.taotucd.com",
url: {
h: ["www.taotucc.com", "www.taotucd.com"],
p: /^\/\d+\.html/
},
imgs: () => fn.getImg("#post_content img[alt]", fn.gt(".pagelist>*:last-child"), 7),
button: [4],
insertImg: ["#post_content", 1],
autoDownload: [0],
next: "a[rel=prev]",
prev: "a[rel=next]",
customTitle: "h1",
category: "nsfw1"
}, {
name: "爱死美女网",
url: {
h: ["www.2mn.cc", "2mn.cc"],
p: "/mm/"
},
imgs: "#post_content img",
button: [4],
insertImg: ["#post_content", 1],
autoDownload: [0],
next: ".post-previous a",
prev: ".nav-links .next",
customTitle: "#content h1",
category: "nsfw1"
}, {
name: "要常来美女图片网",
host: ["yaochanglai.com"],
url: {
p: "/pic/"
},
imgs: "#post_content img",
button: [4],
insertImg: ["#post_content", 1],
customTitle: "#content h1",
category: "nsfw1"
}, {
name: "美图海",
url: {
h: "www.meituhai.com",
p: "/album/",
ee: ".vip-tip"
},
imgs: "#gallery img",
button: [4],
insertImg: ["#gallery", 2],
customTitle: ".home_title",
category: "nsfw1"
}, {
name: "美推网",
host: ["www.meinvtui.com"],
url: {
//h: [/meinvtui\.com$/, "bbs.2tu.me"],
e: [".logo>a[title=美女图片]>img[alt=美女图片],nav.bg-w a[title=美女图片]", ".pp.hh,.contimglist"],
p: ".html"
},
imgs: () => {
let max = fn.gt(".pages>a,.page a").match(/\d+/g).at(-1);
max = Number(max);
return fn.getImg(".pp.hh img[alt],.contimglist img[alt]", max, 9);
},
button: [4],
insertImg: [".pp.hh,.contimglist", 2],
autoDownload: [0],
next: "//b[text()='上一篇:']/following-sibling::a | //a[@class='f-l l2'][@href]",
prev: "//b[text()='下一篇:']/following-sibling::a | //a[@class='f-l l3'][@href]",
customTitle: ".des>h1,.contmbx-title",
category: "nsfw1"
}, {
name: "推图网",
url: {
h: "www.tuiimg.com",
p: /^\/meinv\/\d+\/$/
},
init: () => {
fn.showMsg(DL.str_05, 0);
let url = fn.url.replace("www.tuiimg.com", "m.tuiimg.com");
return fn.xhrDoc(url, {
headers: {
"Referer": url,
"User-Agent": Mobile_UA
}
}).then(dom => {
let code = fn.gst("_pd", dom);
let [, path, , max, , next] = fn.TextToArray(code, "_pd");
path = "https://i.tuiimg.net/" + path;
siteJson.srcs = fn.arr(max, (v, i) => path + (i + 1) + ".jpg");
siteJson.next = null;
if (isNumber(next)) {
siteJson.next = "/meinv/" + next + "/";
}
});
},
imgs: () => siteJson.srcs,
button: [4],
insertImg: ["#content", 2],
insertImgAF: () => fn.remove("#tips,#myfav"),
autoDownload: [0],
next: () => siteJson.next,
prev: 1,
customTitle: "#main>h1",
category: "nsfw1"
}, {
name: "推图网M",
link: "https://m.tuiimg.com/meinv/",
url: {
h: "m.tuiimg.com",
p: "/meinv/",
st: "_pd"
},
init: () => {
let code = fn.gst("_pd");
let [, path, , max, , next] = fn.TextToArray(code, "_pd");
path = "https://i.tuiimg.net/" + path;
siteJson.srcs = fn.arr(max, (v, i) => path + (i + 1) + ".jpg");
siteJson.next = null;
if (isNumber(next)) {
siteJson.next = "/meinv/" + next + "/";
}
},
imgs: () => siteJson.srcs,
button: [4],
insertImg: ["#content", 2],
insertImgAF: () => fn.remove("#page,#tips,#myfav,#downappM"),
autoDownload: [0],
next: () => siteJson.next,
prev: 1,
customTitle: ".main>h1",
category: "nsfw1"
}, {
name: "18AV",
url: {
h: "18av.mm-cg.com",
st: "Large_cgurl",
e: ".sel_enlarge_page,.sel_enlarge"
},
imgs: () => _unsafeWindow.Large_cgurl,
button: [4],
insertImg: ["#show_cg_html,#showcg_container", 2],
customTitle: ".archive-title>h1,h1",
hide: ".ut1_img_content",
category: "nsfw1"
}, {
name: "Xgirls",
url: {
h: ["xgirlscollection.com", "img3xgirls.com"],
p: ["/collection/", "/album/"]
},
imgs: () => fn.getImg("img[id].collection-image,.album-image[data-pin-media]", (fn.gt(".pagination>*:last-child", 2) || 1)),
button: [4],
insertImg: ["//div[img[@data-pin-url]]", 1],
customTitle: ".container>h1",
category: "nsfw1"
}, {
name: "SexyAsianGirl",
url: {
h: ["www.sexyasiangirl.top", "sexyasiangirl.top"],
p: "/album/"
},
init: () => fn.remove("//article/div[a[img]]"),
imgs: () => fn.getImg("img.block", fn.gt("//a[text()='Next']", 2) || 1),
button: [4],
insertImg: ["//div[img[@title]]", 2],
customTitle: "header>h2",
category: "nsfw2"
}, {
name: "尤物丧志/亚色图库/福利姬美图/秀人图/極品妹子圖/涩图社/美乳小姐姐写真/三上悠亚写真图片/AHottie/高清妹子图/Coser/HotGirl",
url: {
h: [
/^youwu\./,
/^setu\./,
/^yase\./,
/^fuligirl\./,
/^xiuren(tu)?\./,
/jipin\./,
"stuba.netlify.app",
"meizi.pics",
"meiru.neocities.org",
"meitu.neocities.org",
"sanshang.neocities.org",
"coser.pics",
/sexygirl/,
/ahottie/,
"hotgirl.lat"
],
e: ["img.block", "//div[img[@title]]", "#main>h1,header>h1"]
},
imgs: async () => {
let srcs = await fn.getImg("img.block", fn.gt("a[rel=next]", 2) || 1);
return srcs.map(e => e.replace("teleimgs.pages.dev", "imgfiles.pages.dev"));
},
button: [4],
insertImg: ["//div[img[@title]]", 2],
next: "//span[contains(text(),'上一篇')]/following-sibling::a[1]",
customTitle: () => fn.dt({
s: "#main>h1,header>h1",
d: [
/\(\d+[\w\s\\\/\.+-/]+\)?|\[\d+[\w\s\\\/\.+-/]+\]?|(\d+[\w\s\\\/\.+-/]+)?|【\d+[\w\s\\\/\.+-/]+】?|\d+P/gi,
/\s?\d+P\+?\d+V/,
/未分类性感写真|^.+人体|AI图区/,
/(\d+月\d+打赏群(自购)?资源)/gi,
/🐾/g
]
}),
hide: "div.flex.m-1:has(>a[style]),.my-2:has(>a[target][referrerpolicy][style]),iframe[id][class][width][height][style],div:has(>script):has(>iframe),div:has([id*='adsby'])",
category: "nsfw2"
}, {
name: "胴体的秘密/AsianSexyBody/福利图库/COSER美女图",
host: ["dongti.netlify.app", "asiansexybody.netlify.app", "fulituku.neocities.org", "coser1.neocities.org"],
url: {
h: /netlify\.app|neocities\.org/,
p: "/posts/"
},
imgs: "#gallery img",
button: [4],
insertImg: ["#gallery", 2],
autoDownload: [0],
next: "//span[text()='Prev:']/following-sibling::a[1]",
prev: "//span[text()='Next:']/following-sibling::a[1]",
customTitle: "h1",
category: "nsfw2"
}, {
name: "网友自拍",
url: {
h: "yunvpicx.top",
s: "id"
},
imgs: ".pic_center img",
button: [4],
insertImg: [
[".content-text", 0, ".content-text br,.content-text .pic_center"], 2
],
customTitle: ".pagetitle",
category: "nsfw2"
}, {
name: "湿女吧",
host: ["shinv.link"],
url: {
t: "湿女吧",
p: "/posts/"
},
imgs: "header~div img[title]",
button: [4],
insertImg: ["header~div:has(>img[title])", 2],
autoDownload: [0],
next: "//span[text()='上一篇:']/following-sibling::a",
prev: "//span[text()='下一篇:']/following-sibling::a",
customTitle: "header h1",
category: "nsfw2"
}, {
name: "浪女吧/Ang4u",
url: {
h: ["langnv.neocities.org", "ang4u.neocities.org"],
p: "/posts/"
},
imgs: "#images img",
button: [4],
insertImg: ["#images", 2],
autoDownload: [0],
next: "#prevpost>a",
prev: "#nextpost>a",
customTitle: ".title",
category: "nsfw2"
}, {
name: "美图鉴赏/美图鉴赏ACG",
url: {
h: ["www.lspimg.com", "acg.lspimg.com"],
p: "/archives/"
},
imgs: "div[data-src]",
button: [4],
insertImg: ["#masonry", 2],
customTitle: () => fn.lh === "www.lspimg.com" ? fn.title(" - 美图鉴赏") : null,
css: "#masonry{position:unset!important;height:unset!important}",
hide: "#popup",
category: "nsfw2"
}, {
name: "ZbWu.Net",
url: {
h: ["img.zbwu.net"],
p: "/imgs/"
},
imgs: "div[data-src]",
button: [4],
insertImg: ["#masonry", 2],
customTitle: () => fn.dt({
s: ".post-info .post-info-text",
d: /[-\[\]\s\dPVGMB]+$/
}),
css: "#masonry{position:unset!important;height:unset!important}",
category: "nsfw1"
}, {
name: "VVCON美瞳网",
url: {
h: "www.vvcon.cn",
p: /^\/\d+\.html$/,
e: "//a[@class='post-list-cat-item b2-radius'][contains(text(),'Cosplay图集')]"
},
imgs: ".talk_pic img,.entry-content img",
customTitle: ".entry-header>h1",
category: "nsfw1"
}, {
name: "VVCON美瞳网",
url: {
h: "www.vvcon.cn",
p: /^\/\d+\.html$/,
e: "//a[@class='post-list-cat-item b2-radius'][contains(text(),'Cosplay图集')]"
},
imgs: ".entry-content p:has(>img)>img",
button: [4],
insertImg: [
[".entry-content p:has(>img)", 1, ".entry-content p:has(>img)"], 2
],
customTitle: ".entry-header>h1",
category: "nsfw1"
}, {
name: "TW Pornstars",
url: {
h: [
"www.twpornstars.com",
"www.twgays.com",
"www.twmilf.com",
"www.twlesbian.com",
"www.twteens.com",
"www.twonfans.com",
"www.twtiktoks.com",
"www.twgaymuscle.com",
"www.twanal.com",
"www.indiantw.com"
],
e: ".usercounters"
},
imgs: async () => {
let pagesNum = 1;
let p_last_t = fn.gt(".pagination li:last-child");
if (p_last_t === "»") {
pagesNum = fn.gt(".pagination li:last-child", 2);
}
let links = fn.arr(pagesNum, (v, i) => i == 0 ? fn.lp : fn.lp + `?page=${i + 1}`);
thumbnailSrcArray = await fn.getImgA(".thumb__img", links);
let videoLink = fn.ge(".videos-link[href]");
if (videoLink) {
let videoPostsLinks = [];
await fn.fetchDoc(videoLink.href).then(async dom => {
videoPostsLinks = fn.gae("a.thumb__link", dom);
let pagesNum = 1;
let p_last_t = fn.gt(".pagination li:last-child", 1, dom);
if (p_last_t === "»") {
pagesNum = fn.gt(".pagination li:last-child", 2, dom);
let links = fn.arr(pagesNum, (v, i) => i == 0 ? videoLink.href : videoLink.href + `?page=${i + 1}`);
links.shift();
let eles = await fn.getEle(links, "a.thumb__link");
eles.forEach(a => videoPostsLinks.push(a.href));
}
let videos = await fn.getEle(videoPostsLinks, "#video_tag source", null, null, 100, 3);
videoSrcArray = videos.map(e => e.src);
});
}
return thumbnailSrcArray.map(e => e.replace("small", "large"));
},
customTitle: ".block__title",
category: "nsfw2"
}, {
name: "tumbex",
url: {
h: "www.tumbex.com"
},
page: () => fn.clp("/post/"),
SPA: () => _this.page(),
observeURL: "head",
imgs: () => _this.page() ? fn.waitEle(".hg-item").then(() => {
let [content] = fn.gae(".post-content");
return fn.gae(".hg-item", content);
}) : [],
capture: () => _this.imgs(),
customTitle: () => _this.page() ? fn.title(" - Tumbex") : null,
referer: "",
category: "nsfw2"
}, {
name: "Simply Cosplay",
url: {
h: "www.simply-cosplay.com"
},
page: () => fn.clp("/gallery/"),
SPA: () => _this.page(),
observeURL: "nav",
init: () => fn.wait(() => !!_unsafeWindow?.user?.identifier),
imgs: () => {
if (!_this.page()) return [];
fn.showMsg(DL.str_05, 0);
let g = fn.clp().split("/").at(-1);
let token = _unsafeWindow?.user?.token ?? "01730876";
return fetch(`https://api.simply-porn.com/v2/gallery/${g}?token=${token}&related=8`, {
"headers": {
"identifier": _unsafeWindow.user.identifier,
},
}).then(res => res.json()).then(json => {
apiCustomTitle = json.data.title;
thumbnailSrcArray = json.data.images.map(e => e.urls.thumb.url);
return json.data.images.map(e => e.urls.url);
});
},
capture: () => _this.imgs(),
category: "nsfw2"
}, {
name: "OSOSEDKI",
url: {
h: ["ososedki.com"],
p: "/photos/"
},
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr("a[data-fancybox] img").sort((a, b) => a.match(/(\d+)\.\w+$/)[1] - b.match(/(\d+)\.\w+$/)[1]);
return fn.gau("a[data-fancybox]").sort((a, b) => a.match(/(\d+)\.\w+$/)[1] - b.match(/(\d+)\.\w+$/)[1]);
},
button: [4],
insertImg: ["//div[div[@id='masonry']]", 2],
customTitle: () => fn.ge("//meta[@property='og:description']").content,
css: ".grid-more{position:relative}",
category: "nsfw2"
}, {
name: "LEAKSFANS/CHARMINGASS/LEAKS PIE/CHERRY LEAKS/SWEETLEAKS/WEB CHARMING/TITSPIE",
url: {
h: [
"leaksfan.com",
"charmingass.com",
"leakspie.com",
"cherryleaks.com",
"sweetleaks.com",
"webcharming.com",
"titspie.com"
],
p: ["/gallery/", "/photo/", "/photos/", "/picture/", "/album/", "/post/", "/image/", "/img/", "/pic/", "/pics/", "/p/", "/g/"]
},
box: [".grid,.grid-,div.row:has(>.bg-dark)", 2],
imgs: "a[data-fancybox],.grid-item>img,.grid-item->img",
button: [4],
insertImg: [
["box", 0, ".grid,.grid-,div.row:has(>.bg-dark)"], 2
],
customTitle: () => fn.ge("h1.text-uppercase:not(.mt-2)").textContent.replace(/^[\w\s]+:/i, "").trim(),
css: ".grid-more{position:relative}",
hide: "noindex:has(>div>center),div:has(>center>noindex)",
category: "nsfw2"
}, {
name: "COSPLAYD.COM/COSPLAYG.COM/COSPLAYJ.COM/COSPLAYK.COM/COSPLAYP.COM",
url: {
t: /COSPLAY[A-Z]\.COM/,
h: /^cosplay[a-z]\.com$/,
p: /^\/\d+\//,
e: "main h1"
},
imgs: ".gallery img",
button: [4],
insertImg: [".gallery", 2],
customTitle: () => fn.dt({
s: "main h1",
d: /[\s\d-]+images.+$/
}),
category: "nsfw2"
}, {
name: "TNApics",
host: ["www.tnapics.com"],
reg: /^https:\/\/www\.tnapics\.com\/[\w-]+\/$/,
imgs: ".post-thumb-img-content img,a[data-fslightbox]",
repeat: 1,
customTitle: ".entry-title",
category: "nsfw2"
}, {
name: "Fapdungeon",
url: {
h: ["fapdungeon.com"]
},
init: () => fn.addMutationObserver(() => fn.remove("div[class][style*='z-index']")),
srcset: ".entry-content img.size-full",
videos: ".entry-content video>source",
customTitle: "h1.entry-title",
referer: "https://fapdungeon.com/",
setFancybox: ".entry-content img",
downloadVideo: true,
category: "nsfw2"
}, {
name: "Thotsbook/Ibradome/Fappenist/Lmlib/Teenswall",
url: {
h: ["thotsbook.com", "ibradome.com", "www.fappenist.com", "lmlib.com", "teenswall.com"],
p: "/photos/",
e: ["a.gallery-view", "h1.art-title"]
},
imgs: () => fn.getEle([fn.gu("a.gallery-view")], ".galeria").then(eles => {
let [g] = eles;
thumbnailSrcArray = fn.getImgSrcArr("img[data-src]", g);
return fn.gae("a.ohidden", g);
}),
capture: () => _this.imgs(),
customTitle: () => fn.dt({
s: "h1.art-title",
d: "Gallery view"
}),
fancybox: {
blacklist: 1
},
category: "nsfw2"
}, {
url: {
h: ["gotanynudes.com"],
},
srcset: ".entry-content img",
videos: "video>source",
customTitle: "h1.entry-title",
downloadVideo: true,
setFancybox: ".entry-content img",
referer: "https://gotanynudes.com/",
category: "nsfw2"
}, {
name: "Nude Cosplay Albums",
url: {
h: "nudecosplaygirls.com",
p: /^\/[^\/]+\/$/
},
imgs: () => {
let srcs = fn.getImgSrcset(".entry-content img.msacwl-img,#post img,.gallery-item img,figure.wp-block-image img");
return srcs.filter(e => !e.includes("/18plus"));
},
button: [4],
insertImg: [".entry-content,#post", 2],
customTitle: ".entry-title",
css: ".entry-content>img{width:auto !important;height:auto !important;max-width:100% !important;display:block !important;margin:0 auto !important}h1.g1-mega{text-align:center}",
hide: "#secondary",
category: "nsfw2"
}, {
name: "Jizz to Nude Girls",
url: {
h: "jizzy.org",
p: /^\/[^\/]+\/$/,
e: ".entry-content img"
},
imgs: () => fn.getImgSrcArr(".entry-content img").filter(src => !src.includes("18xmob")),
button: [4],
insertImg: [".entry-content", 2],
customTitle: ".entry-title",
category: "nsfw2"
}, {
name: "Leaked Models",
host: ["leakedmodels.com"],
reg: /^https?:\/\/leakedmodels\.com\/[^\/]+\/$/,
include: "//a[span[@class='faux-button'][text()='View']][@class='more-link']",
box: ["#site-content", 2],
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr("img.size-large").sort();
let links = fn.gau("//a[span[@class='faux-button'][text()='View']][@class='more-link']");
return fn.getImgA("img.wp-image", links).then(arr => arr.sort());
},
button: [4],
insertImg: ["box", 2],
customTitle: ".entry-title",
category: "nsfw2"
}, {
name: "ThotHub Leaks",
url: {
h: "thothub.vip",
p: "/album/",
e: ".images a img"
},
imgs: () => fn.getImgSrcArr(".images a img").map(e => e.replace(/main\/\d+x\d+/, "sources")),
thums: ".images a img",
button: [4],
insertImg: [".images", 2],
customTitle: ".title",
category: "nsfw2"
}, {
name: "ThotHub Leaks",
url: {
h: "thothub.vip",
e: ".entry-title"
},
imgs: ".entry-content img",
customTitle: () => fn.dt({
s: ".entry-title",
d: /\([\d\s]+Photos\)/i
}),
category: "nsfw2"
}, {
name: "ThotHD Albums / Thothub Albums / Epawg Albums",
host: ["thothd.com", "thothub.org", "thothub.su", "thothub.to", "thothub.lol", "thothub.mx", "thothub.ch", "thethothub.com", "epawg.com"],
url: {
h: [/thothd/, /thothub/, /epawg/],
p: "/albums/",
e: ".images a[data-fancybox-type] .thumb"
},
imgs: () => fn.getImgSrcArr(".images a[data-fancybox-type] .thumb").map(e => e.replace(/main\/\d+x\d+/, "sources")),
thums: ".images a[data-fancybox-type] .thumb",
button: [4],
insertImg: [".images", 2],
customTitle: "h1",
category: "nsfw2"
}, {
name: "Thothub.wtf",
host: ["redthot.com"],
url: {
t: "Thothub.wtf",
p: "/gallery/"
},
imgs: () => fn.getImgSrcset(".gallery_grid img"),
button: [4],
insertImg: [".gallery_grid", 2],
customTitle: () => fn.ge("h1.singletitle")?.textContent,
category: "nsfw2"
}, {
name: "BitchesFost",
url: {
h: ["bitchesfost.com"]
},
box: [".albumgrid-main", 2],
imgs: () => {
videoSrcArray = fn.gau(".albumgrid-main a[data-video-icon]");
thumbnailSrcArray = fn.getImgSrcArr(".albumgrid-main a[data-fancybox]:not([data-video-icon]) img");
return fn.gae(".albumgrid-main a[data-fancybox]:not([data-video-icon])");
},
button: [4],
insertImg: ["box", 2],
customTitle: "h1.entry-title",
category: "nsfw2"
}, {
name: "PornTrex",
url: {
h: "www.porntrex.com",
p: "/albums/"
},
box: [".album-info", 1],
imgs: ".slick-list a[data-fancybox-type]",
thums: ".slick-list a[data-fancybox-type] img",
button: [4],
insertImg: ["box", 2],
customTitle: ".title-video",
category: "nsfw2"
}, {
name: "WhoresHub",
url: {
h: "whoreshub.com",
p: "/albums/",
e: [".gallery-top", ".info-buttons"]
},
box: [".info-buttons", 1],
imgs: () => fn.gae(".gallery-top .swiper-wrapper img").map(e => e.dataset.srcset),
thums: ".gallery-thumbs img",
button: [4],
insertImg: ["box", 2],
customTitle: "h1.title",
category: "nsfw2"
}, {
name: "EachPorn",
url: {
h: "eachporn.com",
p: "/album/"
},
box: [".album-info", 1],
imgs: ".images a",
thums: ".images a img",
button: [4],
insertImg: ["box", 2],
customTitle: ".content h1",
category: "nsfw2"
}, {
name: "The Hentai World",
link: "https://thehentaiworld.com/hentai-cosplay-images/",
url: {
h: "thehentaiworld.com",
p: /^\/[^\/]+\/[^\/]+\/$/
},
box: ["#miniThumbContainer", 2],
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr("#miniThumbContainer img[itemprop='thumbnail']");
return thumbnailSrcArray.map(e => e.replace(/-\d+x\d+(\.\w+)/, "$1"));
},
button: [4],
insertImg: [
["box", 0, "#miniThumbContainer,#doujin,div.ad"], 2
],
customTitle: "h1",
category: "nsfw2"
}, {
name: "Akai Hentai",
link: "https://akaihentai.com/tag/cosplay/",
url: {
h: "akaihentai.com",
p: /^\/[^\/]+\/$/
},
init: () => _unsafeWindow.jQuery("body").off(),
box: [".comments", 1],
imgs: () => {
if (fn.ge(".single-thumbnail-wrap")) {
thumbnailSrcArray = fn.getImgSrcArr(".single-thumbnail-wrap img");
} else {
thumbnailSrcArray = fn.getImgSrcArr(".post-wrap a.image,video[poster]");
}
videoSrcArray = fn.gae("video[poster]").map(e => e.src);
return thumbnailSrcArray.map(e => e.replace(/-\d+x\d+(\.\w+)/, "$1"));
},
button: [4],
insertImg: [
["box", 0, ".single-thumbnail-wrap,.brxe-shortcode"], 2
],
customTitle: ".brxe-post-title",
hide: ".brxe-code",
category: "nsfw2"
}, {
name: "Cosplayers GoneWild",
url: {
h: ["cosplayersgonewild.net"],
p: "/albums/"
},
init: () => fn.waitEle("#main-carousel-list img"),
box: [".grid", 2],
imgs: "#main-carousel-list img",
button: [4],
insertImg: ["box", 2],
customTitle: "h1.text-3xl",
category: "nsfw2"
}, {
name: "奈奈COS",
url: {
h: "nncos.com",
p: ".html"
},
imgs: ".article-content>p>img",
button: [4],
insertImg: [".article-content>p", 2],
autoDownload: [0],
next: ".article-nav-prev a",
prev: ".article-nav-next a",
customTitle: "h1.article-title",
category: "nsfw2"
}, {
name: "Gallery Epic",
host: ["galleryepic.com", "galleryepic.xyz"],
url: {
h: "galleryepic",
p: /^\/(zh|en)\/(cosplay|album)\/\d+$/
},
init: () => fn.waitEle(["img[variant=thumbnail]", "next-route-announcer"]),
imgs: async () => {
fn.showMsg(DL.str_05, 0);
try {
let src = fn.src("img[variant=thumbnail]");
let dir = fn.dir(src);
let id = src.split("/").at(-1);
let dom = await fn.fetchDoc(fn.clp());
let data_a = [...dom.scripts].filter(script => script.textContent.includes(',\\"images\\":\\"['));
if (data_a.length) {
let code = data_a.at(0).textContent.replaceAll("\n", "").replaceAll("\\", "");
let images = fn.TextToArray(code, '"images":');
return images.map(e => dir + e);
}
let data_b = [...dom.scripts].filter(script => [id, '[\\"', '\\"]'].every(str => script.textContent.includes(str)));
if (data_b.length) {
let code = data_b.at(0).textContent.replaceAll("\n", "").replaceAll("\\", "");
let s = code.indexOf('["' + id);
let e = code.indexOf(']', s) + 1;
code = code.slice(s, e);
return JSON.parse(code).map(e => dir + e);
}
debug("代碼解析沒有提取出圖片網址");
await fn.wait(() => {
let button = fn.ge("//button[text()='加载更多' or text()='More']");
if (!!button) {
EClick(button);
}
return !button;
});
return fn.gae("img[variant='thumbnail']");
} catch (error) {
console.error(error);
}
},
button: [4],
insertImgBF: () => fn.createImgBox(".flex.flex-col.items-center:has(>.grid)", 2),
insertImg: ["box", 2],
insertImgAF: () => fn.hideEle(".flex.flex-col.items-center:has(>.grid)"),
customTitle: ".justify-between h2",
category: "nsfw1"
}, {
name: "Gallery Epic Cosplays 分類自動翻頁",
url: {
h: "galleryepic",
p: /^\/(zh|en)\/cosplays\/\d+$/
},
autoPager: {
ele: ".grid:has(>.relative)",
observer: ".grid>.relative",
next: "a[aria-label='Go to next page']:not([tabindex])",
re: "nav[role=navigation]",
showTitle: 0,
bF: (dom) => {
fn.gae(".animate-pulse", dom).forEach(e => {
e.nextSibling.className = "h-auto w-auto object-cover transition-all hover:scale-105 aspect-[3/4]";
e.nextSibling.dataset.src = e.nextSibling.src;
e.remove();
});
},
aF: (dom) => {
let last = fn.gae(".grid:has(>.relative)").at(-1);
fn.gae("img[data-src]", last).forEach(img => {
img.src = loading_bak;
fn.imagesObserver.observe(img);
});
}
},
category: "autoPager"
}, {
name: "Gallery Epic cosers 分類自動翻頁",
url: {
h: "galleryepic",
p: /^\/(zh|en)\/cosers\/\d+\??$/
},
autoPager: {
ele: ".grid:has(>.flex)",
observer: ".grid>.flex",
next: "a[aria-label='Go to next page']:not([tabindex])",
re: "nav[role=navigation]",
showTitle: 0,
bF: (dom) => {
fn.gae(".animate-pulse", dom).forEach(e => {
e.nextSibling.removeAttribute("class");
e.nextSibling.dataset.src = e.nextSibling.src;
e.remove();
});
},
aF: (dom) => {
let last = fn.gae(".grid:has(>.flex)").at(-1);
fn.gae("img[data-src]", last).forEach(img => {
img.src = loading_bak;
fn.imagesObserver.observe(img);
});
}
},
category: "autoPager"
}, {
name: "Gallery Epic Coser 分類自動翻頁",
url: {
h: "galleryepic",
p: /^\/(zh|en)\/coser\/\d+\/\d+\??$/
},
autoPager: {
ele: ".grid:has(>.relative)",
observer: ".grid>.relative",
next: "a[aria-label='Go to next page']:not([tabindex])",
re: "nav[role=navigation]",
showTitle: 0,
bF: (dom) => {
fn.gae(".animate-pulse", dom).forEach(e => {
e.nextSibling.className = "h-auto w-auto object-cover transition-all hover:scale-105 aspect-[3/4]";
e.nextSibling.dataset.src = e.nextSibling.src;
e.remove();
});
},
aF: (dom) => {
let last = fn.gae(".grid:has(>.relative)").at(-1);
fn.gae("img[data-src]", last).forEach(img => {
img.src = loading_bak;
fn.imagesObserver.observe(img);
});
}
},
category: "autoPager"
}, {
name: "Nude Bird/Nude Cosplay",
url: {
h: ["nudebird.biz", "nudecosplay.biz"],
p: /^\/[^\/]+\/$/,
e: "//p[a[img]]",
},
init: () => {
let video = fn.ge(".online-video");
if (video) {
let x = fn.ge("//p[a[img]]");
fn.gae(".online-video").forEach(e => insertBefore(x, e));
}
},
imgs: ".thecontent a,.content-inner>p>a",
button: [4],
insertImg: ["//p[a[img]]", 2],
customTitle: () => fn.dt({
s: "h1",
d: "nudecosplay.biz"
}),
category: "nsfw1"
}, {
name: "Cosplaytele",
url: {
h: ["cosplaytele.com"],
p: /^\/[^/]+\/$/,
},
imgs: "figure.gallery-item a",
button: [4],
insertImg: [".gallery", 2],
endColor: "white",
customTitle: "h1.entry-title",
category: "nsfw2"
}, {
name: "Rule34Cosplay",
url: {
h: ["rule34cosplay.com"],
p: "/feed/"
},
box: ["a[href^='/media/']", 1],
imgs: "a[href^='/media/'] img",
button: [4],
insertImg: [
["box", 0, "a[href^='/media/']"], 2
],
customTitle: "h2.text-base",
category: "nsfw2"
}, {
name: "Cosplay18",
url: {
h: "cosplay18.pics",
p: /^\/[^/]+\/$/,
},
imgs: ".single-page img",
button: [4],
insertImg: [
[".single-page", 0, ".single-page>ul"], 2
],
endColor: "white",
customTitle: "h1.entry-title",
category: "nsfw2"
}, {
name: "HOTPIC",
url: {
h: ["hotpic.cc"],
p: "/album/"
},
imgs: () => {
videoSrcArray = fn.gae("a[data-media=video]").map(e => e.dataset.srcMp4);
return fn.gae("a[data-media=image]");
},
capture: () => _this.imgs(),
customTitle: ".title",
category: "nsfw2"
}, {
name: "RussiaSexyGirls/EuroSexyGirls/UsaSexyGirls/AsianSexyGirls/LatinSexyGirls/EbonySexyGirls",
url: {
h: ["russiasexygirls.com", "eurosexygirls.com", "usasexygirls.com", "asiansexiestgirls.com", "latinsexygirls.com", "ebonysexygirls.com"],
p: /^\/\d+\/[\w-]+\/$/
},
imgs: ".entry-summary img:not([width='18'])",
autoDownload: [0],
next: ".prevPost>a",
prev: ".nextPost>a",
customTitle: "span.entry-title",
category: "nsfw2"
}, {
name: "JimmysOnline.com",
url: {
h: "www.jimmysonline.com",
p: /^\/[^\/]+\/$/,
e: "a.aigpl-img-link[data-mfp-src]"
},
imgs: () => fn.gae("a.aigpl-img-link[data-mfp-src]").map(a => a.dataset.mfpSrc),
button: [4],
insertImg: [".aigpl-gallery", 2],
customTitle: ".entry-title",
category: "nsfw2"
}, {
name: "gaidam18",
url: {
h: ["gaidam18.com", "gaingon18.me"],
p: /^\/[^\/]+\/$/,
e: ".entry-content img"
},
imgs: () => {
if (fn.ge(".gallery-item img")) {
return fn.gae(".gallery-item img");
} else if (fn.ge(".entry-content>.separator>img[src*='blogger.']")) {
return fn.gae(".entry-content>.separator>img[src*='blogger.']");
} else if (fn.ge(".entry-content>div>a[href*='blogger']")) {
return fn.gae(".entry-content>div>a[href*='blogger']").map(a => {
let url = a.href;
let urlArr = url.split("/");
urlArr[urlArr.length - 2] = "s16000";
return urlArr.join("/");
});
} else if (fn.ge(".entry-content img[src*='/wp-content/uploads/']")) {
return fn.gae(".entry-content img[src*='/wp-content/uploads/']");
} else {
return [];
}
},
button: [4],
insertImg: [".gallery,.entry-content", 2],
customTitle: () => fn.dt({
s: "h1.entry-title",
d: "Ảnh sex "
}),
hide: "[class^='float']",
category: "nsfw2"
}, {
name: "Game-happy-life",
url: {
h: "gamehappylife.top",
p: /^\/[^\/]+\/$/,
e: "figure.wp-block-image"
},
imgs: () => fn.getImgA("figure.wp-block-image>a,figure.wp-block-image>img", ".page-links>a"),
button: [4],
insertImg: ["figure.wp-block-image", 2],
autoDownload: [0],
next: ".nav-previous>a",
prev: ".nav-next>a",
customTitle: "h1.entry-title",
category: "nsfw1"
}, {
name: "XikXak",
url: {
h: "www.xikxak.com",
p: /^\/\d+$/
},
imgs: ".entry-content img",
button: [4],
insertImg: [".entry-content", 2],
autoDownload: [0],
next: ".nav-previous>a",
prev: ".nav-next>a",
customTitle: "h1.entry-title",
category: "nsfw1"
}, {
name: "JJCOS",
url: {
h: ["jjcos.com"],
p: "/post/"
},
init: () => (tempEles = fn.gae("#post-content h2")),
imgs: "#post-content img",
button: [4],
insertImg: ["#post-content", 2],
insertImgAF: (_, b) => b.before(...tempEles),
autoDownload: [0],
next: ".next:has(.fa-chevron-left)+a",
prev: ".next:has(.fa-chevron-right)+a",
customTitle: "#post-content h2",
category: "nsfw2"
}, {
name: "Xiunice.com",
url: {
h: ["xiunice.com"]
},
box: [".wp-block-gallery", 1],
imgs: ".wp-block-gallery img",
button: [4],
insertImg: [
["box", 0, ".wp-block-gallery"], 2
],
autoDownload: [0],
next: ".nav-previous .prev>a",
prev: ".nav-previous .next>a",
customTitle: "h1.tdb-title-text,h1.entry-title",
category: "nsfw2"
}, {
name: "CG Cosplay",
url: {
h: ["cgcosplay.org"],
p: /^\/\d+\/$/
},
init: () => {
let video = fn.ge(".fluid_video_wrapper");
if (video) {
let x = fn.ge(".gallery");
fn.gae(".fluid_video_wrapper").forEach(e => insertBefore(x, e));
}
},
imgs: ".gallery .gallery-item a:has(>img:not([src$='/banner']))",
next: ".nav-previous a[rel=prev]",
prev: ".nav-next a[rel=next]",
customTitle: ".elementor-heading-title",
hide: "#page+[id][class]:has(.adblock_title),.code-block",
category: "nsfw1"
}, {
name: "CG Cosplay AAD",
reg: /^https?:\/\/cgcosplay\.org\//,
hide: "#page+[id][class]:has(.adblock_title)",
category: "ad"
}, {
name: "AsiaOnTop",
url: {
h: ["asiaontop.com", "asiaon.top"]
},
SPA: true,
imgs: () => fn.gae(".modula-gallery div[data-src]"),
repeat: 1,
customTitle: () => fn.gt("#__next h1").replace(":", " -"),
category: "nsfw2"
}, {
name: "Mitaku",
url: {
h: "mitaku.net",
e: "a.msacwl-img-link[data-mfp-src]"
},
imgs: () => fn.gae("a.msacwl-img-link[data-mfp-src]").map(a => a.dataset.mfpSrc),
button: [4],
insertImg: [
[".entry-content", 2], 2
],
autoDownload: [0],
next: ".previous>a",
prev: ".next>a",
customTitle: () => fn.dt({
s: "h1.entry-title",
d: /.[\smitaku]{6,7}\.net./
}),
category: "nsfw2"
}, {
name: "Hình ảnh gái",
url: {
h: ["hinhanhgai.com"]
},
page: () => ["/image/", "/article/", "/hentai/content/"].some(p => fn.curl(p)),
data: () => {
fn.showMsg(DL.str_05, 0);
let _fetch;
if (fn.clp("/image/")) {
let id = fn.clp().split("/").at(-1);
_fetch = fetch(`/api/photo/${id}`).then(res => res.json()).then(json => (siteJson = json));
} else if (fn.clp("/hentai/")) {
let id = fn.clp().split("/").at(-1);
_fetch = fetch(`/api/comic/chapter/${id}`).then(res => res.json()).then(json => (siteJson = json));
} else if (fn.clp("/article/")) {
_fetch = fn.fetchDoc(fn.clp()).then(dom => (doc = dom));
}
return _fetch.then(() => fn.hideMsg());
},
SPA: () => _this.page(),
observeURL: "nav",
init: () => _this.page() ? _this.data() : void 0,
imgs: () => {
if (fn.clp("/image/")) {
return siteJson.files.map(e => e.full_url);
} else if (fn.clp("/hentai/")) {
return siteJson.image_urls;
} else if (fn.clp("/article/")) {
return fn.gae(".content img", doc);
}
return [];
},
capture: () => _this.imgs(),
autoDownload: [0],
next: () => {
if (fn.clp("/image/")) {
let next = siteJson?.iterator?.prev?.id;
return next ? "/image/" + next : null;
} else if (fn.clp("/hentai/")) {
let next = siteJson?.next_chapter;
return next ? "/hentai/content/" + next.id : null;
}
return null;
},
prev: 1,
customTitle: () => {
if (fn.clp("/image/")) {
return fn.dt({
t: siteJson.name
});
} else if (fn.clp("/hentai/")) {
return siteJson?.comic?.title + " - " + siteJson?.title;
} else if (fn.clp("/article/")) {
return fn.dt({
t: fn.gt("h1.title", 1, doc)
});
}
return null;
},
hide: "#m_website_float,#m_website_center,#m_image_content_title,.aside_right_ad,#p_image_content_title,#p_website_float,#p_website_center,#p_website_right_float",
category: "nsfw2"
}, {
name: "Maulon",
host: "1sex.maulon.vip",
url: {
t: "Maulon",
p: ".html",
e: ".entry-content .separator"
},
imgs: () => fn.getImgA(".entry-content .separator>a", ".page-links a"),
button: [4],
insertImg: [".entry-content", 2],
customTitle: "h1.entry-title",
category: "nsfw1"
}, {
name: "LUV.VN",
url: {
h: ["luv.vn"],
p: /^\/[^\/]+\/$/
},
srcset: ".wp-block-image img",
customTitle: ".jeg_post_title",
category: "nsfw1"
}, {
name: "✫ Ảnh đẹp ✫",
url: {
h: ["tuyetnhan.com"],
p: /^\/[^\/]+\/$/
},
srcset: ".entry-content img:not([src*='/logo'],[src*='/emoji/'],[src*='/style/'])",
autoDownload: [0],
next: "a[rel=prev]",
prev: "a[rel=next]",
customTitle: ".entry-title,.card_title",
hide: "#cboxOverlay,#cboxWrapper",
category: "nsfw1"
}, {
name: "Gai.vn",
url: {
h: ["www.gai.vn", "gai.vn"]
},
page: () => fn.clp() !== "/" && !fn.clp("/tags-") && fn.ge("#startSlideshow"),
SPA: () => _this.page(),
observeURL: "head",
imgs: () => {
if (!_this.page()) return [];
fn.showMsg(DL.str_05, 0);
return fn.fetchDoc(fn.clp()).then(dom => {
apiCustomTitle = fn.gt(".nav-breadcrumb>.nav-breadcrumb-item:last-child", 1, dom);
let c_eles = fn.gae("a[data-fancybox='slide']", dom);
let c_t_eles = fn.gae("a[data-fancybox='slide'] img", dom);
let pages = fn.ge(".pagination .next-page", dom);
if (pages) {
let max = fn.gt(".pagination .page-item:has(.next-page)", 2, dom);
let links = fn.arr(max, (v, i) => i == 0 ? fn.clp() : fn.clp() + "-startpic-" + (i * 20));
links.shift();
return fn.getEle(links, "a[data-fancybox='slide']").then(p_eles => {
let p_t_eles = p_eles.map(e => fn.ge("img", e));
let t_eles = [...c_t_eles, ...p_t_eles];
thumbnailSrcArray = t_eles.map(e => e.dataset.src);
return [...c_eles, ...p_eles];
});
}
thumbnailSrcArray = c_t_eles.map(e => e.dataset.src);
return c_eles;
});
},
button: [4],
insertImgBF: () => fn.waitEle("#wrapper>.container-fluid").then(e => fn.createImgBox(e, 1, 1200)),
insertImg: [
["box", 0], 2
],
insertImgAF: () => fn.hideEle("#wrapper>.container-fluid,#secondary-navbar,#playerbutton"),
fancybox: {
blacklist: 1
},
category: "nsfw1"
}, {
name: "imgcup.com",
url: {
h: "imgcup.com",
p: ".html"
},
box: [".penci-post-gallery-container", 2],
imgs: ".item-gallery-masonry>a",
thums: ".item-gallery-masonry>a img",
button: [4],
insertImg: [
["box", 0, ".penci-post-gallery-container"], 2
],
autoDownload: [0],
next: ".prev-post-inner>a",
prev: ".next-post-inner>a",
customTitle: ".entry-title",
category: "nsfw1"
}, {
name: "imgcup.com",
url: {
h: ["imgcup.com"],
p: ".html"
},
box: [".wp-block-image", 1],
srcset: ".wp-block-image img[data-srcset]",
button: [4],
insertImg: [
["box", 0, ".wp-block-image"], 2
],
autoDownload: [0],
next: ".prev-post-inner>a",
prev: ".next-post-inner>a",
customTitle: ".entry-title",
category: "nsfw1"
}, {
name: "MissKON.com",
host: ["misskon.com"],
reg: /^https?:\/\/misskon\.com\/[^\/]+\/$/,
imgs: () => fn.getImg(".entry img[decoding]", fn.gt(".page-link>*:last-child"), 4),
button: [4],
insertImg: ["//p[img[@decoding]]", 2],
customTitle: "h1",
category: "nsfw2"
}, {
name: "Xiuren",
url: {
h: ["xiuren.biz"],
p: /^\/[^\/]+\/$/
},
imgs: ".content-inner a[data-lbwps-srcsmall],.content-inner a[rel=noopener],.content-inner a[data-fancybox],.content-inner .fancybox-thumb",
button: [4],
insertImg: [".content-inner", 2],
autoDownload: [0],
next: "a.post.prev-post",
prev: "a.post.next-post",
customTitle: "h1.jeg_post_title",
fancybox: {
v: 3,
css: false
},
category: "nsfw1"
}, {
name: "Asigirl.com",
url: {
h: "asigirl.com",
p: /^\/[^\/]+\/$/
},
box: ["#asigirl-gallery", 1],
imgs: "#asigirl-gallery a",
thums: "#asigirl-gallery a>img",
button: [4],
insertImg: [
["box", 0, "#asigirl-gallery"], 2
],
customTitle: () => {
if (fn.ge("#content-header-title")) {
return fn.dt({
s: "#content-header-title"
});
} else if (fn.ge("meta[property='og:image:alt']")) {
return fn.attr("meta[property='og:image:alt']", "content");
} else {
return document.title;
}
},
fancybox: {
v: 3,
insertLibrarys: 1
},
category: "nsfw1"
}, {
name: "Asigirl.com 分類自動翻頁",
reg: /^https?:\/\/asigirl\.com\//,
autoPager: {
ele: ".oxy-posts",
observer: ".oxy-posts>*",
next: "span.current+a:not(.next)",
re: ".oxy-easy-posts-pages",
pageNum: "span.current"
},
openInNewTab: ".oxy-posts a:not([target=_blank])",
category: "autoPager"
}, {
name: "4KHD",
host: ["www.4khd.com", "csjw.xxtt.ink", "pbnm.cchh.ink"],
url: {
e: "//a[@rel='home'][text()='4KHD']",
p: /^\/content\/\d+\/[^\.\/]+\.html$/
},
imgs: () => fn.getImgA("figure.wp-block-image>a>img,#basicExample>a>img,.entry-content>p>a>img", ".page-link-box a").then(srcs => {
srcs = srcs.map(e => e.replace("pic.4khd.com", "img.4khd.com"));
thumbnailSrcArray = srcs.map(e => e.replace(/\?w=\d+/, "?w=100") + "&ssl=1");
let bigSrcArray = srcs.map(e => e.replace(/\/w\d+-rw\//, "/w2500-h2500-rw/").replace(/\?w=\d+/, ""));
if (fn.lh === "www.4khd.com") {
if (bigSrcArray[0].startsWith("https://img.4khd.com")) {
let host = new URL(bigSrcArray[0]).host;
return bigSrcArray.map(src => src.replace(host, "i1.wp.com/" + host) + "?ssl=1");
}
return bigSrcArray;
} else {
let oldImgHost = new URL(bigSrcArray[0]).host;
let newImgHost = "i1.wp.com/" + oldImgHost;
thumbnailSrcArray = thumbnailSrcArray.map(src => src.replace(oldImgHost, newImgHost));
return bigSrcArray.map(src => src.replace(oldImgHost, newImgHost) + "?ssl=1");
}
}),
button: [4],
insertImg: [
[".page-link-box,.wp-block-post-content>*:last-child,#khd", 1, "#basicExample,.wp-block-image,.entry-content>p:not(#FullPictureLoadEnd),.page-link-box"], 2
],
customTitle: "h3.wp-block-post-title",
css: ".FullPictureLoadImage{max-width:100%!important}",
hide: ".centbtd,.popup,.wp-container-13",
fetch: 1,
category: "nsfw2"
}, {
name: "4KHD AAD",
url: {
e: "//a[@rel='home'][text()='4KHD']"
},
init: () => {
if (fn.lh === "www.4khd.com") {
const replaceSrc = () => {
[...document.querySelectorAll("img[src*='pic.4khd.com']")].forEach(e => {
let src = e.src;
src = src.replace("pic.4khd.com", "img.4khd.com");
e.src = src;
});
};
replaceSrc();
fn.addMutationObserver(replaceSrc);
}
},
hide: ".centbtd,.popup,.wp-container-13",
category: "ad"
}, {
name: "AsianPink",
url: {
h: ["asianpink.net"],
p: /^\/[^\/]+\/$/
},
imgs: () => {
/*
let total = Number(document.querySelector(".album-meta").innerText.match(/\d+/));
let srcs = [...document.querySelectorAll(".gallery-wrapper img")].map(e => decodeURIComponent(e.dataset.lazySrc));
let [src] = srcs;
let d_index = src.lastIndexOf("/") + 1;
let dir = src.slice(0, d_index);
let fileName = src.split("/").at(-1).replace(/\d+/, "${number}");
let _srcs = Array.from({
length: total
}, (v, i) => dir + fileName.replace("${number}", (i + 1)));
debug("_srcs", _srcs);
*/
let max = Number(fn.gt(".pagination .next", 2)) || 1;
if (max > 1) {
let links = fn.arr(max, (v, i) => i == 0 ? fn.lp : `${fn.lp}?gallery_page=${i + 1}`);
return fn.getImgA(".gallery-wrapper img", links).then(srcs => srcs.map(e => decodeURIComponent(e)));
}
return fn.getImgSrcArr(".gallery-wrapper img").map(e => decodeURIComponent(e));
},
button: [4],
insertImg: [".gallery-wrapper", 2],
customTitle: "h1.entry-title",
category: "nsfw1"
}, {
name: "Buon Dua",
url: {
h: ["buondua.com", "buondua.us", "missbaby.top"],
e: ".article-fulltext img[alt]"
},
init: () => {
fn.remove("//div[text()='Sponsored ads']");
fn.remove(".search-form~*");
fn.gae(".pagination a[previous],.pagination a[next]").forEach(e => e.classList.add('disabled'));
},
imgs: () => {
let max = 1;
let end = fn.ge("//nav/a[text()='End']");
if (end) {
max = fn.getUSP("page", end.href);
}
return fn.getImg(".article-fulltext img[alt]", max);
},
button: [4],
insertImg: [".article-fulltext", 2],
customTitle: ".article-header>h1",
referrerpolicy: "strict-origin",
hide: "div:not([class]):has(>small),a[href^=java]",
category: "nsfw2"
}, {
name: "BaoBua.Net",
url: {
h: "www.baobua.net",
p: "/post/"
},
imgs: () => fn.getImg(".wp-block-image img[alt]", (fn.gt(".nav-links>*:last-child") || 1), 6),
button: [4],
insertImg: [".entry-content.read-details", 2],
customTitle: () => fn.title("|", 1),
category: "nsfw2"
}, {
name: "blog.baobua.net",
host: ["blog.baobua.net"],
link: "https://blog.baobua.net/mlem",
url: {
h: "baobua.net",
e: ".article-body"
},
imgs: "a.fancybox",
button: [4],
insertImg: [".article-body", 2],
customTitle: () => fn.title("@BaoBua", 1),
css: "#fix_scale img:hover{transform:none!important}",
category: "nsfw2"
}, {
name: "HOTGIRLchina格式",
url: {
h: ["hotgirlchina.com", "hinhkhieudam.com", "gaidepvietnam.com", "cucnong.com"],
e: ".wp-block-gallery img"
},
init: () => fn.remove("div:has(>iframe),center:has(iframe)"),
imgs: () => fn.getImgSrcArr(".wp-block-gallery img").filter(src => !src.endsWith(".gif")),
button: [4],
insertImg: [".entry-content", 2],
autoDownload: [0],
next: ".nav-previous a",
prev: ".nav-next a",
customTitle: () => fn.dt({
s: ".entry-title",
d: /\(\d+\s?photos\s?\)|(\s?\(\d+\s?photos?\s?\+\s?\d+\s?videos?\))|\([0-9\s]+ảnh[0-9\s\+]+video\)|\([0-9\s]+ảnh.*\)|\/mitaku\.net\//i
}),
hide: "div:has(>iframe),center:has(iframe),#tpbr_topbar,.ad-container,.nwm-hidden-mobile,section[id^='custom_html']",
category: "nsfw2"
}, {
name: "HOTGIRLchina 格式 AD",
url: {
h: ["hotgirlchina.com", "hinhkhieudam.com", "gaidepvietnam.com", "ephimsex.com", "cucnong.com"],
},
init: () => fn.remove("div:has(>iframe),center:has(iframe)"),
hide: "div:has(>iframe),center:has(iframe),#tpbr_topbar,.ad-container,.nwm-hidden-mobile,section[id^='custom_html'],.boxzilla-container,.boxzilla-overlay,.sharrre-container,#vietpub-overlay",
category: "ad"
}, {
name: "3600000 Beauty",
host: ["3600000.xyz"],
reg: /^https?:\/\/3600000\.xyz\/[^\/]+\/$/,
imgs: () => {
let [a, img] = ["//a[img[@file]]", ".entry-content img.ls_lazyimg[file]"];
if (fn.ge(a)) {
return fn.gae(a);
} else if (fn.ge(img)) {
return fn.gae(img).map(e => e.getAttribute("file"));
} else {
return [];
}
},
button: [4],
insertImg: [".entry-content", 2],
autoDownload: [0],
next: ".nav-previous>a",
prev: ".nav-next>a",
customTitle: ".entry-title",
category: "nsfw1"
}, {
name: "Big Boobs Asia",
host: ["www.tokyobombers.com"],
reg: /^https?:\/\/www\.tokyobombers\.com\/\d+\/\d+\/\d+\/[^\/]+\/$/,
imgs: () => {
if (fn.ge(".gallery img[srcset]")) {
return fn.getImgSrcset(".gallery img[srcset]");
} else {
return fn.gae("a[itemprop='contentURL']");
}
},
button: [4],
insertImg: [".gallery", 2],
customTitle: ".entry-title",
category: "nsfw1"
}, {
name: "jangjoo",
link: "https://felix0621.pixnet.net/blog",
url: {
h: "pixnet.net",
p: "/post/",
e: "#article-content-inner img,.article-content-inner img"
},
imgs: () => {
let eles = fn.gae("#article-content-inner img,.article-content-inner img").filter(e => !e.closest(".in-read-ad"));
thumbnailSrcArray = fn.getImgSrcArr(eles);
return thumbnailSrcArray.map(url => {
if (url.includes("?url")) {
url = fn.getUSP("url", url);
}
return url.replace(/_\w\.(\w+)$/i, ".$1");
});
},
capture: () => _this.imgs(),
autoDownload: [0],
next: "//li[contains(text(),'上一篇')]/a",
prev: "//li[contains(text(),'下一篇')]/a",
customTitle: ".title h2,.header-title div",
category: "nsfw1"
}, {
name: "痞客邦相簿",
link: "https://nagoat.pixnet.net/album/list",
url: {
h: "pixnet.net",
p: "/album/",
e: ".photo-grid-list img"
},
box: [".photo-grid-list", 1],
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr(".photo-grid-list img");
return thumbnailSrcArray.map(url => {
if (url.includes("?url")) {
url = fn.getUSP("url", url);
}
return url.replace(/_\w\.(\w+)$/i, ".$1");
});
},
thums: ".photo-grid-list img",
button: [4],
insertImg: [
["box", 0, ".photo-grid-list"], 2
],
insertImgAF: () => fn.remove(".page-function,.upper-page-flip,.lower-page-flip"),
customTitle: ".edit-content",
category: "nsfw1"
}, {
name: "痞客邦相簿M",
url: {
h: "pixnet.net",
p: "/album/",
e: ".newphoto-list img",
d: "m"
},
box: [".newphoto-list", 1],
imgs: async () => {
await fn.getNP(".newphoto-list>li", ".page+a.next", null, ".flip:has(.page)");
thumbnailSrcArray = fn.getImgSrcArr(".newphoto-list img");
return thumbnailSrcArray.map(url => {
if (url.includes("?url")) {
url = fn.getUSP("url", url);
}
return url.replace(/_\w\.(\w+)$/i, ".$1");
});
},
button: [4],
insertImg: [
["box", 0, ".newphoto-list"], 2
],
customTitle: ".album-header a",
category: "nsfw1"
}, {
name: "Nao Kanzaki and a few friends/NYO Cosplay/Navi Cosplay/Picgir",
url: {
h: ["aitoda.blogspot.com", "2bcosplay.blogspot.com", "navicosplay.blogspot.com", "picgir.blogspot.com"],
p: /^\/\d+\/\d+\/[\w-]+\.html/
},
imgs: ".entry-content .separator a:not([data-saferedirecturl]),div.separator>img",
thums: ".entry-content .separator a:not([data-saferedirecturl]) img,div.separator>img",
videos: "iframe[title='YouTube video player'],iframe[id^='BLOGGER-video']",
autoDownload: [0],
next: ".blog-pager-older-link",
prev: ".blog-pager-newer-link",
customTitle: ".entry-title",
category: "nsfw1"
}, {
name: "jangjoo",
url: {
h: ["jangjooart.blogspot.com"],
p: /^\/\d+\/\d+\/[\w-]+\.html/
},
imgs: ".post-body img",
button: [4],
insertImg: [".post-body", 2],
autoDownload: [0],
next: ".blog-pager-older-link",
prev: ".blog-pager-newer-link",
customTitle: ".post_item h1",
category: "nsfw1"
}, {
name: "Photo Beach",
url: {
h: ["photobeach.blogspot.com"],
p: /^\/\d+\/\d+\/[\w-]+\.html/
},
imgs: ".entry-content a:has(>img),br~a,br~img",
category: "nsfw2"
}, {
name: "sekushipic/Idolru Channel/Cosplay Club",
url: {
h: ["sekushipic.blogspot.com", "janidol.blogspot.com", "cosplay-club3.blogspot.com"],
p: /^\/\d+\/\d+\/[^\.]+\.html/
},
imgs: ".separator>a",
thums: ".separator img",
button: [4],
insertImg: [
[".separator", 1, ".separator,.separator~br"], 2
],
autoDownload: [0],
next: "a.blog-pager-older-link",
prev: "a.blog-pager-newer-link",
customTitle: ".entry-title",
hide: ".post-header",
category: "nsfw1"
}, {
name: "IDOL AREA/OppaiMag/adnvadnvvda",
url: {
h: ["idolarea.blogspot.com", "oppaimag.blogspot.com", "maiasihd.blogspot.com"],
p: /^\/\d+\/\d+\/[^\.]+\.html/
},
imgs: ".separator>a",
thums: ".separator img",
button: [4],
insertImg: [".entry-content,.post-content", 2],
customTitle: "h1.entry-title,h1.post-title,h3.entry-title,h3.post-title",
category: "nsfw1"
}, {
name: "25精力旺盛",
url: {
h: ["25jingliwangsheng.blogspot.com"],
p: /^\/\d+\/\d+\/[^\.]+\.html/
},
box: [".entry-content img[alt='']", 1],
imgs: ".entry-content img[alt='']",
button: [4],
insertImg: [
["box", 0, ".entry-content img[alt='']"], 2
],
customTitle: "h1.entry-title,h3.entry-title",
category: "nsfw1"
}, {
name: "Nude Models/Beauty Pretty Sexy",
url: () => isPC && (fn.lh === "blognudemodels.blogspot.com" || fn.lh === "beprse.blogspot.com"),
page: () => fn.clp(".html"),
SPA: () => _this.page(),
observeURL: "loop",
init: () => _this.page() ? fn.waitEle([".overview-header", "h1.entry-title", ".separator>a"]) : fn.waitEle("#gadget-dock"),
imgs: () => _this.page() ? fn.gae(".separator>a") : [],
repeat: 1,
capture: () => _this.imgs(),
next: () => _this.page() ? fn.gu("a.next") : null,
customTitle: () => _this.page() ? fn.delay(200, 0).then(() => fn.dt({
s: "h1.entry-title"
})) : null,
category: "nsfw2"
}, {
name: "Nude Models/Beauty Pretty Sexy",
reg: /^https?:\/\/(blognudemodels\.blogspot\.com|beprse\.blogspot\.com)\/\d+\/\d+\/[^\.]+\.html\?m=1$/,
init: () => fn.waitEle(".separator img"),
imgs: ".separator>a",
button: [4],
insertImg: [
[".separator", 1, ".separator,.separator~br"], 2
],
customTitle: "title",
category: "nsfw2"
}, {
name: "Curvy Asian",
url: {
h: ["curvyasian.blogspot.com"],
p: /^\/\d+\/\d+\/[^\.]+\.html/
},
imgs: "#blogger-gallery a.item-link",
thums: "#blogger-gallery a.item-link img",
button: [4],
insertImg: ["#blogger-gallery", 2],
autoDownload: [0],
next: "a.blog-pager-older-link",
prev: "a.blog-pager-newer-link",
customTitle: ".entry-title",
category: "nsfw1"
}, {
name: "500 Brothers/Safebooru",
url: {
h: ["500brothersfun.blogspot.com", "safebooru.blogspot.com"],
p: /^\/\d+\/\d+\/[^\.]+\.html/
},
box: [".separator", 1],
imgs: () => fn.gau(".separator>a").map(u => u.replace("/s1600/", "/s16000/")),
button: [4],
insertImg: [
["box", 0, ".separator~br,.separator"], 2
],
customTitle: ".entry-title",
category: "nsfw2"
}, {
name: "min: archive/True Pic",
url: {
h: ["min-bin.blogspot.com", "truepichk.blogspot.com"],
p: /^\/\d+\/\d+\/[^\.]+\.html/
},
imgs: () => fn.gau(".separator>a").map(u => u.replace("/s1600/", "/s16000/")),
button: [4],
insertImg: [".post-body", 2],
autoDownload: [0],
next: "a.blog-pager-older-link",
prev: "a.blog-pager-newer-link",
customTitle: ".entry-title",
category: "nsfw2"
}, {
name: "Tabakus Gallery",
reg: /^https?:\/\/tabakus\.blogspot\.com\/\d+\/\d+\/[^\.]+\.html/,
init: () => fn.waitEle(".separator img"),
box: [".separator:has(>a>img[height])", 1],
imgs: ".separator>a:has(>img[height])",
button: [4],
insertImg: [
["box", 0, ".separator:has(>a>img),.separator~br"], 2
],
customTitle: ".post_item>h1",
category: "nsfw2"
}, {
name: "Graphis",
host: ["20sanctuary-grahpis.blogspot.com"],
reg: /^https?:\/\/20sanctuary-grahpis\.blogspot\.com\/\d+\/\d+\/[^\.]+\.html/,
imgs: () => {
thumbnailSrcArray = fn.gae(".separator>a img").map(e => e.src.replace("/s320/", "/w100/"));
return fn.gau(".separator>a").map(u => u.replace("/s1600/", "/s16000/"));
},
button: [4],
insertImg: [".post-body", 2],
customTitle: ".post_item>h1,.entry-titleS",
category: "nsfw2"
}, {
name: "Chinese Nude Art Photos",
url: {
h: ["chinesenudeart.blogspot.com"],
p: /^\/\d+\/\d+\/[\w-]+\.html/i
},
imgs: ".entry-content a[href]",
thums: ".entry-content a[href]>img",
button: [4],
insertImg: [".entry-content", 2],
autoDownload: [0],
next: "a.blog-pager-older-link",
prev: "a.blog-pager-newer-link",
customTitle: () => fn.dt({
s: ".entry-title",
d: [
"Chinese beautiful model Amanda -",
"Beautiful Chinese girl -",
"Beautiful Chinese girl ",
"Chinese Beautiful girl -",
" |18+ Nude model Amateur"
]
}),
mcss: "#outer-wrapper{margin:0px!important;width:100%!important}",
category: "nsfw1"
}, {
name: "Dicas de Animes",
url: {
h: ["dicadeanimesbr.blogspot.com"],
p: /^\/\d+\/\d+\/[\w-]+\.html/i
},
imgs: ".entry-content a:has(>img)",
thums: ".entry-content a:has(>img) img",
autoDownload: [0],
next: "a.prev-post-link",
prev: "a.next-post-link",
customTitle: ".entry-title",
category: "nsfw1"
}, {
name: "CUTE GIRLS ADDICT",
url: {
h: ["cutegirlsaddict.blogspot.com"],
p: /^\/\d+\/\d+\/[a-z0-9-]+\.html/i
},
imgs: async () => {
thumbnailSrcArray = fn.gae(".separator>a>img").map(e => {
let arr = e.src.split("/");
arr[7] = "w100";
return arr.join("/");
});
let srcArr = fn.gau(".separator>a");
let firstSrcArr = srcArr[0].split("/");
if (firstSrcArr.length === 9) {
firstSrcArr[7] = "s16000";
let testMaxSrc = firstSrcArr.join("/");
let obj = await fn.checkImgStatus(testMaxSrc);
debug("\n確認圖片狀態\n", obj);
if (obj.ok) {
srcArr = srcArr.map(src => {
let arr = src.split("/");
arr[7] = "s16000";
return arr.join("/");
});
return srcArr;
} else {
return srcArr;
}
} else {
return srcArr;
}
},
button: [4],
insertImg: [".entry-content", 2],
customTitle: "h1.post-title,h3.entry-title",
category: "nsfw1"
}, {
name: "COSPLAYJP",
url: {
h: ["cosplayjp.wordpress.com"],
p: /^\/\d+\/\d+\/\d+\/[\w-]+\//i
},
imgs: ".entry-content .wp-block-image a",
thums: "entry-content .wp-block-image a img",
autoDownload: [0],
next: ".nav-previous>a",
prev: ".nav-next>a",
customTitle: () => fn.dt({
t: fn.ge(".entry-title").textContent
}),
category: "nsfw1"
}, {
name: "Sexy Fandom",
url: {
h: ["sexyfandom.com"],
p: "/archives/"
},
srcset: ".post_content img",
autoDownload: [0],
next: "#prepost",
prev: "#nextpost",
customTitle: ".entry-title",
category: "nsfw1"
}, {
name: "Daily Cosplay",
url: {
h: ["dailycosplay.com"]
},
imgs: () => fn.gae("tbody td[width='754'] center img[title]").filter(e => !e.closest("img[alt=Previous],img[alt=Next],.t2")),
capture: () => _this.imgs(),
autoDownload: [0],
next: "td[align=LEFT] a:has(img[alt=Previous])",
prev: "td[align=RIGHT] a:has(img[alt=Next])",
customTitle: () => fn.title(" - Daily Cosplay .com"),
category: "nsfw1"
}, {
name: "Animexx",
url: {
h: ["www.animexx.de"],
e: [".header_mitte>a", "#cosplay_tab_holder"],
st: "PHPSESSID"
},
imgs: () => {
fn.showMsg(DL.str_05, 0);
let data_url = new URL(document.querySelector(".header_mitte>a").href).searchParams.get("back").replace(/\?.+$/, "");
let code = [...document.scripts].find(s => s.textContent.includes("PHPSESSID")).textContent;
let [, id] = code.match(/PHPSESSID=(\w+)/);
return fetch(data_url + "photoswipe/?PHPSESSID=" + id, {
"headers": {
"accept": "application/json, text/javascript, */*; q=0.01",
"x-requested-with": "XMLHttpRequest"
}
}).then(res => res.json()).then(data => data.map(e => e.url));
},
capture: () => _this.imgs(),
customTitle: () => fn.title("auf Animexx.de"),
category: "nsfw1"
}, {
name: "Everia.club",
host: ["everia.club"],
url: {
e: ["//div[@id='site-logo']//a[@rel='home'][text()='EVERIA.CLUB']", ".wp-block-image img,.separator>a.no-lightbox,.entry-content img"]
},
imgs: () => {
let [img, a] = [".wp-block-image img", ".separator>a.no-lightbox"]
if (!!fn.ge(img)) {
return fn.gae(img);
} else if (!!fn.ge(a)) {
return fn.gae(a);
} else {
return fn.gae(".entry-content img");
}
},
button: [4],
insertImg: [".entry-content", 2],
customTitle: ".entry-title",
category: "nsfw2"
}, {
name: "Everia club",
url: {
h: "www.everiaclub.com"
},
init: () => (tempEles = fn.gae(".mainleft h1")),
imgs: ".mainleft img",
button: [4],
insertImg: [".mainleft", 2],
insertImgAF: (_, bar) => bar.before(...tempEles),
customTitle: ".mainleft h1",
category: "nsfw2"
}, {
name: "SexyGirl",
url: {
h: ["www.sexygirl.cc", "sexygirl.cc"],
p: ["photo/", "picture/", "cartoon/"],
d: "pc"
},
imgs: ".image-container img",
button: [4],
insertImg: [".col-9:has(.image-container)", 2],
next: "//a[text()='<-Previous']",
prev: "//a[text()='Next->']",
hide: "div[id^='exo-'],h3~.row .overflow-auto:has(div[id^='exo-'])",
category: "nsfw2"
}, {
name: "SexyGirl",
url: {
h: ["www.sexygirl.cc", "sexygirl.cc"],
p: ["photo/", "picture/", "cartoon/"],
d: "m"
},
imgs: ".image-container img",
button: [4],
insertImg: [".row:has(.row .image-container)", 2],
next: "//a[text()='<-Previous']",
prev: "//a[text()='Next->']",
hide: "div[id^='exo-'],h3~.row .overflow-auto:has(div[id^='exo-'])",
category: "nsfw2"
}, {
name: "SexyGirl",
url: {
h: "cp.sexygirl.cc",
p: "picture/"
},
imgs: ".image-container img",
button: [4],
insertImg: [".row:has(.image-container)", 2],
next: "//a[text()='<-Previous']",
prev: "//a[text()='Next->']",
hide: "div[id^='exo-']",
category: "nsfw2"
}, {
name: "Căng Cực",
url: {
h: ["cangcuc.com"]
},
imgs: ".post-single .royal_grid a",
videos: ".royal_grid video>source",
button: [4],
insertImg: [
[".royal_grid", 2, ".royal_grid"], 2
],
autoDownload: [0],
next: ".widget-previous-post a",
prev: ".widget-next-post a",
customTitle: "h1.title",
hide: ".d-flex:has(.img-float),body>div[style^='position'],.container-fluid:has(.mb-2)",
downloadVideo: true,
category: "nsfw1"
}, {
name: "pornpicxxx.com",
url: {
h: "pornpicxxx.com",
p: "/gallery/"
},
imgs: "#grid a",
thums: "#grid a img",
customTitle: ".title h1",
category: "nsfw2"
}, {
name: "Porn Pics",
url: {
h: "www.pornpics.com",
p: "galleries/"
},
imgs: "#tiles a.rel-link",
thums: "#tiles a.rel-link>img",
button: [4],
insertImg: ["#main", 3],
customTitle: ".title-section h1",
category: "nsfw2"
}, {
name: "NakedPics",
url: {
h: ["hotnakedwomen.com"],
p: "/gals/"
},
imgs: ".thumb>a",
thums: ".thumb img",
customTitle: ".long-title",
category: "nsfw2"
}, {
name: "HD Porn Pictures",
url: {
h: [
"hdpornpictures.net",
"bravotube.tv",
"redwap.tv",
"mofosex.net",
"photos.mofosex.net",
"niceporn.tv",
"beeg.porn",
"befuck.net"
],
p: "/id/",
e: "#tiles a.rel-link"
},
imgs: () => {
let imgs = fn.gau("#tiles a.rel-link");
thumbnailSrcArray = imgs.map(e => e + "?w=300");
return imgs;
},
button: [4],
insertImg: ["#main", 3],
customTitle: () => fn.ge(".title-h1")?.textContent,
category: "nsfw2"
}, {
name: "Freebigtit",
host: ["www.freebigtitpornpics.com"],
reg: /^https?:\/\/www\.freebigtitpornpics\.com\/content\/\d+\//,
imgs: "//ul[@id='dylan']//a[img[@data-src]]",
thums: "ul#dylan a>img[data-src]",
button: [4],
insertImg: [
["#dylan", 2], 1
],
category: "nsfw2"
}, {
name: "NongMo.Zone",
host: ["www.ilovexs.com", "ilovexs.com"],
reg: [
/^https?:\/\/(www\.)?ilovexs\.com\/post_id\/\d+\//,
/^https?:\/\/(www\.)?ilovexs\.com\/post\/[^\/]+\//,
],
imgs: ".image-gallery img",
button: [4],
insertImg: [".entry-content", 2],
customTitle: ".entry-title",
category: "nsfw2"
}, {
url: {
h: "idol.gravureprincess.date",
p: /^\/\d+\/\d+\/.+\.html/
},
imgs: ".separator img",
autoDownload: [0],
next: "a.blog-pager-older-link",
prev: "a.blog-pager-newer-link",
customTitle: ".post-title",
category: "nsfw2"
}, {
name: "劍心回憶",
host: ["kenshin.hk"],
link: "https://kenshin.hk/category/jnews/photoalbum/",
reg: /^https?:\/\/kenshin\.hk\/\d+\/\d+\/\d+\/[^/]+\/(#small-1)?$/,
include: "//div[@class='entry-utility']/a[1][text()='寫真組圖'] | //div[@class='cat-tags']/a[1][text()='寫真組圖']",
init: async () => {
let p = fn.ge("//p[contains(text(),'寫真')]");
if (p) {
let tE = fn.ge(".entry-content,.post-page-content");
insertBefore(tE, p);
}
let links = fn.gau("//a[button[contains(text(),'寫真')]]");
await fn.getEle(links, ".entry-content>p>img,.post-page-content>p>img,.videoWrapper", ".entry-content,.post-page-content");
let v = fn.ge(".videoWrapper");
if (v) {
let tE = fn.ge(".entry-content,.post-page-content");
insertBefore(tE, v);
}
},
imgs: ".entry-content>img,.post-page-content>img",
button: [4],
insertImg: [".entry-content,.post-page-content", 2],
customTitle: () => fn.dt({
s: "h1.entry-title,h2.post-title",
d: /【寫真】|\s?\(\d+P,片\)/gi
}),
category: "nsfw1"
}, {
name: "Gravia",
url: {
h: ["www.gravia.site", "gravia.site"],
p: "show.php",
s: "id="
},
box: [".slideshow.for_box", 2],
imgs: ".slideshow .item>img",
thums: ".thums img",
button: [4],
insertImg: [
["box", 0, ".slideshow.for_box"], 2
],
customTitle: () => fn.dt({
s: ".container>h1",
d: /\s?【\d+枚】/
}),
css: "img.small{max-width:100% !important;max-height:auto !important}",
hide: ".cmd_bar.wide",
category: "nsfw1"
}, {
name: "AI.img/AI2D",
host: ["aiimg.fun", "ai2d.fun"],
reg: [
/^https?:\/\/aiimg\.fun\/note\/public\.php\?id=\d+/,
/^https?:\/\/ai2d\.fun\/note\/public\.php\?id=\d+/,
/^https?:\/\/ai2d\.fun\/ubox\/rom\.php\?id=\d+/
],
exclude: ".not_found.small",
box: [".thums", 2],
imgs: async () => {
await fn.getNP(".thums>.item", ".pager>a.now+a", null, ".pager");
thumbnailSrcArray = fn.getImgSrcArr(".thums img");
return fn.gae("div.item[org_img_url]");
},
button: [4],
insertImg: [
["box", 0, ".thums,.slideshow,.pager,.search_range"], 2
],
customTitle: () => fn.gt("h1").replace(/\s\(\d+枚\)/, "").replaceAll("/", "/"),
category: "nsfw2"
}, {
name: "抜けるっ!二次元エロ画像&イラストまとめ",
url: {
h: "ero-gazou.jp",
e: ".grid-container img"
},
init: () => fn.addMutationObserver(() => document.documentElement.classList.remove("pum-open", "pum-open-overlay", "pum-open-scrollable")),
imgs: () => fn.getImgA(".grid-container img", ".pager-numbers a"),
capture: () => _this.imgs(),
autoDownload: [0],
next: "a.prev-post",
prev: "a.next-post",
customTitle: "h1.entry-title",
css: "html.pum-open{overflow: auto}",
hide: "#content-top,#content-bottom,.pum-overlay",
category: "nsfw2"
}, {
name: "NEWSグラビアアイドル.net",
url: {
h: "news.idolsenka.net",
p: "/archives/"
},
imgs: ".post_content img",
videos: "iframe[title='YouTube video player']",
customTitle: ".c-postTitle__ttl",
category: "nsfw1"
}, {
name: "グラビア週刊誌 格式",
url: {
h: [
"magazinejapanese.livedoor.blog",
"magazinejapanese.blog.jp",
"magazinejapanese3.blog.jp",
"magazinejapanese4.doorblog.jp",
"magazinejapanese5.blog.jp",
"magazinejapanese6.blog.jp",
"gravurezasshi7.livedoor.blog",
"gravurezasshi9.doorblog.jp",
"gravuremagazine12.blog.jp",
"gravurezasshiex.blog.jp"
],
p: "/archives/"
},
imgs: ".article-body-inner>a,#article-contents>a",
thums: ".article-body-inner>a>img,#article-contents>a>img",
button: [4],
insertImg: [".article-body-inner,#article-contents", 2],
autoDownload: [0],
next: "//li[text()='前の記事: ']/a | //a[text()='前の記事'] | //li/a[text()='< 前の記事'] | //li[@class='prev']/a",
prev: "//li[text()='次の記事: ']/a | //a[text()='次の記事'] | //li/a[text()='次の記事 >'] | //li[@class='next both']/a",
customTitle: "h1.article-title>a,.article-header>h1",
category: "nsfw1"
}, {
name: "グラビア週刊誌 - 分類自動翻頁",
url: {
h: [
"magazinejapanese.livedoor.blog",
"magazinejapanese.blog.jp",
"magazinejapanese3.blog.jp",
"magazinejapanese4.doorblog.jp",
"magazinejapanese5.blog.jp",
"magazinejapanese6.blog.jp",
"gravurezasshi7.livedoor.blog",
"gravurezasshi9.doorblog.jp",
"gravuremagazine12.blog.jp",
"gravurezasshiex.blog.jp"
],
p: /^\/(\?p=\d+)?$|^\/archives\/([\d-]+|cat_\d+)\.html(\?p=\d+)?$/
},
autoPager: {
ele: ".autopagerize_page_element,.article-list-outer",
observer: "article.article,.article-list-outer>li",
next: "//li[@class='current']/following-sibling::li[1]/a | //a[span[text()='次へ']]",
re: ".pager,.pager_fixed,.fractional-page",
pageNum: () => nextLink.match(/\?p=(\d+)/)[1]
},
openInNewTab: ".autopagerize_page_element a[href]:not([target=_blank]),.article-list-outer a[href]:not([target=_blank])",
category: "autoPager"
}, {
name: "エロマニア 猿!/グラドルマニア 猿!",
url: {
h: ["nisokudemosandal.blog.jp", "ippondemoninjin.livedoor.blog"],
p: "/archives/"
},
imgs: ".article-body a[title]:has(>img)",
autoDownload: [0],
next: "//li[@class='prev']/a | //a[text()='前の記事']",
prev: "//li[@class='next both']/a | //a[text()='次の記事']",
customTitle: ".article-title",
setFancybox: true,
category: "nsfw2"
}, {
name: "Gravure Idols",
url: {
h: ["gravureidols.top"],
p: /^\/\d+\/\d+\/\d+\/[^\/]+\/$/
},
imgs: ".content-inner>div:not(.apss-social-share) a",
button: [4],
insertImg: [
["//p[a[img]]", 2, "//p[a[img]]"], 1
],
autoDownload: [0],
next: ".jeg_prevnext_post a",
prev: ".jeg_prevnext_post a",
customTitle: ".jeg_post_title",
category: "nsfw1"
}, {
name: "水着グラビア",
url: {
h: ["www.mizugigurabia.com"],
s: "p="
},
init: () => {
fn.clearAllTimer();
fn.remove("#content-top");
},
imgs: () => {
let srcs_a = fn.getImgSrcset(".article img[srcset]");
let srcs_b = fn.gae(".entry-content a:has(>img)").map(a => {
if (a?.firstElementChild?.src) {
let src = a.firstElementChild.src;
src = src.replace(/s(\.\w+)/i, "$1");
if (src == a.href) {
return a.href;
}
}
return a?.firstElementChild?.src;
});
return [...srcs_a, ...srcs_b];
},
capture: () => _this.imgs(),
customTitle: ".entry-title",
category: "nsfw2"
}, {
name: "エロ酒場",
url: {
h: ["ero-sakaba.com"],
s: "p="
},
imgs: () => {
let srcs = fn.getImgSrcArr(".post_thum img,#post_body img[data-srcset]");
return srcs.map(e => e.replace(/-\d+x\d+\./, "."));
},
capture: () => _this.imgs(),
autoDownload: [0],
next: "a.nav_link_l",
prev: "a.f_row_r",
customTitle: "h1.post_title",
hide: "#cboxOverlay,#colorbox",
category: "nsfw2"
}, {
name: "エロ画像まとめ",
host: ["geinou-nude.com"],
reg: /^https?:\/\/geinou-nude\.com\/[^\/]+\/(#.*)?$/,
init: () => fn.addMutationObserver(() => fn.remove(".widgetarea_sp,.widget_execphp,.adContainer")),
imgs: ".post_thum>img,.post_content a[href*='/uploads/']",
videos: "iframe[src*=youtube]",
autoDownload: [0],
next: "a.nav_link_l",
prev: "a.f_row_r",
customTitle: "h1.post_title",
hide: ".widgetarea_sp,.widget_execphp,.adContainer",
setFancybox: true,
category: "nsfw2"
}, {
name: "お宝エログ幕府",
url: {
h: "bakufu.jp",
p: "/archives/"
},
imgs: () => {
let srcs = fn.getImgSrcArr(".entry-content a[href*=bakufu]:has(img[src*=bakufu])");
return srcs.map(e => e.replace("-scaled.", "."));
},
capture: () => _this.imgs(),
autoDownload: [0],
next: ".nav-previous>a",
prev: ".nav-next>a",
customTitle: "h1.entry-title",
setFancybox: true,
category: "nsfw2"
}, {
name: "お宝エロ画像ぷにぷに",
url: {
h: ["puni-puni.com"]
},
srcset: ".p-articleThumb>img,.wp-block-image img",
customTitle: "h1.c-postTitle__ttl",
category: "nsfw2"
}, {
name: "惚れた.net",
url: {
h: ["horeta.net"],
p: /^\/[\w-]+\/$/
},
imgs: () => {
let srcs = fn.getImgSrcArr(".entry-content p>img.alignnone,.gallery-item img");
return srcs.map(e => e.replace("-scaled.", "."));
},
capture: () => _this.imgs(),
autoDownload: [0],
next: ".st-next-link",
prev: ".st-prev-link",
customTitle: ".entry-title",
category: "nsfw1"
}, {
name: "エロ画像女神ちゃんねる",
url: {
h: ["megamich.com"],
p: /^\/[^\/]+\/\d+\.html$/
},
imgs: () => {
let pages = fn.ge(".page-numbers");
if (pages) {
let max = fn.gt(".page-numbers a:last-child");
return fn.getImg("img[id^='entry_image']", max, 9);
} else {
return fn.gae("img[id^='entry_image']");
}
},
capture: () => _this.imgs(),
customTitle: "#Single_h1",
hide: ".sidesticky_l:has(#im_wrap_left),.sidesticky_r:has(#im_wrap_right)",
category: "nsfw2"
}, {
name: "裏ピク",
url: {
h: "www.urapic.com",
p: "/blog-entry-"
},
imgs: "//div[@class='entry-body']//a[img[@title]] | //div[@class='entry_body']//a[img[@title]]",
autoDownload: [0],
next: "link[rel=prev],.next_entry>a",
prev: "link[rel=next],.prev_entry>a",
customTitle: () => fn.gt(".entry-title,.entry_title>h1").replace(/[w]+$/, ""),
setFancybox: true,
category: "nsfw2"
}, {
name: "画像ナビ!",
url: {
h: "gazounabi.com",
p: "/archives/"
},
imgs: ".article-body-more a[title],#article-contents a[title]",
autoDownload: [0],
next: ".article-pager>.prev a",
prev: ".article-pager>.next a",
customTitle: "h2.entry-title,h1.article-title",
category: "nsfw2"
}, {
name: "エロ画像ぱしゃりずむ",
url: {
h: "pashalism.com"
},
imgs: ".single-post-main a:has(>img[class*='wp-image'])",
customTitle: "h1.single-post-title",
category: "nsfw2"
}, {
name: "肉感美ガール/コスッピ!",
url: () => fn.checkUrl({
h: ["bi-girl.net", "cosppi.net"],
p: [/\/[^\/]+$/, "/user/"],
e: ".img_wrapper_nontop .img_wrapper"
}) && !fn.lp.startsWith("/search"),
imgs: () => {
let links = [fn.lp];
let pages = fn.ge(".pagination_num_wrapper");
if (pages) {
let max = fn.gt(".pagination_num_wrapper .next", 2);
links = fn.arr(max, (v, i) => i == 0 ? fn.lp + "?sort=old" : fn.lp + `/page/${i + 1}?sort=old`);
}
return fn.getEle(links, ".img_wrapper_nontop .img_wrapper").then(eles => eles.map(e => {
let video = fn.ge("div[data-link]:has(.video)", e);
if (video) {
videoSrcArray.push(video.dataset.link);
}
return fn.ge("img", e)?.dataset.src?.replace(":small", "");
}));
},
capture: () => _this.imgs(),
customTitle: ".entry-title",
hide: ".ad_caution,aside:has(.box_ad_sp_top)",
category: "nsfw2"
}, {
name: "アイドルセクシー画像集&裏",
link: "http://intervalues.com/idol.html",
url: {
h: "intervalues",
p: /^\/\w\/\w+\.html$/,
e: ".idolname"
},
box: ["body", 0, 1200],
imgs: async () => {
let eles;
let url = fn.gu("a:has(.idolname)");
let max = fn.gae("div[class^=Page] a").length;
if (max > 0) {
let links = fn.arr(max, (v, i) => i == 0 ? url : url.replace(".html", "") + `${i + 1}.html`);
eles = await fn.getEle(links, "a:has(>img)");
} else {
eles = fn.gae("a:has(>img)");
}
return eles.map(a => {
let src = fn.src("img", a);
thumbnailSrcArray.push(src);
return a;
});
},
button: [4],
insertImg: ["box", 2],
customTitle: ".idolname",
category: "nsfw2"
}, {
name: "エロ画像-ラブコアラ-",
url: {
h: "lovekoala.com",
p: /^\/[^\/]+\/$/,
e: ".gallery"
},
imgs: async () => {
let links = [fn.lp];
let pages = fn.ge("p.pmt");
if (pages) {
let max = fn.gu("//a[text()='最後']")?.match(/\d+/g)?.at(-1) || fn.gu(".pmt a:last-child")?.match(/\d+/g)?.at(-1);
links = fn.arr(max, (v, i) => i == 0 ? fn.lp : fn.lp + `${i + 1}/`);
}
return fn.getEle(links, ".gallery .pbox>a").then(eles => eles.map(a => {
let src = fn.src("img", a);
thumbnailSrcArray.push(src);
return a;
}));
},
capture: () => _this.imgs(),
customTitle: "h1.htxt1",
category: "nsfw2"
}, {
name: "復刻書林",
url: {
h: ["reprint-kh.com"],
p: "/archives/"
},
imgs: async () => {
if (fn.ge(".gallery-row")) {
await fn.getNP(".gallery-row", "//a[span[text()='次のページ']]");
}
if (fn.ge(".ngg-gallery-thumbnail-box")) {
await fn.getNP(".ngg-gallery-thumbnail-box", "span.current+a");
}
thumbnailSrcArray = fn.getImgSrcArr(".tiled-gallery a img,.ngg-gallery-thumbnail-box a img");
return fn.gae(".tiled-gallery a,.ngg-gallery-thumbnail-box a");
},
button: [4],
insertImg: [
[".single-post-main>.share,.single-post-main .content", 2], 2
],
insertImgAF: (parent) => {
for (let node of [...parent.childNodes]) {
if (node.id === "FullPictureLoadOptionsButtonParentDiv") {
break;
}
node.remove();
}
},
autoDownload: [0],
next: ".previous_post>a",
prev: ".next_post>a",
customTitle: () => fn.dt({
s: ".single-post-title",
d: /\d+photos/
}),
category: "nsfw2"
}, {
name: "Rikitake.com",
url: {
h: ["rikitake.com"],
p: "/g/"
},
imgs: "a[data-lightbox]",
videos: "video>source",
button: [4],
insertImg: [".entry-content", 2],
customTitle: () => fn.dt({
d: "|Rikitake.com"
}),
downloadVideo: true,
observerClick: ".age-link.enter",
category: "nsfw2"
}, {
name: "マブい女画像集/ちょい懐女画像集",
url: {
h: ["mabui-onna.com", "cyoinatu-onna.com"],
p: "blog-entry-"
},
init: () => {
let texts = fn.gae("//div[@class='entry_body']//div[not(br)][not(a[img])][not(@class='fc2_footer')][not(@class='topentry_text')][not(@class='fc2button-clap')][not(@class='entry_footer')][not(@class='entry_data')]");
if (texts.length > 0) {
let te = fn.ge(".topentry_text,.entry_body");
texts.forEach(e => insertBefore(te, e));
}
},
box: [".entry_body", 1],
imgs: ".topentry div>a:not([href*='.html'],[href*='.dmm.']),.wrapper section div>a:not([href*='.html'],[href*='.dmm.'])",
button: [4],
insertImg: [
["box", 0, "div:has(>a[target]>img[alt]),div[id^='bnc_ad']"], 2
],
insertImgAF: () => {
let e = fn.ge("div:has(>a[href*='.dmm.'])");
if (e) {
let x = fn.ge(".entry_body");
insertBefore(x, e);
}
},
autoDownload: [0],
next: "a.pager_next,.next_entry>a",
prev: "a.pager_prev,.prev_entry>a",
customTitle: ".topentry_title span,.entry_title h1>strong",
hide: "div[class$=Ad]",
category: "nsfw1"
}, {
name: "アイドル村",
host: ["idol-gazoum.net", "zilli-on.ru"],
reg: [
/^https?:\/\/idol-gazoum\.net\/\d+\.html$/,
/^https?:\/\/zilli-on\.ru\/rushporn\/\d+\.html$/
],
imgs: async () => {
let pages = fn.ge(".pagination");
if (pages) {
let max = fn.gt("span.next", 2);
thumbnailSrcArray = await fn.getImg(".blog-feed-content-image .blog-image img", max);
} else {
thumbnailSrcArray = fn.getImgSrcArr(".blog-feed-content-image .blog-image img");
}
return thumbnailSrcArray.map(e => e.replace("middle_resize_", ""));
},
videos: "iframe[src*='youtube']",
button: [4],
insertImg: [".blog-feed-content-image", 2],
customTitle: "h1.articles_header",
category: "nsfw1"
}, {
name: "アイドル画像魂",
host: ["blog.livedoor.jp"],
reg: /^https?:\/\/blog\.livedoor\.jp\/idol_gravure_sexy\/archives\/\d+\.html$/,
imgs: () => fn.getImgSrcArr(".pict").map(e => e.replace("-s.", ".")),
capture: () => _this.imgs(),
autoDownload: [0],
next: ".article-pager>.prev a",
prev: ".article-pager>.next a",
customTitle: "h1.article-title",
category: "nsfw1"
}, {
name: "グラビア大銀河",
url: {
h: "gravuregalaxy.hatenablog.com",
p: "/entry/"
},
imgs: "img.hatena-fotolife",
customTitle: "h1.entry-title",
category: "nsfw1"
}, {
name: "美女の集い",
url: {
h: ["bizyonotudoi.com"],
p: /^\/d\/\d+\.html$/
},
imgs: ".thumb-img-area>img",
button: [4],
insertImg: [".kizi-thumb-list", 2],
customTitle: ".page-title",
hide: "#pagemap-navi",
category: "nsfw1"
}, {
name: "水着画像まとめ",
url: {
h: ["mizugazo.com"],
p: "/archives/"
},
imgs: () => {
let srcs = fn.getImgSrcArr(".single_thumbnail>img,.wp-block-gallery img");
return srcs.map(e => e.replace(/-\d+x\d+\./, "."));
},
capture: () => _this.imgs(),
customTitle: ".entry-title",
category: "nsfw1"
}, {
name: "裏垢女子ランキングナビ",
url: {
h: "uraaka-ranking.com"
},
imgs: () => {
let srcs = fn.getImgSrcArr(".in-pict img");
return srcs.map(e => e.replace(":small", ""));
},
capture: () => _this.imgs(),
customTitle: "h1.entry-title",
category: "nsfw2"
}, {
name: "エロ画像まとめ えっちなお姉さん。",
url: {
h: "hnalady.com",
p: "/blog-entry-"
},
imgs: () => fn.gae(".entry_body img,#more img,.entry_more img").filter(e => !e.closest(".relation_entry,.wakupr")),
capture: () => _this.imgs(),
autoDownload: [0],
next: ".page_next a,.next_entry a",
prev: ".page_prev a,.prev_entry a",
customTitle: "#main h2,.big_title h2",
category: "nsfw2"
}, {
name: "キモ男陵辱同人道",
url: {
h: "kimootoko.net",
p: "/archives/"
},
imgs: () => fn.gae(".post_content .midashigazou img,.post_content a[data-wpel-link]:not(.syousaimoji):has(img)").filter(e => !e.closest(".fanzakiji-hako,.pickup")),
capture: () => _this.imgs(),
customTitle: ".c-postTitle__ttl",
category: "nsfw2"
}, {
name: "二次萌エロ画像ブログ",
url: {
h: "moeimg.net",
p: ".html"
},
imgs: ".box:not(.moeimg-ad) img",
autoDownload: [0],
next: ".nav-next a[rel=prev]",
prev: ".nav-previous a[rel=next]",
customTitle: "h1.title",
category: "nsfw2"
}, {
name: "エロ画像が見たいんだ!",
url: {
h: "eromitai.com",
p: "/archives/"
},
imgs: ".entry-content img",
autoDownload: [0],
next: "a.prev-post",
prev: "a.next-post",
customTitle: "h1.entry-title",
category: "nsfw2"
}, {
name: "女体エロエロ画像集~",
url: {
h: "www.eroero-gazou.net",
p: "/archives/"
},
imgs: ".entry-content a:has(img):not(.yarpp-thumbnail,[href$='8f5a-8.png'])",
autoDownload: [0],
next: ".prev a[rel=prev]",
prev: ".next a[rel=next]",
customTitle: "h1.entry-title",
category: "nsfw2"
}, {
name: "JK 街撮り",
url: {
h: "jk-street-snap.com",
p: "/archives/"
},
imgs: ".eye-catch-wrap img,.entry-content img",
videos: ".entry-content video",
autoDownload: [0],
next: "a.prev-post",
prev: "a.next-post",
customTitle: "h1.entry-title",
downloadVideo: true,
category: "nsfw1"
}, {
name: "芸能人のエロ画像",
url: {
h: "geinoujin-gazou.mixh.jp"
},
imgs: ".eye-catch-wrap img,.entry-content img",
autoDownload: [0],
next: "a.prev-post",
prev: "a.next-post",
customTitle: "h1.entry-title",
category: "nsfw1"
}, {
name: "JKワールド",
link: "https://jkeroina.net/3zigazou/",
url: {
h: "jkeroina.net"
},
imgs: () => fn.gae(".single_thumbnail img,.single-post-main .content img").filter(e => !e.closest("#wp_rp_first")),
capture: () => _this.imgs(),
autoDownload: [0],
next: ".navigation a[rel=prev]",
prev: ".navigation a[rel=next]",
customTitle: "h1.entry-title",
category: "nsfw1"
}, {
name: "JK太ももコレクション",
url: {
h: "suginamijk.blog.2nt.com",
p: "/blog-entry-"
},
imgs: () => fn.gae(".ently_text img").filter(e => !e.closest(".relate_dl")),
capture: () => _this.imgs(),
autoDownload: [0],
next: "a[title='次ページへ進む']",
prev: "a[title='前ページへ戻る']",
customTitle: ".ently_title",
category: "nsfw1"
}, {
name: "美巨乳美女図鑑@素人画像サイト",
url: {
h: "bikyonyu-bijo-zukan.com",
p: "/post"
},
imgs: () => fn.getImgSrcArr(".entry-content img:not(.w_b_ava_img,[src$='ps-loader.svg'])").map(e => e.replace("-scaled.", ".")),
capture: () => _this.imgs(),
customTitle: "h1.entry-title",
hide: "div:has(.adblock_title),.widget_custom_html",
category: "nsfw2"
}, {
name: "性癖エロ画像",
url: {
h: "1000giribest.com",
p: ".html"
},
imgs: ".entry-content img:not([alt^='管理人']),.entry-content-more img:not([alt^='管理人'])",
autoDownload: [0],
next: ".nav-single-previous a,.nav-previous a[rel=prev]",
prev: ".nav-single-next a,.nav-next a[rel=next]",
customTitle: "h1.entry-title",
category: "nsfw2"
}, {
name: "写真倉庫/いあんの女神たち",
link: "https://ameblo.jp/shashinsouko/,https://ameblo.jp/himemiyaian/",
url: {
h: ["ameblo.jp"]
},
page: () => fn.clp("/entry-"),
SPA: () => _this.page(),
observeURL: "head",
init: () => fn.waitEle("a.pagingNext,a[href$=html]:has(p.skinWeakColor)"),
imgs: () => _this.page() ? fn.waitEle(["#entryBody .PhotoSwipeImage,main article img"]).then(eles => {
let imgs = eles.filter(e => !e.closest(".snslink"));
return fn.getImgSrcset(imgs).map(e => e.replace(/\?caw=\d+$/, ""));
}) : [],
capture: () => _this.imgs(),
autoDownload: [0],
next: "//a[contains(@class,'pagingNext')] | //a[p[text()='次の記事']]",
prev: "//a[contains(@class,'pagingPrev')] | //a[p[text()='前の記事']]",
customTitle: () => _this.page() ? fn.waitEle(".js-entryWrapper h1,main article h1").then(e => fn.gt(e)) : null,
hide: "div[aria-hidden]:has(#blogPCOverlayGeneral)",
category: "nsfw2"
}, {
name: "日刊エログ",
url: {
h: "nikkanerog.com",
p: "/blog-entry-"
},
imgs: () => {
let eles = fn.gae(".mainEntryBody img,.mainEntryMore img,#entry .entry-body img").filter(e => !e.closest("a[href*='html'],a[href*='?']"));
let srcs = fn.getImgSrcArr(eles);
return srcs.map(e => e.replace(/s(\.\w+)$/, "$1"));
},
capture: () => _this.imgs(),
autoDownload: [0],
next: "a:has(>img[src$='next.png']),#nav-top .next a",
prev: "a:has(>img[src$='previous.png']),#nav-top .prev a",
customTitle: ".entry_title_h2_ver2,header.entry-title h1",
category: "nsfw2"
}, {
name: "素人エロ画像やったる夫",
url: {
h: "yaruo.info"
},
imgs: ".entry-content img",
autoDownload: [0],
next: ".prev a",
prev: ".next a",
customTitle: "h1.entry-title",
category: "nsfw2"
}, {
name: "パンダ28号の有名人DAI好キング!",
url: {
h: "www.pandagazo.net",
s: "p="
},
srcset: ".eye-catch img,.entry-content .wp-block-image img,.wp-block-gallery img",
autoDownload: [0],
next: "a.prev-post",
prev: "a.next-post",
customTitle: "h1.entry-title",
category: "nsfw1"
}, {
name: "JKちゃんねる",
url: {
h: "channel-jk.com",
s: "p="
},
imgs: "#the-content img,.content-box .content img",
customTitle: "h1.entry-title,h1.title",
category: "nsfw1"
}, {
name: "ぷるるんお宝画像庫",
link: "http://blog.livedoor.jp/pururungazou/",
reg: /^https?:\/\/blog\.livedoor\.jp\/pururungazou\/archives\/\d+\.html$/,
imgs: () => {
videoSrcArray = fn.gae("video[src]").map(e => e.src);
return fn.gae(`
.entry-content img[src*='/pururungazou/imgs/'],
.entry-content img[src*='/media/'],
.article-body img[src*='/pururungazou/imgs/'],
.article-body img[src*='/media/'],
a[title][href*='thetv.jp/i/']
`).map(e => {
if (e.nodeName === "A") {
return e.href.replace(/\?w=.+$/, "");
} else {
return e.src.replace(/-s(\.\w+)$/, "$1");
}
});
},
capture: () => _this.imgs(),
customTitle: ".entry-title,.article-title",
downloadVideo: true,
category: "nsfw2"
}, {
name: "えろJK画像のエロ萌え",
url: {
h: ["eromoe.xyz"],
p: "/blog/"
},
imgs: () => {
let max = fn.gt("//a[text()='Next Page »']", 2) || 1;
return fn.getImg(".entry-content img", max, 7);
},
button: [4],
insertImg: [".entry-content", 2],
autoDownload: [0],
next: "span.prev>a",
prev: "span.next>a",
customTitle: ".entry-title",
category: "nsfw1"
}, {
name: "Love Asian Babes",
url: {
h: ["amazon-love.com"],
p: /^\/[^.]+\.html$/
},
imgs: () => {
let max = fn.gt("//a[text()='Next Page »']", 2) || 1;
return fn.getImg(".entry-content img", max, 7);
},
button: [4],
insertImg: [".entry-content", 2],
autoDownload: [0],
next: "span.prev>a",
prev: "span.next>a",
customTitle: ".entry-title",
category: "nsfw1"
}, {
name: "Permanent Bachelor",
host: ["www.saladpuncher.com"],
reg: /^https?:\/\/www\.saladpuncher\.com\/\d+\/\d+\/[^\/]+\//,
box: [".entry-container", 2],
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr(".rsTmb>img");
return thumbnailSrcArray.map(e => e.replace(/-\d+x\d+(\.\w+)$/, "$1"))
},
button: [4],
insertImg: ["box", 2],
customTitle: ".posttitle",
category: "nsfw1"
}, {
name: "IVPhoto_Gravure",
host: ["ivphoto.tistory.com"],
reg: /^https?:\/\/ivphoto\.tistory\.com\/(m\/)?\d+/,
imgs: ".imageblock img",
button: [4],
insertImg: [".entry-content,.blogview_content", 3],
customTitle: ".tit_blogview,.hgroup h1",
setFancybox: true,
category: "nsfw1"
}, {
name: "Kemono/Coomer SPA",
links: [
"https://kemono.cr/artists",
"https://coomer.st/artists",
"https://kemono.cr/fantia/user/17148",
"https://coomer.st/fansly/user/365239425979916288",
"https://coomer.st/onlyfans/user/arty42575619"
],
url: {
h: ["kemono.cr", "coomer.st"]
},
page: () => fn.clp("/user/"),
SPA: () => _this.page(),
observeURL: "head",
init: () => {
if (fn.clp("/post/")) {
return fn.waitEle(["#main", ".post__user-name", ".post__title"]);
} else if (fn.clp("/user/")) {
return fn.waitEle(["#main", "span[itemprop=name]"]);
} else {
return fn.waitEle("#main");
}
},
getPostJson: url => fetch("/api/v1" + new URL(url).pathname, {
"headers": {
"accept": "text/css"
}
}).then(async res => {
return {
status: res.status,
json: await res.json()
}
}).then(({
status,
json
}) => {
let {
previews,
videos
} = json;
let images = previews?.map(e => e.server + "/data" + e.path + "?f=" + e.name);
videos = videos?.map(e => e.server + "/data" + e.path + "?f=" + e.name);
return {
status,
images,
videos
}
}),
fn: async () => {
if (checkGeting() && !!fn.ge(".card-list")) return;
isFetching = true;
isGetAll = false;
let url = document.URL.replace(document.location.search, "");
let small = fn.gt(".paginator small");
let postsTotal = small.match(/\d+/g).at(-1);
let pagesTotal = Math.ceil(Number(postsTotal) / 50);
let api = "/api/v1" + fn.clp() + "/posts";
let pageLinks = fn.arr(pagesTotal, (v, i) => i == 0 ? api : api + `?o=${i * 50}`);
fn.showMsg(DL.str_05, 0);
let fetchNum = 0;
let resArr = [];
let error = false;
for (let [i, url] of pageLinks.entries()) {
let res = await fetch(url).then(async res => {
return {
status: res.status,
json: await res.json()
}
}).then(({
status,
json
}) => {
if (status == 200) {
fn.showMsg(`${DL.str_06}${i + 1}/${pageLinks.length}`, 0);
return json.results.map(e => document.URL + "/post/" + e.id);
} else {
error = true;
}
});
if (error) {
alert("API Request Error");
isFetching = false;
fn.hideMsg();
return;
}
resArr.push(res);
}
Promise.all(resArr).then(async arr => {
let postUrls = arr.flat();
resArr = [];
fn.showMsg(DL.str_05, 0);
for (let [i, url] of postUrls.entries()) {
let res = await _this.getPostJson(url);
if (res.status != 200) {
alert("API Request Error");
isFetching = false;
fn.hideMsg();
return;
}
resArr.push(res);
fn.showMsg(`${DL.str_06}${i + 1}/${postUrls.length}`, 0);
}
Promise.all(resArr).then(arr => {
videoSrcArray = arr.map(obj => obj.videos).flat();
globalImgArray = arr.map(obj => obj.images).flat();
debug("videoSrcArray", videoSrcArray);
debug("globalImgArray", globalImgArray);
fn.hideMsg();
isGetAll = true;
isFetching = false;
});
});
},
imgs: async () => {
if (isGetAll) return globalImgArray;
if (fn.ge(".card-list")) {
//fn.createImgBox(".site-section", 2);
let links = fn.gau(".card-list__items a");
let resArr = [];
fn.showMsg(DL.str_05, 0);
for (let [i, url] of links.entries()) {
let res = await _this.getPostJson(url);
if (res.status != 200) {
alert("API Request Error");
fn.hideMsg();
return [];
}
resArr.push(res);
fn.showMsg(`${DL.str_06}${i + 1}/${links.length}`, 0);
}
return Promise.all(resArr).then(arr => {
videoSrcArray = arr.map(obj => obj.videos).flat();
return arr.map(obj => obj.images).flat();
});
} else if (fn.clp("/post/")) {
//fn.createImgBox(".post__body", 2);
fn.showMsg(DL.str_05, 0);
return _this.getPostJson(document.URL).then(obj => {
if (obj.status == 200) {
videoSrcArray = obj.videos;
return obj.images;
} else {
alert("API Request Error");
fn.hideMsg();
return [];
}
});
} else {
return [];
}
},
repeat: 1,
customTitle: () => {
if (fn.ge(".card-list")) {
return fn.gt("span[itemprop=name]");
} else if (fn.clp("/post/")) {
return fn.gt(".post__user-name") + " - " + fn.gt(".post__title");
} else {
return null;
}
},
downloadVideo: true,
//fetch: 1,
fancybox: {
blacklist: 1
},
category: "nsfw2"
}, {
name: "Nekohouse",
links: [
"https://nekohouse.su/artists",
"https://nekohouse.su/fantia/user/18"
],
url: {
h: ["nekohouse.su"],
p: "/user/",
e: [".site-section", ".card-list"]
},
fn: () => {
if (checkGeting()) return;
isFetching = true;
let url = location.href.replace(location.search, "");
let small = fn.gt(".paginator small");
let postsTotal = small.match(/\d+/g).at(-1);
let pagesTotal = Math.ceil(Number(postsTotal) / 50);
let pageLinks = fn.arr(pagesTotal, (v, i) => i == 0 ? url : url + `?o=${i * 50}`);
fn.getEle(pageLinks, ".card-list__items a").then(eles => {
let postLinks = eles.map(a => a.href);
fn.getEle(postLinks, "div.fileThumb[href],a[download]").then(files => {
let images = [];
files.forEach(e => {
if (e.tagName === "DIV") {
let img = fn.ge("img", e);
let src = img.dataset.src ?? img.src;
thumbnailSrcArray.push(src);
images.push(fn.lo + e.getAttribute("href"));
} else if (e.tagName === "A") {
let url = e.href;
if (fn.isVideo(url)) {
videoSrcArray.push(url);
} else if (fn.isZip(url)) {
fileUrlArray.push(url);
}
}
});
globalImgArray = images;
isFetching = false;
});
});
},
box: ["#main", 2],
imgs: () => {
let links = fn.gau(".card-list__items a");
return fn.getEle(links, "div.fileThumb[href],a[download]").then(eles => {
let images = [];
eles.forEach(e => {
if (e.tagName === "DIV") {
let img = fn.ge("img", e);
let src = img.dataset.src ?? img.src;
thumbnailSrcArray.push(src);
images.push(fn.lo + e.getAttribute("href"));
} else if (e.tagName === "A") {
let url = e.href;
if (fn.isVideo(url)) {
videoSrcArray.push(url);
} else if (fn.isZip(url)) {
fileUrlArray.push(url);
}
}
});
return images;
});
},
button: [4],
insertImg: ["box", 3],
customTitle: "span[itemprop=name]",
fetch: 1,
category: "nsfw2"
}, {
name: "Nekohouse",
url: {
h: "nekohouse.su",
p: "/post/",
e: "div.fileThumb[href]"
},
box: [".scrape__body", 2],
imgs: () => {
let urls = fn.gau("a[download]");
if (urls.length > 0) {
urls.forEach(url => {
if (fn.isVideo(url)) {
videoSrcArray.push(url);
} else if (fn.isZip(url)) {
fileUrlArray.push(url);
}
});
}
thumbnailSrcArray = fn.gae("div.fileThumb>img").map(e => e.dataset.src ?? e.src);
return fn.gae("div.fileThumb[href]").map(e => fn.lo + e.getAttribute("href"));
},
button: [4],
insertImg: ["box", 3],
customTitle: [".scrape__user-name", ".scrape__title"],
fetch: 1,
category: "nsfw2"
}, {
name: "套图之家",
url: {
h: ["www.taotuhome.com", "taotuhome.com"],
p: /^\/\d+\.html/
},
imgs: () => fn.getImg(".single-content img[alt]", (fn.gt(".page-links>*:last-child", 2) || 1), 7),
button: [4],
insertImg: [".single-content", 2],
autoDownload: [0],
next: "a[rel=prev]:not([href^=j])",
prev: "a[rel=next]:not([href^=j])",
customTitle: () => fn.gt(".entry-title").replace("-套图之家", ""),
category: "nsfw1"
}, {
name: "俊美图",
host: ["www.meijuntu.com", "www.junmeitu.com", "www.jeya.de", "www.jeya.jp"],
url: {
h: [
/^(www\.)?meijuntu\.com$/,
/^(www\.)?junmeitu\.com$/,
/^(www\.)?jeya\.\w+$/,
],
p: /\/([a-z]{2}\/)?\w+\/\w+\.html$/i,
e: ".pictures img"
},
imgs: async () => {
let imgsArr = [];
let max = fn.gt("#pages>*:last-child", 2) || 1;
let url = siteUrl.replace(/(-\d+)?\.html$/, "");
let links = fn.arr(max, (v, i) => url + "-" + (i + 1) + ".html");
for (let [page, link] of links.entries()) {
let dom = await new Promise(async resolve => {
for (let check = 1; check <= 100; check++) {
let res = await fetch(link);
if (res.status == 304 || res.status == 200) {
let buffer = await res.arrayBuffer();
let decoder = new TextDecoder(document.characterSet || document.charset || document.inputEncoding);
let htmlText = decoder.decode(buffer);
let dom = fn.doc(htmlText);
resolve(dom);
break;
} else {
fn.showMsg(`第${page + 1}頁${res.status}重試第${check}次`, 2900);
await delay(3000);
}
}
});
let imgs = fn.gae(".pictures img", dom);
let te = fn.gae(".pictures img").at(-1);
imgs.forEach(e => {
imgsArr.push(e.cloneNode(true));
if (page != 0) insertAfter(te, e.cloneNode(true));
});
if (page != 0) {
let ce = fn.gae("#pages");
let re = fn.gae("#pages", dom);
if (ce.length == re.length) {
ce.forEach((e, i) => (e.outerHTML = re[i].outerHTML));
}
}
await delay(1000);
}
return imgsArr;
},
button: [4],
insertImg: [".pictures", 1],
autoDownload: [0],
next: "//span[contains(text(),'下一')]/following-sibling::a",
prev: "//span[contains(text(),'上一')]/following-sibling::a",
customTitle: "h1.title",
hide: ".pre_picture,.next_picture",
category: "nsfw1"
}, {
name: "妹子图",
url: {
h: ["www.mt316.com", "mt316.com"],
p: /^\/\w+\/\d+\.html$/
},
imgs: ".m-list-content img",
button: [4],
insertImg: [".m-list-content", 2],
autoDownload: [0],
next: ".sxpage_l>a",
prev: 1,
customTitle: ".m-list-tools>h2",
css: ".m-list-content img{max-width:100%!important}",
category: "nsfw1"
}, {
name: "心动美图",
host: ["www.wai55.com", "www.wai76.com", "www.wai77.com", "www.zan69.com", "www.zei22.com", "www.zei33.com", "www.zei77.com", "www.zei99.com", "www.zai66.com", "www.zai33.com", "www.tai90.com", "www.shi54.com", "www.xie69.com", "www.yan44.com"],
url: {
t: "心动美图",
p: /^\/[^\/]+\//,
e: ".entry-content div[data-src]"
},
imgs: () => {
let links = [fn.url];
if (fn.ge(".page-links a")) {
links = fn.gau(".page-links a");
links = [fn.url, ...links];
}
return fn.getEle(links, ".entry-content div[data-src]").then(divs => {
thumbnailSrcArray = divs.map(e => fn.src("img", e));
return divs;
});
},
button: [4],
insertImg: [".entry-content", 2],
customTitle: ".entry-title",
category: "nsfw1"
}, {
name: "美女集合",
url: {
h: ["meinvjihe.cc"],
p: "/thread-"
},
imgs: ".message>img",
button: [4],
insertImg: [".message", 2],
customTitle: ".media-body>span.break-all",
category: "nsfw1"
}, {
name: "美女库",
url: {
h: "www.meinvku.org.cn",
p: "/album/"
},
box: ["#img_src", 1],
imgs: async () => {
let src = fn.src("#img_src img");
let dir = fn.dir(src);
let [, max] = fn.gt("//span[contains(text(),'页次')]").match(/\/(\d+)/);
let arr = fn.arr(max, (v, i) => dir + (i + 1) + ".jpg");
return arr;
},
button: [4],
insertImg: [
["box", 0, "#img_src"], 2
],
category: "nsfw1"
}, {
name: "图宅网/咔咔西三/YouFreeX",
url: {
h: ["www.tuzac.com", "www.kkc3.com", "www.youfreex.com"],
p: "/file/"
},
imgs: () => {
let a = fn.ge("#the-photo-link");
if (a) a.outerHTML = a.innerHTML;
let max = fn.attr("#auto-play", "total");
let [id] = fn.attr("#auto-play", "data").match(/\d+/);
fn.showMsg(DL.str_05, 0);
let fetchNum = 0;
return fn.arr(max, (v, i) => fetch(`/api/?ac=get_album_images&id=${id}&num=${i + 1}`).then(res => res.json()).then(json => {
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${max}`, 0);
return json.src;
}));
},
button: [4],
insertImg: ["#task,#fdp-photo,#fdp-photo-old", 2],
customTitle: () => fn.dt({
s: ".fc-text-content>h1",
d: /(\[\d+P\]|\n|\(\d+P\))/gi
}),
css: ".content-container .content{margin-right:0px!important}",
hide: ".ad-container,.fdp-click-area,.ad-side-right,.footer",
category: "nsfw2"
}, {
name: "图宅网/咔咔西三/YouFreeX",
url: {
h: ["www.tuzac.com", "www.kkc3.com", "www.youfreex.com"]
},
hide: ".ad-container",
category: "ad"
}, {
name: "七仙子图片",
host: ["www.qixianzi.com"],
reg: /^https?:\/\/www\.qixianzi\.com\/\w+\/\d+\.html$/,
imgs: () => {
let url = fn.src("#diggnum script");
let classid = fn.getUSP("classid", url);
let id = fn.getUSP("id", url);
let links = [`/e/wap/show.php?classid=${classid}&id=${id}`];
return fn.getImgA(".arcmain img", links);
},
button: [4],
insertImg: [".picture_content", 2],
endColor: "white",
next: "//li[contains(text(),'上一篇')]/a",
prev: "//li[contains(text(),'下一篇')]/a",
customTitle: "h1.diy-h1",
hide: "nav:has(.pagination)",
category: "nsfw1"
}, {
name: "七仙子图片M",
host: ["www.qixianzi.com"],
link: "https://www.qixianzi.com/e/wap/",
reg: /^https?:\/\/www\.qixianzi\.com\/e\/wap\/show\.php\?/,
imgs: ".arcmain img",
button: [4],
insertImg: [".arcmain", 1],
customTitle: ".header>span",
category: "nsfw1"
}, {
name: "嘿~色女孩",
url: {
h: ["heysexgirl.com"],
p: "/archives/"
},
imgs: () => {
let max = fn.gt(".page-links>*:last-child");
return fn.getImg(".entry-content p>a,.entry-content p>img", max, "4");
},
button: [4],
insertImg: [".entry-container", 2],
autoDownload: [0],
next: ".nav-previous>a",
prev: ".nav-next>a",
customTitle: "h1.page-title",
category: "nsfw2"
}, {
name: "嘿~色女孩 分類自動翻頁",
reg: [
/^https?:\/\/heysexgirl\.com\/(page\/\d+)?$/,
/^https?:\/\/heysexgirl\.com\/archives\/category\/\w+(\/page\/\d+)?$/
],
init: () => fn.waitEle(".blog-posts-wrapper[style]"),
autoPager: {
mode: 1,
waitEle: ".blog-posts-wrapper[style]",
ele: ".blog-posts-wrapper",
observer: ".blog-posts-wrapper",
next: "span.current+a",
re: ".nav-links",
pageNum: () => nextLink.match(/\d+$/)[0]
},
openInNewTab: ".blog-posts-wrapper a:not([target=_blank])",
css: ".blog-posts-wrapper article.has-post-thumbnail .entry-container{margin:0 auto 0 !important}",
category: "autoPager"
}, {
name: "性趣套图",
host: ["tt.539765.xyz", "tt.xqtt.de"],
url: {
e: ["//div[@class='logo']/a[text()='性趣套图']", ".entry img"],
p: "/e/action/ShowInfo.php"
},
imgs: async () => {
if (fn.ge("embed[src*='sendvid']")) {
let links = fn.gae("embed").map(e => e.src);
let resArr = links.map(url => fn.xhrDoc(url).then(dom => fn.src("video>source", dom)));
videoSrcArray = await Promise.all(resArr);
}
return fn.getImg(".entry img", fn.gt("a[title=总数]"), 8)
},
button: [4],
insertImg: ["//div[@class='entry']//img/parent::*", 1],
autoDownload: [0],
next: "//p[contains(text(),'上一')]/a",
prev: "//p[contains(text(),'下一')]/a",
customTitle: ".contitle",
css: ".main-content{margin-left:0px!important;}body{background:#ededed!important;}",
hide: "aside.side",
category: "nsfw2"
}, {
name: "苍井优图",
host: ["34.28tyu.com", "w33.28rty.com", "33.28ery.com", "www.28wer.com", "www.028kkp.com", "sldlxz.com", "34.yuxiangcao.com", "282471.xyz", "284019.xyz"],
url: {
e: "//div[@class='logo']/a[text()='苍井优图']",
p: "/e/action/ShowInfo.php"
},
imgs: "img[id^='aimg'],.entry img",
button: [4],
insertImg: [".entry", 2],
autoDownload: [0],
next: "//p[contains(text(),'上一')]/a",
prev: "//p[contains(text(),'下一')]/a",
customTitle: ".contitle",
category: "nsfw2"
}, {
name: "AVJB/The AV Porn",
host: ["avjb.com", "theavporn.com"],
link: "https://avjb.github.io/,https://avjb.com/albums/,https://theavporn.com/albums/",
url: {
e: "//a[text()='爱微社区'] | //title[contains(text(),'The AV Porn')]",
p: /^\/albums\/\d+\//
},
init: () => {
new MutationObserver((mutations, observer) => {
if (fn.ge(".chatra--webkit")) {
fn.ge(".chatra--webkit").remove();
observer.disconnect();
}
}).observe(document.body, MutationObserverConfig);
},
box: [".images", 2],
imgs: () => fn.getImgSrcArr(".images>a>img").map(e => e.replace(/\/main\/\d+x\d+\//, "/sources/")),
thums: ".images>a>img",
button: [4],
insertImg: [
["box", 0, ".images"], 2
],
customTitle: ".headline>h1",
hide: ".sponsor,.chatra--webkit",
category: "nsfw2"
}, {
name: "AVJB 去廣告",
url: {
e: "//a[text()='爱微社区']",
},
init: () => {
new MutationObserver((mutations, observer) => {
if (fn.ge(".chatra--webkit")) {
fn.ge(".chatra--webkit").remove();
observer.disconnect();
}
}).observe(document.body, MutationObserverConfig);
},
hide: ".sponsor,.chatra--webkit",
category: "ad"
}, {
name: "Asian To Lick",
url: {
h: ["asiantolick.com"],
p: "/post"
},
box: [".spotlight-group", 2],
imgs: () => fn.removeImageCDN(fn.gae("div[data-src]").map(e => e.dataset.src)),
button: [4],
insertImg: [
["box", 0, ".spotlight-group"], 2
],
customTitle: "h1",
hide: "#touch_to_see",
category: "nsfw2"
}, {
name: "Asian To Lick 移除圖片CDN",
url: {
h: ["asiantolick.com"]
},
init: () => fn.addMutationObserver(() => {
[...document.querySelectorAll("#container img[data-src*='wsrv.nl']")].forEach(e => {
e.src = fn.getUSP("url", e.dataset.src);
e.removeAttribute("data-src");
e.removeAttribute("src-original");
});
}),
category: "none"
}, {
name: "Goddess247/BestPrettyGirl/Girl Sweetie/Girl Dreamy/BestGirlSexy",
url: () => fn.checkUrl({
h: ["goddess247.com", "bestprettygirl.com", "girlsweetie.com", "girldreamy.com", "bestgirlsexy.com"]
}) && !/^\/tag\/|^\/category\//.test(fn.lp),
box: ["//p[img] | //img[@class='aligncenter size-full']", 1],
imgs: ".elementor-widget-container p img[alt],.elementor-widget-container img.aligncenter.size-full,.elementor-widget-theme-post-content img",
button: [4],
insertImg: [
["box", 0, "//p[img] | //img[@class='aligncenter size-full']"], 2
],
customTitle: () => fn.title(/ - Goddess247| - BestPrettyGirl| - Girl Sweetie| - Girl Dreamy| - BestGirlSexy/),
fancybox: {
v: 3,
css: false
},
category: "nsfw1"
}, {
name: "WordPress樣板",
links: [
"https://niwatori.my.id/category/uncategorized/",
"https://quenbox.top/?cat=1",
"https://nekobox.top/index.php/category/blog/",
"https://imgyagi.top/category/blog/"
],
url: {
h: ["niwatori.my.id", "quenbox.top", "nekobox.top", "imgyagi.top"],
e: ".post-navigation .nav-links"
},
srcset: ".entry-content .wp-block-gallery img",
button: [4],
insertImg: [".entry-content", 2],
autoDownload: [0],
next: ".nav-previous>a",
prev: ".nav-next>a",
customTitle: "h1.entry-title",
category: "nsfw1"
}, {
name: "Sexy Girl Pictures",
url: {
h: "beautypics.org",
p: "/archives/"
},
srcset: ".elementor-widget-theme-post-content img",
button: [4],
insertImg: [".elementor-widget-theme-post-content", 2],
autoDownload: [0],
next: ".elementor-post-navigation a[rel=prev]",
prev: ".elementor-post-navigation a[rel=next]",
customTitle: "h1.elementor-heading-title",
category: "nsfw1"
}, {
name: "Girl Atlas",
url: {
h: ["www.girl-atlas.com", "girl-atlas.com", "www.girl-atlas.net", "girl-atlas.net", "www.koipb.com", "koipb.com"],
p: "/album",
s: "id="
},
box: [".gallery", 1],
imgs: ".gallery a[data-fancybox]",
thums: ".gallery img",
customTitle: ".header-title",
fancybox: {
blacklist: 1
},
category: "nsfw1"
}, {
name: "Danryoku",
url: {
h: ["danryoku.com"]
},
imgs: () => fn.getImgA(".dynamic-entry-content img", ".ipp-image-nav .nav-center a"),
button: [4],
insertImg: [".dynamic-entry-content", 2],
customTitle: "h1.gb-headline",
category: "nsfw1"
}, {
name: "MINISUKA",
url: {
h: ["minisuka.top"],
p: /^\/\d+\/\d+\/\d+\//
},
imgs: ".wp-block-gallery img",
button: [4],
insertImg: [
[".entry-content", 0, ".wp-block-gallery"], 2
],
customTitle: ".entry-title",
category: "nsfw2"
}, {
name: "BreakBrunch",
url: {
h: ["breakbrunch.com"]
},
imgs: ".single-content img",
customTitle: "h1.single-title",
category: "nsfw2"
}, {
name: "PhimVu/Kutekorean.Com",
host: ["m.phimvuspot.com", "m.kutekorean.com"],
reg: [
/^https?:\/\/m\.(phimvuspot|kutekorean)\.com\/\w+\/\w+\.cfg/i,
/^https?:\/\/m\.kutekorean\.com\/[^\.]+\.html/i
],
include: [".post-content img", "h1.post-title"],
imgs: () => {
let max;
try {
[, max] = fn.gt("h1.post-title")?.match(/\/(\d+)$/);
} catch {
max = 1;
}
return /\?m=1/.test(siteUrl) ? fn.getImg(".post-content img", max, "8") : fn.getImg(".post-content img", max);
},
button: [4],
insertImg: [".post-content", 2],
customTitle: () => fn.dt({
s: "h1.post-title",
d: [
/[\s\|]+Page[\s\d\/]+/,
"E-CUP"
]
}),
category: "nsfw2"
}, {
name: "Poringa!",
host: ["www.poringa.net", "m.poringa.net"],
url: {
h: "poringa.net",
p: "/posts/"
},
imgs: ".post-content img,.content-post-img>img",
customTitle: ".post-title,h1.title",
category: "nsfw2"
}, {
name: "HayVn.Net",
url: {
h: "www.hayvn.net",
p: /^\/\d+\/\d+\/[^\.]+\.html$/,
e: ".separator>a"
},
imgs: () => fn.gau(".separator>a").map(u => u.replace("/s1600/", "/s16000/")),
button: [4],
insertImg: [
[".separator", 1, ".separator"], 2
],
customTitle: ".entry-title",
category: "nsfw1"
}, {
name: "HayVn.Net",
url: {
h: "www.hayvn.net"
},
imgs: ".entry-content img",
customTitle: ".entry-title",
setFancybox: true,
category: "nsfw1"
}, {
name: "YeuGai.Net",
host: ["yeugai.org"],
reg: /^https?:\/\/yeugai\.org\/[^\/]+\/$/i,
init: async () => {
await fn.waitEle(".mirror-image img");
fn.run("jQuery(document).off()");
let e = fn.ge(".relpost-thumb-wrapper");
let f = fn.ge(".penci-entry-footer");
if (e && f) {
insertBefore(f, e);
}
},
imgs: () => {
videoSrcArray = fn.gau("video>source[type='video/mp4']+a[href*='.mp4']");
if (fn.ge(".mirror-image img[src*=blog]")) {
let imgsSrcArr = fn.gae(".mirror-image img[src*=blog]").map(e => {
let arr = e.src.split("/");
if (arr.length === 9) {
arr[7] = "s16000";
return arr.join("/");
} else {
return e.src;
}
});
thumbnailSrcArray = imgsSrcArr.map(e => e.replace("/s16000/", "/w100/"));
return imgsSrcArr;
} else {
return fn.gae(".mirror-image img");
}
},
capture: () => _this.imgs(),
customTitle: () => fn.dt({
s: ".entry-title",
d: /^Ảnh.+Xinh\s|^Ảnh Cosplay 18\+\s|^Clip.+Em\s/
}),
downloadVideo: true,
category: "nsfw2"
}, {
name: "Gái Đẹp Sexy",
url: {
h: "gaidepsexy.vaileu.com"
},
imgs: ".entry p>img",
button: [4],
insertImg: [".entry", 2],
customTitle: "h2.title",
category: "nsfw1"
}, {
name: "GenZ Relax/ẢNH GÁI XINH/Hot Girl Xinh 18+/Hình ảnh gái xinh",
url: {
h: ["genzrelax.com", "anhgaixinh.tv", "girlxinh18.com", "gaixinh.photo"],
e: ".entry-image img,.entry-content img:not(#img_video)"
},
imgs: () => fn.gae(".entry-image img,.entry-content img:not(#img_video)").filter(e => !e.closest("a[href*='?']")),
capture: () => _this.imgs(),
customTitle: "h1.entry-title,h1.page-title",
category: "nsfw1"
}, {
name: "DopaGirls.Com",
url: {
h: ["dopagirls.com"]
},
srcset: ".wp-block-gallery img",
autoDownload: [0],
next: ".next_prev a[rel=prev]",
prev: ".next_prev a[rel=next]",
customTitle: ".xtra-post-title",
category: "nsfw1"
}, {
name: "Tin Hay VIP",
url: {
h: ["tinhayvip.com"]
},
srcset: "img.entry-thumb[srcset],img[class*='wp-image'][srcset]",
customTitle: "h1.tdb-title-text",
category: "nsfw1"
}, {
name: "Hot Girl Xinh 18+",
url: {
h: ["girlxinh18.com"]
},
srcset: ".row-main p>img[srcset]",
customTitle: ".row-main h1",
category: "nsfw1"
}, {
name: "Ảnh Sex",
url: {
h: "anhsex.asia"
},
box: ["article p:has(img)", 1],
imgs: "article p img",
button: [4],
insertImg: [
["box", 0, "article p:has(img)"], 2
],
endColor: "white",
customTitle: "h1.entry-title",
hide: ".tbpopup",
category: "nsfw1"
}, {
name: "Quatvn Club",
url: {
h: "quatvnclub.com",
p: ".html"
},
srcset: ".wp-block-image img",
customTitle: () => fn.dt({
s: ".entry-title",
d: /^Ảnh.+Xinh\s|^Ảnh Cosplay 18\+\s|^Clip.+Em\s/
}),
observerClick: ".catfish-bottom-close",
category: "nsfw2"
}, {
name: "Asia Idols",
url: {
h: ["asiaidols.wordpress.com"],
p: /^\/\d+\/\d+\/\d+\/[^\/]+\/$/
},
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr("img[alt='image host']");
let imageHostLinks = fn.gau("//a[img[@alt='image host']]");
return fn.getImageHost(imageHostLinks);
},
button: [4],
insertImg: [".entry-content", 3],
customTitle: ".entry-title",
category: "nsfw2"
}, {
name: "Asia Porn Photo/Asses Photo/Nuded Photo",
url: {
h: ["www.asiapornphoto.com", "www.assesphoto.com", "www.nudedxxx.com"],
p: /^\/[^\.]+\.shtml$/
},
box: [".image-container", 1],
imgs: ".image-container img",
button: [4],
insertImg: [
["box", 0, ".image-container"], 2
],
customTitle: ".container h1",
category: "nsfw2"
}, {
name: "4KUP",
host: ["4kup.net"],
reg: /^https?:\/\/4kup\.net\/(?!getlink)[^\/]+\/$/,
exclude: "//button[text()='Click here to continue']",
imgs: "a.thumb-photo",
thums: "a.thumb-photo>img",
button: [4],
insertImg: ["#gallery", 2],
autoDownload: [0],
next: "a[rel=prev]",
prev: "a[rel=next]",
customTitle: ".entry-title",
category: "nsfw2"
}, {
name: "呦糖社",
host: ["www.nicesss.com"],
reg: /^https?:\/\/www\.nicesss\.com\/archives\/[\w-]+\/([\w-]+\/)?\d+\.html$/i,
box: [".entry-content>img[data-srcset],.entry-content>p>img[data-srcset]", 1],
imgs: () => fn.gae(".entry-content>img[data-srcset],.entry-content>p>img[data-srcset]").map(e => e.dataset.srcset),
button: [4],
insertImg: [
["box", 0, ".entry-content>img[data-srcset],.entry-content>p:has(>img[data-srcset])"], 2
],
customTitle: ".entry-title>a",
fancybox: {
v: 3,
css: false
},
category: "nsfw1"
}, {
name: "呦糖社C+",
host: ["www.nicezzz.com", "www.nicekkk.com"],
reg: [
/^https?:\/\/www\.nicezzz\.com\/archives\/[\w-]+\/([\w-]+\/)?\d+\.html$/i,
/^https?:\/\/www\.nicekkk\.com\/archives\/[\w-]+\/[\w-]+\.html$/i
],
box: [".wp-posts-content>img,.wp-posts-content>p>img", 1],
imgs: ".wp-posts-content>img,.wp-posts-content>p>img",
button: [4],
insertImg: [
["box", 0, ".wp-posts-content>img,.wp-posts-content>p:has(>img)"], 2
],
customTitle: ".article-title>a",
fancybox: {
v: 3,
insertLibrarys: 1
},
category: "nsfw1"
}, {
name: "Fliporn",
host: ["fliporn.biz"],
reg: /^https?:\/\/fliporn\.biz\/videos\//,
include: "//span[@class='entry-category']/a[text()='亚洲贴图' or text()='写真' or text()='动漫贴图' or text()='性感贴图' or text()='欧美贴图' or text()='网友自拍']",
box: ["//center[img] | //center[p[img]] | //div[@id='conttpc' and img] | //div[@id='conttpc' and p[img]] | //div[@class='entry-content']//p[img] | //div[figure[div[img]]]", 1],
imgs: async () => {
let srcs;
let pages = fn.ge(".custom-pagination");
if (pages) {
let max = fn.gt(".next.page-numbers", 2);
srcs = await fn.getImg("article img", max, 7);
} else {
srcs = fn.getImgSrcArr("article img");
}
return srcs.map(e => e.replace("%3C/center%3E%3C/p%3E%3Cdiv%20class=", "").replace(/\?w=858(&ssl=1)?/, ""));
},
button: [4],
insertImg: [
["box", 0, "//br | //div[@class='custom-pagination'] | //center[img] | //center[p[img]] | //div[@id='conttpc' and img] | //div[@id='conttpc' and p[img]] | //div[@class='entry-content']//p[img] | //div[figure[div[img]]]"], 2
],
customTitle: () => fn.dt({
s: ".entry-title",
d: /\n|[\s\d]+$/g
}),
category: "nsfw2"
}, {
name: "91图录",
url: {
h: "www.91tulu.com",
p: /^\/\d+\.html$/
},
imgs: ".wp-posts-content img",
button: [4],
insertImg: [".wp-posts-content", 2],
autoDownload: [0],
next: "//a[p[text()='上一篇']]",
prev: "//a[p[text()='下一篇']]",
customTitle: ".article-title",
css: ".wp-posts-content{max-height:unset!important}",
category: "nsfw1"
}, {
name: "91HD视频",
host: ["91hd.com"],
link: "https://www.91hdzq.cc/category/%E6%88%90%E4%BA%BA%E8%89%B2%E5%9B%BE/",
url: {
h: /www\.91hd/,
p: /^\/[^\/]+\/$/,
e: ".image-container"
},
imgs: () => fn.getImgA(".image-container img", ".post-nav-links>a"),
button: [4],
insertImg: [".post-content", 2],
customTitle: ".post-title",
css: "body{padding:unset!important}.sidebar-secondary{top:70px!important}",
hide: ".tuadx,body>*[id][style]:has(>img)",
category: "nsfw2"
}, {
name: "91HD视频 AD",
reg: /^https?:\/\/www\.91hd\w+\.\w+\//,
css: "body{padding:unset!important}.sidebar-secondary{top:70px!important}",
hide: ".tuadx,body>*[id][style]:has(>img)",
category: "ad"
}, {
name: "91高清",
url: {
t: "91HD",
p: "/thread-"
},
imgs: ".t_fsz img[id^='aimg']",
customTitle: () => fn.dt({
t: fn.ge("meta[name=keywords]").content
}),
category: "nsfw2"
}, {
name: "淫淫小说写真馆",
host: ["books.xxgirls.vip"],
url: {
h: "xxgirls",
p: "artdetail"
},
imgs: "#read_tpc img,.hl-article-content img",
button: [4],
insertImg: ["#read_tpc,.hl-article-content", 2],
autoDownload: [0],
next: ".hl-next",
prev: ".hl-prev",
customTitle: () => fn.dt({
s: ".hl-article-title",
d: /-[\d\s]+P?$|\(\d+P\)?.*$|【\d+P】$/i
}),
category: "nsfw2"
}, {
name: "成人图片 Qinimg",
url: {
h: "www.qinimg.com",
p: "/image/"
},
imgs: () => {
thumbnailSrcArray = fn.gae("#image a>img").map(e => e.getAttribute("img") != "" ? e.getAttribute("img") : e.src);
return fn.gae("#image a");
},
button: [4],
insertImg: [
["#image", 2], 2
],
customTitle: ".box>h1",
category: "nsfw2"
}, {
name: "Elite Babes格式",
url: {
h: ["www.elitebabes.com", "pmatehunter.com", "www.jperotica.com", "www.metarthunter.com", "www.femjoyhunter.com", "nakedporn.pics", "plum.gent", "uludagspot.com", "funphotoguys.com", "suikachallenge.com"],
e: ".list-gallery",
ee: "#content video"
},
init: () => fn.waitEle(".list-gallery a[data-fancybox]"),
imgs: () => fn.gae(".list-gallery a[data-fancybox]"),
thums: ".list-gallery a[data-fancybox]>img",
button: [4, "23%"],
insertImg: [
[".list-gallery", 2], 2
],
customTitle: "#content>p",
fancybox: {
v: 3,
css: false
},
category: "nsfw2"
}, {
name: "Naked Women Pics/VIEW GALS/Hot Pussy Pics/Busty Women Pics",
host: ["nakedwomenpics.com", "viewgals.com", "hotpussypics.com", "bustypassion.com"],
reg: [
/^https?:\/\/nakedwomenpics\.com\/pics\/[^\/]+\/$/,
/^https?:\/\/viewgals\.com\/pics\/[^\/]+\/$/,
/^https?:\/\/hotpussypics\.com\/pics\/[^\/]+\/$/,
/^https?:\/\/bustypassion\.com\/pics\/[^\/]+\/$/,
],
imgs: "a.ss-image",
button: [4],
insertImg: [".m-content-con", 2],
customTitle: "h1",
category: "nsfw2"
}, {
name: "TeenPussyPics.com",
url: {
h: ["teenpussypics.com"],
p: "/images/"
},
imgs: "//div[@id='lucrezia']//a[img[@data-src]]",
button: [4],
insertImg: ["#lucrezia", 2],
customTitle: "h1",
css: "#lucrezia{height:auto!important}",
category: "nsfw2"
}, {
name: "Wb-express porno",
url: {
h: "wb-express.ru"
},
imgs: ".pw-description img",
button: [4],
insertImg: [".pw-description", 2],
customTitle: ".page-wrap h1",
category: "nsfw2"
}, {
name: "NSFWalbum",
url: {
h: ["nsfwalbum.com"],
p: "/album/"
},
box: [".album", 2],
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr(".albumPhoto");
fn.showMsg(DL.str_05, 0);
let fetchNum = 0;
return fn.gae(".album .item>a").map(async (a, i, arr) => {
let img = fn.ge("img", a);
let src = img.dataset.src ?? img.src;
if (/imx\.to/.test(src)) {
return src.replace("/t/", "/i/");
} else {
await delay(100 * i);
return fetch(a.href).then(res => res.text()).then(async text => {
await delay(200 * i);
let id = a.href.split("/").at(-1);
text = fn.stringSlicer(text, "spirit = ", "))");
let spirit = fn.run(text);
let api = `/backend.php?&spirit=${spirit}&photo=${id}`;
return fetch(api).then(res => res.json()).then(json => {
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${arr.length}`, 0);
return json[0];
});
});
}
});
},
button: [4, "24%", 3],
insertImg: [
["box", 0, ".album"], 2
],
customTitle: () => fn.dt({
s: ".gallery_name",
d: [
/\s-[\s\d]+px[\s\d-]+pictures/i,
/\sx\d{1,4}.*/i,
/-\sx\d{1,4}.*/i,
/-\s\d{1,4}x.*/i,
/-[\d\s]+pic.+/i,
/-\s\d{2}.\d{2}.\d{4}.*/i,
/\(x\d+\).*/i,
/[\d\s]+pics.*/i,
/\([\w\s\.\+,]+\)/i,
/\|[\s\dx]+\|.*/i,
/[\s\d-]+x[\s\d\+]+covers/i
]
}),
category: "nsfw2"
}, {
name: "Adult photo sets",
url: {
h: "adultphotosets.best",
e: "//a[img[@data-src][@data-maxwidth]] | //a[img[@data-src][@border='0']]"
},
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr("//img[@data-src][@data-maxwidth] | //img[@data-src][@border='0']");
let [src] = thumbnailSrcArray;
if (src.includes("imx.to/u/t/")) {
return thumbnailSrcArray.map(e => e.replace("/t/", "/i/"));
}
let URLs = fn.gau("//a[img[@data-src][@data-maxwidth]] | //a[img[@data-src][@border='0']]");
return fn.getImageHost(URLs);
},
button: [4],
insertImg: [
["//a[img[@data-src][@data-maxwidth]] | //a[img[@data-src][@border='0']]", 2, "//a[img[@data-src][@data-maxwidth]] | //a[img[@data-src][@border='0']]"], 2
],
customTitle: ".title",
category: "nsfw2"
}, {
name: "Ciberhentai",
url: {
h: "www.ciberhentai.com",
p: ".html"
},
imgs: "a[data-gallery],#mangacomic img",
thums: "a[data-gallery]>img",
autoDownload: [0],
next: ".prev-post a",
prev: ".next-post a",
customTitle: "span.post-title",
hide: ".arcenter-container.flex-container",
category: "nsfw2"
}, {
name: "ChoChoX",
url: {
h: ["chochoxhd.com"]
},
box: ["#fullscreen-btn+p", 2],
imgs: "#fullscreen-btn+p img",
button: [4],
insertImg: [
["box", 0, "#fullscreen-btn+p"], 2
],
autoDownload: [0],
next: ".prev-post a",
prev: ".next-post a",
customTitle: "span.post-title",
hide: ".arcenter-container.flex-container",
category: "hcomic"
}, {
name: "Lucious Hentai",
url: {
h: ["lucioushentai.com"]
},
box: [".entry-content p:has(>a>img)", 2],
imgs: ".entry-content img",
button: [4],
insertImg: [
["box", 0, ".entry-content p:has(>a>img)"], 2
],
customTitle: ".entry-title",
category: "hcomic"
}, {
name: "Pics-X",
url: {
h: ["pics-x.com"],
p: "/gallery/"
},
init: () => fn.waitEle("#images-container img"),
imgs: "#images-container .images-container-image",
button: [4],
insertImg: ["#images-container", 2],
customTitle: () => fn.title(" | Pics-X"),
category: "nsfw2"
}, {
name: "Redpics",
host: ["www.redpics.top"],
reg: /^https?:\/\/www\.redpics\.top\/(japanese|korean|chinese|hardcore|softcore|lesbian)\/[\w-]+\/?$/,
imgs: () => {
let aEles = fn.gae("#extra-content>a,.post-content a");
thumbnailSrcArray = aEles.map(a => fn.src("img", a));
let [src] = thumbnailSrcArray;
if (src.includes("imx.to/u/t/")) {
return thumbnailSrcArray.map(e => e.replace("/t/", "/i/"));
}
let URLs = aEles.map(a => a.href);
return fn.getImageHost(URLs);
},
button: [4],
insertImg: ["#post-content", 3],
autoDownload: [0],
next: () => fn.gu("//div[text()='Previous Post']/following-sibling::div[1]/a"),
prev: () => fn.gu("//div[text()='Next Post']/following-sibling::div[1]/a"),
customTitle: "#photoset-title",
category: "nsfw2"
}, {
name: "SXYPIX",
url: {
h: ["sxypix.com"],
p: "/w/"
},
box: [".gallgrid", 2],
imgs: async () => {
fn.showMsg(DL.str_05, 0);
let pid = fn.ge("div.grid-item").dataset.photoid;
let aid = fn.gu(".gall_info_panel a.tdn").split("/").at(-1);
let ghash = fn.ge(".gall_cp[data-ghash]").dataset.ghash;
let total = Number(fn.gt(".ip_count"));
let pages = Math.ceil(total / 36);
let headers = {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-requested-with": "XMLHttpRequest"
};
let resArr = fn.arr(pages, (v, i) => fetch("/php/apg.php", {
"headers": headers,
"body": `mode=w¶m={"page":${(i + 1)},"ghash":"${ghash}"}`,
"method": "POST"
}).then(res => res.json()).then(json => json.r));
thumbnailSrcArray = await Promise.all(resArr).then(data => data.flat()).then(arr => {
let html = arr.join("");
let dom = fn.doc(html);
return fn.gae(".gall_cover", dom).map(e => e.dataset.src ?? e.src);
});
return fetch("/php/gall.php", {
"headers": headers,
"body": `x=x&pid=${pid}&aid=${aid}&ghash=${ghash}&width=1920`,
"method": "POST"
}).then(res => res.json()).then(json => {
let arr = json.r;
let html = arr.join("");
let dom = fn.doc(html);
return fn.gae("div.gall_pix_el", dom);
});
},
button: [4],
insertImg: [
["box", 0, ".grid"], 2
],
endColor: "white",
customTitle: ".gall_title",
category: "nsfw2"
}, {
name: "Boombo!",
host: ["hot.boombo.biz", "boombo.biz"],
url: {
h: "boombo.biz"
},
imgs: () => fn.getImgSrcArr(".text div[style] img,.text div.fimg img").map(e => e.replace("thumbs/", "")),
thums: ".text div[style] img,.text div.fimg img",
button: [4],
insertImg: [".text div[style],.news .text", 2],
customTitle: "#dle-content h1",
category: "nsfw2"
}, {
name: "GayBoysTube",
url: {
h: "www.gayporntube.com",
p: "/galleries/"
},
init: () => {
if (isM) {
fn.addMutationObserver(() => fn.remove(".after_header"));
}
},
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr("#tab5 img");
return thumbnailSrcArray.map(e => e.replace(/main\/\d+x\d+/, "sources").replace("thumbs/", ""));
},
button: [4],
insertImg: ["#tab5", 2],
customTitle: "h1.title",
hide: ".content>.block-album",
category: "nsfw2"
}, {
name: "BoyFriendTv.com",
url: {
h: "www.boyfriendtv.com",
p: "/pics/",
d: "pc"
},
box: [".gallery-detail", 2],
imgs: async () => {
let eles;
if (fn.ge("//a[@class='rightKey'][text()='Next']")) {
let max = fn.gt("//a[text()='Next']", 2) ?? 1;
let links = [fn.lp, ...fn.gau(".gallery-detail .ajax-pager a[href]")];
eles = await fn.getEle(links, ".gallery-detail .thumb-item a[style^='background-image']", null, null, 0);
} else {
eles = fn.gae(".gallery-detail .thumb-item a[style^='background-image']");
}
thumbnailSrcArray = eles.map(a => {
let backgroundImage = a.style.backgroundImage;
return backgroundImage.slice(5, -2).trim();
});
return thumbnailSrcArray.map(e => e.replace("-320-", "-800-"));
},
button: [4],
insertImg: ["box", 2],
customTitle: "#gallery h1",
category: "nsfw2"
}, {
name: "МЕДИА ТРЕНД",
link: "https://jb5.ru/shoubiz/onlyfans-sliv/",
url: {
h: ["jb5.ru"]
},
srcset: ".gallery-item a,span[itemprop=image]>img,.entry-content img[srcset],.entry-content img[class*='wp-image']",
customTitle: ".entry-title>h1",
category: "nsfw2"
}, {
name: "alt Goddess",
url: {
h: "altgoddess.com"
},
init: () => {
if ("adde_modal_detector" in _unsafeWindow) {
_unsafeWindow.adde_modal_detector(false);
}
},
imgs: "a[data-fancybox],.mpc-grid-images img",
autoDownload: [0],
next: ".mk-post-next",
prev: ".mk-post-prev",
customTitle: ".page-title",
observerClick: ".adde_modal_detector-action-btn-close",
category: "nsfw2"
}, {
name: "alt Goddess",
url: {
h: "altgoddess.com"
},
init: () => {
if ("adde_modal_detector" in _unsafeWindow) {
_unsafeWindow.adde_modal_detector(false);
}
},
observerClick: ".adde_modal_detector-action-btn-close",
category: "ad"
}, {
name: "GamEYE",
url: {
h: ["gameye.ru", "gameye.kz"]
},
imgs: ".wp-block-gallery img",
customTitle: "section h1",
category: "nsfw1"
}, {
name: "CQ",
url: {
h: ["cq.ru"]
},
imgs: ".p__header-image img[srcset],a.swipebox:has(img[srcset]),.gallery-top a.swiper-slide",
customTitle: "h1.h1-h2",
hide: ".m.--top",
category: "nsfw1"
}, {
name: "GameMAG",
url: {
h: "gamemag.ru"
},
imgs: () => {
thumbnailSrcArray = fn.getImgSrcset("#gallery img");
return thumbnailSrcArray.map(src => src.replace("/small", "/original"));
},
capture: () => _this.imgs(),
videos: "iframe[src*='vk.com/video']",
customTitle: "h1.overview__title",
category: "nsfw1"
}, {
name: "GameFans",
url: {
h: "gamefans.ru"
},
imgs: "#fstory img",
customTitle: "#pageTitle",
category: "nsfw1"
}, {
name: "Фото идеи и картинки",
url: {
h: "nd27.ru",
e: ".entry-title"
},
imgs: ".gallery-item img",
customTitle: () => fn.dt({
s: ".entry-title",
d: /\([\d\s]+фото\)|\(\d+[\sфотfots]+\)|\d+[\sфотfots]+/
}),
category: "nsfw1"
}, {
name: "Картинки и фото",
url: {
h: "cojo.ru",
e: ".entry-title"
},
imgs: ".wp-block-image img",
customTitle: () => fn.dt({
s: ".entry-title",
d: /\([\d\s]+фото\)|\(\d+[\sфотfots]+\)|\d+[\sфотfots]+/
}),
setFancybox: true,
category: "nsfw1"
}, {
name: "geekfan.site",
url: {
h: "geekfan.site",
e: [".sgb-data,.entry-content img", ".entry-title"]
},
imgs: () => {
let data = fn.ge(".sgb-data");
if (data) {
return fn.gae(".sgb-data").flatMap(data => {
let text = data.textContent;
let json = JSON.parse(text);
return json.images.map(e => e.url.replace("-scaled", ""));
});
} else if (fn.ge("a[href*='/images/']")) {
return fn.gae("a[href*='/images/']");
} else {
return fn.gae(".entry-content img");
}
},
capture: () => _this.imgs(),
autoDownload: [0],
next: ".nav-previous a[rel=prev]",
prev: ".nav-next a[rel=next]",
customTitle: () => fn.dt({
s: ".entry-title",
d: [
/\(\d+[\sфотfots]+\)|[\d\sфотfots]+/,
/\(?[\d\s]+фото\)?/,
/[\d\s]+горячих/,
"слив"
]
}),
category: "nsfw1"
}, {
name: "CLANNAD",
url: {
h: "clannadhouse.com",
p: /^\/[^\/]+\/$/
},
imgs: () => {
let g = "a.fox-lightbox-gallery-item";
let g2 = "div[class*='lightbox'] img";
if (fn.ge(g)) {
return fn.gae(g);
} else if (fn.ge(g2)) {
return fn.getImgSrcset(g2);
} else {
return fn.getImgSrcset(".hero56__background>img,.entry-content img");
}
},
capture: () => _this.imgs(),
customTitle: ".post-title",
category: "nsfw1"
}, {
name: "Szexképek",
url: {
h: "szexkepek.net",
p: ".html",
e: ".row:has(>.col-xs-6>a>img.gallerythumb)"
},
imgs: () => {
let links = fn.gau("a:has(>img.gallerythumb)");
return fn.getImgA("img.img-responsive", links);
},
thums: "img.gallerythumb",
button: [4],
insertImg: [".row:has(>.col-xs-6)", 2],
customTitle: "h1.page-header",
category: "nsfw2"
}, {
name: "BugilOnly",
url: {
h: "bugilonly.com"
},
imgs: ".s-post-content img",
button: [4],
insertImg: [".s-post-content", 2],
autoDownload: [0],
next: "a.next-page-link",
prev: "a.prev-page-link",
customTitle: "h1.entry-title",
category: "nsfw2"
}, {
name: "Terekspos",
url: {
h: "terekspos.com"
},
imgs: () => {
let is = ".post-content>center>a>img,.post-content>p>a>img";
let as = ".post-pagination a";
let pages = fn.ge(as);
return pages ? fn.getImgA(is, as) : fn.gae(is);
},
capture: () => _this.imgs(),
autoDownload: [0],
next: "div.next a",
prev: "div.previous a",
customTitle: "h1.post-title",
category: "nsfw2"
}, {
name: "SoCaseiras",
url: {
h: "www.socaseiras.com.br",
p: "/galeria/"
},
imgs: ".galeria .fotos img",
button: [4],
insertImg: [".galeria .fotos", 2],
customTitle: ".galeria h1",
category: "nsfw2"
}, {
name: "LigaDasNovinhas",
url: {
h: "www.ligadasnovinhas.com"
},
imgs: "#post-info img",
customTitle: ".post h1",
category: "nsfw2"
}, {
name: "Não Conto",
url: {
h: "www.naoconto.com",
p: ".html",
e: ".title"
},
imgs: "article img",
customTitle: () => fn.ge(".title")?.textContent,
category: "nsfw2"
}, {
name: "Vagabundas Do Orkut",
url: {
h: "www.vagabundasdoorkut.net"
},
srcset: ".post-texto img",
customTitle: ".pagina-titulo",
category: "nsfw2"
}, {
name: "Nudes",
url: {
h: "nudes.blog.br"
},
srcset: ".gallery-item img[srcset]",
customTitle: ".meio h1",
category: "nsfw2"
}, {
name: "MinhaMulher",
url: {
h: "www.minhamulher.com"
},
box: [".conteudo p:has(>img)", 1],
imgs: ".conteudo img",
button: [4],
insertImg: [
["box", 0, ".conteudo p:has(>img)"], 2
],
customTitle: ".titulo>h1",
category: "nsfw2"
}, {
name: "Fotos Porno",
url: {
h: "www.fotosporno.blog"
},
imgs: ".gallery img",
videos: ".wp-video source",
button: [4],
insertImg: [".gallery", 2],
customTitle: ".cn-article h1",
downloadVideo: true,
category: "nsfw2"
}, {
name: "Nevsepic",
host: ["nevsepic.com.ua"],
url: {
h: "nevsepic",
e: ["//div[@class='full-comms']/a[text()='18+']", ".full-text img,a.highslide", ".share_widget"]
},
box: [".share_widget", 1],
imgs: async () => {
let srcs;
let pages = fn.ge(".bottom-nav");
if (pages) {
let last = fn.ge(".navigation>a:last-child");
let max = last.innerText;
let url = last.pathname;
let links = fn.arr(max, (v, i) => i == 0 ? fn.url : url.replace(/(\/page\,)(\d+\,)/, `$1${(i + 1) + ","}`));
srcs = await fn.getImgA("a.highslide,.full-text img", links);
} else {
srcs = fn.getImgSrcArr("a.highslide,.full-text img");
}
return srcs.filter(src => !src.includes("/thumbs/") && !src.includes("attach.png"));
},
button: [4],
insertImg: [
["box", 0, ".full-text img:not(.FullPictureLoadImage,[src$='attach.png']),.full-text img:not(.FullPictureLoadImage,[src$='attach.png'])~br,a.highslide,a.highslide~br,.bottom-nav"], 2
],
customTitle: ".f-page-title",
category: "nsfw2"
}, {
name: "Nevsepic",
host: ["nevsepic.com.ua"],
url: {
h: "nevsepic",
e: [".full-text img,a.highslide", ".share_widget"]
},
imgs: async () => {
let srcs;
let pages = fn.ge(".bottom-nav");
if (pages) {
let last = fn.ge(".navigation>a:last-child");
let max = last.innerText;
let url = last.pathname;
let links = fn.arr(max, (v, i) => i == 0 ? fn.url : url.replace(/(\/page\,)(\d+\,)/, `$1${(i + 1) + ","}`));
srcs = await fn.getImgA("a.highslide,.full-text img", links);
} else {
srcs = fn.getImgSrcArr("a.highslide,.full-text img");
}
return srcs.filter(src => !src.includes("/thumbs/") && !src.includes("attach.png"));
},
capture: () => _this.imgs(),
button: [4],
customTitle: ".f-page-title",
category: "nsfw2"
}, {
name: "erohd.icu",
url: {
h: "erohd.icu"
},
imgs: ".sigFreeThumb a.fancybox-gallery",
thums: ".sigFreeThumb a.fancybox-gallery img",
customTitle: ".article-title",
fancybox: {
v: 3,
css: false
},
category: "nsfw2"
}, {
name: "Ero-Top",
url: {
h: "ero-top.name",
p: ".html"
},
imgs: "#img-bl a",
thums: "#img-bl a img",
customTitle: "#dle-content h1",
category: "nsfw2"
}, {
name: "ADULT SITE 18+",
host: ["go1.kiski.top"],
url: {
e: ".prev_row_full .statya",
p: ".html"
},
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr(".prev_row_full .statya img");
return thumbnailSrcArray.map(e => e.replace("thumbs/", ""));
},
capture: () => _this.imgs(),
customTitle: "main h1",
fancybox: {
v: 3,
css: false
},
category: "nsfw2"
}, {
name: "erovizor.top",
url: {
h: "erovizor.top"
},
imgs: ".entry-content a.lg-thumb-item",
customTitle: ".entry-title",
fancybox: {
v: 3,
css: false
},
category: "nsfw2"
}, {
name: "DTF",
url: {
h: "dtf.ru"
},
page: () => fn.clp(/^\/(u|s)\/[^\/]+\/\d+/) || fn.clp(/^\/[^\/]+\/\d+/) && !fn.clp("/u/"),
SPA: () => _this.page(),
observeURL: "nav",
imgs: () => {
if (!_this.page()) return [];
fn.showMsg(DL.str_05, 0);
return fn.fetchDoc(fn.clp()).then(dom => {
//console.log(dom);
let id = fn.clp().split("/").at(-1).match(/\d+/)[0];
//console.log(id);
let code = fn.gst("__INITIAL_STATE__", dom);
let s = code.indexOf("'") + 1;
let e = code.lastIndexOf("'");
code = code.slice(s, e).replaceAll("\\\\", "\\");
let obj = new Function("return " + code)();
//console.log(obj);
let data = obj["entry@" + id];
//console.log(data);
let images = [];
let videos = [];
data.blocks.filter(e => e.type == "media").forEach(e => {
if (e?.data?.items[0]?.image?.data?.type == "gif") {
videos.push(`https://leonardo.osnova.io/${e.data.items[0].image.data.uuid}/-/format/mp4/#t=0.1v`);
} else {
images.push("https://leonardo.osnova.io/" + e.data.items[0].image.data.uuid);
}
});
data.blocks.filter(e => e.type == "video").forEach(e => {
if (e?.data?.video?.data?.external_service?.name == "youtube") {
videos.push("https://www.youtube.com/watch?v=" + e.data.video.data.external_service.id);
if (e?.data?.video?.data?.thumbnail?.data?.uuid) {
images.push("https://leonardo.osnova.io/" + e.data.video.data.thumbnail.data.uuid);
}
}
});
if (data?.media?.type == "video" && data?.media?.data?.thumbnail?.data?.uuid) {
images.push("https://leonardo.osnova.io/" + data.media.data.thumbnail.data.uuid);
if (data?.media.data.external_service.name == "youtube") {
videos.push("https://www.youtube.com/watch?v=" + data.media.data.external_service.id);
}
}
let title;
if (data.title == "") {
title = "Пост в блоге " + data.author.name;
} else {
title = data.title + " — " + data.author.name;
}
//console.log(title);
apiCustomTitle = fn.dt({
t: title
});
//console.log(images);
videoSrcArray = [...new Set(videos)];
return [...new Set(images)];
});
},
capture: () => _this.imgs(),
button: [4],
insertImgBF: () => fn.waitEle([".content__blocks", ".content"]).then(() => fn.createImgBox(".content", 1)),
insertImg: ["box", 3],
category: "nsfw2"
}, {
name: "Reddit",
url: {
h: "www.reddit.com"
},
page: () => fn.clp("/comments/"),
SPA: () => _this.page(),
observeURL: "nav",
imgs: () => {
if (!_this.page()) return [];
return fn.showMsg(DL.str_05, 0).then(() => fn.fetchDoc(fn.clp()).then(dom => {
let pics = fn.getImgSrcset("gallery-carousel li>img,.media-lightbox-img img", dom);
let gifs = fn.gae("shreddit-post[content-href*='.gif']", dom).map(e => e.getAttribute("content-href"));
apiCustomTitle = fn.dt({
t: fn.gt("h1[id^='post-title']", 1, dom)
});
return [...pics, ...gifs];
}));
},
capture: () => _this.imgs(),
button: [4],
category: "nsfw2"
}, {
name: "uCrazy",
url: {
h: ["ucrazy.org", "girls.ucrazy.org"]
},
page: () => !!fn.ge("#addcomment"),
SPA: () => _this.page(),
observeURL: "loop",
imgs: () => {
if (!_this.page()) return [];
return fn.showMsg(DL.str_05, 0).then(() => fn.fetchDoc(fn.clp()).then(dom => {
let jsonText = fn.gst("description", dom);
apiCustomTitle = fn.dt({
t: fn.gt("h1.news__title", 1, dom),
});
videoSrcArray = fn.gae(".news__content_wrapper video>source", dom).map(e => e.src);
if (jsonText && fn.clp("/video/")) {
let json = JSON.parse(jsonText);
let data = Object.values(json).find(e => isArray(e));
if (isArray(data[0]?.image)) {
return data[0].image;
}
}
return fn.gae(".news__content_wrapper img:not(.news__tags-more-icon)", dom);
}));
},
capture: () => _this.imgs(),
hide: ".banner:has(>#advideo_adv_container),.banner:has(>#app_rulive)",
category: "nsfw2"
}, {
name: "bdsmlr",
link: "https://chasti-wabbit.bdsmlr.com/post/265859932",
url: {
h: ".bdsmlr.com",
e: ".image_container img",
d: "pc"
},
SPA: true,
init: async () => {
addNewTabViewButton();
const get = async () => {
let imgs = fn.gae(".image_container img:not(.get)");
if (imgs.length > 0) {
imgs.forEach(img => img.classList.add("get"));
fn.getImgSrcArr(imgs).forEach(src => setArray.add(src));
}
let videos = fn.gae("video.vjs-tech[value][poster]:not(.get)");
if (videos.length > 0) {
videos.forEach(video => {
video.classList.add("get");
let src = video.getAttribute("value");
setVideoArray.add(src);
setArray.add(video.poster);
});
videoSrcArray = [...setVideoArray];
}
if (captureTotal != setArray.size) {
captureTotal = setArray.size;
await captureSrcB();
}
customTitle = document.title;
};
await get();
fn.addMutationObserver(async () => {
if (captureExclude()) return;
await get();
});
},
imgs: () => setArray,
capture: () => _this.imgs(),
infiniteCapture: 1,
hide: ".reblogcontainerouter",
downloadVideo: true,
focus: "last:.image_container",
closeAF: () => {
let ask = fn.ge(".askholder");
if (ask) {
EClick(".cancelbutton");
}
},
aeg: 0,
category: "nsfw2"
}, {
name: "Дзен",
url: {
h: ["dzen.ru"]
},
SPA: () => {
let url = new URL(document.URL);
return url.pathname.startsWith("/a/") && url.search === "";
},
observeURL: "body",
imgs: () => {
//每張圖片讀取完成後會將圖片網址存到sessionStorage屬性hermioneStatPixels裡
//sessionStorage.getItem("hermioneStatPixels");
return _this.SPA() ? fn.wait(() => {
fn.showMsg(DL.str_04, 0);
let imgs = fn.gae("figure img");
let loadeds = fn.gae("figure img[srcset*='w, ']");
if (imgs.length > 0) {
fn.showMsg("Waiting for loading " + loadeds.length + "/" + imgs.length, 0);
return imgs.at(-1)?.getAttribute("srcset")?.includes("w, ");
} else {
return false;
}
}, 6000).then(() => {
fn.hideMsg();
//return fn.getImgSrcArr("figure img[srcset]");
let srcs = JSON.parse(sessionStorage.getItem("hermioneStatPixels"));
srcs = srcs.filter(src => src.includes("/pub_"));
thumbnailSrcArray = [...new Set(srcs.map(src => src.replace(/\d+$/, "360")))];
return [...new Set(srcs.map(src => src.replace(/\w+$/, "orig")))];
}) : [];
},
capture: () => _this.imgs(),
customTitle: () => fn.delay(1000, 0).then(() => fn.dt({
d: /\|.+$/
})),
category: "nsfw2"
}, {
name: "NUDE_ART_EROTIC",
url: {
h: "nude-art-erotic.livejournal.com",
p: /^\/\d+\.html$/
},
imgs: ".entry-content img:not([src$='19736856'])",
customTitle: ".entry-title",
setFancybox: true,
category: "nsfw2"
}, {
name: "Развлекательно-эротический блог",
url: {
h: "tettie.net",
s: "p="
},
imgs: () => fn.getImgSrcArr(".postContent img").filter(e => !e.includes("-ads")),
customTitle: ".postTitle",
setFancybox: true,
category: "nsfw2"
}, {
name: "URLGalleries",
host: ["urlgalleries.net"],
url: {
h: "urlgalleries",
p: "/porn-gallery-"
},
imgs: () => fn.getEle([fn.url + "&a=10000"], "#wtf>a").then(aArr => {
thumbnailSrcArray = aArr.map(a => fn.src("img", a));
let links = aArr.map(a => a.href);
fn.showMsg(DL.str_05, 0);
let fetchNum = 0;
let imageHostLinks = links.map(url => fetch(url).then(res => res.text()).then(text => {
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${links.length}`, 0);
let dom = fn.doc(text);
let code = fn.gst("window.location.href", dom);
let [, link] = code.match(/window\.location\.href[\s\='"]+([^'";]+)/);
return link;
}));
return Promise.all(imageHostLinks).then(urls => fn.getImageHost(urls));
}),
button: [4],
insertImg: [
["#wtf", 2, "#wtf"], 3
],
customTitle: ".galleryhead>h3>a,.galleryhead h1",
hide: ".mobilehide",
category: "nsfw2"
}, {
name: "GirlsTop",
url: {
h: "girlstop.info",
p: "/psto",
s: "id="
},
imgs: "a[id^=pic]",
thums: "a[id^=pic] img",
customTitle: ".content-block h1,.gallery h1",
category: "nsfw2"
}, {
name: "wikiFeetX / wikiFeet",
host: ["wikifeet.com", "wikifeetx.com"],
url: {
h: "wikifeet",
st: "gallery"
},
init: () => fn.waitEle("#gallery a").then(() => (siteJson = _unsafeWindow.tdata)),
imgs: () => {
let src = fn.gu("#gallery a");
let dir = fn.dir(src);
thumbnailSrcArray = siteJson.gallery.map(e => "https://thumbs.wikifeet.com/" + e.pid + ".jpg").sort();
return siteJson.gallery.map(e => dir + e.pid + ".jpg").sort();
},
capture: () => _this.imgs(),
customTitle: () => siteJson.cname,
hide: "div:has(>iframe),div:has(>a>picture)",
category: "nsfw2"
}, {
name: "VK",
host: ["vk.com", "m.vk.com"],
url: {
h: "vk.com",
p: "/album"
},
getVK: (list, picNum) => {
fn.showMsg(DL.str_05, 0);
let max = Math.ceil(Number(picNum) / 10);
let fetchNum = 0;
let resArr = [];
for (let i = 0; i < Number(picNum); i += 10) {
let data = new URLSearchParams({
act: "show",
al: 1,
direction: 1,
list,
offset: i
}).toString();
let res = fn.xhr("https://vk.com/al_photos.php?act=show", {
headers: {
"content-type": "application/x-www-form-urlencoded",
"x-requested-with": "XMLHttpRequest"
},
data,
responseType: "json",
method: "POST"
}).then(json => {
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${max}`, 0);
return json.payload[1][3].map(e => e.w_src ?? e.z_src ?? e.y_src ?? e.x_src);
});
resArr.push(res);
};
return Promise.all(resArr).then(data => data.flat());
},
imgs: () => {
let list = fn.lp.split("/").at(-1);
let picNum;
if (fn.lh.startsWith("m.")) {
[picNum] = document.title.split("–").at(-1).replaceAll(",", "").match(/\d+/);
} else {
picNum = fn.gt(".ui_crumb_count").replaceAll(",", "");
}
return _this.getVK(list, picNum);
},
capture: () => _this.imgs(),
customTitle: ".photos_album_intro>h1,.AlbumPage__title",
category: "nsfw2"
}, {
name: "CyberDrop",
url: {
h: "cyberdrop.me",
p: "/a/"
},
box: ["#table", 2],
imgs: async () => {
let fileIds = fn.gau("a.image").map(u => u.split("/").at(-1));
fn.showMsg(DL.str_05, 0);
let fetchNum = 0;
let resArr = [];
for (let id of fileIds) {
let api = `https://api.cyberdrop.me/api/file/info/${id}`
let res = fetch(api, {
"headers": {
"accept": "application/json, text/plain, */*",
},
}).then(res => res.json()).then(json => {
let isV = /^video/.test(json.type);
let isI = /^image/.test(json.type);
let isO = json.type === "application/octet-stream";
if (isV || isI || isO) {
return fetch(json.auth_url, {
"headers": {
"accept": "application/json, text/plain, */*",
}
}).then(res => res.json()).then(obj => {
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${fileIds.length}`, 0);
if (isV) {
return {
v: obj.url
}
} else {
return {
i: obj.url
}
}
});
} else {
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${fileIds.length}`, 0);
return {
n: null
}
}
});
resArr.push(res);
}
return Promise.all(resArr).then(data => {
videoSrcArray = data.filter(obj => "v" in obj)?.map(e => e.v);
return data.filter(obj => "i" in obj)?.map(e => e.i);
});
},
button: [4],
insertImg: ["box", 3],
customTitle: "#title",
downloadVideo: true,
category: "nsfw2"
}, {
name: "FitNakedGirls",
url: {
h: ["fitnakedgirls.com"],
p: "/gallery/"
},
imgs: () => {
let srcs;
let [a, b] = [".wp-block-image img[data-src]", ".entry-content img"];
if (!!fn.ge(a)) {
srcs = fn.gae(a).map(e => e.dataset.src.replace(/-\d+x\d+(\.\w+)$/, "$1"));
} else {
srcs = fn.gae(b).map(e => e.dataset.src ?? e.src);
}
return srcs.filter(src => !src.includes("18xmob.png") && !src.includes("/18plus"));
},
button: [4],
insertImg: [".entry-content", 2],
customTitle: ".entry-title",
css: ".g1-column-2of3{width:100%!important}",
hide: "#secondary",
category: "nsfw2"
}, {
name: "R18hub",
link: "https://r18hub.com/photos",
url: {
h: ["r18hub.com"],
p: "/photo/"
},
imgs: () => {
let eles = fn.gae("#photos>li");
thumbnailSrcArray = eles.map(e => e.dataset.thumb);
return eles.map(e => e.dataset.src);
},
button: [4],
insertImg: ["#photos", 2],
customTitle: () => fn.title(" - R18hub"),
category: "nsfw2"
}, {
name: "ZzUp.Com",
host: ["www.zzup.com", "zzup.com", "w.zzup.com"],
link: "https://zzup.com/user-album/3338/petmer/index.html",
url: {
h: "zzup.com",
p: "/content/"
},
init: () => fn.remove("//iframe|//div[div[center[script[contains(text(),'juicy')]]]][@class='container']|//font[b[contains(text(),'ads')]]"),
box: ["//div[div[div[@class='picbox']]] | //div[@id='content'][div[@class='picbox']]", 2],
imgs: async () => {
let max = Number(fn.gt(".imgpagebar h2")?.match(/\d+/g)?.at(-1)) || 1;
let links;
if (max > 1) {
let url = fn.dir(fn.lp);
let pages = fn.arr(max, (v, i) => url + "page-" + (i + 1) + ".html");
let picboxSelector;
if (fn.ge("//div[@id='content'][div[@class='picbox']]")) {
picboxSelector = "#content>.picbox";
} else {
picboxSelector = "//div[div[@class='picbox']]"
}
return fn.getEle(pages, picboxSelector).then(picboxs => {
let te = fn.ge("//div[@class='row'][div[div[@class='picbox']]] | //div[@id='content'][div[@class='picbox']]");
te.innerHTML = "";
te.append(...picboxs);
thumbnailSrcArray = picboxs.map(b => fn.src("img", b));
links = picboxs.map(b => fn.ge("a", b).href);
return fn.getImgA("//main//a[img]", links, 100);
});
}
thumbnailSrcArray = fn.getImgSrcArr(".picbox img");
links = fn.gau(".picbox>a");
return fn.getImgA("//main//a[img]", links, 100);
},
button: [4],
insertImg: [
["box", 0, "//div[div[div[@class='picbox']]] | //div[@id='content'][div[@class='picbox']] | //div[@class='container text-center']"], 2
],
customTitle: () => fn.dt({
d: " - ZzUp.Com"
}),
category: "nsfw2"
}, {
name: "ZzUp.Com 分類自動翻頁",
reg: /^https?:\/\/(www\.)?zzup\.com\//,
ad: () => fn.remove("iframe[src*='ad']") && fn.remove("//div[div[@class='picbox'][center[a[b[text()='Zzup Ads']]]]]"),
init: () => _this.ad(),
autoPager: {
ele: "//div[div[@class='picbox'][not(script)]]",
observer: "//div[div[@class='picbox']]",
next: "//a[h3[span[@class='glyphicon glyphicon-arrow-right']]]",
re: "//div[div[@class='imgpagebar']]",
pageNum: () => nextLink.match(/page-(\d+)/)[1],
aF: () => _this.ad()
},
category: "autoPager"
}, {
name: "ZzUp.Com 分類自動翻頁",
reg: /^https?:\/\/w\.zzup\.com\//,
init: () => {
if (fn.gae(".imgpagebar").length > 1) {
fn.ge("main:has(.imgpagebar)")?.remove();
}
fn.remove("iframe[src*='ad']");
},
autoPager: {
mode: 1,
ele: "#content,#content2",
observer: ".picbox",
next: "//a[h3[span[@class='glyphicon glyphicon-arrow-right']]]",
re: "//div[div[@class='imgpagebar']]",
pageNum: () => nextLink.match(/page-(\d+)/)[1]
},
css: ".autoPagerTitle{width:99%!important}",
category: "autoPager"
}, {
name: "FreeXcafe",
host: ["www.freexcafe.com"],
reg: /^https?:\/\/www\.freexcafe\.com\/erotica\/[\w-]+\/[\w-]+\/index\.php/,
box: ["#content>*:last-child", 2],
imgs: () => fn.getImgA("#imagelink>img,#bigphoto>img", ".thumbs>a", 500),
thums: ".thumbs>a>img",
button: [4],
insertImg: [
["box", 2, ".thumbs"], 2
],
category: "nsfw2"
}, {
url: {
name: "TUPIC.TOP",
h: "tupic.top",
p: ".html",
e: "#post_content h1"
},
box: ["#metadata_qrcode", 2],
imgs: ".gallery_img",
button: [4],
insertImg: [
["box", 0, ".spotlight-group,#touch_to_see"], 2
],
customTitle: () => fn.ge("#post_content h1").textContent.replaceAll("\n", "").trim(),
category: "nsfw2"
}, {
name: "EPORNER Photo",
host: ["www.eporner.com"],
url: {
h: ".eporner.com",
p: "/gallery/"
},
box: [".photosgrid", 2],
imgs: () => {
thumbnailSrcArray = fn.gae("#container img").map(e => e.src);
return thumbnailSrcArray.map(e => e.replace("_296x1000", ""));
},
button: [4],
insertImg: [
["box", 2, ".photosgrid"], 2
],
endColor: "white",
customTitle: "#galleryheader>h1",
category: "nsfw2"
}, {
name: "EPORNER Albums",
url: {
h: "www.eporner.video",
p: "/album/"
},
box: [".album-info", 1],
imgs: ".images a",
thums: ".images a img",
button: [4],
insertImg: ["box", 2],
endColor: "white",
customTitle: ".content h1",
hide: ".link-sponsor",
category: "nsfw2"
}, {
name: "KISSJAV",
url: {
h: "kissjav.com",
p: "/album/"
},
imgs: ".images a",
thums: ".images img",
button: [4],
insertImg: [".images", 2],
customTitle: "h1.title",
category: "nsfw2"
}, {
name: "X1HUB",
url: {
h: "x1hub.com",
p: "/albums/",
e: ".album-info"
},
imgs: ".images a",
thums: ".images img",
button: [4],
insertImg: [".images", 2],
customTitle: "h1",
category: "nsfw2"
}, {
name: "Xasiat",
host: ["www.xasiat.com", "areegator.net", "snapmoms.com"],
link: "https://www.xasiat.com/albums/",
url: {
h: [
/^www\.xasiat\.com$/,
/^(www\.)?areegator\.net$/,
/^(www\.)?snapmoms\.com$/
],
p: /^\/([\w]{2}\/)?albums\/\d+\/[\w-]+\/$/
},
init: () => {
fn.gae("img.thumb[data-original]").forEach(img => (img.src = img.dataset.original));
fn.remove(".sponsor,.footer-margin");
},
box: [".images", 2],
imgs: ".images>a",
thums: ".images>a>img[data-original]",
button: [4],
insertImg: [
["box", 0, ".images"], 2
],
endColor: "white",
customTitle: ".headline>h1",
css: ".block-album{display:block !important}",
hide: ".block-album>.table,.top,.footer~*:not([id^='Full'],[class^='Full'],[id^='pv-'],[class^='pv-'],#comicRead,#fab,*[class^=fancybox])",
category: "nsfw2"
}, {
name: "Xasiat 自動翻頁",
url: {
h: [
/^www\.xasiat\.com$/,
/^(www\.)?areegator\.net$/,
/^(www\.)?snapmoms\.com$/
],
p: /^\/([\w]{2}\/)?albums\/(\d+\/)?/
},
init: () => {
setInterval(() => {
fn.remove("//div[iframe] | //iframe");
if (document.body.getAttribute("class").length > 13) document.body.setAttribute("class", "big-container");
}, 500);
fn.remove(".footer~*", 2000);
},
autoPager: {
ele: "#list_albums_common_albums_list_items",
observer: "#list_albums_common_albums_list_items>.item",
next: () => {
let [num] = fn.attr(".load-more>a", "data-parameters")?.match(/\d+$/);
let [p] = fn.lp.match(/^\/([\w]{2}\/)?albums\//);
return num ? `${p}${num}/` : null;
},
re: ".load-more>a",
pageNum: () => nextLink.match(/\d+/)[0],
lazySrc: "img[data-original]"
},
openInNewTab: "#list_albums_common_albums_list_items a:not([target=_blank])",
hide: ".footer~*",
category: "autoPager"
}, {
name: "Erotic Pics",
url: {
h: ["erotic.pics"],
p: /^\/[^\/]+\/$/
},
imgs: ".entry-content img",
button: [4],
insertImg: [".entry-content", 2],
customTitle: () => fn.dt({
s: ".entry-title",
d: /\s–\s\d+\spics/
}),
category: "nsfw2"
}, {
name: "Erotic Pics 分類自動翻頁",
reg: /^https?:\/\/erotic\.pics\//,
autoPager: {
ele: "#masonry",
observer: "#masonry>article",
next: "span.current+a",
re: ".wp-pagenavi",
pageNum: "span.current"
},
openInNewTab: "a.entry-thumbnail:not([target=_blank])",
category: "autoPager"
}, {
name: "xHamster gallery",
host: ["xhamster.com"],
link: "https://zh.xhamster.com/users/eros721_official/photos",
url: {
h: "xhamster.com",
p: /^\/photos\/gallery\/[^/]+$/,
e: "div[class*=photosList]",
d: "pc"
},
imgs: async () => {
await fn.getNP("#initials-script", "//div[@class='prev-next-list']//li[a[contains(@class,'active')]]/following-sibling::li[1]/a", null, "nav:has(>.prev-next-list)");
let photos = fn.gae("#initials-script").map(script => {
let json = JSON.parse(script.innerText.replace(/window.initials=|;/g, ""));
return json.photosGalleryModel.photos;
}).flat();
thumbnailSrcArray = photos.map(e => e.thumbURL);
return photos.map(e => e.imageURL);
},
button: [4],
insertImg: [
["main>article", 2, "main>article,nav:has(>.prev-next-list),div:has(>.start-slideshow)"], 2
],
customTitle: "div[data-role='gallery-page'] h1",
category: "nsfw2"
}, {
name: "xHamsterM gallery M",
url: {
h: "xhamster.com",
p: /^\/photos\/gallery\/[^/]+$/,
e: "div[class*=photosList]",
d: "m"
},
imgs: async () => {
await fn.getNP("#initials-script", ".prev-next-list a[rel=next]", null, "nav:has(>.prev-next-list)");
let photos = fn.gae("#initials-script").map(script => {
let json = JSON.parse(script.innerText.replace(/window.initials=|;/g, ""));
return json.galleryPage.photoItems;
}).flat();
thumbnailSrcArray = photos.map(e => e.imgSrcset);
return photos.map(e => e.imgSrc);
},
button: [4],
insertImg: [
["main>article", 2, "main>article,nav:has(>.prev-next-list),div:has(>.start-slideshow)"], 2, 1000
],
customTitle: "div[data-role='gallery-page'] h1",
category: "nsfw2"
}, {
name: "PornHub photo", //很容易會被短暫封IP
host: ["pornhub.com"],
link: "https://pornhub.com/albums",
url: {
h: "pornhub.com",
p: /^\/album\/\d+$/
},
imgs: () => fn.getImgA("#photoImageSection img", ".js_lazy_bkg a", 200),
button: [4],
insertImg: [
[".photoBlockBox .clear", 1], 1
],
customTitle: ".photoAlbumTitleV2",
category: "nsfw2"
}, {
name: "BITCHES GIRLS/FAPSLY LIVE",
url: {
h: ["bitchesgirls.com", "fapsly.live", "fapsly.net"],
st: "pagesAmount",
d: "pc"
},
imgs: () => {
fn.showMsg(DL.str_05, 0);
const getUrls = (dom = document, pageUrl = siteUrl) => {
let images = [];
let thums = [];
let videos = [];
let code = fn.gst("thumbnailUrl", dom);
let json = JSON.parse(code.replace(/\n/g, "").replace(/\s+/g, " "));
let {
image,
video
} = json;
image = image?.filter(e => e["@type"] === "ImageObject");
video = video?.filter(e => e["@type"] === "VideoObject");
if (video.length > 0) {
videos = video.map(e => e.url);
} else {
videos = fn.gae(".albumgrid img[type=video]").map(e => e.getAttribute("original"));
}
if (image.length > 0) {
thums = image.map(e => e.thumbnailUrl);
images = image.map(e => e.url);
thums = thums.filter(e => !e.includes("/logos/"));
images = images.filter(e => !e.includes("/logos/"));
} else {
thums = fn.gae(".albumgrid img[type=image]", dom).map(e => e.src);
images = fn.gae(".albumgrid img[type=image]", dom).map(e => e.getAttribute("original"));
}
return {
images,
thums,
videos
}
}
const max = _unsafeWindow.adConstants.pagesAmount;
if (max > 1) {
fn.showMsg(DL.str_05, 0);
let fetchNum = 0;
let resArr = fn.arr(max, (v, i) => {
let url = i == 0 ? siteUrl : siteUrl + `${i + 1}/`;
return fn.fetchDoc(url).then(dom => {
fn.showMsg(`${DL.str_06}${fetchNum += 1}/${max}`, 0);
return getUrls(dom, url);
});
});
return Promise.all(resArr).then(data => {
thumbnailSrcArray = data.map(e => e.thums).flat();
videoSrcArray = data.map(e => e.videos).flat();
return data.map(e => e.images).flat();
});
} else {
let obj = getUrls();
thumbnailSrcArray = obj.thums;
videoSrcArray = obj.videos;
return obj.images;
}
},
button: [4],
insertImg: [
[".button-container", 2, ".albumgrid,.popup-container"], 2
],
hide: "a#loadMore,.my-girls-popup-element",
category: "nsfw2"
}, {
name: "X-video",
url: {
h: ["x-video.tube"],
p: "/albums/"
},
box: [".album-view", 2],
imgs: () => {
fn.showMsg(DL.str_05, 0);
let total = Number(fn.gt(".media-data__list-value"));
let max;
if (total > 12) {
max = Math.ceil(total / 100) + 1;
} else {
max = 1;
}
let fetchNum = 0;
let resArr = fn.arr(max, (v, i) => {
let url = i == 0 ? "?mode=async&function=get_block&block_id=album_view_album_view" : "?mode=async&function=get_block&block_id=album_view_album_view&load=more&from=" + i;
return fn.fetchDoc(url, {
"headers": {
"accept": "text/html, */*; q=0.01",
"x-requested-with": "XMLHttpRequest"
}
}).then(dom => {
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${max}`, 0);
return {
thumbs: fn.getImgSrcArr("a.grid-item img", dom),
originals: fn.gae("a.grid-item", dom)
}
});
});
return Promise.all(resArr).then(data => {
thumbnailSrcArray = data.map(e => e.thumbs).flat();
return data.map(e => e.originals).flat();
});
},
button: [4],
insertImg: [
["box", 0, ".album-view"], 2
],
customTitle: ".title",
category: "nsfw2"
}, {
name: "EroThots",
host: ["erothots.co", "erothots1.com"],
url: {
t: "EroThots",
p: ["/album/", "/a/"]
},
box: [".album-gallery", 2],
imgs: () => {
videoSrcArray = fn.gae(".album-gallery a.item-album-gallery.has-video").map(e => e.dataset.src);
return fn.gae(".album-gallery a.item-album-gallery:not(.has-video)");
},
thums: ".album-gallery a.item-album-gallery:not(.has-video) img",
button: [4],
insertImg: ["box", 2],
customTitle: ".head-title",
downloadVideo: true,
referer: "",
category: "nsfw2"
}, {
name: "jimpicotphotography.com",
url: {
h: "jimpicotphotography.com"
},
imgs: ".con>img,#post-navigation img",
customTitle: () => fn.dt({
d: " - jimpicotphotography.com"
}),
category: "nsfw2"
}, {
name: "EroMe",
host: ["www.erome.com"],
url: {
h: "erome.com",
p: "/a/",
e: "div[id^='album'].page-content"
},
imgs: () => {
videoSrcArray = fn.gae(".video source[type='video/mp4']").map(e => e.src);
return isM ? fn.gae(".img>img[data-src]") : fn.gae("div.img[data-src]");
},
button: [4],
insertImg: ["div[id^='album'].page-content", 2],
customTitle: ".page-content h1",
category: "nsfw2"
}, {
name: "EroMe",
url: {
h: "erome.fan",
p: "/a/",
e: ".entry-content"
},
imgs: () => {
videoSrcArray = fn.gae(".video source[type='video/mp4']").map(e => e.src);
return isM ? fn.gae(".img>img[data-src]").map(e => e.currentSrc) : fn.gae("div.img[data-src]");
},
button: [4],
insertImg: [".entry-content", 2],
customTitle: ".entry-title",
category: "nsfw2"
}, {
url: {
h: ["sarlatimmobilier.com", "studiobangchau.com", "monsterbusterclub.tv", "ecopak.cz"]
},
imgs: "#gallery .img-blur a",
button: [4],
insertImg: ["#gallery", 2],
customTitle: "#page h1:not(:has(i))",
fancybox: {
v: 3,
css: false
},
category: "nsfw2"
}, {
name: "luxurybeachresorts.net",
host: ["www.luxurybeachresorts.net"],
url: {
h: [/luxurybeachresorts\.net$/, "artlantic.design"],
e: "#gallery .media-group",
d: "pc"
},
box: [".media-group", 1],
imgs: () => {
videoSrcArray = fn.gae(".video source[type='video/mp4']").map(e => e.src);
thumbnailSrcArray = fn.getImgSrcArr(".media-group div.img[data-src]");
return thumbnailSrcArray.map(src => src.replace(/(\?)([^&]+&)/, "$1"));
},
button: [4],
insertImg: [
["box", 0, ".media-group"], 2
],
customTitle: "#page #page h1",
category: "nsfw2"
}, {
name: "Pornotaran.com photo",
url: {
h: "pornotaran.com",
p: ".html",
e: ".inner-page__desc div:has(img[data-src])"
},
imgs: () => fn.getImgSrcArr(".inner-page__desc img[data-src]").map(e => e.replace("/thumbs", "")),
button: [4],
insertImg: [".inner-page__desc div:has(img[data-src])", 2],
customTitle: ".inner-page__title",
category: "nsfw2"
}, {
name: "Babepedia",
url: {
h: "www.babepedia.com",
p: ["/gallery/", "/babe/"]
},
imgs: "#gallery a[data-fancybox],.gallery a[rel=gallery]",
thums: "#gallery a[data-fancybox] img,.gallery a[rel=gallery] img",
autoDownload: [0],
next: ".gallerynavigation a:has(>img[alt*=older])",
prev: ".gallerynavigation a:has(>img[alt*=newer])",
customTitle: "#gallery h1,#babename",
category: "nsfw2"
}, {
name: "Hot Celebs Home",
url: {
h: "www.hotcelebshome.com",
e: ".tiled-gallery__gallery img"
},
imgs: () => fn.getImgSrcArr(".tiled-gallery__gallery img").map(e => e.replace(/(-\d+x\d+)(.\w+)/i, "$2")),
capture: () => _this.imgs(),
customTitle: "h1.entry-title",
category: "nsfw2"
}, {
name: "PicHunter",
url: {
h: "www.pichunter.com",
p: "/gallery/"
},
imgs: () => {
if (fn.ge(".flex-images figure>a>img")) {
thumbnailSrcArray = fn.gae(".flex-images figure>a>img").map(e => e.getAttribute("xs"));
} else {
thumbnailSrcArray = fn.gae("#main-grid a img").map(e => e.src);
}
return fn.gae(".flex-images figure>a,#main-grid a");
},
button: [4],
insertImg: [
[".flex-images,#main-grid", 2], 1
],
customTitle: "h1",
fancybox: {
v: 3,
css: false
},
category: "nsfw2"
}, {
name: "Pictoa",
url: {
h: "www.pictoa.com",
p: ["/thumbs/", "/albums/"],
e: "#player img"
},
imgs: () => fn.getImgA("#player img", fn.gau(".thumb-nav-img a")),
thums: ".thumb-nav-img img",
button: [4],
insertImg: ["#player", 2],
customTitle: ".title>h1",
css: "#gallery #player{cursor:unset!important}",
hide: ".ad-placement",
category: "nsfw2"
}, {
name: "PimpAndHost",
host: ["pimpandhost.com"],
link: "https://pimpandhost.com/site/trending",
reg: /^https?:\/\/pimpandhost\.com\/(image|album)\/\d+/,
init: () => {
if (/image/.test(location.href)) location.href = fn.ge("a[title=Album]").href;
fn.remove(".flex-block-1,.flex-block-2,#comments,.ano_po");
},
imgs: async () => {
await fn.getNP("#album-images>.image-block", "li.active+li:not(.next)>a", null, ".pagination");
return fn.gae("#album-images .image-block a[data-src]");
},
button: [4],
insertImg: [
[".summary", 2], 2
],
customTitle: ".author-header__album-name",
category: "nsfw2"
}, {
name: "PimpAndHost 隱藏廣告",
reg: /^https?:\/\/pimpandhost\.com\//,
init: () => fn.remove(".flex-block-1,.flex-block-2,#comments,.ano_po"),
hide: ".list-view:not(#main-list-view) .item:not(.image-block)",
category: "ad"
}, {
name: "Pornpaw 圖片清單頁",
url: {
h: "www.pornpaw.com",
p: "/gallery/"
},
box: [".row .row:has(.frame)", 2],
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr("img[data-src],img.img");
return thumbnailSrcArray.map(e => e.replace("x160.", "."));
},
button: [4],
insertImg: [
["box", 0, ".row .row:has(.frame)"], 2
],
customTitle: "h1",
hide: "div:has(>ins)",
category: "nsfw2"
}, {
name: "ImageFap 圖片清單頁",
url: {
h: "www.imagefap.com",
p: ["/gallery/", "/pictures/"],
e: "#gallery table a"
},
box: ["#gallery", 2],
imgs: async () => {
let temps = [];
let originals = [];
let thumbs = [];
let gid;
let gid_url = fn.gu("a[href*='&gid']");
if (gid_url) {
gid = fn.getUSP("gid", gid_url);
} else {
[, , gid] = fn.lp.split("/");
if (!Number(gid)) return [];
}
let loop = true;
let pn = 0;
fn.showMsg(DL.str_05, 0);
const get = () => {
return fn.fetchDoc(`/ajax/actions.php?gid=${gid}&page=${pn}&action=getGallery`).then(dom => {
fn.showMsg(`${DL.str_05} (Page${pn + 1})`, 0);
if (!fn.ge("#hgallery", dom)) {
loop = false;
return;
}
for (let img of [...dom.images]) {
let noParams = new URL(img.dataset.full).pathname;
if (temps.includes(noParams)) {
loop = false;
return;
} else {
temps.push(noParams);
originals.push(img.dataset.full);
thumbs.push(img.dataset.original);
}
}
});
};
while (loop) {
await get();
pn++;
}
thumbnailSrcArray = thumbs;
return originals;
},
button: [4],
insertImg: ["box", 2],
customTitle: () => {
if (fn.ge("#menubar font,h1 b")) {
return fn.gt("#menubar font,h1 b");
} else {
return document.title;
}
},
category: "nsfw2"
}, {
name: "ImageFap",
url: {
h: "www.imagefap.com",
p: "/photo/",
d: "pc"
},
init: () => {
fn.remove("//td[div[@id='main']]/following-sibling::td[1] | //div[iframe]");
fn.ge("#main").removeAttribute("style");
fn.ge("//table[@width='750']").width = "1000";
},
imgs: async () => {
/*
let max = Number(fn.attr("div[data-total]", "data-total"));
let pages = Math.ceil(max / 24);
let pid = fn.ge("#imageid_input").value;
let gid = fn.ge("#galleryid_input").value;
let resArr = [];
let fetchNum = 0;
fn.showMsg(DL.str_05, 0);
for (let i = 0; i < max; i += 24) {
let url = `/photo/${pid}/?gid=${gid}&idx=${i}&partial=true`;
let res = await fn.fetchDoc(url).then(dom => {
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${pages}`, 0);
if (!fn.ge(".thumbs a", dom)) {
alert("Encountered human-machine verification");
window.location.href = siteUrl;
}
return fn.gae(".thumbs a", dom).map(a => {
let original = a.href;
let thumb = fn.attr("img", "src", a);
return {
original,
thumb
}
});
});
resArr.push(res);
await delay(1000);
}
return Promise.all(resArr).then(data => data.flat()).then(arr => {
let thumbs = arr.map(e => e.thumb);
thumbnailSrcArray = thumbs;
let originals = arr.map(e => e.original);
return originals;
});
*/
let temps = [];
let originals = [];
let thumbs = [];
let gid = fn.ge("#galleryid_input").value;
let loop = true;
let pn = 0;
fn.showMsg(DL.str_05, 0);
const get = () => {
return fn.fetchDoc(`/ajax/actions.php?gid=${gid}&page=${pn}&action=getGallery`).then(dom => {
fn.showMsg(`${DL.str_05} (Page${pn + 1})`, 0);
if (!fn.ge("#hgallery", dom)) {
loop = false;
return;
}
for (let img of [...dom.images]) {
let noParams = new URL(img.dataset.full).pathname;
if (temps.includes(noParams)) {
loop = false;
return;
} else {
temps.push(noParams);
originals.push(img.dataset.full);
thumbs.push(img.dataset.original);
}
}
});
};
while (loop) {
await get();
pn++;
}
thumbnailSrcArray = thumbs;
return originals;
},
button: [4],
insertImg: ["//td[div[@id='slideshow']]", 2],
customTitle: "#main h1",
category: "nsfw2"
}, {
name: "ImageFapM",
url: {
h: "beta.imagefap.com",
p: ["/gallery/", "/pictures/"],
d: "m"
},
imgs: async () => {
let gid = fn.ge("#gid").value;
let max = Number(fn.gt(".newNav b")?.match(/\d+/g)?.at(-1)) || 1;
let pages = [`/ajax/actions.php?gid=${gid}&page=0&action=getGallery`];
if (max > 1) {
pages = fn.arr(max, (v, i) => `/ajax/actions.php?gid=${gid}&page=${i}&action=getGallery`);
}
let resArr = [];
let fetchNum = 0;
fn.showMsg(DL.str_05, 0);
for (let url of pages) {
let res = await fn.fetchDoc(url).then(dom => {
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${max}`, 0);
return [...dom.images].map(img => {
let original = img.dataset.full;
let thumb = img.dataset.original;
return {
original,
thumb
}
});
});
resArr.push(res);
//await delay(1000);
}
return Promise.all(resArr).then(data => data.flat()).then(arr => {
let thumbs = arr.map(e => e.thumb);
thumbnailSrcArray = thumbs;
let originals = arr.map(e => e.original);
return originals;
});
},
button: [4],
insertImg: ["#gallery", 2],
customTitle: ".nMobHeader>h1,.userPageInfoGal strong",
hide: ".ad_placeholder",
category: "nsfw2"
}, {
name: "Fuskator 圖片清單頁",
host: ["fuskator.com"],
reg: /^https?:\/\/fuskator\.com\/thumbs\/[\w-~]+\/[\w-~]+\.html$/i,
init: () => fn.showMsg(DL.str_04, 0).then(() => fn.waitEle(".pic_pad").then(() => fn.hideMsg())),
imgs: "#thumbimages a,.swipebox a",
thums: "#thumbimages a>img,.swipebox a>img",
button: [4],
insertImg: [
["//a[text()='View full images']", 2], 2
],
category: "nsfw2"
}, {
name: "Fuskator 大圖頁",
host: ["fuskator.com"],
reg: /^https?:\/\/fuskator\.com\//i,
include: "//a[text()='View gallery thumbnails']",
imgs: "img.full",
button: [4],
insertImg: ["#fullimages", 2, 1000],
category: "nsfw2"
}, {
name: "TOKYO Motion",
host: ["www.tokyomotion.net"],
link: "https://www.tokyomotion.net/albums",
reg: /^https?:\/\/www\.tokyomotion\.net\/album\/\d+\/.+/,
imgs: async () => {
await fn.getNP("div[id^=album_photo]", ".pagination li.active+li>a", null, ".pagination");
thumbnailSrcArray = fn.gae(".thumb-overlay img").map(e => e.src);
return thumbnailSrcArray.map(e => e.replace("tmb/", ""));
},
button: [4],
insertImg: [
["//div[div[div[contains(@id,'album_photo')]]]", 0], 2
],
customTitle: () => fn.gae(".pull-left")[2].innerText.trim(),
category: "nsfw2"
}, {
name: "JavBangers",
url: {
h: "javbangers.com",
p: "/albums/",
e: ".album-info"
},
imgs: () => fn.gau(".images a"),
thums: ".images img",
button: [4],
insertImg: [
[".album-info", 2, ".images"], 2
],
customTitle: ".headline>h1",
category: "nsfw2"
}, {
name: "multi.xnxx.com",
url: {
h: ["multi.xnxx.com"],
p: "/gallery/"
},
imgs: ".galleryPage .boxImg",
button: [4],
insertImg: [
[".originalLink", 2], 1
],
category: "nsfw2"
}, {
name: "色情圖片網",
url: {
h: "www.photos18.com",
p: "/v/"
},
imgs: ".imgHolder a[data-fancybox]",
button: [4],
insertImg: ["#content", 2],
customTitle: "h1.title",
fancybox: {
v: 3,
css: false
},
hide: ".no-gutters",
category: "nsfw2"
}, {
name: "趣事館",
link: "https://17sex.vip/list/4858",
url: {
h: ["17sex.vip"],
p: "/pic/"
},
imgs: () => {
let max = fn.gt(".count-pageindex") || 1;
return fn.getImg(".page>img", max, "4");
},
button: [4],
insertImg: [
[".page", 0], 2
],
customTitle: "h3",
hide: ".topzanpage",
category: "nsfw2"
}, {
name: "久久热/GavPorn",
url: {
h: ["www.99re.com", "cav103.com"],
p: "/albums/"
},
imgs: "a[data-fancybox-type]",
button: [4],
insertImg: [".sponsor,.images", 2],
customTitle: ".headline>h1",
hide: ".top",
category: "nsfw2"
}, {
name: "Hentai Image",
host: ["hentai-img-xxx.com", "hentai-cosplay-xxx.com", "porn-image.com"],
url: {
h: [/hentai-img-xxx\.com$/, /hentai-cosplay-xxx\.com$/, /porn-image\.com$/],
p: "/image/",
e: ["#display_image_detail,#detail_list", "#title>h2,#page h3"]
},
imgs: () => {
let [, , url] = fn.lp.split("/");
url = `/story/${url}/`;
return fn.getImgA("amp-img", [url]).then(srcs => {
thumbnailSrcArray = srcs.map(src => {
let f = src.split("/").at(-1);
let dir = fn.dir(src);
return dir + "p=160x200/" + f;
});
return srcs;
});
},
button: [4],
insertImg: ["#display_image_detail,#detail_list", 2],
insertImgAF: () => fn.remove("#paginator:has(a[href*='/page/']),.paginator_area:has(.paginator_page)"),
autoDownload: [0],
next: () => {
let next = fn.ge("//a[text()='Prev Article' or text()='前の記事' or text()='前一篇']");
return next ? next.href : null;
},
prev: "//a[text()='Next Article' or text()='次の記事' or text()='下一篇文章']",
customTitle: () => fn.dt({
s: "#title>h2,#page h3",
d: /\s?Photo\s?\d+P|\s?-\s?\d+\/\d+\s?|\([0-9\s]+ảnh\)/i
}),
css: "#display_image_detail img{max-width:100% !important}",
category: "nsfw2"
}, {
name: "Fapator 圖片清單頁",
host: ["www.fapator.com"],
reg: /^https?:\/\/www\.fapator\.com\/\?content_id=/i,
init: () => fn.remove("//div[@class='img' and a[@target and img]]"),
imgs: "a[data-lightbox]",
thums: "a[data-lightbox]>img",
button: [4],
insertImg: [".fcon+.fapad", 1],
next: "//a[contains(text(),'next photos')]",
prev: 1,
css: ".fapad{width:auto !important;height:auto !important}",
category: "nsfw2"
}, {
name: "SMUTPOND",
url: {
h: "www.smutpond.com",
p: ["/gallery-thumbs/", "/gallery-pics/"],
s: "uid="
},
imgs: () => {
fn.showMsg(DL.str_05, 0);
let cdn = "https://cdn.smutpond.com/";
let id = fn.getUSP("uid");
return fetch(`https://api.smutpond.com/content/cm/${id}/?media_type=photo_gallery`).then(res => res.json()).then(json => {
thumbnailSrcArray = json.media_data.thumbs.map(e => cdn + e);
customTitle = json.title;
return json.media_data.images.map(e => cdn + e);
});
},
capture: () => _this.imgs(),
fancybox: {
v: 3,
css: false
},
category: "nsfw2"
}, {
url: {
h: "getababy.net",
},
box: [".entry-content a[data-caption]", 1],
imgs: ".entry-content a[data-caption]",
button: [4],
insertImg: [
["box", 0, ".entry-content a[data-caption]"], 2
],
customTitle: "h1.entry-title",
category: "nsfw2"
}, {
name: "Hoastie",
url: {
h: "hoastie.com",
p: "/a/",
e: "h1.entry-title"
},
imgs: () => {
let s = ".entry-content img";
let v = ".entry-content video>source";
if (fn.ge(v)) {
videoSrcArray = fn.gae(v).map(e => e.src);
s = ".entry-featured-media img,.entry-content img";
}
let imgs = fn.gae(s).filter(e => !e.closest("aside,.g1-teaser"));
return fn.getImgSrcset(imgs);
},
button: [4],
insertImg: [".entry-content", 2],
autoDownload: [0],
next: "a.g1-teaser-prev",
prev: "a.g1-teaser-next",
customTitle: () => fn.ge("h1.entry-title").textContent,
downloadVideo: true,
category: "nsfw2"
}, {
name: "DirtyShip.com",
url: {
h: ["dirtyship.com"],
p: "/gallery/"
},
srcset: ".gallery_grid img,.gallery_grid~img",
thums: ".gallery_grid img,.gallery_grid~img",
button: [4],
insertImg: [
[".gallery_grid", 0, ".gallery_grid img:not(.FullPictureLoadImage),.gallery_grid~img"], 2
],
customTitle: () => fn.title(" - DirtyShip.com"),
category: "nsfw2"
}, {
name: "ᑕ❶ᑐ Onlyfans +18",
host: ["www.tiktaks.de"],
reg: /^https?:\/\/www\.tiktaks\.de\/onlyfans\/[^\/]+\/$/,
imgs: "figure.wp-block-image>img",
button: [4],
insertImg: [".entry-content", 2],
customTitle: ".title",
category: "nsfw2"
}, {
name: "SexyGirlsPics",
url: {
h: ["sexygirlspics.com"],
p: "/pics/"
},
imgs: "a.ss-image",
thums: "a.ss-image>img",
button: [4],
insertImg: [
[".sponsor-button", 2], 1
],
category: "nsfw2"
}, {
name: "PornPic",
url: {
h: ["www.pornpic.com", "pornpic.com"],
p: "/gallery/"
},
imgs: ".gallery-grid a.item-link[data-fancybox]",
thums: ".gallery-grid a.item-link[data-fancybox] img",
button: [4],
insertImg: [
[".gallery-info", 2], 1
],
fancybox: {
v: 3,
css: false
},
category: "nsfw2"
}, {
name: "Girlsreleased",
url: {
h: "girlsreleased.com",
p: "/set/"
},
init: () => fn.waitEle("a[target=imageView] img[img-id]").then(() => fn.createImgBox(".images", 2)),
imgs: async () => {
let selector = "a[target=imageView] img[img-id]";
let f_img = await fn.waitEle(selector);
thumbnailSrcArray = fn.gae(selector).map(e => e.src);
let src = fn.attr(selector, "src");
let images = fn.gae(selector);
if (/imx\.to/.test(src)) {
let tempSrc = src.replace("https://imx.to/u/t/", "https://i.imx.to/i/");
return new Promise(async resolve => {
let obj = await fn.checkImgStatus(tempSrc);
if (obj.ok && obj.width > 200) {
resolve(images.map(e => e.src.replace("https://imx.to/u/t/", "https://i.imx.to/i/")));
} else {
resolve(images.map(e => e.src.replace("/t/", "/i/")));
}
});
} else if (/imgadult\.com/.test(src)) {
return images.map(e => e.src.replace("small-medium/", "big/"));
} else if (/pixhost\.to/.test(src)) {
return images.map(e => e.src.replace("https://t", "https://img").replace("/thumbs/", "/images/"));
} else if (/imagevenue/.test(src)) {
if (f_img?.parentElement?.href.endsWith("_o.jpg")) {
return fn.gae("a[target=imageView]");
}
return fn.getImgCorsA("#main-image", "a[target=imageView]");
} else {
return [];
}
},
button: [4],
insertImg: [
["box", 0], 2
],
referer: "src",
mcss: "#FullPictureLoadMainImgBox{width:100%;max-width:1400px;margin:0 auto}",
category: "nsfw2"
}, {
name: "Girlsreleased 載入更多",
reg: /^https?:\/\/girlsreleased\.com\/$/,
init: () => fn.waitEle("//button[text()='load more sets']"),
observerClick: "//button[text()='load more sets']",
openInNewTab: ".content .main a",
category: "autoPager"
}, {
name: "ViperGirls/PornCoven/ErotiCity",
link: "https://viper.to/threads/10623260-Coser-UmekoJ-NieR-2B",
url: {
h: ["vipergirls.to", "viper.to", "viperohilia.art", "vipervault.link", "viperbb.rocks", "viperkats.eu", "planetviper.club", "porncoven.com", "eroticity.net"],
p: "/threads/",
e: ".postdetails",
d: "pc"
},
init: () => {
document.addEventListener("click", event => {
if (event.target.className === "postdetails") {
tempEles = [];
if (event.target.querySelector("img[src*='imx.to/u/t/']")) {
tempEles = [...event.target.querySelectorAll("img[src*='imx.to/u/t/']")];
return fn.showMsg(`Capture ${tempEles.length} Links`);
}
let links = [];
if (event.target.querySelector("a[href$='.jpg']:not([href^='http://imagetwist.com/'])")) {
links = [...event.target.querySelectorAll("a[href$='.jpg']")].map(a => a.href);
} else {
links = [...event.target.querySelectorAll(`
a[href^='https://imgspice.com/'],
a[href*='pixhost.to'],
a[href^='http://imagetwist.com/'],
a[href*='postimg.cc'],
a[href*='fastpic.org'],
a[href*='vipr.im'],
a[href*='turboimagehost'],
a[href*='imgbox.com'],
a[href*='imagevenue'],
a[href*='imagebam']
`)].map(a => a.href);
}
captureLinksArray = links;
fn.showMsg(`Capture ${links.length} Links`);
debug("captureLinksArray", captureLinksArray);
}
});
},
imgs: () => {
if (tempEles.length) {
return fn.getImgSrcArr(tempEles).map(e => e.replace("/t/", "/i/"));
}
return fn.getImageHost();
},
repeat: 1,
category: "nsfw2"
}, {
name: "Kitty Kats Forum",
url: {
h: ["kitty-kats.net"],
p: "/threads/",
e: ".message-cell.message-cell--user",
d: "pc"
},
init: () => {
document.addEventListener("click", event => {
cancelDefault(event);
if (event.target.className === "message-cell message-cell--user") {
tempEles = [];
if (event.target.querySelector("img[src*='imx.to/u/t/']")) {
tempEles = [...event.target.querySelectorAll("img[src*='imx.to/u/t/']")];
return fn.showMsg(`Capture ${tempEles.length} Links`);
}
let links = [];
if (event.target.parentNode.querySelector("a[href$='.jpg']:not([href^='http://imagetwist.com/'])")) {
links = [...event.target.parentNode.querySelectorAll("a[href$='.jpg']")].map(a => a.href);
} else {
links = [...event.target.parentNode.querySelectorAll(`
a[href^='https://imgspice.com/'],
a[href*='pixhost.to'],
a[href^='http://imagetwist.com/'],
a[href*='postimg.cc'],
a[href*='fastpic.org'],
a[href*='vipr.im'],
a[href*='turboimagehost'],
a[href*='imgbox.com'],
a[href*='imagevenue'],
a[href*='imagebam']
`)].map(a => a.href);
}
captureLinksArray = links;
fn.showMsg(`Capture ${links.length} Links`);
debug("captureLinksArray", captureLinksArray);
}
});
},
imgs: () => {
if (tempEles.length) {
return fn.getImgSrcArr(tempEles).map(e => e.replace("/t/", "/i/"));
}
return fn.getImageHost();
},
repeat: 1,
category: "nsfw2"
}, {
name: "Teen Photos",
link: "https://teenphotos.forumes.ru/viewtopic.php?id=324",
url: {
h: ["teenphotos.forumes.ru"],
p: "viewtopic.php",
s: "id=",
e: ".container",
d: "pc"
},
init: () => {
document.addEventListener("click", event => {
cancelDefault(event);
tempEles = [];
if (event.target.querySelector("img[src*='imx.to/u/t/']")) {
tempEles = [...event.target.querySelectorAll("img[src*='imx.to/u/t/']")];
return fn.showMsg(`Capture ${tempEles.length} Links`);
}
if (event.target.className === "container") {
let links = [...event.target.querySelectorAll(`
a[href^='https://imgspice.com/'],
a[href*='pixhost.to'],
a[href^='http://imagetwist.com/'],
a[href*='postimg.cc'],
a[href*='fastpic.org'],
a[href*='vipr.im'],
a[href*='turboimagehost'],
a[href*='imgbox.com'],
a[href*='imagevenue'],
a[href*='imagebam']
`)].map(a => a.href);
captureLinksArray = links;
fn.showMsg(`Capture ${links.length} Links`);
debug("captureLinksArray", captureLinksArray);
}
});
},
imgs: () => {
if (tempEles.length) {
return fn.getImgSrcArr(tempEles).map(e => e.replace("/t/", "/i/"));
}
return fn.getImageHost();
},
repeat: 1,
category: "nsfw2"
}, {
name: "XONLY",
host: ["xonly8.com"],
link: "https://xonly8.com/index.php?topic=229069.0",
url: {
h: /xonly\d?\.com$/,
p: "index.php",
s: "topic=",
e: ".post_wrapper",
d: "pc"
},
init: () => {
document.addEventListener("click", event => {
cancelDefault(event);
if (event.target.className === "post_wrapper") {
tempEles = [];
if (event.target.querySelector("img[src*='imx.to/u/t/']")) {
tempEles = [...event.target.querySelectorAll("img[src*='imx.to/u/t/']")];
return fn.showMsg(`Capture ${tempEles.length} Links`);
}
let links = [...event.target.querySelectorAll(`
a[href^='https://imgspice.com/'],
a[href*='pixhost.to'],
a[href^='http://imagetwist.com/'],
a[href*='postimg.cc'],
a[href*='fastpic.org'],
a[href*='vipr.im'],
a[href*='turboimagehost'],
a[href*='imgbox.com'],
a[href*='imagevenue'],
a[href*='imagebam']
`)].map(a => a.href);
captureLinksArray = links;
fn.showMsg(`Capture ${links.length} Links`);
debug("captureLinksArray", captureLinksArray);
}
});
},
imgs: () => {
if (tempEles.length) {
return fn.getImgSrcArr(tempEles).map(e => e.replace("/t/", "/i/"));
}
return fn.getImageHost();
},
repeat: 1,
category: "nsfw2"
}, {
name: "Teen Models",
host: ["teen-models.forum"],
link: "https://teen-models.forum/thread-13449.html",
url: {
h: "teen-models.forum",
p: "/thread-",
e: ".post_author",
d: "pc"
},
init: () => {
document.addEventListener("click", event => {
cancelDefault(event);
if (event.target.className === "post_author") {
tempEles = [];
if (event.target.nextElementSibling.querySelector("img[src*='imx.to/u/t/']")) {
tempEles = [...event.target.nextElementSibling.querySelectorAll("img[src*='imx.to/u/t/']")];
return fn.showMsg(`Capture ${tempEles.length} Links`);
}
let links = [...event.target.nextElementSibling.querySelectorAll(`
a[href*='https://imgspice.com/'],
a[href*='pixhost.to'],
a[href^='http://imagetwist.com/'],
a[href*='postimg.cc'],
a[href*='fastpic.org'],
a[href*='vipr.im'],
a[href*='turboimagehost'],
a[href*='imgbox.com'],
a[href*='imagevenue'],
a[href*='imagebam']
`)].map(a => {
if (a.href.includes("linkanonymous")) {
return a.href.replace("https://linkanonymous.com/?", "");
}
return a.href;
});
captureLinksArray = links;
fn.showMsg(`Capture ${links.length} Links`);
debug("captureLinksArray", captureLinksArray);
}
});
},
imgs: () => {
if (tempEles.length) {
return fn.getImgSrcArr(tempEles).map(e => e.replace("/t/", "/i/"));
}
return fn.getImageHost();
},
repeat: 1,
category: "nsfw2"
}, {
name: "imx.to gallery",
host: ["imx.to"],
reg: /^https?:\/\/imx\.to\/g\/\w+$/i,
imgs: () => fn.gae("img.imgtooltip").map(e => e.src.replace("/t/", "/i/")),
button: [4],
insertImg: [
["#content", 2], 2
],
category: "nsfw2"
}, {
name: "imx.to",
host: ["imx.to"],
reg: /^https?:\/\/imx\.to\/i\/\w+$/i,
autoClick: ".button.blue.large,#continuebutton,a[title='Show gallery']",
category: "none"
}, {
name: "亚洲色吧",
host: ["yazhouseba.com", "yazhouse8.com"],
url: {
h: "yazhouse",
p: "/meinv/img-",
e: "#next-url"
},
imgs: () => {
fn.showMsg(DL.str_05, 0);
let pid = fn.ge("#next-url").rel;
return fetch("/meinv/ajax.php", {
"headers": {
"accept": "application/json, text/javascript, */*; q=0.01",
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-requested-with": "XMLHttpRequest"
},
"body": `action=src&pid=${pid}`,
"method": "POST"
}).then(async res => {
try {
return await res.json();
} catch {
return {};
}
}).then(json => json?.urls?.map(e => _unsafeWindow.img_dir + e) ?? []);
},
button: [4],
insertImg: [".content>.image", 2],
customTitle: ".content>h1",
category: "nsfw2"
}, {
name: "1000艺术摄影/169图片大全",
url: {
h: ["www.1000yishu.com", "www.169tp.com", "wap.169tp.com"],
p: /^\/\w+\/\d+\/\d+\/\d+\.html/
},
imgs: () => {
let max = Number(fn.gt(".pagelist a")?.match(/\d+/)) || 1;
return fn.getImg(".big-pic img,.inside_box img", max, 9);
},
button: [4],
insertImg: [".big-pic,.inside_box", 2],
autoDownload: [0],
next: ".fenxianga a,.pre_arct a",
prev: ".fenxianga a:last-child,.next_arct a",
hide: ".ad,union",
category: "nsfw1"
}, {
name: "亿秀美女",
host: ["www.itu11.com", "m.itu11.com"],
reg: /^https?:\/\/(www|m)\.i?tu11\.com\/\w+\/(\d+\/)?\d+\/\d+\.html$/i,
include: "#showimg img,.img-box img",
imgs: async () => {
await fn.getNP("#showimg img,.img-box img", "a.curpage+a:not(.prepage)", null, "#paginationEle", 0, null, 0, 0);
return fn.gae("#showimg img,.img-box img");
},
button: [4],
insertImg: ["#showimg,.img-box", 2],
autoDownload: [0],
next: "//div[contains(text(),'上一篇')]/a | //a[text()='上一篇']",
prev: "//div[contains(text(),'下一篇')]/a | //a[text()='下一篇']",
category: "nsfw1"
}, {
name: "爱美女网",
url: {
h: "www.aimeinv6.com",
p: /^\/\w+\/\d+\.html$/
},
init: () => {
let a = fn.ge("a[href*=dPlayNext]");
a.outerHTML = `<div class="imgBox">${a.innerHTML}</div>`;
},
imgs: () => {
let max = Number(fn.gt("//a[contains(text(),'共')]")?.match(/\d+/)) || 1;
return fn.getImg("#bigimg", max, 9);
},
button: [4],
insertImg: [".imgBox", 2],
autoDownload: [0],
next: "//span[contains(text(),'上一篇')]/a",
prev: "//span[contains(text(),'下一篇')]/a",
category: "nsfw1"
}, {
name: "JavCup",
url: {
h: "javcup.com",
p: "/movie/",
e: ["#video[poster]", ".movies-images li"]
},
box: ["#play-card", 2],
imgs: () => {
let videoSrc = fn.src("#video>source");
videoSrcArray[0] = videoSrc;
let poster = fn.attr("#video[poster]", "poster");
let srcs = fn.getImgSrcArr(".movies-images li");
srcs.unshift(poster);
return srcs;
},
button: [4],
insertImg: ["box", 2],
customTitle: "h1.title",
downloadVideo: true,
category: "nsfw2"
}, {
name: "JavCup",
url: {
h: "javcup.com",
p: "/video/",
e: "#video[poster]"
},
imgs: () => {
let videoSrc = fn.src("#video>source");
videoSrcArray[0] = videoSrc;
let poster = fn.attr("#video[poster]", "poster");
return [poster];
},
customTitle: "h1.title",
downloadVideo: true,
category: "nsfw2"
}, {
name: "JavCup",
url: {
h: "javcup.com",
p: "/photo/"
},
box: [".content>.body", 2],
imgs: "#photos>li",
button: [4],
insertImg: ["box", 2],
customTitle: "h1.title",
category: "nsfw2"
}, {
name: "JavCup",
url: {
h: "javcup.com",
p: "/model/"
},
init: () => fn.gae("section img[data-src]").forEach(e => (e.src = e.dataset.src)),
box: [".content>.body", 2],
imgs: () => {
let links = fn.gau("a[href*='type=photos']");
if (links.length > 1) {
let url = links.at(0);
let [max] = links.at(-1).match(/\d+$/);
links = fn.arr(max, (v, i) => url + "&page=" + (i + 1));
return fn.getEle(links, "#photos>ul").then(uls => {
links = uls.map(ul => fn.gau(".photo-grid-item a", ul));
links = links.flat();
return fn.getImgA("#photos>li", links, 1);
});
} else {
links = fn.gau("#photos .photo-grid-item a");
return fn.getImgA("#photos>li", links, 1);
}
},
button: [4],
insertImg: ["box", 3],
customTitle: "h1 span",
category: "nsfw2"
}, {
name: "JJGirls",
url: {
h: "jjgirls.com",
e: ".L664 a:has(>img:not([src^='/thumbs/']))",
d: "pc"
},
box: [".L664"],
imgs: () => {
let pagesE = fn.ge(".matchlinks");
let pages = /\/\d+\/$/.test(fn.lp);
if (pagesE && pages) {
let url = fn.lp.replace(/\/\d+\/$/, "");
let max;
let link = fn.gu(".matchlinks>a:has(+img)");
if (/more$/.test(link)) {
max = fn.gt(".matchlinks>a+b");
} else {
[, max] = link.match(/\/(\d+)\/$/);
}
let links = fn.arr(max, (v, i) => `${url}/${(i + 1)}/`);
return fn.getImgA(".L664 a:has(>img:not([src^='/thumbs/']))", links, 1);
} else {
return fn.getImgA(".L664 a:has(>img:not([src^='/thumbs/']))", [fn.url]);
}
},
button: [4],
insertImg: ["box", 2],
category: "nsfw2"
}, {
name: "エロ画像 オナップル",
url: {
h: "onapple.jp",
p: "/archives/"
},
imgs: ".permanent_text img",
customTitle: ".permanent_title",
category: "nsfw2"
}, {
name: "JavTube/PureJapanese/ThumbNow/69DV/JapaneseThumbs/AsiaUncensored",
url: {
h: [
"javtube.com",
"purejapanese.com",
"thumbnow.com",
"69dv.com",
"japanesethumbs.com",
"asiauncensored.com"
],
e: ".L664 a:has(>img:not([src^='/thumbs/']))",
d: "pc"
},
box: [".L664,.L996"],
imgs: () => {
let pagesE = fn.ge(".matchlinks");
let pages = /\/\d+\/$/.test(fn.lp);
if (pagesE && pages) {
let url = fn.lp.replace(/\/\d+\/$/, "");
let max;
let last = fn.ge("//div[@class='matchlinks']/a[text()='Last']");
if (last) {
let link = fn.gu("//div[@class='matchlinks']/a[text()='Last']");
[, max] = link.match(/\/(\d+)\/$/);
} else {
max = fn.gt(".matchlinks>a:last-child", 2);
}
let links = fn.arr(max, (v, i) => `${url}/${(i + 1)}/`);
return fn.getImgA(".L664 a:has(>img:not([src^='/thumbs/']))", links, 1);
} else {
return fn.getImgA(".L664 a:has(>img:not([src^='/thumbs/']))", [fn.url]);
}
},
button: [4],
insertImg: ["box", 2],
category: "nsfw2"
}, {
name: "人体艺术",
link: "https://dsqs8.com/",
url: {
e: ".umBody",
p: /^\/post\/\d+/
},
init: () => fn.clearAllTimer(),
box: [".viewall_plugin", 2],
imgs: ".LightGallery_Item",
button: [4],
insertImg: [
["box", 0, ".viewall_plugin"], 2
],
autoDownload: [0],
next: ".prev>a",
prev: ".next>a",
customTitle: "h1.tit",
category: "nsfw2"
}, {
name: "Girl Girl Go",
reg: /^https?:\/\/(\w{2}\.)?(girlgirlgo|girlygirlpic)\.(org|net|xyz|icu|com|biz|top)\/a\/\w+/,
imgs: ".figure-link",
button: [4],
insertImg: [".post-media-body", 2],
next: async () => {
await fn.waitEle("a[rel=next]", 30);
let next = fn.ge("a[rel=next]");
return next ? next.href : null;
},
prev: "a[rel=prev]",
customTitle: () => fn.waitEle(".figure-link").then(() => fn.gt(".entry-title a").split(" No.")[0].trim()),
category: "nsfw1"
}, {
name: "QGirlz/CuteLadyPic",
url: {
e: [
".main-image",
"//a[@data-title and picture/source]",
".next",
".main-title"
]
},
imgs: () => fn.getImg("//a[@data-title and picture/source]", (fn.gt(".next", 2) || 1), 16),
button: [4],
insertImg: [".main-image", 2],
customTitle: () => fn.gt(".main-title").split(" No.")[0].trim(),
category: "nsfw1"
}, {
name: "QGirlz/CuteLadyPic M",
url: {
p: "/m/",
e: [
".place-padding+.place-padding",
"//a[@data-title and picture/source]",
".prev-next-page",
".blog-title"
]
},
box: ["#post-tag", 1],
imgs: () => {
let [, max] = fn.gt(".prev-next-page").match(/\d+/g);
return fn.getImg("//a[@data-title and picture/source]", max, "4");
},
button: [4],
insertImg: [
["box", 0, "#content>div:first-child[style],#content>article,#content>.place-padding:not([id])"], 2
],
customTitle: () => fn.gt(".blog-title").split(" No.")[0].trim(),
category: "nsfw1"
}, {
name: "cn.angirlz.com",
url: {
h: /^\w{2}\.angirlz\.com$/
},
page: () => fn.clp("/album/"),
SPA: () => _this.page(),
observeURL: "loop",
imgs: () => _this.page() ? fn.showMsg(DL.str_05, 0).then(() => fn.fetchDoc(fn.clp()).then(dom => {
apiCustomTitle = fn.dt({
t: fn.gt("div[key=album_info] h1", 1, dom)
});
return fn.gae("#divGallery a", dom);
})) : [],
capture: () => _this.imgs(),
css: "div[key=album_main]{text-align:-webkit-center}",
category: "nsfw2"
}, {
name: "KawaiiX系列 一 分頁",
url: {
p: /^\/[^/]+\/\w+/,
e: [
".separator>a[href]",
".album-post-body .clear,.album-post-share-wrap",
".nav-links"
]
},
imgs: () => {
let max;
if (isM && fn.ge(".current-page")) {
max = fn.gt(".current-page").match(/\d+/g).at(-1);
} else {
max = fn.gt(".nav-links>*:last-child", 2) || 1
}
return fn.getImg(".separator>a[href]", max, 16);
},
button: [4],
insertImg: [
[".album-post-body .clear,.album-post-share-wrap", 1, "div[itemprop='description articleBody'],.album-post-body>*:not(.album-post-inner):not(.album-post-share-wrap):not(#FullPictureLoadOptionsButtonParentDiv,.FullPictureLoadImage,a[data-fancybox]):not(#FullPictureLoadEnd)"], 2
],
customTitle: ".breadcrumbs>span:last-child",
hide: "#openRss",
category: "nsfw2"
}, {
name: "KawaiiX系列 一",
url: {
e: ".album-post-inner,.album-postmeta-primarypix"
},
imgs: ".separator>a[href]",
button: [4],
insertImg: [
[".album-post-inner,.album-postmeta-primarypix", 2, ".separator"], 2
],
customTitle: ".breadcrumbs>span:last-child",
hide: "#openRss",
category: "nsfw2"
}, {
name: "KawaiiX系列 二 分頁",
url: {
e: [
"//a[@data-title and picture/source]",
".hero+.hero,.entry-content,.d-flex>.col-24,.album-post",
".entry-title,.album-title,.album-post-title,.col-12>h1,.album-h1",
".nav-links"
]
},
imgs: () => {
let max;
if (isM && fn.ge(".current-page")) {
max = fn.gt(".current-page").match(/\d+/g).at(-1);
} else {
max = fn.gt(".nav-links>*:last-child", 2) || 1
}
return fn.getImg("//a[@data-title and picture/source]", max, 16);
},
button: [4],
insertImg: [".hero+.hero,.entry-content,.d-flex>.col-24,.album-post", 2],
customTitle: () => fn.gt(".entry-title,.album-title,.album-post-title,.col-12>h1,.album-h1").split(" No.")[0].trim(),
css: ".flex-grid:not(.masonry){display:block!important;}",
hide: "#openRss,div.loading[style]",
category: "nsfw2"
}, {
name: "KawaiiX系列 二",
url: {
e: [
".hero+.hero,.entry-content,.d-flex>.col-24,.album-post",
".entry-title,.album-title,.album-post-title,.col-12>h1,.album-h1",
"//a[@data-title and picture/source]"
]
},
imgs: "//a[@data-title and picture/source]",
button: [4],
insertImg: [".hero+.hero,.entry-content,.d-flex>.col-24,.album-post,.album-h1", 2],
customTitle: () => fn.title(/\s-\s[\w\.]+$/i).replace(/\s?\(\d+\s?photos\)/, "").trim(),
hide: "#openRss,div.loading[style]",
category: "nsfw2"
}, {
name: "壹纳网",
host: ["yinaw.com"],
reg: /^https?:\/\/yinaw\.com\/\d+\.html$/,
include: ".article-content img:not([src*='yinaw.png'])",
init: async () => {
let baiduApi = "https://image.baidu.com/search/down?thumburl=https://baidu.com&url=";
let links = fn.gau(".fenye>a");
if (links.length > 0) {
await fn.getEle(links, ".article-content>*:not(.open-message,.fenye,.article-social)", [".open-message", 1], ".fenye");
}
let imgs = fn.gae(".article-content img:not([src*='yinaw.png'])");
imgs.forEach(img => {
if (/^https?:\/\/\w+\.sinaimg\.cn\//.test(img.src)) {
img.dataset.src = img.src.replace(/^(https?:\/\/\w+\.sinaimg\.cn\/)/, `${baiduApi}$1`).replace(/\/orj\d+\/|\/mw\d+\//, "/large/");
} else if (/^https?:\/\/i\d\.wp\.com\//.test(img.src)) {
img.dataset.src = img.src.replace(/\/orj\d+\/|\/mw\d+\//, "/large/").replace(/\?w=.+$/, "").replace(/^https?:\/\/i\d\.wp\.com\//, `${baiduApi}https://`);
} else {
img.dataset.src = img.src.replace(/\/orj\d+\/|\/mw\d+\//, "/large/");
}
});
if (setYinawSinaOriginalURL == 1) {
imgs.forEach(img => (img.dataset.src = img.dataset.src.replace(baiduApi, "")));
}
imgs.forEach(img => {
img.src = loading_bak;
fn.imagesObserver.observe(img);
});
},
imgs: ".article-content img:not([src*='yinaw.png'])",
autoDownload: [0],
next: ".article-nav-prev>a",
prev: ".article-nav-next>a",
customTitle: ".article-title",
referer: "https://weibo.com/",
category: "nsfw1"
}, {
name: "正妹六区",
url: {
h: "prettysix.com",
p: "/thread"
},
imgs: "img[id^=aimg][zoomfile]",
customTitle: "#thread_subject",
category: "nsfw2"
}, {
name: "五樓自拍",
host: ["www.porn5f.com"],
url: {
t: "五樓自拍",
p: "/album/"
},
imgs: ".photo-owl-carousel img",
category: "nsfw2"
}, {
name: "尼克成人網 人體寫真",
host: ["nick20.com"],
link: "https://nick20.com/pic/index.html",
reg: /^https?:\/\/nick20\.com\/pic\/pic\d+\.html$/i,
imgs: () => {
thumbnailSrcArray = _unsafeWindow.Large_cgurl.filter(Boolean);
return thumbnailSrcArray.map(e => e.replace("https://thumbs", "https://images").replace("_t.", "_o."));
},
button: [4],
insertImg: ["//center[img]", 2],
customTitle: ".bbs_entry_wrapper>h2",
category: "nsfw2"
}, {
name: "尼克成人網 成人漫畫",
reg: /^https?:\/\/nick20\.com\/bbs2\/index\.cgi\?read=\d+/i,
imgs: "a[id][onclick]",
button: [4],
insertImg: ["p.img", 2],
customTitle: ".bbs_entry_wrapper>h2",
category: "nsfw2"
}, {
name: "尼克成人網 成人貼圖 本土自拍 走光偷拍",
reg: /^https?:\/\/nick20\.com\/bbs(3|5)?\/\d+\.html/i,
imgs: "p#img>img",
button: [4],
insertImg: ["p#img", 2],
customTitle: ".bbs_entry_wrapper>h2",
category: "nsfw2"
}, {
name: "尼克成人網M",
host: ["m.nick20.com"],
link: "https://nick20.com/pic/index.html",
reg: [
/^https?:\/\/m\.nick20\.com\/pic\/index\.(html|cgi)\?read=\d+$/i,
/^https?:\/\/m\.nick20\.com\/bbs(2|3|5)?\/\d+\.html$/i
],
imgs: () => {
let [bp] = fn.gae(".bbs_pictures");
let imgs = fn.gae("img", bp);
return fn.getImgSrcArr(imgs).filter(src => !/\/images\/share|\/add\/|aav999/.test(src));
},
button: [4],
insertImg: [".bbs_pictures", 2],
customTitle: ".entryBlock>strong",
category: "nsfw2"
}, {
name: "小濕妹圖庫",
url: {
h: ["xsmpic.com"],
p: /^\/\d+\/$/
},
imgs: ".entry-content img:not([data-src])",
customTitle: "h1.entry-title",
category: "nsfw2"
}, {
name: "五歌的开心网",
url: {
h: ["happy.5ge.net"],
p: "/archives/",
e: "//ul[@class='joe_bread__bread']//a[contains(text(),'图册')]"
},
imgs: ".joe_detail__article img",
button: [4],
insertImg: [".joe_detail__article", 2],
customTitle: () => fn.dt({
t: fn.gt(".joe_detail__title").replaceAll("---", " "),
d: /[-PVGMB\d\.]+$/
}),
fancybox: {
v: 3,
css: false
},
hide: "div:has(>center>a>img)",
category: "nsfw2"
}, {
name: "好视角",
host: ["shijiao.meinvnews.com"],
url: {
e: ".logo img[alt=好视角]",
p: /^\/\w+\.html$/
},
imgs: () => {
let pages = fn.ge(".page-normal a");
if (pages) {
let [, max] = fn.gu("//a[text()='尾页']").match(/_(\d+).html/);
max = Number(max) + 1;
return fn.getImg(".tit+.text img:not([onerror]),.tit+.pic img:not([onerror])", max, 3);
} else {
return fn.gae(".tit+.text img:not([onerror]),.tit+.pic img:not([onerror])");
}
},
button: [4],
insertImg: [".tit+.text,.tit+.pic", 2],
autoDownload: [0],
next: "//p[contains(text(),'上一篇')]/a",
prev: "//p[contains(text(),'下一篇')]/a",
customTitle: ".tit>h1,.grjs h1",
css: ".tit+.text img{width:100%!important}",
mcss: ".pro_article .tpxq .pic{width: calc(100% - 10px)!important}",
hide: ".tit+.pic img{margin:auto!important}.mbx_nav~div:not([class]),body>em,.page-normal",
gallery: 1,
category: "nsfw2"
}, {
name: "秘秘秘/美鲍儿",
host: ["ktacf.click", "lingleis.info"],
url: {
e: "#menu_top_gg+.table,#content_top_gg"
},
imgs: "#content_top_gg+.titletablerow img",
button: [4],
insertImg: ["#content_top_gg+.titletablerow", 2],
autoDownload: [0],
next: "//div[text()='下篇']/preceding-sibling::div[1]/a",
prev: "//div[text()='上篇']/following-sibling::div[1]/a",
customTitle: ".cell3.clmtop3",
hide: "#header,#sidebar_left,#sidebar_right,.logo_top_gg,#menu_top_gg,#menu_bottom_gg,#content_top_gg,#content_bottom_gg,#page_bottom_top_gg,#page_bottom_bottom_gg,div:has(>#page_bottom_link_gg)",
category: "nsfw2"
}, {
name: "秘秘秘/美鲍儿 AD",
url: {
e: ".topbody .logo+.table,#menu_top_gg+.table"
},
hide: "#tnoticegg,.topnotice,#header,#sidebar_left,#sidebar_right,.logo_top_gg,#menu_top_gg,#menu_bottom_gg,#page_bottom_top_gg,#page_bottom_bottom_gg,div:has(>#page_bottom_link_gg),.titletablerow:has(>.titletablecell>a:not([href$=html]))",
category: "ad"
}, {
name: "啪啪凸凸",
host: ["papatutu.com"],
url: {
e: "#content.card-body",
p: "/a/show/"
},
imgs: "div.lightbox",
button: [4],
insertImg: ["#content", 2],
autoDownload: [0],
next: "a:has(.fa-arrow-right)",
prev: "a:has(.fa-arrow-left)",
customTitle: ".container>h4",
hide: "#span_h4",
category: "nsfw2"
}, {
url: {
p: "/show/"
},
imgs: "#content img[loading]",
button: [4],
insertImg: ["#content", 2],
customTitle: ".container .bg-info",
category: "nsfw2"
}, {
name: "哔咔庇护所v2",
host: ["ios.pipigou830.top"],
url: {
t: "哔咔庇护所",
s: "&catid=",
ee: "#dplayer.dplayer"
},
init: async () => {
fn.remove("//div[@class='row'][div/a/img]");
await fn.waitEle("#lightbox~img");
},
imgs: () => fn.ge("#lightbox a") ? fn.gae("#lightbox a") : fn.gae("#lightbox~img"),
button: [4],
insertImg: ["//div[div[@id='lightbox']]", 2],
customTitle: "#comic-view-main .text-center",
hide: "div:has(>.nav-pills)",
category: "nsfw2"
}, {
name: "G-AVSTAR",
url: {
h: "g-avstar.com",
p: /^\/\d+\/\d+\/\d+\/[^\/]+\/$/,
e: "//p[contains(text(),'更多美图')]"
},
box: [".ngg-galleryoverview", 1],
imgs: async () => {
await fn.getNP(".ngg-gallery-thumbnail-box", ".ngg-navigation>span.current+a:not(.prev)", null, ".ngg-navigation");
return fn.gae(".ngg-gallery-thumbnail a");
},
thums: ".ngg-gallery-thumbnail img",
button: [4],
insertImg: [
["box", 0, ".ngg-galleryoverview,.ngg-navigation"], 2
],
customTitle: ".entry-title",
category: "nsfw2"
}, {
name: "XO福利圖",
links: [
"https://kb1.a7xofulitu.com/%E5%84%BF%E6%AD%8C%E4%B8%89%E7%99%BE%E9%A6%96/",
"https://www.xofulitu521.xyz/xoxo",
"https://www.xofulitu9ok999.xyz/xoxo",
"https://diedk1123-ake33i.xofulitu2za222.sbs/xoxo",
"https://ponds-attract-ducks.xofulitu1qqq111.xyz/xoxo"
],
url: {
t: "XO福利圖",
h: "xofulitu",
e: ".picture-wrap img",
p: /\/art\/pic\/id\/\d+\/$/i
},
imgs: () => fn.getImgSrcArr(".picture-wrap img").filter(src => !src.includes("loading")),
button: [4],
insertImg: [".container.clearfix", 2],
customTitle: () => fn.dt({
d: [
/ - XO福利圖.+$/,
/[\/\s]?[\(\[(【“]\d+[\w\s\\\/\.+-/]+[\)\])】”]|\s?\d+p[\+\s]+\d+v|\s?\d+p\d+v|\s?\d+P|\(\d\)/gi,
/[\s-]+$/
]
}),
hide: ".custom_link-wrapper,div:has(>#floating-ad)",
category: "nsfw2"
}, {
name: "XO福利圖 分類自動翻頁",
url: {
h: "xofulitu",
t: "XO福利圖",
p: /^\/arttype\//i
},
autoPager: {
ele: ".container.clearfix",
observer: ".container.clearfix .album",
next: ".paging-item--current+a",
re: ".pagging-div",
lazySrc: "img[data-src]",
pageNum: ".paging-item--current"
},
openInNewTab: ".picture-list a:not([target=_blank])",
hide: ".custom_link-wrapper,div:has(>#floating-ad)",
category: "autoPager"
}, {
name: "XO福利圖AD",
url: {
h: "xofulitu",
t: "XO福利圖"
},
hide: ".custom_link-wrapper,div:has(>#floating-ad)",
category: "ad"
}, {
name: "ONS漂亮MM图库",
link: "https://www.rb1.es/momotk/",
url: {
h: ["ons.ooo"],
p: "/article/"
},
imgs: ".article-content img",
button: [4],
insertImg: [".article-content", 2],
customTitle: ".focusbox-title",
category: "nsfw1"
}, {
name: "XXAV",
host: ["xxav.one", "www.xxav2235.com"],
url: {
t: "XXAV",
p: ["/view/", "/artdetail"]
},
box: ["article:has(>img),article:has(>p>img)", 1],
imgs: "article>img,article>p>img",
button: [4],
insertImg: [
["box", 0, "article:has(>img)"], 2
],
autoDownload: [0],
next: "//em[text()='上一篇:']/a",
prev: "//em[text()='下一篇:']/a",
customTitle: () => fn.title("-XXAV"),
hide: ".suspend",
category: "nsfw1"
}, {
name: "多多影视/多多影音/全网影视/哥哥在线/微微资讯/酷酷影音/男人社区 模式A",
link: "https://xxselove.com/artmv/",
url: {
e: [
".v_nav .sel_wrap",
"#content_news img"
],
p: /^\/art\w+\//
},
imgs: () => {
let pages = fn.ge("//div[@id='page']/a[@class='next'][starts-with(text(),'尾')]");
if (pages) {
let [max] = fn.gt(pages).match(/\d+/);
let dir = fn.dir(fn.lp);
let links = fn.arr(max, (v, i) => i == 0 ? dir : dir + `index${i + 1}.html`);
return fn.getImgA("#content_news img", links);
}
return fn.gae("#content_news img");
},
button: [4],
insertImg: ["#content_news", 2],
customTitle: ".title h1 a",
category: "nsfw2"
}, {
name: "多多影视/多多影音/全网影视/哥哥在线/微微资讯/酷酷影音/男人社区 模式B",
link: "https://m.rusese.org/artmv/",
url: {
e: [
"a.fed-nav-title[href='/artmv/']",
".fed-arti-content img"
],
p: /^\/art\w+\//
},
imgs: () => {
let pages = fn.ge(".fed-page-info a[href*='/index']");
if (pages) {
let [max] = fn.gt(".fed-page-info a:last-child").match(/\d+/);
let dir = fn.dir(fn.lp);
let links = fn.arr(max, (v, i) => i == 0 ? dir : dir + `index${i + 1}.html`);
return fn.getImgA(".fed-arti-content img", links);
}
return fn.gae(".fed-arti-content img");
},
button: [4],
insertImg: [".fed-arti-content", 2],
customTitle: ".fed-arti-info h2",
category: "nsfw2"
}, {
name: "多多影视/多多影音/全网影视/哥哥在线/微微资讯/酷酷影音/男人社区 模式C",
link: "https://xxk555.com/arttype/meituqu.html",
url: {
e: [
"a.fed-nav-title[href='/arttype/meituqu.html']",
".fed-arti-content img"
],
p: "/artdetail/"
},
imgs: () => {
let pages = fn.ge("//a[text()='尾页']");
if (pages) {
let max = fn.gu("//a[text()='尾页']").match(/\d+/g).at(-1);
let url = fn.lp.replace(/(-\d+)?\.html$/, "");
let links = fn.arr(max, (v, i) => i == 0 ? url + ".html" : url + `-${i + 1}.html`);
return fn.getImgA(".fed-arti-content img", links);
}
return fn.gae(".fed-arti-content img");
},
button: [4],
insertImg: [".fed-arti-content", 2],
customTitle: ".fed-arti-info h2",
category: "nsfw2"
}, {
name: "多多影视/多多影音/全网影视/哥哥在线/微微资讯/酷酷影音/男人社区 模式D",
link: "https://xoxvi.com/arttype/jipinmeinv.html",
url: {
e: [
"#sidebarTogglePcDown",
".single-video-info-content img"
],
p: "/artdetail/"
},
imgs: async () => {
let pages = fn.ge(".page-item.active+li>a:not([title='下一页'])");
if (pages) {
await fn.getNP(".single-video-info-content>*", ".page-item.active+li>a:not([title='下一页'])", null, ".pagination");
}
return fn.gae(".single-video-info-content img");
},
button: [4],
insertImg: [".single-video-info-content", 1],
customTitle: ".single-video-title h2",
category: "nsfw2"
}, {
name: "SexBee.TV",
link: "https://sexbee.tv/arttype/jipinmeinv/",
host: ["sexbee.tv", "m.beebee.top", "m.beeku.top", "蜜.2025tv.top", "m.aistv.top", "xiaobee.vip", "meimeibee.com"],
url: {
e: [
"#site-header .app-nav-toggle>.lines",
"#site-header a.logo>img[src='/assets/images/logo.png']",
"#list_art_common_art_show img"
],
st: ["pageContext", "toastMessage"],
p: "/artdetail/"
},
imgs: () => {
let pages = fn.ge(".pagination");
if (pages) {
let max = fn.gu("//a[text()='最後 »']").match(/\d+/g).at(-1);
let links = fn.arr(max, (v, i) => `?mode=async&function=get_block&block_id=list_art_common_art_show&sort_by=&from=${i + 1}`);
return fn.getImgA("#list_art_common_art_show img", links);
}
return fn.gae("#list_art_common_art_show img");
},
button: [4],
insertImg: ["#list_art_common_art_show", 2],
customTitle: ".content-header h2",
fancybox: {
v: 3,
insertLibrarys: 1
},
category: "nsfw2"
}, {
name: "adultspic色情成人圖片",
url: {
h: ["adultspic.com"],
p: ".html"
},
imgs: () => fn.getNP(".wp-block-image", "//a[text()='下一頁']").then(() => fn.gae(".wp-block-image img").map(e => e.src)),
button: [4],
insertImg: [".article-content", 2],
autoDownload: [0],
next: ".article-nav-prev>a",
prev: ".article-nav-next>a",
customTitle: ".article-title",
hide: ".ssr-content",
category: "nsfw2"
}, {
name: "中国街拍",
host: ["jiepai.sifang.app"],
url: {
e: "meta[content=中国街拍]",
p: /^\/\d+\/[\w-]+\.html$/
},
imgs: "a[data-fancybox]",
button: [4],
insertImg: [
["//p[a[img]]", 2, "//p[a[img]]"], 2
],
customTitle: "article>h1",
fancybox: {
v: 3,
css: false
},
mcss: "article{width:100%!important}",
category: "nsfw1"
}, {
name: "美图收藏夹",
url: {
h: ["sifang.app"],
p: "/node/"
},
imgs: "a[data-fancybox]",
button: [4],
insertImg: [
["//p[a[img]]", 2, "//p[a[img]]"], 2
],
customTitle: ".page-title",
fancybox: {
v: 3,
css: false
},
mcss: "article{width:100%!important}",
category: "nsfw1"
}, {
name: "名腿网",
host: ["www.mingtuiw.com", "mingtui.net"],
reg: /^https?:\/\/(www\.mingtuiw\.com|mingtui\.net)\/archives\/\d+$/,
exclude: ".swpm-more-tag-not-logged-in,.swpm-more-tag-restricted-msg",
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr(".entry-content img");
return thumbnailSrcArray.map(e => e.replace(/-\d+x\d+(\.\w+)$/, "$1"))
},
button: [4],
insertImg: [".entry-content>p", 2],
autoDownload: [0],
next: ".nav-previous>a[rel=prev]",
prev: ".nav-next>a[rel=next]",
customTitle: () => fn.dt({
s: ".entry-title",
d: /(\d+图)/
}),
category: "nsfw1"
}, {
name: "名腿网",
host: ["www.mingtuiw.com"],
url: () => {
if (fn.curl(/^https?:\/\/www\.mingtuiw\.com\/archives\/\d+$/)) {
let [, num] = fn.gt(".entry-title").match(/((\d+)图)/);
let tImgsNum = fn.gae(".entry-content img").length;
if (num == tImgsNum) return true;
}
return false;
},
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr(".entry-content img");
return thumbnailSrcArray.map(e => e.replace(/-\d+x\d+(\.\w+)$/, "$1"))
},
button: [4],
insertImg: [".entry-content>p", 2],
autoDownload: [0],
next: ".nav-previous>a[rel=prev]",
prev: ".nav-next>a[rel=next]",
customTitle: () => fn.dt({
s: ".entry-title",
d: /(\d+图)/
}),
category: "nsfw1"
}, {
name: "名腿网",
host: ["www.mingtuiw.com"],
reg: /^https?:\/\/www\.mingtuiw\.com\/archives\/\d+\/.+$/,
exclude: "#div_img_vip",
imgs: async () => {
let links = fn.gau("#thumb_imglist>a");
let imgSrcs = await fn.getImgA(".entry-content img.attachment-large", links);
return imgSrcs.map(e => e.replace(/-\d+x\d+(\.\w+)$/, "$1"))
},
button: [4],
insertImg: [".entry-content", 2],
customTitle: () => fn.dt({
d: /(\d+\/\d+).+/
}),
category: "nsfw1"
}, {
name: "Kungfutv/Series Donghua",
host: ["kungfutv.net", "seriesdonghua.net"],
reg: [
/^https?:\/\/kungfutv\.net\/cosplay\/[^\/]+\//,
/^https?:\/\/seriesdonghua\.net\/cosplay\/[^\/]+\//
],
box: [".entry-content p:has(img),#readerarea img", 1],
imgs: ".entry-content img,#readerarea img",
button: [4],
insertImg: [
["box", 0, ".entry-content p:has(img),.ts-main-image"], 2
],
endColor: "white",
customTitle: ".entry-title",
category: "nsfw1"
}, {
name: "Rule34Comic圖片清單頁",
url: {
h: "rule34comic.party",
p: "/comics/"
},
box: [".block-album"],
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr(".thumbs-gallery img");
fn.showMsg(DL.str_05, 0);
let url = fn.gu("//a[span[text()='Read']]");
return fn.fetchDoc(url).then(dom => fn.gae("#album_view_album_view img[data-page]", dom));
},
button: [4],
insertImg: ["box", 2],
customTitle: ".title_video",
category: "hcomic"
}, {
name: "Rule34Comic閱讀頁",
url: {
h: "rule34comic.party",
p: "/read/"
},
imgs: "#album_view_album_view img[data-page]",
customTitle: ".title_video",
category: "hcomic"
}, {
name: "AhentaiZ.net",
url: {
h: "ahentaiz.net",
e: "#imageContainer"
},
imgs: () => {
fn.showMsg(DL.str_05, 0);
let json_url = fn.attr("#imageContainer", "data-json-url");
let s = new URL(json_url).origin;
return fetch(json_url).then(res => res.json()).then(arr => arr.map(e => s + e));
},
button: [4],
insertImgBF: () => fn.waitEle("#imageContainer img[alt]"),
insertImg: ["#imageContainer", 2],
customTitle: () => fn.dt({
d: [
"Read online Hentai Manga 2025 year",
" - Ahentaiz",
/"/g
]
}),
category: "hcomic"
}, {
name: "HentaiBe",
url: {
h: "hentaibe.com",
p: "/g/"
},
box: [".masonry", 2],
imgs: () => {
fn.showMsg(DL.str_05, 0);
thumbnailSrcArray = fn.getImgSrcArr(".entry__thumb img");
let url = fn.gu("//a[text()='SHOW ALL ORIGINAL']");
return fn.fetchDoc(url).then(dom => fn.gae(".s-content img", dom));
},
button: [4],
insertImg: ["box", 2],
insertImgAF: () => fn.hideEle(".masonry"),
customTitle: ".s-content__header-title",
category: "hcomic"
}, {
name: "KomikDewasa",
url: {
h: "komikdewasa.id",
p: "/baca/"
},
imgs: "section[data-chapter-number] img",
button: [4],
insertImg: ["section[data-chapter-number] .items-center", 2],
autoDownload: [0],
next: "#next-chapter-button",
prev: "//a[contains(text(),'Prev')]",
customTitle: "#chapter-title",
category: "hcomic"
}, {
name: "Hentai City",
url: {
h: "www.hentaicity.com",
p: "/gallery/"
},
box: [".thumb-list.ac:not(.title-spacing)", 2],
imgs: () => {
let b = ".thumb-list.ac:not(.title-spacing) a.thumb-img";
let t = ".thumb-list.ac:not(.title-spacing) img";
thumbnailSrcArray = fn.getImgSrcArr(t);
return fn.ge(b) ? fn.gae(b) : fn.gae(t);
},
button: [4],
insertImg: ["box", 2],
insertImgAF: () => fn.hideEle(".thumb-list.ac:not(.title-spacing)"),
customTitle: ".content h1",
category: "hcomic"
}, {
name: "HentaiKisu",
url: {
h: "hentaikisu.com",
p: /^\/g\/\d+$/
},
box: [".card-hentai:has(.book-list)", 2],
init: () => fn.waitVar("decode_base64"),
imgs: () => {
let url = fn.gu("a:has(.irx-eye)");
return fn.getCode(url, {
mode: "dom",
key: "la ="
}).then(() => {
let {
decode_base64,
la
} = _unsafeWindow;
return decode_base64(la).split(",");
});
},
button: [4],
insertImg: ["box", 2],
customTitle: () => fn.dt({
s: "#info h1",
d: /"/g
}),
category: "hcomic"
}, {
name: "Cutie Comics",
url: {
h: "cutiecomics.com",
P: ".html"
},
imgs: ".galery img",
button: [4],
insertImg: [".galery", 2],
customTitle: "#page-title",
category: "hcomic"
}, {
name: "Hentai FR",
url: {
h: "hentaifr.net"
},
imgs: ".rl-gallery-container img",
customTitle: ".entry-title",
category: "hcomic"
}, {
name: "Prismblush",
url: {
h: "prismblush.com",
p: "/comic/"
},
imgs: () => {
let jump = fn.gae(".comic-nav-jumptocomic").at(0);
let links = fn.gae(".level-0", jump).map(e => e.value);
return fn.getImgA("#comic img", links);
},
button: [4],
insertImg: ["#comic", 2],
endColor: "white",
customTitle: "h1.elementor-heading-title",
category: "hcomic"
}, {
name: "Xpicvid",
host: ["www.xpicvid.com", "www.nicohentai.com"],
url: {
e: "#Comic_Top_Nav img[alt=logo][src$='_nico.png']",
p: /^\/(moeupup-\d-\d+\.html|showinfo-\d+-\d+-\d\.html)$/,
ee: ".dplayer-container"
},
init: () => fn.getNP(".row.thumb-overlay-albums img,.artwork-container .artwork img", ".pagination li.active+li>a:not(.prevnext)"),
imgs: ".row.thumb-overlay-albums img,.artwork-container .artwork img",
button: [4],
insertImg: [".row.thumb-overlay-albums,.artwork-container .artwork", 2],
next: "//a[span[text()='下一页']][@href]",
prev: 1,
customTitle: () => {
let url = fn.gu("//a[span[text()='漫畫簡介']]");
if (url) {
return fn.fetchDoc(url).then(albumDoc => {
let comicName = fn.gt(".panel-heading h1", 1, albumDoc);
let episode = fn.ge(".episode", albumDoc);
return episode ? comicName + " - " + fn.gt(".panel-heading>.pull-left") : comicName;
}).then(text => fn.dt({
t: text,
d: [
/\(\d+[\w\s\.\+-]+\)/i,
/[\d+[\w\s\.\+-]+]/i
]
}));
}
return document.title;
},
category: "hcomic"
}, {
name: "Doujindesu.XXX",
url: {
h: "doujindesu.tv",
e: "#reader>.main"
},
init: async () => {
await fn.waitEle("#reader>.main img");
for (const sheet of document.styleSheets) {
if (sheet.href?.includes("doujindesu.css")) {
for (const rule of sheet.rules) {
if (rule.selectorText === ".darkmode input, .darkmode button") {
rule.style.setProperty("color", "#fff");
return;
}
}
}
}
},
imgs: () => fn.gae("#reader>.main img"),
button: [4],
insertImg: ["#reader>.main", 2],
next: "a:has(>.fa-chevron-right):not([href='#'])",
prev: "a:has(>.fa-chevron-left):not([href='#'])",
customTitle: "#reader h1",
hide: "center:has(a>img)",
category: "hcomic"
}, {
name: "Doujindesu/Doujin89",
url: {
h: ["doujindesu.asia", "doujin89.com"]
},
imgs: "#readerarea img",
button: [4],
insertImg: ["#readerarea", 2],
next: ".ch-next-btn:not(.disabled)",
prev: ".ch-prev-btn:not(.disabled)",
customTitle: ".entry-title",
hide: ".blox.mlb.kln",
category: "hcomic"
}, {
name: "NAKAL",
url: {
h: "www.nakal.me",
p: "/chapter/"
},
imgs: ".chapter-content img",
button: [4],
insertImg: [".chapter-content", 2],
autoDownload: [0],
current: () => {
let chapters = fn.gae("#chapter-list option");
let c_chapter = chapters.find(e => e.value == fn.url);
return c_chapter;
},
next: () => {
let next = _this.current()?.nextElementSibling;
return next ? next.value : null;
},
prev: () => {
let prev = _this.current()?.previousElementSibling;
return prev ? prev.value : null;
},
customTitle: () => fn.dt({
t: fn.ge(".container h1").textContent
}),
category: "hcomic"
}, {
name: "Hentai18",
url: {
h: "hentai18.net",
p: "/read-hentai/"
},
imgs: ".chapter-content img",
button: [4],
insertImg: [".chapter-content", 2],
customTitle: () => fn.dt({
t: fn.ge(".container h1").textContent
}),
category: "hcomic"
}, {
name: "Manga Lotus/Yaoi Manga Online",
url: {
h: ["mangalotus.com", "yaoimangaonline.com"]
},
box: [".meta-tags", 1],
imgs: ".entry-content img",
button: [4],
insertImg: [
["box", 0, ".entry-content .code-block,.entry-content p:has(img)"], 2
],
customTitle: ".entry-title",
category: "hcomic"
}, {
name: "XZhentai",
host: ["xzhentai.net", "hz-hentai.ru", "www.hz-hentai.com"],
url: {
e: "//a[text()='XZhentai']",
p: /^\/m\/\d+$/
},
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr(".gallery img");
return thumbnailSrcArray.map(e => e.replace("/t", "/"));
},
button: [4],
insertImg: [".gallery", 2],
customTitle: () => fn.getText(["h2", "h1"]),
category: "hcomic"
}, {
name: "Naruto hentai Doujins/Ai Generated Hentai MILFS",
host: ["narutodoujins.com", "syntheticgirls.com"],
reg: [
/^https?:\/\/(www\.)?narutodoujins\.com\/\d+\//,
/^https?:\/\/(www\.)?syntheticgirls\.com\/\d+\//
],
imgs: async () => {
let srcs = [];
let links;
if (fn.ge(".post-items-list")) {
let pages = fn.ge(".page-item-next");
if (pages) {
let max = fn.gt(".page-item-next", 2);
links = fn.arr(max, (v, i) => i == 0 ? fn.lp : fn.lp + `?page=${i + 1}`);
srcs = await fn.getEle(links, ".post-items-list a").then(eles => {
links = eles.map(a => a.href);
return fn.getImgA(".lightbox", links);
});
} else {
links = fn.gau(".post-items-list a");
srcs = await fn.getImgA(".lightbox", links);
}
} else if (fn.ge(".post-images-carousel-wrap")) {
links = fn.gau(".post-images-carousel-wrap a");
srcs = await fn.getImgA(".lightbox", links);
} else {
srcs = fn.getImgSrcArr(".lightbox");
}
let hd = srcs.filter(src => src.includes("/original/"));
if (hd.length) {
return hd;
}
return srcs;
},
capture: () => _this.imgs(),
customTitle: "h1.text-center",
category: "hcomic"
}, {
name: "熱辣漫畫M SPA",
url: () => fn.checkUrl({
h: ["m.relamanhua.org", "m.2024manga.com", "m.manga2024.com", "m.manga2025.com"],
i: 0
}) && isMobileDeviceUA,
clearLoop: true,
page: () => fn.clp("/v2h5/comicContent/"),
getHeaders: () => ({
headers: {
accept: "application/json",
platform: 1,
version: "2025.08.08",
webp: 1
}
}),
json: (url = fn.clp(), msg = 1) => {
if (msg == 1) fn.showMsg(DL.str_05, 0);
let split = url.split("/");
let word = split.at(-2);
let id = split.at(-1);
let api = `https://mapi.hotmangasf.com/api/v3/comic/${word}/chapter/${id}`;
return axios.get(api, _this.getHeaders()).then(json => json.data);
},
SPA: () => _this.page() ? true : (siteJson = {}) && false,
observeURL: "nav",
init: () => _this.page() ? _this.json().then(json => (siteJson = json) && fn.hideMsg()) : (_unsafeWindow.aboutBlank = null),
imgs: (json = siteJson) => {
if (!_this.page()) return [];
return json.results.chapter.contents.map(e => e.url);
},
capture: () => _this.imgs(),
button: [4],
insertImgBF: () => fn.waitEle(".van-image__img").then(() => fn.createImgBox(".comicContentPopupImageList", 2)),
insertImg: [
["box", 0, ".comicContentPopupImageList"], 2
],
insertImgAF: (p) => {
const addHtml = (url, text) => {
let str = `<div style="padding: 10px 0; text-align: center; font-size: initial !important;"><a href="${url}"style="width: 100%;font-size: 26px;line-height: 50px;height: 50px;text-align: center;">${text}</a></div>`;
p.insertAdjacentHTML("afterend", str);
};
let word = fn.clp().split("/").at(-2);
let url = `/v2h5/details/comic/${word}`;
let hUrl = "/v2h5/index";
addHtml(hUrl, "首頁");
addHtml(url, "目錄");
if (nextLink) addHtml(nextLink, "點選進入下一話");
fn.hideEle(".comicFixed,div:has(>.noApp)");
},
next: () => {
if (!_this.page()) return null;
let next = siteJson.results.chapter.next;
return next ? fn.dir(fn.clp()) + next : null;
},
prev: 1,
chapters: () => {
let name = fn.curl().split("/").at(5);
return axios.get(`https://mapi.hotmangasd.com/api/v3/comic/${name}/group/default/chapters?limit=500&offset=0`, _this.getHeaders()).then(json => {
let chapters = json.data.results.list;
return chapters.map(({
name,
comic_path_word,
uuid,
}) => ({
text: name,
url: `/v2h5/comicContent/${comic_path_word}/${uuid}`
}));
});
},
customTitle: (json = siteJson) => _this.page() ? json.results.comic.name + " - " + json.results.chapter.name : null,
preloadNext: () => {
_this.json(nextLink, 0).then(json => {
let srcs = _this.imgs(json);
let title = _this.customTitle(json);
fn.picPreload(srcs, title, "next");
});
},
fancybox: {
blacklist: 1
},
gallery: 0,
infiniteScroll: true,
category: "comic"
}, {
name: "熱辣漫畫",
url: {
h: [
"www.relamanhua.org",
"relamanhua.org",
"www.2024manga.com",
"2024manga.com",
"www.manga2024.com",
"manga2024.com",
"www.manga2025.com",
"manga2025.com"
],
e: [
".disData[contentKey]",
".disPass[contentkey]",
".comicContent-list"
],
i: 0
},
init: async () => {
await fn.waitVar("webpackJsonp");
fn.copymangaUI();
fn.createImgBox(".comicContent-list", 1);
let readHistoryData = localStorage.getItem("readHistory");
let [, , word, , id] = fn.lp.split("/");
let json;
readHistoryData ? json = JSON.parse(readHistoryData) : json = {};
json[word] = id;
localStorage.setItem("readHistory", JSON.stringify(json));
},
imgs: async (dom = document) => {
let key = fn.attr(".disPass", "contentkey", dom);
let raw = fn.attr(".disData", "contentkey", dom);
let images = await fn.copymanga_decrypt_A(raw, key);
return images.map(({
url
}) => url.replace("800x.", "1500x."));
},
button: [4, "24%", 2],
insertImg: [
["box", 0, ".comicContent-list"], 2
],
endColor: "white",
next: "//a[text()='下一話'][starts-with(@href,'/')]",
prev: "//a[text()='上一話'][starts-with(@href,'/')]",
chapters: () => {
let [, , comicName] = fn.lp.split("/");
return axios.get(`/comicdetail/${comicName}/chapters`).then(json => {
let key = fn.attr(".disPass", "contentkey");
let data = fn.copymanga_decrypt_B(json.data.results, key);
let chapters = data.groups.default.chapters;
let dir = fn.dir(fn.url);
return chapters.map(({
name,
id
}) => ({
text: name,
url: dir + id
}));
});
},
customTitle: (dom = document) => fn.dt({
t: dom.title,
d: / - 熱辣漫畫.+$/
}),
preloadNext: true,
infiniteScroll: true,
category: "comic"
}, {
name: "熱辣漫畫 自動翻頁",
url: {
h: [
"www.relamanhua.org",
"relamanhua.org",
"www.2024manga.com",
"2024manga.com",
"www.manga2024.com",
"manga2024.com",
"www.manga2025.com",
"manga2025.com"
],
e: [
".disData[contentKey]",
".disPass[contentkey]",
".comicContent-list"
],
i: 1
},
setReadHistory: () => {
let readHistoryData = localStorage.getItem("readHistory");
let [, , word, , id] = fn.clp().split("/");
let json;
readHistoryData ? json = JSON.parse(readHistoryData) : json = {};
json[word] = id;
localStorage.setItem("readHistory", JSON.stringify(json));
},
getSrcs: async (dom) => {
let key = fn.attr(".disPass", "contentkey", dom);
let raw = fn.attr(".disData", "contentkey", dom);
let images = await fn.copymanga_decrypt_A(raw, key);
return images.map(({
url
}) => url.replace("800x.", "1500x."));
},
getImgs: async (dom = document) => {
let srcs = await _this.getSrcs(dom);
return fn.createImgArray(srcs);
},
init: async () => {
await fn.waitVar("webpackJsonp");
fn.copymangaUI();
let tE = fn.createImgBox(".comicContent-list", 1);
let imgs = await _this.getImgs();
tE.innerHTML = "";
fragment.append(...imgs);
tE.append(fragment);
fn.remove(".comicContent-list");
await fn.lazyload();
_this.setReadHistory();
},
autoPager: {
ele: (dom) => _this.getImgs(dom),
pos: ["#FullPictureLoadMainImgBox", 0],
observer: "#FullPictureLoadMainImgBox>img",
next: "//a[text()='下一話'][starts-with(@href,'/')]",
title: (dom) => dom.title.replace(/ - 熱辣漫畫.+$/, ""),
re: ".header,.footer",
preloadNextPage: 1,
aF: () => _this.setReadHistory()
},
category: "comic autoPager"
}, {
name: "熱辣漫畫 目錄頁",
url: {
h: [
"www.relamanhua.org",
"relamanhua.org",
"www.2024manga.com",
"2024manga.com",
"www.manga2024.com",
"manga2024.com",
"www.manga2025.com",
"manga2025.com"
],
p: /^\/comic\/\w+$/
},
init: async () => {
await fn.waitEle(".tab-pane.show.active a");
const updateLastChapter = () => {
let [, , comic] = fn.lp.split("/");
let readHistoryData = localStorage.getItem("readHistory");
if (!!readHistoryData) {
let json = JSON.parse(readHistoryData);
if (comic in json) {
let selector = `.tab-content a[href$="${json[comic]}"]`;
fn.gae(".lastchapter").forEach(a => a.classList.remove("lastchapter"));
fn.gae(selector).forEach(a => a.classList.add("lastchapter"));
setTimeout(() => {
let lastReadUrl = fn.lp + "/chapter/" + json[comic];
let lastText = fn.ge(".lastchapter").title;
let lastE = fn.ge("#lastRead");
if (!lastE && !fn.ge("//span[contains(text(),'最後閱讀')]")) {
let a = document.createElement("a");
a.id = "lastRead";
a.target = "_blank";
let tableRight = fn.ge(".table-default-right");
tableRight.insertAdjacentElement("afterbegin", a);
const span = document.createElement("span");
span.innerText = "最後閱讀:";
tableRight.insertAdjacentElement("afterbegin", span);
a.href = lastReadUrl;
a.innerText = lastText;
} else if (!!lastE) {
let a = lastE;
a.href = lastReadUrl;
a.innerText = lastText;
}
}, 200);
}
}
};
updateLastChapter();
document.addEventListener("visibilitychange", updateLastChapter);
if ("aboutBlank" in _unsafeWindow) _unsafeWindow.aboutBlank = null;
setTimeout(() => fn.clearAllTimer(3), 1000);
},
css: ".lastchapter{color:#fff !important;background:#ff0000}",
hide: ".comicDetailAds",
category: "none"
}, {
name: "熱辣漫畫M 自動翻頁",
url: {
h: ["m.relamanhua.org", "m.2024manga.com", "m.manga2024.com", "m.manga2025.com"],
p: "/v2h5/comicContent/",
i: 1
},
clearLoop: true,
getData: () => {
let split = document.URL.split("/");
let word = split.at(-2);
let id = split.at(-1);
let api = `https://mapi.hotmangasf.com/api/v3/comic/${word}/chapter/${id}`;
return axios.get(api, {
headers: {
accept: "application/json",
platform: 1,
version: "2025.08.08",
webp: 1
}
}).then(json => json.data).then(json => {
let {
contents,
name,
next
} = json.results.chapter;
const images = contents.map(e => e.url);
if (!!next) {
next = fn.dir(document.URL) + next;
} else {
next = null;
}
siteJson = {
images,
name,
next
}
console.log("\n熱辣漫畫M_JSON\n", siteJson);
});
},
init: async () => {
fn.showMsg(DL.str_135, 0);
await _this.getData();
let imgs = fn.createImgArray(siteJson.images);
let tE = fn.ge("#comicContentMain");
fragment.append(...imgs);
tE.append(fragment);
fn.hideEle(".comicContentPopupImageList");
await fn.lazyload();
fn.clearAllTimer(3);
if ("aboutBlank" in _unsafeWindow) _unsafeWindow.aboutBlank = null;
fn.hideMsg();
let word = siteUrl.split("/").at(-2);
let url = `/v2h5/details/comic/${word}`;
let hUrl = "/v2h5/index";
const addHtml = (url, text) => {
let str = `<div style="padding: 10px 0; text-align: center;"><a href="${url}"style="width: 100%;font-size: 26px;line-height: 50px;height: 50px;text-align: center;">${text}</a></div>`;
fn.ge("#comicContentMain").insertAdjacentHTML("afterend", str);
};
addHtml(hUrl, "首頁");
addHtml(url, "目錄");
},
autoPager: {
ele: () => fn.createImgArray(siteJson.images),
pos: ["#comicContentMain", 0],
observer: "#comicContentMain>img",
next: () => siteJson.next,
wait: async () => await _this.getData(),
title: () => siteJson.name
},
css: ".comicContentPopup #comicContentMain{position:unset!important}",
hide: ".comicFixed",
category: "comic autoPager"
}, {
name: "熱辣漫畫 清除不給開啟開發人員工具",
url: {
h: [
/^(www\.|m.)?relamanhua\.org$/,
/^(www\.|m.)?2024manga\.com$/,
/^(www\.|m.)?manga2024\.com$/,
/^(www\.|m.)?manga2025\.com$/
],
},
init: () => {
if ("aboutBlank" in _unsafeWindow) _unsafeWindow.aboutBlank = null;
setTimeout(() => fn.clearAllTimer(3), 1000);
},
category: "ad"
}, {
name: "禁漫天堂",
url: {
e: "meta[property='og:site_name'][content=禁漫天堂]",
p: /^\/photo\/\d+/
},
imgs: async () => {
await fn.getNP(".scramble-page", ".pagination li.active+li>a:not(.prevnext)");
fn.showMsg(DL.str_01, 0);
const {
aid,
scramble_id,
get_num
} = _unsafeWindow;
let arr = [];
let fetchNum = 0;
let imgs = fn.gae(".scramble-page img[id],.owl-item .center img[id]");
for (let i = 0; i < imgs.length; i++) {
let getRedraw = new Promise(async resolve => {
const url = imgs[i].dataset.original ?? imgs[i].dataset.src;
let error = false;
if (url.includes(".gif") || aid < scramble_id) {
resolve(url);
} else {
const blob = await fetch(url).then(res => res.blob());
const fileName = new URL(url).pathname.split("/").at(-1);
const [id, ex] = fileName.split(".");
const img = new Image();
await new Promise(load => {
img.onload = load;
img.onerror = () => {
error = true;
resolve(null);
}
img.src = URL.createObjectURL(blob);
});
if (error) return;
const imgWidth = img.naturalWidth;
const imgHeight = img.naturalHeight;
const canvas = new OffscreenCanvas(imgWidth, imgHeight);
const canvas_2d = canvas.getContext("2d");
const num = get_num(btoa(aid), btoa(id));
const cropHeight = Number(imgHeight % num);
const sHeight = Math.floor(imgHeight / num);
let sy = imgHeight - cropHeight - sHeight;
let dy = cropHeight;
canvas_2d.drawImage(img, 0, sy, imgWidth, cropHeight + sHeight, 0, 0, imgWidth, cropHeight + sHeight);
for (let i = 1; i < num; ++i) {
canvas_2d.drawImage(img, 0, sy -= sHeight, imgWidth, sHeight, 0, dy += sHeight, imgWidth, sHeight);
}
URL.revokeObjectURL(img.src);
canvas.convertToBlob({
type: blob.type,
quality: 0.9
}).then(blob => {
fn.showMsg(`DrawImage ${fetchNum+=1}/${imgs.length}`, 0);
resolve(URL.createObjectURL(blob));
});
}
});
arr.push(getRedraw);
await delay(100);
}
return arr;
},
button: [4, "24%", 1],
insertImg: ["//div[@class='panel-body'][div[@class='row thumb-overlay-albums']]", 0],
next: "//a[span[text()='下一話']][@href]",
prev: 1,
customTitle: () => {
return fn.fetchDoc(fn.gu("//a[span[text()='漫畫簡介']]")).then(albumDoc => {
let comicName = fn.gt(".panel-heading h1", 1, albumDoc).replaceAll("/", "").replace(/\s?\[禁漫漢化組\]/, "");
let episode = fn.ge(".episode", albumDoc);
if (episode) {
let [id] = fn.lp.match(/\d+/);
let selector = `a[data-album="${id}"]`;
let a = fn.ge(selector, episode);
let chapterName = fn.dt({
t: a?.firstElementChild?.firstChild?.textContent?.replace(/\s+/g, " ")
});
chapterName = chapterName.replace(/(話).+/, "$1");
return comicName + " - " + chapterName;
} else {
return fn.dt({
t: comicName
});
}
});
},
hide: ".hidden-lg:not(.panel)[style*='z-index'],div:has(>.photo_center_div)",
observerClick: ["#chk_cover", "#chk_guide", "div[class^='btn_hide']"],
category: "hcomic"
}, {
name: "禁漫天堂",
url: {
e: "meta[property='og:site_name'][content=禁漫天堂]",
},
observerClick: ["#chk_cover", "#chk_guide", "div[class^='btn_hide']"],
category: "ad"
}, {
name: "E-Hentai圖片清單頁",
url: {
h: ["e-hentai.org", "exhentai.org", "ex.moonchan.xyz", "ex.nmbyd2.top"],
p: "/g/",
ee: "//h1[text()='Content Warning']"
},
box: ["#gdt", 2],
imgs: async () => {
await fn.getNP("#gdt>*", ".ptds+td>a", null, "//tr[td[@class='ptds']]");
if (options.fancybox == 1 && !isDownloading) {
//預覽縮圖網址需要裁剪難弄...
if (fn.ge(".gdtm img[style],.gdtl img[style],#gdt>a>div[style*='url(']")) {
let num_a;
let num_b;
let thumbnailsHeightData = [...document.querySelectorAll(".gdtm img,.gdtl img,#gdt>a>div[style*='url(']")].map(e => Number(e.style.height.match(/\d+/)[0]));
let thumbnailUrls = [...document.querySelectorAll(".gdtm>div,.gdtl>div,#gdt>a>div[style*='url(']")].map(div => getComputedStyle(div).getPropertyValue("background-image").slice(5, -2));
num_a = thumbnailUrls.length;
thumbnailUrls = [...new Set(thumbnailUrls)];
num_b = thumbnailUrls.length;
if (num_a === num_b) {
thumbnailSrcArray = thumbnailUrls;
} else {
let getThumbnai = 0;
fn.showMsg("Get Thumbnailsing...", 0);
let blobs = thumbnailUrls.map((url, i, arr) => fn.xhr(url, {
responseType: "blob"
}).then(blob => {
fn.showMsg(`Get Thumbnails ${getThumbnai += 1}/${arr.length}`, 0);
return blob;
}));
let heightIndex = 0;
let crop = 0;
await Promise.all(blobs).then(async blobArr => {
fn.hideMsg();
for (let blob of blobArr) {
fn.showMsg(`Thumbnails Crop ${crop += 1}/${blobArr.length}`, 0);
//console.log(`預覽縮圖裁切第${crop}張`);
let img = new Image();
await new Promise((resolve, reject) => {
img.onload = resolve;
img.onerror = reject;
img.src = URL.createObjectURL(blob);
});
for (let w = 0; w < img.width; w += 100) {
let canvas = document.createElement("canvas");
canvas.height = thumbnailsHeightData[heightIndex];
canvas.width = 100;
canvas.getContext("2d").drawImage(img, -Math.abs(w), 0);
let dataURL = canvas.toDataURL("image/webp", 0.5);
if (dataURL.startsWith("data:image/webp;")) {
let thumbnailBlobURL = fn.dataURLtoBlobURL(dataURL);
thumbnailSrcArray.push(thumbnailBlobURL);
//console.log(thumbnailBlobURL);
heightIndex++;
}
}
}
});
}
} else {
thumbnailSrcArray = [...document.querySelectorAll(".gdtm img,.gdtl img")].map(e => e.src);
}
}
if (E_HENTAI_LoadOriginalImage == 1) {
fn.showMsg(DL.str_01, 0);
let fetchNum = 0;
return fn.gau(".gdtm a,.gdtl a,#gdt a").map(async (url, i, arr) => {
await delay(100 * i);
return fn.fetchDoc(url).then(async (dom) => {
fn.showMsg(`${DL.str_02}${fetchNum+=1}/${arr.length}`, 0);
let fullimg = fn.ge("a[href*=fullimg]", dom);
let img = fn.ge("#img", dom);
if (fullimg) {
url = fullimg.href;
let res = await fn.xhrHEAD(url);
let finalUrl = res.finalUrl;
return /login\.php/.test(finalUrl) ? img.src : url;
} else {
return img.src;
}
});
});
} else {
let links = fn.gau(".gdtm a,.gdtl a,#gdt a");
return fn.getImgA("#img", links, 100);
}
},
button: [4],
insertImg: ["box", 3],
customTitle: () => fn.dt({
t: fn.getText(["#gj", "#gn"])
}),
topButton: true,
category: "hcomic"
}, {
name: "E-Hentai圖片清單頁",
link: "https://e-hentai.org/lofi/",
url: {
h: ["e-hentai.org"],
p: "/lofi/g/"
},
imgs: async () => {
await fn.getNP(".gi,#gh>a", "//a[text()='Next Page >' or text()='下一页 >']", null, "#ia");
let links = fn.gau(".gi>a,#gh>a");
return fn.getImgA("#sm", links, 100);
},
button: [4],
insertImg: [
["#ia", 2], 3
],
customTitle: () => fn.title(" - E-Hentai", 1).replace(/\|.+/, "").replace(/\//, "").trim(),
topButton: true,
category: "hcomic"
}, {
name: "Chin² Scanlations",
url: {
h: "chin2.net",
p: /^\/Gallery\/Translation\/\d+$/
},
box: [".row-cols-lg-5", 2],
imgs: async () => {
await fn.getNP(".row-cols-lg-5>*", "div[role=toolbar] a.disabled+a", null, "div[role=toolbar]");
let links = fn.gau(".row-cols-lg-5 a");
return fn.getImgA("main img", links, 100);
},
button: [4],
insertImg: ["box", 3],
customTitle: () => {
let eles = fn.gae(".release-title");
let text = eles.at(-1).innerText;
return fn.dt({
t: text
});
},
category: "hcomic"
}, {
name: "nhentai圖片清單頁",
url: {
h: [
"nhentai.net",
"www.hentai.name",
"nhentai.xxx",
"nhentai.to",
"nhentai.website",
"nhentai.jp.net",
"doujin.uk",
"nhentai.moe",
"nhentai.wtf",
"simplyhentai.org",
"simplyhentai.us",
"imhentai.to",
"ehentai.to"
],
p: /^\/g\/\d+\/?$/
},
imgs: async () => {
thumbnailSrcArray = fn.getImgSrcArr("a.gallerythumb>img");
if (fn.lh === "nhentai.net") {
let image_domain = "i1.nhentai.net";
let srcs = _unsafeWindow._gallery.images.pages.map((e, i) => `https://image_domain/galleries/${_unsafeWindow._gallery.media_id}/${i + 1}.${fn.ex(e.t)}`);
let hostArray = ["i.nhentai.net", "i5.nhentai.net", "i6.nhentai.net", "i7.nhentai.net", "i8.nhentai.net", "i9.nhentai.net", "i1.nhentai.net", "i2.nhentai.net", "i3.nhentai.net", "i4.nhentai.net"];
let code = fn.gst("image_cdn_urls");
if (code) {
hostArray = fn.TextToArray(code, "image_cdn_urls");
}
for (let host of hostArray.reverse()) {
fn.showMsg(DL.str_56 + "\n" + host, 0);
let src = srcs[0].replace("image_domain", host);
let status = await fn.xhrHEAD(src).then(res => res.status);
if (status == 200) {
image_domain = host;
break;
}
}
fn.hideMsg();
return srcs.map(e => e.replace("image_domain", image_domain));
} else if (fn.lh === "nhentai.xxx") {
fn.showMsg(DL.str_05, 0);
let [max] = fn.gt(".pages").match(/\d+/);
let img = fn.ge(".gallery_thumbs img");
let src = img.dataset.src ?? img.src;
let dir = fn.dir(src);
let url = fn.gu(".gallery_thumbs a");
let iframe = await fn.iframeVar(url, "g_th");
return fn.arr(max, (v, i) => `${dir}${(i + 1)}.${fn.ex(iframe.g_th.fl[(i + 1)][0])}`);
} else if (["nhentai.to", "nhentai.website", "nhentai.jp.net", "doujin.uk", "nhentai.moe", "nhentai.wtf", "simplyhentai.us", "imhentai.to", "ehentai.to"].some(h => fn.lh === h)) {
fn.showMsg(DL.str_05, 0);
let url = fn.gu("a.gallerythumb");
return fn.fetchDoc(url).then(dom => {
let code = fn.gst("reader", dom);
let s = code.indexOf('({') + 1;
let e = code.indexOf('});', s) + 1;
code = code.slice(s, e);
let json = fn.run(code);
let [src] = fn.getImgSrcArr(".gallerythumb img");
let dir = fn.dir(src);
return json.gallery.images.pages.map((e, i) => `${dir}${(i + 1)}.${fn.ex(e.t)}`);
});
} else if (fn.lh === "simplyhentai.org") {
return fn.gae(".thumbs img,.thumb-container img").map(e => e.dataset.src ? e.dataset.src.replace(/t(\.\w+)$/, "$1") : e.src.replace(/t(\.\w+)$/, "$1"));
} else if (fn.lh === "www.hentai.name") {
return fn.gae(".thumb-container img").map(e => e.src.replace(/_thumb(\.\w+)$/, "$1"));
}
},
button: [4],
insertImg: [".thumbs,#thumbnail-container,.outer_thumbs", 2],
customTitle: () => {
if (fn.lh === "nhentai.net") {
const {
_gallery
} = _unsafeWindow;
return _gallery.title.japanese ?? _gallery.title.english;
} else {
let h2 = fn.gt("h2.title,h2");
return h2.length > 4 ? h2 : fn.gt("h1.title,h1");
}
},
topButton: true,
hide: ".advt,ins[data-key]",
category: "hcomic"
}, {
name: "nhentai閱讀頁",
host: ["nhentai.net"],
reg: /^https?:\/\/nhentai\.net\/g\/\d+\/\d+\/$/,
init: () => fn.waitEle("#image-container img[src*='nhentai.net']"),
imgs: async () => {
const {
_gallery
} = _unsafeWindow;
let image_domain;
let srcs = _unsafeWindow._gallery.images.pages.map((e, i) => `https://image_domain/galleries/${_unsafeWindow._gallery.media_id}/${i + 1}.${fn.ex(e.t)}`);
let hostArray = ["i.nhentai.net", "i5.nhentai.net", "i6.nhentai.net", "i7.nhentai.net", "i8.nhentai.net", "i9.nhentai.net", "i1.nhentai.net", "i2.nhentai.net", "i3.nhentai.net", "i4.nhentai.net"];
let code = fn.gst("image_cdn_urls");
if (code) {
hostArray = fn.TextToArray(code, "image_cdn_urls");
}
for (let host of hostArray.reverse()) {
fn.showMsg(DL.str_56 + "\n" + host, 0);
let src = srcs[0].replace("image_domain", host);
let status = await fn.xhrHEAD(src).then(res => res.status);
if (status == 200) {
image_domain = host;
break;
}
}
fn.hideMsg();
return srcs.map(e => e.replace("image_domain", image_domain));
},
button: [4],
insertImg: ["#image-container", 2],
customTitle: () => {
const {
_gallery
} = _unsafeWindow;
return _gallery.title.japanese ?? _gallery.title.english;
},
category: "hcomic"
}, {
name: "www.hentai.name閱讀頁",
reg: /^https?:\/\/www\.hentai\.name\/g\/\d+\/\d+\/$/,
imgs: () => {
let max = fn.gt(".num-pages");
let src = fn.src("#image-container img");
let [, dir, ex] = src.match(/(.+\/)\d+(\.\w+)$/);
return fn.arr(max, (v, i) => `${dir}${(i + 1)}${ex}`);
},
button: [4],
insertImg: ["#image-container", 2],
customTitle: () => fn.title(" - Hentai.name"),
category: "hcomic"
}, {
name: "simplyhentai.org閱讀頁",
reg: /^https?:\/\/simplyhentai\.org\/g\/\d+\/\d+\/$/,
imgs: () => {
let max = fn.gt(".num-pages");
let src = fn.src("#image-container img");
let [, dir, ex] = src.match(/(.+\/)\d+(\.\w+)$/);
return fn.arr(max, (v, i) => `${dir}${(i + 1)}${ex}`);
},
button: [4],
insertImg: ["#image-container", 2],
customTitle: () => fn.title(" » ", 1),
category: "hcomic"
}, {
name: "Yabai!",
url: {
h: ["yabai.si"],
},
page: () => fn.clp("/g/"),
json: () => fn.showMsg(DL.str_05, 0).then(() => fn.fetchDoc(fn.clp()).then(dom => {
let pageData = JSON.parse(fn.ge("#app", dom).dataset.page);
let {
version
} = pageData;
let token = decodeURIComponent(fn.cookie("XSRF-TOKEN"));
let readApi = fn.curl() + "/read";
return fetch(readApi, {
"headers": {
"accept": "text/html, application/xhtml+xml",
"x-inertia": "true",
"x-inertia-version": version,
"x-requested-with": "XMLHttpRequest",
"x-xsrf-token": token
}
}).then(res => res.json()).then(json => (siteJson = json) && fn.hideMsg());
})),
SPA: () => _this.page() ? true : (siteJson = {}) && false,
observeURL: "gm",
init: () => _this.page() ? _this.json() : void 0,
imgs: () => {
if (!_this.page()) return [];
let {
code,
hash,
head,
rand,
root,
type
} = siteJson.props.pages.data.list;
let srcs = [];
head.forEach((e, i) => (srcs[Number(e) - 1] = `${root}/${code}/${e.padStart(4, "0")}-${hash[i]}-${rand[i]}.${type[i]}`));
return srcs;
},
button: [4],
insertImgBF: () => fn.waitEle(".grid img").then(() => fn.createImgBox(".article>:last-child", 2)),
insertImg: [
["box", 0], 2
],
customTitle: () => _this.page() ? siteJson.props.post.data.name : null,
category: "hcomic"
}, {
name: "akuma.moe",
reg: /^https?:\/\/akuma\.moe\/g\/\w+$/i,
init: () => fn.waitEle("#pages"),
imgs: async () => {
fn.showMsg(DL.str_05, 0);
const {
pag,
ajx
} = _unsafeWindow;
if (options.fancybox == 1 && !isDownloading) {
let pages = pag.cnt;
if (pages > 40) {
let max = Math.ceil(pages / 20);
let resArr = fn.arr(max, (v, i) => fetch(pag.act, {
"headers": {
"accept": "*/*",
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-csrf-token": ajx.hdr["X-CSRF-TOKEN"],
"x-requested-with": "XMLHttpRequest"
},
"body": `index=${i}`,
"method": "POST",
}).then(res => res.text()).then(text => fn.doc(text)).then(dom => [...dom.images]));
thumbnailSrcArray = await Promise.all(resArr).then(data => fn.getImgSrcArr(data.flat()));
} else {
thumbnailSrcArray = fn.getImgSrcArr("#pages img");
}
}
let url = fn.gu("#pages a");
let dir = await fn.iframeVar(url, "img_prt").then(w => w.img_prt + "/");
return fetch(siteUrl, {
"headers": {
"accept": "*/*",
"x-csrf-token": ajx.hdr["X-CSRF-TOKEN"],
"x-requested-with": "XMLHttpRequest"
},
"body": null,
"method": "POST"
}).then(res => res.json()).then(arr => arr.map(e => dir + e));
},
button: [4],
insertImg: [
["#pages", 0], 2
],
customTitle: () => fn.getText([".entry-header>span", ".entry-title"]),
category: "hcomic"
}, {
name: "3hentai/HentaiVox圖片清單頁",
host: ["3hentai.net", "hentaivox.com"],
reg: [
/^https?:\/\/(\w{2}\.)?3hentai\.net\/d\/\d+$/,
/^https?:\/\/hentaivox\.com\/view\/\d+$/
],
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr(".single-thumb>a>img");
fn.showMsg(DL.str_05, 0);
let url = fn.gu(".single-thumb>a");
return fn.fetchDoc(url).then(dom => {
let code = fn.gst("readerPages", dom);
let jsonCode = fn.stringSlicer(code, "readerPages =", "))");
return fn.run(jsonCode);
}).then(json => {
let max = json.lastPage;
let dir = json.baseUriImg.replace("%s", "");
return fn.arr(max, (v, i) => dir + json.pages[(i + 1)].f);
});
},
button: [4],
insertImg: ["#thumbnail-gallery,#gallery-pages", 2],
customTitle: () => fn.getText(["#main-info>h2", "#main-info>h1", "#gallery-main-info>h2", "#gallery-main-info>h1"]),
topButton: true,
category: "hcomic"
}, {
name: "3hentai/HentaiVox閱讀頁",
host: ["3hentai.net", "hentaivox.com"],
reg: [
/^https?:\/\/(\w{2}\.)?3hentai\.net\/d\/\d+\/\d+$/,
/^https?:\/\/hentaivox\.com\/view\/\d+\/\d+$/
],
imgs: () => {
const {
readerPages
} = _unsafeWindow;
let max = readerPages.lastPage;
let dir = readerPages.baseUriImg.replace("%s", "");
return fn.arr(max, (v, i) => dir + readerPages.pages[(i + 1)].f);
},
button: [4],
insertImg: [".reader-image,.gallery-reader-img", 2],
customTitle: () => fn.dt({
d: / - Page.+$/
}),
category: "hcomic"
}, {
name: "9Hentai",
host: ["9hentai.so"],
reg: /^https:\/\/9hentai\.so\/g\/\d+\//,
imgs: async () => {
let [, , id] = fn.lp.split("/");
let data = {
id
};
let json = await fetch("/api/getBookByID", {
method: "POST",
body: JSON.stringify(data),
headers: {
"Content-Type": "application/json",
}
}).then(res => res.json());
let {
total_page,
image_server,
title
} = json.results;
apiCustomTitle = title;
thumbnailSrcArray = fn.arr(total_page, (v, i) => image_server + id + "/preview/" + (i + 1) + "t.jpg");
return fn.arr(total_page, (v, i) => image_server + id + "/" + (i + 1) + ".jpg");
},
capture: () => _this.imgs(),
category: "hcomic"
}, {
name: "HentaiFox圖片清單頁",
host: ["hentaifox.com"],
reg: /^https?:\/\/hentaifox\.com\/gallery\/\d+\/$/,
include: "//a[text()=' Read Online']",
init: () => fn.wait((_, win) => !!ge(".gallery_thumb img") && ("g_th" in win)),
box: [".gallery_bottom"],
imgs: async () => {
fn.showMsg(DL.str_05, 0);
let u_id = fn.ge("#gallery_id").value;
let g_id = fn.ge("#load_id").value;
let img_dir = fn.ge("#load_dir").value;
let total_pages = fn.ge("#load_pages").value;
thumbnailSrcArray = await fn.fetchDoc("/includes/thumbs_loader.php", {
"headers": {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-requested-with": "XMLHttpRequest"
},
"body": `u_id=${u_id}&g_id=${g_id}&img_dir=${img_dir}&visible_pages=0&total_pages=${total_pages}&type=2`,
"method": "POST"
}).then(dom => [...dom.images].map(e => e.dataset.src ?? e.src));
let [max] = fn.gt(".pages").match(/\d+/);
let img = fn.ge(".gallery_thumb img");
let src = img.dataset.src ?? img.src;
let dir = fn.dir(src);
return fn.arr(max, (v, i) => `${dir}${(i + 1)}.${fn.ex(_unsafeWindow.g_th[(i + 1)][0])}`);
},
button: [4],
insertImg: ["box", 2],
customTitle: () => fn.gt(".info>h1").replace("|", "-"),
topButton: true,
category: "hcomic"
}, {
name: "HentaiFox閱讀頁",
host: ["hentaifox.com"],
reg: /^https?:\/\/hentaifox\.com\/g\/\d+\/\d+\/$/,
init: () => fn.wait((_, win) => !!ge("#gimg") && ("g_th" in win)),
imgs: () => {
let max = fn.ge("#pages").value;
let img = fn.ge("#gimg");
let src = img.dataset.src ?? img.src;
let dir = fn.dir(src);
return fn.arr(max, (v, i) => `${dir}${(i + 1)}.${fn.ex(_unsafeWindow.g_th[(i + 1)][0])}`);
},
button: [4],
insertImg: [".full_image", 2],
customTitle: () => fn.title(/ - Page \d+ - HentaiFox/).replace("|", "-"),
category: "hcomic"
}, {
name: "HentaiClap圖片清單頁",
host: ["hentaiclap.com"],
reg: /^https?:\/\/hentaiclap\.com\/gallery\/\d+\/$/,
include: ".read_online",
init: () => fn.wait((_, win) => !!ge(".gb_thumb img") && ("g_th" in win)),
box: [".gallery_bottom"],
imgs: async () => {
fn.showMsg(DL.str_05, 0);
let u_id = fn.ge("#gallery_id").value;
let g_id = fn.ge("#load_id").value;
let img_dir = fn.ge("#load_dir").value;
let total_pages = fn.ge("#load_pages").value;
thumbnailSrcArray = await fn.fetchDoc("/inc/thumbs_loader.php", {
"headers": {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-requested-with": "XMLHttpRequest"
},
"body": `u_id=${u_id}&g_id=${g_id}&img_dir=${img_dir}&visible_pages=0&total_pages=${total_pages}&type=2`,
"method": "POST"
}).then(dom => [...dom.images].map(e => e.dataset.src ?? e.src));
let [max] = fn.gt(".pages").match(/\d+/);
let img = fn.ge(".gb_thumb img");
let src = img.dataset.src ?? img.src;
let dir = fn.dir(src);
return fn.arr(max, (v, i) => `${dir}${(i + 1)}.${fn.ex(_unsafeWindow.g_th[(i + 1)][0])}`);
},
button: [4],
insertImg: ["box", 2],
customTitle: () => fn.gt(".gt_right h1").replace("|", "-"),
category: "hcomic"
}, {
name: "HentaiClap閱讀頁",
host: ["hentaiclap.com"],
reg: /^https?:\/\/hentaiclap\.com\/read\/\d+\/\d+\/$/,
init: () => fn.wait((_, win) => !!ge("#fimg") && ("g_th" in win)),
box: [".reader_back", 1],
imgs: () => {
let max = fn.ge("#pages").value;
let img = fn.ge("#fimg");
let src = img.dataset.src ?? img.src;
let dir = fn.dir(src);
return fn.arr(max, (v, i) => `${dir}${(i + 1)}.${fn.ex(_unsafeWindow.g_th[(i + 1)][0])}`);
},
button: [4],
insertImg: ["box", 2],
insertImgAF: () => fn.hideEle(".reader_top,.reader_middle,.reader_bottom"),
customTitle: () => fn.gt(".reader_title").replace("|", "-"),
category: "hcomic"
}, {
name: "HentaiForce圖片清單頁",
host: ["hentaiforce.net"],
reg: /^https?:\/\/hentaiforce\.net\/view\/\d+$/,
init: () => {
let url = fn.gu(".single-thumb a");
return fn.fetchDoc(url).then(dom => {
let code = fn.gst("readerPages", dom);
let s = code.indexOf("JSON");
let e = code.lastIndexOf(";");
siteJson = fn.run(code.slice(s, e));
});
},
imgs: () => fn.arr(siteJson.lastPage).map((v, i) => siteJson.baseUriImg.replace("%c", siteJson.pages[i + 1].l).replace('%s', siteJson.pages[i + 1].f)),
thums: ".single-thumb img",
button: [4],
insertImg: ["#gallery-pages", 2],
customTitle: () => fn.dt({
t: siteJson.title,
d: / - Page.+$/
}),
category: "hcomic"
}, {
name: "HentaiForce閱讀頁",
host: ["hentaiforce.net"],
reg: /^https?:\/\/hentaiforce\.net\/view\/\d+\/\d+$/,
box: [".gallery-reader-img", 2],
imgs: () => {
let {
readerPages: {
lastPage,
baseUriImg,
pages
}
} = unsafeWindow;
return fn.arr(lastPage).map((v, i) => baseUriImg.replace("%c", pages[i + 1].l).replace('%s', pages[i + 1].f));
},
button: [4],
insertImg: [
["box", 0, ".gallery-reader-img"], 2
],
customTitle: () => fn.dt({
t: unsafeWindow.readerPages.title,
d: / - Page.+$/
}),
category: "hcomic"
}, {
name: "HenTalk",
url: {
h: ["hentalk.pw"]
},
page: () => fn.clp(/^\/g\/\d+$/),
SPA: () => _this.page(),
observeURL: "head",
data: () => fetch(`${fn.clp()}/__data.json?x-sveltekit-trailing-slash=1&x-sveltekit-invalidated=001`).then(res => res.json()).then(json => {
let data = json.nodes[2].data;
let gallery = data?.[data.find((e) => e?.gallery)?.gallery];
let slug = data?.[gallery?.hash] || data?.[data.find((e) => e?.hash && e?.id).hash];
let images = data?.[gallery.images].map((i) => data[i]).map((i) => data[i.filename]);
siteJson = {
data,
gallery,
slug,
images
};
}),
init: () => _this.page() ? _this.data() : void 0,
imgs: () => _this.page() ? siteJson.images.map(e => `https://hentalk.pw/image/${siteJson.slug}/${e}`) : [],
capture: () => _this.imgs(),
customTitle: () => _this.page() ? siteJson.data[siteJson.gallery.title] : null,
category: "hcomic"
}, {
name: "APE XXX圖片清單頁",
host: ["ape.su"],
reg: /^https?:\/\/ape\.su\/\d+\/$/,
include: "#append_thumbs",
box: ["#comments_div"],
imgs: async () => {
fn.showMsg(DL.str_05, 0);
let server = fn.ge("#load_server").value;
let u_id = fn.ge("#gallery_id").value;
let g_id = fn.ge("#load_id").value;
let g_ch = fn.ge("#gallery_ch").value;
let img_dir = fn.ge("#load_dir").value;
let total_pages = fn.ge("#load_pages").value;
thumbnailSrcArray = await fn.fetchDoc("/thumbs_loader", {
"headers": {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-requested-with": "XMLHttpRequest"
},
"body": `server=${server}&u_id=${u_id}&g_id=${g_id}&g_ch=${g_ch}&img_dir=${img_dir}&visible_pages=0&total_pages=${total_pages}&type=2`,
"method": "POST"
}).then(dom => [...dom.images].map(e => e.dataset.src ?? e.src));
return thumbnailSrcArray.map(e => e.replace(/-\d+x\d+\./, "."));
},
button: [4],
insertImg: ["box", 2],
customTitle: ".right_details h1",
hide: "div:has(>iframe)",
category: "hcomic"
}, {
name: "HentaiZap圖片清單頁",
host: ["hentaizap.com"],
reg: /^https?:\/\/hentaizap\.com\/gallery\/\d+\/$/,
init: () => fn.wait((_, win) => !!ge(".gp_th img") && ("g_th" in win)),
box: ["#comments_div"],
imgs: async () => {
fn.showMsg(DL.str_05, 0);
let _token = fn.attr('meta[name="csrf-token"]', "content");
let server = fn.ge("#load_server").value;
let u_id = fn.ge("#gallery_id").value;
let g_id = fn.ge("#load_id").value;
let img_dir = fn.ge("#load_dir").value;
let total_pages = fn.ge("#load_pages").value;
thumbnailSrcArray = await fn.fetchDoc("/inc/thumbs_loader.php", {
"headers": {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-requested-with": "XMLHttpRequest"
},
"body": `_token=${_token}&server=${server}&u_id=${u_id}&g_id=${g_id}&img_dir=${img_dir}&visible_pages=0&total_pages=${total_pages}&type=2`,
"method": "POST"
}).then(dom => [...dom.images].map(e => e.dataset.src ?? e.src));
let [max] = fn.gt(".info_pg").match(/\d+/);
let img = fn.ge(".gp_th img");
let src = img.dataset.src ?? img.src;
let dir = fn.dir(src);
return fn.arr(max, (v, i) => `${dir}${(i + 1)}.${fn.ex(_unsafeWindow.g_th[(i + 1)][0])}`);
},
button: [4],
insertImg: [
["box", 0], 2
],
customTitle: () => fn.gt(".gp_top_right>h1").replace("|", "-"),
category: "hcomic"
}, {
name: "HentaiZap閱讀頁",
host: ["hentaizap.com"],
reg: /^https?:\/\/hentaizap\.com\/g\/\d+\/\d+\/$/,
init: () => fn.waitVar("g_th"),
imgs: async () => {
let max = fn.ge("#pages").value;
let img = fn.ge("#fimg");
let src = img.dataset.src ?? img.src;
let dir = fn.dir(src);
return fn.arr(max, (v, i) => `${dir}${(i + 1)}.${fn.ex(_unsafeWindow.g_th[(i + 1)][0])}`);
},
button: [4],
insertImg: [".mid_rd", 2],
customTitle: () => fn.title(/ - Page \d+ - HentaiZap/).replace("|", "-"),
category: "hcomic"
}, {
name: "HentaiRead圖片清單頁",
url: {
h: "hentairead.com",
p: "/hentai/",
e: "//span[text()='Read Now']"
},
box: [".main-container:has(.chapter-image-item)", 2],
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr(".chapter-image-item img");
return thumbnailSrcArray.map(e => e.replace("hencover.xyz", "henread.xyz").replace("preview/", ""));
},
button: [4],
insertImg: ["box", 2],
customTitle: () => fn.getText([".manga-titles h2", ".manga-titles h1"]),
category: "hcomic"
}, {
name: "HentaiRox圖片清單頁",
host: ["HentaiRox.com"],
reg: /^https?:\/\/hentairox\.com\/gallery\/\d+\/$/,
include: "#append_thumbs",
init: () => fn.showMsg(DL.str_04, 0).then(() => fn.waitEle("#append_thumbs img").then(() => fn.hideMsg())),
box: ["#comments_div"],
imgs: async () => {
fn.showMsg(DL.str_05, 0);
let server = fn.ge("#load_server").value;
let u_id = fn.ge("#gallery_id").value;
let g_id = fn.ge("#load_id").value;
let img_dir = fn.ge("#load_dir").value;
let total_pages = fn.ge("#load_pages").value;
thumbnailSrcArray = await fn.fetchDoc("/inc/thumbs_loader.php", {
"headers": {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-requested-with": "XMLHttpRequest"
},
"body": `server=${server}&u_id=${u_id}&g_id=${g_id}&img_dir=${img_dir}&visible_pages=0&total_pages=${total_pages}&type=2`,
"method": "POST"
}).then(dom => [...dom.images].map(e => e.dataset.src ?? e.src));
let [max] = fn.gt(".pages").match(/\d+/);
let img = fn.ge(".gthumb img");
let src = img.dataset.src ?? img.src;
let dir = fn.dir(src);
return fn.arr(max, (v, i) => `${dir}${(i + 1)}.${fn.ex(_unsafeWindow.g_th[(i + 1)][0])}`);
},
button: [4],
insertImg: ["box", 2],
customTitle: () => fn.getText([".subtitle", "h1"]),
topButton: true,
category: "hcomic"
}, {
name: "HentaiRox閱讀頁",
host: ["HentaiRox.com"],
reg: /^https?:\/\/hentairox\.com\/view\/\d+\/\d+\/$/,
imgs: async () => {
let max = fn.ge("#pages").value;
let img = fn.ge("#gimg");
let src = img.dataset.src ?? img.src;
let dir = fn.dir(src);
return fn.arr(max, (v, i) => `${dir}${(i + 1)}.${fn.ex(_unsafeWindow.g_th[(i + 1)][0])}`);
},
button: [4],
insertImg: [".pre_img", 2],
customTitle: () => fn.title(/ - Page \d+ - HentaiRox/).replace("|", "-"),
css: ".pre_img{max-height:unset!important}",
category: "hcomic"
}, {
name: "HentaiEnvy圖片清單頁",
host: ["www.hentaienvy.com", "hentaienvy.com"],
reg: /^https?:\/\/(www\.)?hentaienvy\.com\/gallery\/\d+\/$/,
include: ".gallery_thumbs",
init: () => fn.showMsg(DL.str_04, 0).then(() => fn.waitEle("#thumbs_box img").then(() => fn.hideMsg())),
box: [".gallery_thumbs", 0],
imgs: async () => {
fn.showMsg(DL.str_05, 0);
let _token = fn.attr('meta[name="csrf-token"]', "content");
let server = fn.ge("#load_server").value;
let u_id = fn.ge("#gallery_id").value;
let g_id = fn.ge("#load_id").value;
let img_dir = fn.ge("#load_dir").value;
let total_pages = fn.ge("#load_pages").value;
thumbnailSrcArray = await fn.fetchDoc("/inc/thumbs_loader.php", {
"headers": {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-requested-with": "XMLHttpRequest"
},
"body": `_token=${_token}&server=${server}&u_id=${u_id}&g_id=${g_id}&img_dir=${img_dir}&visible_pages=0&total_pages=${total_pages}&type=2`,
"method": "POST"
}).then(dom => [...dom.images].map(e => e.dataset.src ?? e.src));
let [max] = fn.gt("//ul[span[text()='Pages:']]").match(/\d+/);
let img = fn.ge(".th_gp img");
let src = img.dataset.src ?? img.src;
let dir = fn.dir(src);
await fn.waitVar("g_th");
return fn.arr(max, (v, i) => `${dir}${(i + 1)}.${fn.ex(_unsafeWindow.g_th[(i + 1)][0])}`);
},
button: [4],
insertImg: ["box", 2],
customTitle: () => fn.getText([".subtitle", "h1"]),
topButton: true,
category: "hcomic"
}, {
name: "HentaiEnvy閱讀頁",
host: ["www.hentaienvy.com", "hentaienvy.com"],
reg: /^https?:\/\/(www\.)?hentaienvy\.com\/g\/\d+\/\d+\/$/,
imgs: async () => {
await fn.waitVar("g_th");
let max = fn.ge("#pages").value;
let img = fn.ge("#fimg");
let src = img.dataset.src ?? img.src;
let dir = fn.dir(src);
return fn.arr(max, (v, i) => `${dir}${(i + 1)}.${fn.ex(_unsafeWindow.g_th[(i + 1)][0])}`);
},
button: [4],
insertImg: [".rd_fimg", 2],
customTitle: () => fn.title(/ - Page \d+ - HentaiEnvy/).replace("|", "-"),
css: ".rd_fimg{width:auto!important;max-height:unset!important}",
category: "hcomic"
}, {
name: "lhentai.com圖片清單頁",
host: ["lhentai.com"],
reg: /^https?:\/\/lhentai\.com\/g\/\d+$/,
imgs: async () => {
thumbnailSrcArray = fn.getImgSrcArr(".gallerythumb img");
fn.showMsg(DL.str_05, 0);
let url = fn.gu("a.gallerythumb");
let dom = await fn.fetchDoc(url);
let code = fn.gst("images_ext", dom);
let images_ext = fn.TextToArray(code, "images_ext");
let post_url = fn.textVar(code, "post_url");
return images_ext.map((e, i) => `${post_url}${(i + 1)}.${fn.ex(e)}`);
},
button: [4],
insertImg: [".thumbs", 2],
customTitle: () => fn.getText(["#info>h2", "#info>h1"]),
category: "hcomic"
}, {
name: "lhentai.com閱讀頁",
host: ["lhentai.com"],
reg: /^https?:\/\/lhentai\.com\/g\/\d+\/\d+\/?$/,
imgs: () => {
let src = fn.src(".fit-horizontal");
let dir = fn.dir(src);
return _unsafeWindow.images_ext.map((e, i) => `${dir}${(i + 1)}.${fn.ex(e)}`);
},
button: [4],
insertImg: ["#page-container", 2],
category: "hcomic"
}, {
name: "EAHentai",
url: {
h: ["eahentai.com"]
},
page: () => fn.clp("/a/"),
json: () => fn.showMsg(DL.str_05, 0).then(() => fn.clp().split("/").at(-1)).then(id => fetch(`/api/image/album/${id}`).then(res => res.json()).then(arr => (siteJson = arr[0]) && fn.hideMsg())),
SPA: () => _this.page(),
observeURL: "head",
init: () => _this.page() ? _this.json() : void 0,
imgs: () => {
if (!_this.page()) return [];
let cdn = "https://i.eahentai.com/file/ea-gallery/";
return siteJson.images.map(({
thumbnailUri,
imageUri
}) => {
thumbnailSrcArray.push(cdn + thumbnailUri);
return cdn + imageUri;
});
},
button: [4],
insertImgBF: () => fn.waitEle(".gallery-img"),
insertImg: [".gallery-container", 2],
customTitle: () => _this.page() ? siteJson.title : null,
category: "hcomic"
}, {
name: "Fhentai圖片清單頁",
url: {
h: "fhentai.net",
p: "/f/"
},
imgs: async () => {
thumbnailSrcArray = fn.getImgSrcArr(".rounded-md:has(>.grid) img");
return thumbnailSrcArray.map(e => e.replace("/thumb/", "/raw/"));
},
button: [4],
insertImg: [".rounded-md:has(>.grid)", 2],
customTitle: "main h1",
category: "hcomic"
}, {
name: "Fhentai閱讀頁",
url: {
h: "fhentai.net",
p: "/read/"
},
imgs: "main .rounded-md img",
button: [4],
insertImg: ["main .rounded-md", 2],
customTitle: "main h1",
category: "hcomic"
}, {
name: "M-Hentai圖片清單頁",
host: ["m-hentai.net"],
reg: /^https?:\/\/m-hentai\.net\/gallery\?id=\d+$/,
imgs: async () => {
thumbnailSrcArray = fn.getImgSrcArr(".bookthumbnail .lazyloadimage");
fn.showMsg(DL.str_05, 0);
let url = fn.gu(".bookthumbnail>a");
return fn.iframeVar(url, "displayimagelist").then(w => w.displayimagelist.map(e => e.image_url));
},
button: [4],
insertImg: [".bookthumbnailcontainer", 2],
customTitle: () => fn.getText([".gallerysubtitle", ".gallerytitle"]),
category: "hcomic"
}, {
name: "M-Hentai閱讀頁",
host: ["m-hentai.net"],
reg: /^https?:\/\/m-hentai\.net\/read\?index=\d+/,
imgs: () => _unsafeWindow.displayimagelist.map(e => e.image_url),
button: [4],
insertImg: [".imagereadercontainer", 2],
insertImgAF: () => fn.run("$(document).off()"),
customTitle: () => fn.title(/ - Page .+/),
category: "hcomic"
}, {
name: "HentaiNexus圖片清單頁",
host: ["hentainexus.com"],
reg: /^https?:\/\/hentainexus\.com\/view\/\d+$/,
imgs: async () => {
thumbnailSrcArray = fn.getImgSrcArr(".card-image img");
fn.showMsg(DL.str_05, 0);
let url = fn.gu("//a[div[@class='card']]");
return fn.iframe(url, {
waitVar: "pageData",
cb: async (_, frame) => {
await fn.wait(() => isArray(frame.pageData));
}
}).then(async (object) => {
const {
frame
} = object;
let CDN_Srcs = frame.pageData.map(e => e.image);
let siteSrcs = CDN_Srcs.map(e => e.replace(/i\d\.wp\.com\/|\?filter=null/g, ""));
fn.showMsg(DL.str_56, 0);
let status = await fn.xhrHEAD(siteSrcs[0]).then(res => res.status);
fn.hideMsg();
return status === 200 ? siteSrcs : CDN_Srcs;
});
},
button: [4],
insertImg: [".container .box:has(.card-image)", 2],
customTitle: ".title",
category: "hcomic"
}, {
name: "HentaiNexus閱讀頁",
host: ["hentainexus.com"],
reg: /^https?:\/\/hentainexus\.com\/read\/\d+/,
imgs: async () => {
let CDN_Srcs = _unsafeWindow.pageData.map(e => e.image);
let siteSrcs = CDN_Srcs.map(e => e.replace(/i\d\.wp\.com\/|\?filter=null/g, ""));
fn.showMsg(DL.str_56, 0);
let status = await fn.xhrHEAD(siteSrcs[0]).then(res => res.status);
return status === 200 ? siteSrcs : CDN_Srcs;
},
button: [4],
insertImg: ["#pageChangeSnap", 2],
customTitle: () => _unsafeWindow.baseTitle.replace(" :: HentaiNexus", ""),
category: "hcomic"
}, {
name: "HentaiLoop圖片清單頁",
host: ["hentailoop.com"],
reg: /^https?:\/\/hentailoop\.com\/manga\/[^\/]+\/$/,
box: [".preview", 2],
imgs: async () => {
fn.showMsg(DL.str_05, 0);
thumbnailSrcArray = await fetch("/wp-admin/admin-ajax.php", {
"headers": {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-requested-with": "XMLHttpRequest"
},
"body": `action=loadpreviews&postID=${_unsafeWindow.ajaxData.postID}`,
"method": "POST"
}).then(res => res.text()).then(text => fn.doc(text)).then(dom => [...dom.images].map(e => e.src));
let url = fn.gu(".previews>a");
return fn.iframeVar(url, "ajax").then(w => {
let html = w.ajax.pages.join("");
let dom = fn.doc(html);
return [...dom.images].map(e => e.dataset.src ?? e.src);
});
},
button: [4],
insertImg: ["box", 2],
customTitle: "//meta[@content='4']/preceding-sibling::span[1]",
category: "hcomic"
}, {
name: "HentaiLoop閱讀頁",
host: ["hentailoop.com"],
reg: /^https?:\/\/hentailoop\.com\/manga\/[^\/]+\/read/,
box: [".manga-read-wrapp", 2],
imgs: () => {
let html = _unsafeWindow.ajax.pages.join("");
let dom = fn.doc(html);
return [...dom.images].map(e => e.dataset.src ?? e.src);
},
button: [4],
insertImg: [
["box", 0, ".manga-read-buttons,.manga-read-wrapp"], 2
],
customTitle: () => fn.title(/Page \d+ of | - Hentai.+|\(by[\w\s]+\)/ig).trim(),
category: "hcomic"
}, {
name: "nhentai.xxx閱讀頁",
host: ["nhentai.xxx"],
reg: /^https?:\/\/nhentai\.xxx\/g\/\d+\/\d+\/$/,
imgs: async () => {
await fn.waitVar("g_th");
let img = fn.ge("#fimg");
let src = img.dataset.src ?? img.src;
let dir = fn.dir(src);
let max = fn.ge("#pages").value;
return fn.arr(max, (v, i) => `${dir}${(i + 1)}.${fn.ex(_unsafeWindow.g_th.fl[(i + 1)][0])}`);
},
button: [4],
insertImg: [".reader_overlay", 2],
category: "hcomic"
}, {
name: "nhentai/simplyhentai閱讀頁",
url: {
h: ["nhentai.to", "nhentai.website", "nhentai.jp.net", "doujin.uk", "nhentai.moe", "nhentai.wtf", "simplyhentai.us", "imhentai.to", "ehentai.to"],
p: /^\/g\/\d+\/\d+\/?$/
},
init: () => fn.fetchDoc(fn.lp).then(dom => {
let code = fn.gst("reader", dom);
let s = code.indexOf('({') + 1;
let e = code.indexOf('});', s) + 1;
code = code.slice(s, e);
siteJson = fn.run(code);
}),
imgs: () => {
const {
gallery
} = siteJson;
let src = fn.src("#image-container img");
let dir = fn.dir(src);
return gallery.images.pages.map((e, i) => `${dir}${(i + 1)}.${fn.ex(e.t)}`);
},
button: [4],
insertImg: ["#image-container", 2],
customTitle: () => {
const {
gallery
} = siteJson;
return gallery.title.japanese ?? gallery.title.english;
},
hide: "ins[data-key]",
category: "hcomic"
}, {
name: "The Hentai圖片清單頁",
url: {
h: "thehentai.net",
p: /^\/[^\/]+\/$/
},
init: () => fn.waitVar("imagensbg"),
imgs: () => {
thumbnailSrcArray = _unsafeWindow.imagensbg;
return thumbnailSrcArray.map(e => fn.lo + e.replace("-300x400.", "."));
},
button: [4],
insertImg: [".post_imgs", 2],
autoDownload: [0],
next: () => {
let next = fn.ge(".select option[selected]+option");
return next ? next.value : null;
},
prev: 1,
customTitle: () => fn.title(/\s-\s[^-]+\s-\s[^-]+$/),
category: "hcomic"
}, {
name: "MangaHen圖片清單頁",
host: ["manga-hen.com"],
reg: /^https?:\/\/manga-hen\.com\/manga\/[\w-]+\/$/,
box: [".rounded-lg", 2],
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr(".img-thumb img,.lazy-img-thumb img");
fn.showMsg(DL.str_05, 0);
return fn.xhrDoc(fn.gu(".img-thumb>a"), {
cookie: "reader_mode=1"
}).then(dom => fn.gae(".justify-between~img[data-src]", dom));
},
button: [4],
insertImg: ["box", 2],
customTitle: "h1[class^=text]",
category: "hcomic"
}, {
name: "TMOHentai圖片清單頁",
host: ["tmohentai.com"],
reg: /^https?:\/\/tmohentai\.com\/contents\/\w+$/i,
imgs: async () => {
await fn.waitEle("div[style*='background']");
let div = fn.ge("div[style*='background']");
let [, src] = div.style.background.split('"');
let dir = fn.dir(src);
let max = fn.gae("div[style*='background']").length;
return fn.arr(max, (v, i) => dir + String(i).padStart(3, "0") + ".webp");
},
button: [4],
insertImg: [".panel-body:has(.well)", 2],
customTitle: ".panel-title h3",
category: "hcomic"
}, {
name: "TMOHentai閱讀頁",
host: ["tmohentai.com"],
reg: /^https?:\/\/tmohentai\.com\/reader\/\w+\/paginated\//i,
imgs: async () => {
await fn.waitEle("img.content-image");
let img = fn.ge("img.content-image");
let src = img.dataset.original ?? img.src;
let dir = fn.dir(src);
let max = fn.gae("#select-page option").length;
return fn.arr(max, (v, i) => dir + String(i).padStart(3, "0") + ".webp");
},
button: [4],
insertImg: [".reader-info+.text-center", 2],
customTitle: ".reader-title",
category: "hcomic"
}, {
name: "Download Doujin",
host: ["cin.cx", "cin.mom"],
url: {
h: "cin",
p: /^\/v\/\d+$/
},
checkStatus: async (src) => {
let host = new URL(src).host;
let hosts = ["a", "b", "c", "d", "e", "f", "g"].map(e => host.replace(/^[a-g]/i, e));
let cs = hosts.map(h => src.replace(host, h));
for (let url of cs) {
let status;
try {
let res = await fetch(url, {
method: "HEAD"
});
status = res.status;
} catch {
status = 503;
}
if (status == 200) {
return url;
}
}
return src;
},
imgs: async () => {
fn.showMsg(DL.str_05, 0);
let json = JSON.parse(fn.gt("#__NEXT_DATA__"));
let srcs;
if (json?.props?.pageProps?.data) {
let {
images: {
pages
},
title: {
english,
japanese,
pretty
}
} = json.props.pageProps.data;
srcs = pages.map(e => e.t);
customTitle = japanese ?? english ?? pretty;
} else {
let id = json.query.id;
srcs = await fetch("https://same.yui.pw/api/v6/book/" + id).then(res => res.json()).then(json => {
let {
images: {
pages
},
title: {
english,
japanese,
pretty
}
} = json;
customTitle = japanese ?? english ?? pretty;
return pages.map(e => e.t);
});
}
let fetchNum = 0;
return srcs.map(async (src, i, arr) => {
await delay(i * 500);
src = await _this.checkStatus(src);
return fetch(src).then(res => res.blob()).then(blob => {
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${arr.length}`, 0);
return URL.createObjectURL(blob);
});
});
},
gallery: 1,
category: "hcomic"
}, {
name: "Pururin圖片清單頁",
host: ["pururin.me"],
reg: /^https?:\/\/pururin\.me\/gallery\/\d+\/.+/,
box: [".box:has(.gallery-preview)", 2],
imgs: () => {
let url = fn.gu(".gallery-preview>a");
return fn.fetchDoc(url).then(dom => {
let ele = fn.ge(".img-viewer", dom);
let svr = ele.dataset.svr;
let data = JSON.parse(ele.dataset.img);
let arr = data.images.sort((a, b) => a.page - b.page);
arr = arr.map(e => svr + "/" + data.directory + "/" + e.filename);
thumbnailSrcArray = arr.map(e => e.replace(/(\.\w+)$/, "t$1"));
return arr;
});
},
button: [4],
insertImg: ["box", 2],
endColor: "white",
insertImgAF: () => {
setTimeout(() => {
fn.css(FullPictureLoadStyle, "FullPictureLoadMainStyle");
if (siteData.key != 0 && !isAddKeyEvent) {
document.addEventListener("keydown", addKeyEvent);
isAddKeyEvent = true;
}
if (options.icon == 1 || siteData.icon == 1) addFullPictureLoadButton();
if (isPC && ShowFullPictureLoadFixedMenu === 1) addFullPictureLoadFixedMenu();
}, 1000);
},
customTitle: () => fn.ge("[placeholder=Japanese]")?.value || fn.ge("[placeholder='Alternative names']")?.value,
category: "hcomic"
}, {
name: "Pururin閱讀頁",
host: ["pururin.me"],
reg: /^https?:\/\/pururin\.me\/read\/\d+\/\d+\/.+/,
imgs: () => {
let ele = fn.ge(".img-viewer");
let svr = ele.dataset.svr;
let data = JSON.parse(ele.dataset.img);
//按頁數排列
let arr = data.images.sort((a, b) => a.page - b.page);
arr = arr.map(e => svr + "/" + data.directory + "/" + e.filename);
thumbnailSrcArray = arr.map(e => e.replace(/(\.\w+)$/, "t$1"));
return arr;
},
button: [4],
insertImg: [".img-viewer", 2],
endColor: "white",
customTitle: () => fn.ge("[placeholder=Japanese]")?.value || fn.ge("[placeholder='Alternative names']")?.value,
css: ".box.img-reader .img-viewer{position:unset!important;white-space:unset!important}",
category: "hcomic"
}, {
name: "Manga Mischief圖片清單頁",
url: {
h: ["xmanga.org"],
},
page: () => fn.clp("/album/"),
json: () => fn.showMsg(DL.str_05, 0).then(() => fn.clp().split("/").at(2)).then(id => fetch(`https://mangamischief.com/backend/image?albumId=${id}`).then(res => res.json()).then(json => (siteJson = json) && fn.hideMsg())),
SPA: () => _this.page() ? true : (siteJson = {}) && false,
observeURL: "head",
init: () => _this.page() ? _this.json().then(() => fn.waitEle(["div:has(>.max-w-gallery) img", "h1.text-lg"])) : void 0,
imgs: () => _this.page() ? siteJson.data.map(e => e.url) : [],
button: [4],
insertImg: ["div:has(>.max-w-gallery)", 2],
endColor: "white",
customTitle: "h1.text-lg",
category: "hcomic"
}, {
name: "AsmHentai圖片清單頁",
host: ["asmhentai.com"],
reg: /^https?:\/\/asmhentai\.com\/g\/\d+\/$/,
box: [".gallery"],
imgs: async () => {
if (fn.ge("#load_id")) {
fn.showMsg(DL.str_05, 0);
let _token = fn.attr('meta[name="csrf-token"]', "content");
let id = fn.ge("#load_id").value;
let dir = fn.ge("#load_dir").value;
let t_pages = fn.ge("#t_pages").value;
thumbnailSrcArray = await fn.fetchDoc("/inc/thumbs_loader.php", {
"headers": {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-requested-with": "XMLHttpRequest"
},
"body": `_token=${_token}&id=${id}&dir=${dir}&visible_pages=0&t_pages=${t_pages}&type=2`,
"method": "POST"
}).then(dom => [...dom.images].map(e => e.dataset.src ?? e.src));
} else {
thumbnailSrcArray = fn.getImgSrcArr("#append_thumbs img");
}
return thumbnailSrcArray.map(e => e.replace("t.", "."));
},
button: [4],
insertImg: ["box", 2],
endColor: "white",
customTitle: () => fn.getText([".info>h2", ".info>h1"]),
category: "hcomic"
}, {
name: "AsmHentai閱讀頁",
host: ["asmhentai.com"],
reg: /^https?:\/\/asmhentai\.com\/gallery\/\d+\/\d+\/$/,
imgs: async () => {
fn.showMsg(DL.str_05, 0);
let _token = fn.attr('meta[name="csrf-token"]', "content");
let id = fn.ge("#gallery_id").value;
let dir = fn.ge("#image_dir").value;
let t_pages = fn.ge("#pages").value;
thumbnailSrcArray = await fn.fetchDoc("/inc/thumbs_loader.php", {
"headers": {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-requested-with": "XMLHttpRequest"
},
"body": `_token=${_token}&id=${id}&dir=${dir}&visible_pages=0&t_pages=${t_pages}&type=2`,
"method": "POST"
}).then(dom => [...dom.images].map(e => e.dataset.src ?? e.src));
return thumbnailSrcArray.map(e => e.replace("t.", "."));
},
button: [4],
insertImg: [".rd_fimg", 2],
endColor: "white",
customTitle: () => fn.title(" Page", 1),
css: ".preloader{text-indent:unset !important}",
category: "hcomic"
}, {
name: "MultPorn閱讀頁",
url: {
h: "multporn.net",
st: "configUrl"
},
imgs: () => {
fn.showMsg(DL.str_05, 0);
let code = fn.gst("configUrl")
let [, url] = code.match(/configUrl":"([^"]+)/);
url = url.replaceAll("\\", "");
return fetch(url).then(res => res.text()).then(text => {
let xml = fn.xml(text);
let imgs = fn.gae("image", xml);
thumbnailSrcArray = imgs.map(e => e.getAttribute("thumbURL"));
return imgs.map(e => e.getAttribute("linkURL"));
});
},
button: [4],
insertImg: [
[".juicebox-parent", 2], 2
],
endColor: "white",
autoDownload: [0],
next: "//a[text()='Next Part']",
prev: "//a[text()='Previous Part']",
customTitle: "#page-title",
category: "hcomic"
}, {
name: "KingComiX/Chochox/Comics18",
url: {
h: ["kingcomix.com", "chochox.com", "comics18.org"]
},
imgs: "figure img,.entry-content img:not(a img),.wp-content img",
button: [4],
insertImg: [".entry-content,.wp-content", 2],
customTitle: "h1.singleTitle-h1,h1.titl,h1.title",
category: "hcomic"
}, {
name: "ilikecomix.com",
url: {
h: ["ilikecomix.com"],
e: ".entry-content img[data-jg-srcset]"
},
imgs: () => fn.getImgSrcset(".entry-content img[data-jg-srcset]").map(src => src.replace("-scaled", "")),
button: [4],
insertImg: [".entry-content", 2],
customTitle: () => fn.ge(".entry-title")?.textContent,
category: "hcomic"
}, {
name: "MyReadingManga",
url: {
h: "myreadingmanga.info",
p: /^\/[^\/]+\/$/,
e: [".entry-content img,video[poster]", ".entry-meta"]
},
imgs: async () => {
if (fn.ge("video[poster]")) {
await fn.waitEle("#MRM_video_html5_api");
videoSrcArray = [fn.ge("video[poster] source").src];
return [fn.ge("video[poster]").poster];
}
return fn.getImgA(".entry-content img", ".entry-pagination a");
},
button: [4],
insertImg: [".entry-content", 2],
endColor: "white",
customTitle: ".entry-title",
hide: "div[class^=root][style]:has(video)",
category: "hcomic"
}, {
name: "MANGA HENTAI",
url: {
h: ["adulthentai.net", "www.manga-hentai.net", "hentaiweb.net", "hentai-freak.com"],
},
box: [".thumbs", 2],
imgs: () => {
let links = fn.gau(".thumbs:not(:last-child) a");
return fn.getImgA(".big-picture img", links);
},
thums: ".thumbs:not(:last-child) img",
button: [4],
insertImg: [
["box", 0, ".thumbs"], 2
],
customTitle: ".wrapper h2",
category: "hcomic"
}, {
name: "HENTAI NARUTO/HENTAI SITE",
url: {
h: ["hentai-naruto.org", "hentai-site.net"],
},
box: [".gallerywrapper", 2],
imgs: ".gallerywrapper a",
thums: ".gallerywrapper img",
button: [4],
insertImg: [
["box", 0, ".gallerywrapper"], 2
],
customTitle: ".wrapper h1",
category: "hcomic"
}, {
name: "HENTAISET.COM/HENTAIVID.NET/HENTAITOP.ORG/HENTAI-IMAGES.COM/HENTAIKA.ORG/HENTAISIN.COM/WWW.HENTAIGALLERY.ORG/HENTAIHOOKED.COM",
url: {
h: ["www.hentaiset.com", "hentaivid.net", "hentaitop.org", "hentai-images.com", "hentaika.org", "hentaisin.com", "www.hentaigallery.org", "hentaihooked.com"],
e: ".main-container h1"
},
box: ["#lightgallery", 2],
imgs: "#lightgallery li.thumb,#lightgallery div.thumb",
thums: "#lightgallery img[is='lazyload-image']",
button: [4],
insertImg: [
["box", 0, "#lightgallery"], 2
],
customTitle: () => fn.ge(".main-container h1")?.textContent,
category: "hcomic"
}, {
name: "HENTAIDOWN.COM/FANHENTAI.NET/HENTAIBRO.COM/HENTAIEVA.COM/HENTAI24X7.COM/GURUHENTAI.COM/HOSTHENTAI.COM/HENTAIDL.NET/HENTAIUP.NET/HENTAILOVE.ORG/COMICSPORN.ORG/HENTAIRIPS.COM",
url: {
h: ["www.hentaidown.com", "www.fanhentai.net", "www.hentaibro.com", "hentaieva.com", "hentai24x7.com", "www.guruhentai.com", "hosthentai.com", "hentaidl.net", "hentaiup.net", "www.hentailove.org", "comicsporn.org", "hentairips.com"],
e: [".image-gallery-box", ".content h1"]
},
imgs: ".gallery-thumbs a",
thums: ".gallery-thumbs img",
button: [4],
insertImg: [".image-gallery-box", 2],
customTitle: () => fn.ge(".content h1")?.textContent,
category: "hcomic"
}, {
name: "JAVMOBILE.MOBI",
link: "https://javmobile.mobi/latest/?content=hentai",
url: {
h: ["javmobile.mobi"]
},
box: [".gal-obol", 2],
imgs: "#imgs_container img",
button: [4],
insertImg: ["box", 2],
customTitle: ".topbar h1",
category: "hcomic"
}, {
name: "Neko Hentai閱讀頁",
host: ["neko-hentai.net"],
reg: /^https?:\/\/neko-hentai\.net\//i,
include: "#manga-content img",
imgs: "#manga-content img",
button: [4],
insertImg: ["#manga-content", 2],
endColor: "white",
customTitle: () => fn.title(/ - Neko Hentai.*$/),
category: "hcomic"
}, {
name: "Super Hentai閱讀頁",
host: ["superhentai.blog"],
reg: /^https?:\/\/superhentai\.blog\/[^\/]+\/$/i,
include: ".gallery",
imgs: ".gallery img",
button: [4],
insertImg: [".gallery", 2],
endColor: "white",
customTitle: "#single h1",
category: "hcomic"
}, {
name: "HENTAICELEB.COM閱讀頁",
host: ["www.hentaiceleb.com"],
reg: /^https?:\/\/www\.hentaiceleb\.com\/\w+\/\w+\/[^\.]+\.html$/i,
imgs: ".gallery-thumbs a[data-src]",
button: [4],
insertImg: [".media-bg", 2],
endColor: "white",
customTitle: ".full-main-col h1",
category: "hcomic"
}, {
name: "HENTAICREDO.COM圖片清單頁",
host: ["www.hentaicredo.com"],
reg: /^https?:\/\/www\.hentaicredo\.com\/content\/\w+\/[^\/]+\/$/i,
imgs: () => {
let [thumbs] = fn.gae(".thumbs");
let imgs = fn.gae("img", thumbs);
let links = fn.gau("a", thumbs);
thumbnailSrcArray = fn.getImgSrcArr(imgs);
return fn.getImgA(".big-picture img", links);
},
button: [4],
insertImg: [".thumbs", 2],
customTitle: "h2",
category: "hcomic"
}, {
name: "HentaiHere閱讀頁",
host: ["hentaihere.com"],
reg: /^https?:\/\/hentaihere\.com\/m\/\w+\/\d+\/\d+\/$/i,
init: async () => {
await fn.waitVar(["rff_imageList", "jQuery"]);
setTimeout(() => fn.run("jQuery(document).off()"), 1000);
},
imgs: () => _unsafeWindow.rff_imageList.map(e => "https://hentaicdn.com/hentai" + e),
button: [4],
insertImg: ["#reader-content", 2],
autoDownload: [0],
next: "//li[a[@class='bg-info']]/following-sibling::li[1]/a",
prev: 1,
customTitle: ["#detail span", "#chapter span"],
hide: ".afs_ads,[data-type]",
category: "hcomic"
}, {
name: "HentaiPaw/Hentai-One/エロ漫画SHOW",
url: {
h: [/([a-z]{2}\.)?hentaipaw.com/, /([a-z]{2}\.)?hentai-one.com/, "eromanga-show.com"],
p: "/articles/"
},
init: () => fn.waitEle(["next-route-announcer", ".grid .group>img"]),
imgs: () => {
fn.createImgBox(".container:has(>.grid)");
fn.showMsg(DL.str_05, 0);
let url = fn.gu(".container:has(>.grid) a");
return fn.fetchDoc(url).then(dom => {
let text = fn.__next_f(dom);
return fn.TextToArray(text, '"slides":').map(e => e.src);
});
},
thums: ".grid .group>img",
button: [4],
insertImg: [
["box", 0, "//div[@id='FullPictureLoadMainImgBox']/preceding-sibling::div[1]"], 2, 2000
],
insertImgAF: () => {
let loop = setInterval(() => {
if (!fn.ge(".FullPictureLoadImage")) {
fn.immediateInsertImg();
}
}, 500);
setTimeout(() => clearInterval(loop), 10000);
},
customTitle: () => {
if (fn.lh.includes("hentai-one.com")) {
let text = fn.gt("h1.text-wrap");
return text.includes("|") ? text.split("|")[1].trim() : text;
} else {
return fn.gt("h1.text-wrap").replace(/\/|\|/g, " ");
}
},
css: "#article-details{margin-top:5rem!important}",
hide: "#article-details+.mx-auto,.container:has(>div>script),#button-group a,.container:has(video)",
category: "hcomic"
}, {
name: "HDpornComics圖片清單頁",
host: ["hdporncomics.com"],
reg: /^https?:\/\/hdporncomics\.com\/[^/]+\/([^/]+\/)?$/i,
include: ".my-gallery.scrollmenu",
imgs: ".my-gallery a[data-size]",
thums: ".my-gallery a[data-size] img",
button: [4],
insertImg: [
[".postContent>.items-center,#likeDislikeVue", 2], 2
],
customTitle: () => fn.dt({
s: "#infoBox>h1",
d: [
" – Gay Manga",
" Comic Porn"
]
}),
category: "hcomic"
}, {
name: "HDpornComics閱讀頁",
host: ["hdporncomics.com"],
reg: /^https?:\/\/hdporncomics\.com\/manhwa\/[^/]+\/chapter/i,
imgs: "#imageContainer>img",
button: [4],
insertImg: ["#imageContainer", 2],
autoDownload: [0],
next: "//a[contains(text(),'Next')]",
prev: "//a[contains(text(),'Prev')]",
customTitle: [".list-reset li:nth-child(5)>a", "option[selected]"],
category: "hcomic"
}, {
name: "Doujins圖片清單頁",
host: ["doujins.com"],
reg: /^https?:\/\/doujins\.com\/.+\/.+/i,
include: "#thumbnails",
exclude: ".thumbnails .gallery-info",
init: () => fn.waitEle(".doujin"),
imgs: () => {
let imgs = fn.gae(".doujin[data-file]");
thumbnailSrcArray = imgs.map(e => e.dataset.thumb);
return imgs.map(e => e.dataset.file);
},
button: [4],
insertImg: [
["#thumbnails", 2], 2
],
customTitle: ".folder-title>a:last-child",
category: "hcomic"
}, {
name: "Simply Hentai閱讀頁",
url: {
h: ["www.simply-hentai.com"]
},
page: () => fn.clp("/page/"),
json: () => fn.showMsg(DL.str_05, 0).then(() => fn.fetchDoc(fn.clp()).then(dom => JSON.parse(fn.gt("#__NEXT_DATA__", 1, dom))).then(json => (siteJson = json) && fn.hideMsg())),
SPA: () => _this.page() ? true : (siteJson = {}) && false,
observeURL: "head",
init: () => _this.page() ? _this.json() : void 0,
imgs: () => {
thumbnailSrcArray = siteJson.props.pageProps.data.pages.map(e => e.sizes.small_thumb);
return siteJson.props.pageProps.data.pages.map(e => e.sizes.full)
},
button: [4],
insertImgFB: () => fn.waitEle("#reader-image img"),
insertImg: ["#reader-image", 2],
customTitle: () => _this.page() ? siteJson.props.pageProps.data.title.replace(/\/|\|/g, "-") : null,
category: "hcomic"
}, {
name: "Hanime1圖片清單頁",
host: ["hanime1.me"],
link: "https://hanime1.me/comics",
reg: /^https?:\/\/hanime1\.me\/comic\/\d+$/,
imgs: async () => {
fn.showMsg(DL.str_05, 0);
let url = fn.gu(".comics-thumbnail-wrapper>a");
return fn.fetchDoc(url).then(dom => {
let dir = fn.ge("#current-page-image", dom).dataset.prefix;
let code = fn.gst("extensions", dom);
code = code.replaceAll(""", '"');
let extensions = fn.TextToArray(code, "extensions");
return extensions.map((e, i) => {
if (dir.includes("nhentai")) {
return `${dir}${(i + 1)}.${fn.ex(e)}`;
} else {
return dir + e + ".jpg";
}
});
});
},
button: [4],
insertImg: [".comics-thumbnail-wrapper", 2],
endColor: "white",
customTitle: "h4.title",
referer: "src",
category: "hcomic"
}, {
name: "Hanime1閱讀頁",
host: ["hanime1.me"],
link: "https://hanime1.me/comics",
reg: /^https?:\/\/hanime1\.me\/comic\/\d+\/\d+$/,
imgs: async () => {
let dir = fn.ge("#current-page-image").dataset.prefix;
return _unsafeWindow.extensions.map((e, i) => {
if (dir.includes("nhentai")) {
return `${dir}${(i + 1)}.${fn.ex(e)}`;
} else {
return dir + e + ".jpg";
}
});
},
button: [4],
insertImg: ["#comic-content-wrapper", 2],
endColor: "white",
customTitle: () => fn.dt({
t: fn.ge("//meta[@property='og:title']").content,
d: /第\d+頁 - /
}),
referer: "src",
category: "hcomic"
}, {
name: "My Hentai Gallery圖片清單頁",
host: ["myhentaigallery.com", "myhentaicomics.com"],
reg: [
/^https?:\/\/myhentaigallery\.com\/g\/\d+$/,
/^https?:\/\/myhentaicomics\.com\/gallery\/thumbnails\/\d+$/
],
imgs: () => {
thumbnailSrcArray = fn.gae(".comic-thumb>img").map(e => e.src);
return thumbnailSrcArray.map(e => e.replace("thumbnail", "original"));
},
button: [4],
insertImg: [".comic-listing:has(.comics-grid)", 2],
endColor: "white",
customTitle: ".comic-description>h1",
category: "hcomic"
}, {
name: "XYZ PORN COMICS圖片清單頁",
host: ["xyzcomics.com"],
reg: /^https?:\/\/xyzcomics\.com\/[^\/]+\/$/,
include: ".post-title",
init: () => fn.waitEle(".jig-link>img"),
imgs: ".jig-link",
thums: ".jig-link>img",
button: [4],
insertImg: [
[".entry-content", 0], 2
],
endColor: "white",
customTitle: ".post-title",
category: "hcomic"
}, {
name: "LoLHentai.net",
host: ["www.lolhentai.net"],
link: "https://www.lolhentai.net/index?/category/chinese",
reg: /^https?:\/\/www\.lolhentai\.net\/index\?\/category\/\d+-.+$/i,
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr("#thumbnails img");
return thumbnailSrcArray.map(src => {
let dir = fn.dir(src);
dir = dir.replace("/_data/i", "");
let file = src.split("/").at(-1);
let ex = file.split(".").at(-1);
ex = "." + ex;
let [a, b] = file.split("-");
b = b.replace(/\.\w+$/i, "");
return `${dir}${a}-${b}${ex}`;
});
},
box: ["#thumbnails", 2],
button: [4],
insertImg: [
["box", 0, "#thumbnails"], 2
],
endColor: "white",
customTitle: "h1.name a:last-child",
category: "hcomic"
}, {
name: "BestPornComix",
url: {
h: "bestporncomix.com",
p: "/gallery/"
},
box: [".dgwt-jg-gallery", 2],
imgs: "figure a",
button: [4],
insertImg: [
["box", 0, ".dgwt-jg-gallery"], 2
],
customTitle: ".entry-title",
category: "hcomic"
}, {
name: "FSIComics",
url: {
h: "fsicomics.com"
},
imgs: ".wp-block-gallery img",
button: [4],
insertImg: [".wp-block-gallery", 2],
customTitle: ".s-title",
category: "hcomic"
}, {
name: "GNTAI.net",
url: {
h: "www.gntai.net",
st: "pages"
},
imgs: () => {
let code = fn.gst("pages");
return fn.TextToArray(code, "pages").map(e => e.page_image);
},
button: [4],
insertImg: ["#img-page", 2],
insertImgAF: () => fn.hideEle("#chapter-pages,#grid-buttons"),
customTitle: "#main h1",
category: "hcomic"
}, {
name: "BRHENTAI",
url: {
h: ["brhentai.win"]
},
imgs: ".listaImagens img",
button: [4],
insertImg: [".listaImagens", 2],
customTitle: "h1.post-titulo",
category: "hcomic"
}, {
name: "IMHentai圖片清單頁",
host: ["imhentai.xxx"],
reg: /^https?:\/\/imhentai\.xxx\/gallery\/\d+\//,
init: () => fn.waitVar("g_th"),
box: ["#comments_div"],
imgs: async () => {
fn.showMsg(DL.str_05, 0);
let server = fn.ge("#load_server").value;
let u_id = fn.ge("#gallery_id").value;
let g_id = fn.ge("#load_id").value;
let img_dir = fn.ge("#load_dir").value;
let total_pages = fn.ge("#load_pages").value;
thumbnailSrcArray = await fn.fetchDoc("/inc/thumbs_loader.php", {
"headers": {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-requested-with": "XMLHttpRequest"
},
"body": `server=${server}&u_id=${u_id}&g_id=${g_id}&img_dir=${img_dir}&visible_pages=0&total_pages=${total_pages}&type=2`,
"method": "POST"
}).then(dom => [...dom.images].map(e => e.dataset.src ?? e.src));
return fn.getImhentaiSrc();
},
button: [4],
insertImg: ["box", 2],
customTitle: () => fn.waitEle(".subtitle").then(() => {
let t = fn.gt(".subtitle");
return t.length > 0 ? t : fn.gt("h1").replace(/\||\+/g, "");
}),
topButton: true,
category: "hcomic"
}, {
name: "IMHentai閱讀頁",
host: ["imhentai.xxx"],
reg: /^https?:\/\/imhentai\.xxx\/view\/\d+\/\d+\//,
init: "setTimeout(()=>{fn.ge('.pre_img').removeAttribute('style');$('a.next_img').unbind('click');},1000)",
imgs: () => fn.getImhentaiSrc(),
button: [4],
insertImg: [".pre_img", 2],
customTitle: () => fn.title("-", 1),
category: "hcomic"
}, {
name: "HentaiEra圖片清單頁/Comic Porn XXX圖片清單頁",
url: {
h: ["hentaiera.com", "comicporn.xxx"],
p: "/gallery/",
e: "#append_thumbs"
},
init: () => fn.waitVar("g_th"),
box: ["#thumbs_gallery_div", 2],
imgs: async () => {
fn.showMsg(DL.str_05, 0);
let server = fn.ge("#load_server").value;
let u_id = fn.ge("#gallery_id").value;
let g_id = fn.ge("#load_id").value;
let img_dir = fn.ge("#load_dir").value;
let total_pages = fn.ge("#load_pages").value;
thumbnailSrcArray = await fn.fetchDoc("/inc/thumbs_loader.php", {
"headers": {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-requested-with": "XMLHttpRequest"
},
"body": `server=${server}&u_id=${u_id}&g_id=${g_id}&img_dir=${img_dir}&visible_pages=0&total_pages=${total_pages}&type=2`,
"method": "POST"
}).then(dom => [...dom.images].map(e => e.dataset.src ?? e.src));
let max = fn.ge("#load_pages").value;
let img = fn.ge(".gthumb img");
let src = img.dataset.src ?? img.src;
let dir = fn.dir(src);
return fn.arr(max, (v, i) => `${dir}${(i + 1)}.${fn.ex(_unsafeWindow.g_th[(i + 1)][0])}`);
},
button: [4],
insertImg: ["box", 2],
customTitle: () => fn.getText([".subtitle", "h1"]),
category: "hcomic"
}, {
name: "HentaiEra閱讀頁/Comic Porn XXX閱讀頁",
url: {
h: ["hentaiera.com", "comicporn.xxx"],
p: "/view/"
},
init: async () => {
await fn.waitVar("g_th");
let html = fn.ge(".pre_img img").outerHTML;
fn.ge(".pre_img").outerHTML = `<div class="imgBox">${html}</div>`;
},
imgs: () => {
let max = fn.ge("#pages").value;
let img = fn.ge("#gimg");
let src = img.dataset.src ?? img.src;
let dir = fn.dir(src);
return fn.arr(max, (v, i) => `${dir}${(i + 1)}.${fn.ex(_unsafeWindow.g_th[(i + 1)][0])}`);
},
button: [4],
insertImg: [".imgBox", 2],
customTitle: () => {
let title = fn.gt(".gallery_view h1");
if (/ \/ /.test(title)) {
title = title.split(" / ").at(-1);
} else if (/ \| /.test(title)) {
let s = title.split(" | ");
if (s.length == 2) {
title = s.at(-1);
}
}
return fn.dt({
t: title,
d: / - Page[\s\d]+/
});
},
category: "hcomic"
}, {
name: "TSUMINO圖片清單頁",
url: {
h: "www.tsumino.com",
p: "/entry/"
},
init: () => fn.waitEle("#thumbnails-container a"),
imgs: () => {
let prges = fn.ge("div[data-pages]").dataset.pages;
fn.showMsg(DL.str_05, 0);
return fn.fetchDoc(fn.gu("#thumbnails-container a")).then(dom => {
let url = fn.ge("div[data-cdn]", dom).dataset.cdn;
let obj = new URL(url);
let dir = obj.origin + obj.pathname.replace("[PAGE]", "");
let search = obj.search;
return fn.arr(prges, (v, i) => dir + (i + 1) + search);
});
},
button: [4],
insertImg: [
["#thumbnails-container", 2, "#thumbnails-container"], 2
],
customTitle: () => {
let title = fn.gt(".book-data");
if (/ \/ /.test(title)) {
return title.split(" / ").at(-1);
} else if (/ \| /.test(title)) {
let s = title.split(" | ");
return s.length == 2 ? s.at(-1) : title;
}
return title;
},
category: "hcomic"
}, {
name: "TSUMINO閱讀頁",
url: {
h: "www.tsumino.com",
p: "/Read/"
},
imgs: async () => {
await fn.waitEle(".reader-img");
let [max] = fn.gt("//h1[span[@id='pageNumberText']]").match(/\d+$/);
let url = fn.ge("div[data-cdn]").dataset.cdn;
let obj = new URL(url);
let dir = obj.origin + obj.pathname.replace("[PAGE]", "");
let search = obj.search;
return fn.arr(max, (v, i) => dir + (i + 1) + search);
},
button: [4],
insertImg: [".reader-page", 2],
category: "hcomic"
}, {
name: "nHentai/HentaiHand",
url: {
h: ["nhentai.com", "hentaihand.com"]
},
page: () => fn.clp("/en/comic/"),
json: () => fn.showMsg(DL.str_05, 0).then(() => {
let comic = fn.clp().split("/").at(3);
let csrfToken = fn.ge("meta[name='csrf-token']").content;
let xsrfToken = fn.cookie("XSRF-TOKEN");
return fetch(`/api/comics/${comic}/images`, {
"headers": {
"accept": "application/json, text/plain, */*",
"x-csrf-token": csrfToken,
"x-requested-with": "XMLHttpRequest",
"x-xsrf-token": xsrfToken
}
}).then(res => res.json()).then(json => (siteJson = json) && fn.hideMsg());
}),
SPA: () => _this.page() ? true : (siteJson = {}) && false,
observeURL: "head",
init: () => _this.page() ? _this.json().then(() => fn.waitEle(".vertical-image img[data-src],.comic-gallery img,.comic-gallery img")) : void 0,
imgs: async () => {
if (!_this.page()) return [];
thumbnailSrcArray = siteJson.images.map(e => e.thumbnail_url);
return siteJson.images.map(e => e.source_url);
},
button: [4],
insertImgBF: () => fn.createImgBox("div:has(>div>.comic-gallery),.reader", 2),
insertImg: [
["box", 0, ".box-header,div:has(>div>.comic-gallery),.reader"], 2
],
customTitle: () => _this.page() ? siteJson.comic.alternative_title ?? siteJson.comic.title : null,
category: "hcomic"
}, {
name: "同人エロ漫画・エロ同人誌ならエロコミックハンター",
host: ["ero-comic-hunter.net"],
reg: /^https?:\/\/ero-comic-hunter\.net\/\d+\.html$/,
imgs: "#single-more_wid~a[href*='/wp-content/uploads/']",
customTitle: ".kijibox_title a",
category: "hcomic"
}, {
name: "エロ漫画 ヌキブックス",
url: {
h: "nukibooks.com",
p: "/articles/"
},
init: () => fn.waitEle("next-route-announcer"),
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr(".grid-container .image-item img,.article-page-list img");
let text = fn.__next_f();
return fn.TextToArray(text, '"pages":').map(e => "https://gazou.nukibooks.com/" + e.fileName);
},
capture: () => _this.imgs(),
customTitle: ".detail-ttl",
category: "hcomic"
}, {
name: "エロモモ",
url: {
h: "momoniji.com",
e: "#cif"
},
imgs: () => fn.getImgA("#cif img", ".singlepager a"),
capture: () => _this.imgs(),
customTitle: "main h1",
category: "hcomic"
}, {
name: "H研-成年コミック研究会",
url: {
h: "www.b-hentai.com",
p: ".html"
},
imgs: () => fn.getImgA(".content img", ".article-pagination a"),
autoDownload: [0],
next: "//a[div[div[div[text()='Previous']]]]",
prev: "//a[div[div[div[text()='Next']]]]",
customTitle: "h1.post-title",
category: "hcomic"
}, {
name: "エロ漫画同人誌画像",
url: {
h: "eromangarev.blog"
},
box: [".entry-content>p:has(>a>img)", 1],
imgs: ".entry-content>p>a:has(img)",
button: [4],
insertImg: [
["box", 0, ".entry-content>p:has(>a>img)"], 2
],
autoDownload: [0],
next: "a:has(.prev-post-title)",
prev: "a:has(.next-post-title)",
customTitle: "h1.entry-title",
category: "hcomic"
}, {
name: "俺のエロ本",
url: {
h: "oreno-erohon.com",
p: "/public/",
d: "pc"
},
srcset: ".entry-content img",
button: [4],
insertImg: [".entry-content", 2],
autoDownload: [0],
next: ".nav-prev a",
prev: ".nav-next a",
customTitle: ".entry-title",
category: "hcomic"
}, {
name: "俺のエロ本",
url: {
h: "oreno-erohon.com",
p: "/public/",
d: "m"
},
box: [".entry-content .wpfp-area", 1],
srcset: ".entry-content img",
button: [4],
insertImg: [
["box", 0, ".entry-content>div:not([class],[id])"], 2
],
autoDownload: [0],
next: ".nav-previous a",
prev: ".nav-next a",
customTitle: ".article-title",
hide: ".sp_head_box,.sp_footer,.sp_widget_box",
category: "hcomic"
}, {
name: "ひめぼん",
url: {
h: "himebon.blog",
P: "/eromanga/"
},
box: [".entry-content>p:has(>a>img)", 1],
srcset: ".entry-content>p>a:has(img)",
button: [4],
insertImg: [
["box", 0, ".entry-content>p:has(>a>img)"], 2
],
customTitle: "h1.entry-title",
category: "hcomic"
}, {
name: "KAIMANGA",
url: {
h: "kaimanga.top"
},
srcset: ".entry-content img",
button: [4],
insertImg: [".entry-content", 2],
autoDownload: [0],
next: "a:has(.prev-post-title)",
prev: "a:has(.next-post-title)",
customTitle: "h1.entry-title",
category: "hcomic"
}, {
name: "エロジン",
url: {
h: "erozine.jp",
p: ["/eromanga/", "/gazou/", "/3d/"]
},
imgs: "#ar_content img",
autoDownload: [0],
next: "a.ab:has(img[alt=next])",
prev: "a.ab:has(img[alt=prev])",
customTitle: "#ar_title",
category: "hcomic"
}, {
name: "モモンガッ!!",
url: {
h: ["momon-ga.com", "pingporn.ru"],
p: ["/fanzine/mo", "/magazine/mo"]
},
imgs: "#post-hentai img",
button: [4],
insertImg: ["#post-hentai", 2],
customTitle: "#post-data h1",
hide: "div[style]:has(>div[id^='bnc_ad']),div[style]:has(>script[src*='.ad'])",
category: "hcomic"
}, {
name: "同人村",
url: {
h: "doumura.com",
p: "/archives/"
},
imgs: ".entry-content img",
button: [4],
insertImg: [".entry-content", 2],
customTitle: ".entry-title",
category: "hcomic"
}, {
name: "Hentai2Read",
host: ["hentai2read.com"],
reg: /^https?:\/\/hentai2read\.com\/\w+\/\d+\/(\d+\/)?$/,
imgs: () => _unsafeWindow.gData.images.map(e => "https://static.hentai.direct/hentai" + e),
button: [4],
insertImg: ["#js-reader", 2],
autoDownload: [0],
next: "//li[a[contains(@class,'bg-info')]]/preceding-sibling::li[1]/a",
prev: 1,
customTitle: () => fn.gt(".reader-left-text.text-ellipsis").replace(/\//g, "-"),
category: "hcomic"
}, {
name: "XlecX",
url: {
h: ["xlecx.one"],
p: /^\/[^\.\/]+\.html$/
},
imgs: () => fn.getImgSrcArr(".ug-thumb-image,img[data-src]").map(e => e.replace("thumbs/", "")),
button: [4],
insertImg: [
[".page__col-left", 0], 2
],
customTitle: ".page__col-left>h1",
category: "hcomic"
}, {
name: "HentaiPal.com",
host: ["hentaipal.com"],
reg: /^https?:\/\/hentaipal\.com\/content\/[^\/]+\/[^\/]+\/index\.html$/,
init: () => fn.remove("iframe[src*='ad'],font[color=red],div:has(>div.row a[href='switch.html'])"),
imgs: async () => {
let max;
try {
[, max] = fn.gu(".imgpagebar>a:last-child").match(/page-(\d+)/);
} catch {
max = 1;
}
if (max > 1) {
let links = [];
let url = siteUrl.replace("index.html", "");
for (let i = 2; i <= max; i++) {
links.push(url + "page-" + i + ".html");
}
await fn.getEle(links, "div:has(>.picbox)", ["div:has(>div>.picbox)", 0]);
}
return fn.getImgA("main img[style^=m]", ".picbox>a");
},
button: [4],
insertImg: ["div:has(>div>.picbox)", 2],
customTitle: () => fn.title(" - HentaiPal.Com"),
category: "hcomic"
}, {
name: "HentaiPal.com 分類自動翻頁",
reg: /^https?:\/\/hentaipal\.com\//,
init: () => fn.remove("iframe[src*='ad']"),
autoPager: {
ele: "div:has(>div>div>.picbox)",
observer: "div:has(>.picbox)",
next: ".imgpagebar a:has(.glyphicon-arrow-right)",
re: ".imgpagebar",
pageNum: () => nextLink.match(/page-(\d+)/)[1]
},
css: ".autoPagerTitle{width:100%!important}",
category: "autoPager"
}, {
name: "HentaiPorns",
url: {
h: ["hentaiporns.net"],
},
srcset: "#chapter-gallery-wrapper img,.wp-block-gallery img,.gallery img",
thums: "#chapter-gallery-wrapper img,.wp-block-gallery img,.gallery img",
button: [4],
insertImg: ["#chapter-gallery-wrapper,.wp-block-gallery,.gallery", 2],
customTitle: ".middle-title,#main-content h1",
category: "hcomic"
}, {
name: "8muses",
host: ["comics.8muses.com"],
reg: /^https?:\/\/comics\.8muses\.com\/comics\/album\/[\w-]+\/[\w-]+\//i,
include: ".gallery",
exclude: ".image-title>.title-text",
imgs: () => {
let srcs = fn.gae("img[data-src]").map(e => e.dataset.src.replace("/image/th/", "https://comics.8muses.com/image/fl/"));
let xhrNum = 0;
fn.showMsg("fn.xhrHEAD...", 0);
return srcs.map(async src => {
let res = await fn.xhrHEAD(src);
fn.showMsg(`fn.xhrHEAD(${xhrNum+=1}/${srcs.length})`, 0);
let status = res.status;
return status == 404 ? src.replace("/fl/", "/fm/") : src;
});
},
button: [4],
insertImg: [
[".gallery", 2], 1
],
endColor: "white",
category: "hcomic"
}, {
name: "EROFUS",
url: {
h: ["www.erofus.com"],
e: ".thumbnail img[alt^=picture]"
},
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr(".thumbnail img[alt^=picture]");
return thumbnailSrcArray.map(e => e.replace("/thumb/", "/medium/"));
},
capture: () => _this.imgs(),
customTitle: () => fn.dt({
d: " | Erofus - Sex and Porn Comics"
}),
category: "hcomic"
}, {
name: "MULT34",
url: {
h: ["mult34.com"]
},
srcset: ".gallery img[srcset],.gallery img[data-src]",
customTitle: () => fn.ge(".entry-title")?.textContent,
category: "hcomic"
}, {
name: "X-Manga",
url: {
h: ["x-manga.net"]
},
imgs: ".wpb_content_element img",
button: [4],
insertImg: [".wpb_content_element:has(img)", 2],
customTitle: ".entry-title",
category: "hcomic"
}, {
name: "FreeAdultComix",
url: {
h: ["freeadultcomix.com"]
},
imgs: ".foto img,.post-texto a:has(img[data-jg-srcset])",
endColor: "white",
customTitle: ".post-conteudo h1",
category: "hcomic"
}, {
name: "Manga18.club/hanman18.com/18PornComic",
init: async () => {
await fn.waitVar("jQuery");
fn.run("jQuery(document).off()");
},
url: {
h: [
"manga18.club",
"hanman18.com",
"18porncomic.com"
],
st: "slides_p_path"
},
imgs: () => _unsafeWindow.slides_p_path.map(e => atob(e)),
capture: () => _this.imgs(),
autoDownload: [0],
next: () => _unsafeWindow.next_chapter ? _unsafeWindow.next_chapter : null,
prev: () => _unsafeWindow.prev_chapter ? _unsafeWindow.prev_chapter : null,
customTitle: () => {
if (fn.lh === "manga18.club" || fn.lh === "hanman18.com" || fn.lh === "18porncomic.com") {
return document.title;
} else {
return fn.gt(".story_name>h1");
}
},
category: "hcomic"
}, {
name: "ReadManga18",
url: {
h: ["www.readmanga18.com", "readmanga18.com"]
},
imgs: ".read-content img",
button: [4],
insertImg: [".read-content", 2],
autoDownload: [0],
next: "a.navi-change-chapter-btn-next",
prev: "a.navi-change-chapter-btn-prev",
customTitle: ".read-manga h1",
category: "hcomic"
}, {
name: "MANGA DISTRICT/apcomics/manga18free/HipercooL/Ero18x/Manhwa-latino/Manhwa-es",
url: {
h: ["mangadistrict.com", "apcomics.org", "manga18free.com", "mi.manytoon.com", "hiper.cool", "ero18x.com", "manhwa-latino.com", "manhwa-es.com", "gedecomix.com", "hentaixyuri.com", "hentaixcomic.com", "hentaixdickgirl.com", "allporncomics.co"]
},
imgs: ".reading-content img",
button: [4],
insertImg: [".reading-content", 2],
endColor: () => fn.ge(".text-ui-light") ? "white" : "black",
autoDownload: [0],
next: "a.next_page",
prev: "a.prev_page",
customTitle: "#chapter-heading",
category: "hcomic"
}, {
name: "AllPornComic",
host: ["allporncomic.com"],
reg: /^https?:\/\/allporncomic\.com\/porncomic\/[^\/]+\/[^\/]+\/$/i,
include: ".read-container",
imgs: ".wp-manga-chapter-img",
button: [4],
insertImg: [".read-container", 2],
endColor: "white",
autoDownload: [0],
next: "a.next_page",
prev: "a.prev_page",
customTitle: "#chapter-heading",
category: "hcomic"
}, {
name: "vermangasporno/vercomicsporno",
url: {
h: ["vermangasporno.com", "vercomicsporno.com"]
},
imgs: ".wp-content img",
button: [4],
insertImg: [".wp-content", 2],
customTitle: "h1.titl",
category: "hcomic"
}, {
name: "7mmtvH漫畫貼圖",
url: {
h: "7mmtv.sx",
p: "hcomic",
st: "Large_cgurl"
},
imgs: () => {
const {
Large_cgurl
} = _unsafeWindow;
let arr = Large_cgurl.map(e => /imgur/.test(e) ? e : null).filter(Boolean);
return arr.length == 0 ? Large_cgurl : arr;
},
button: [4],
insertImg: ["#show_cg_html", 2],
insertImgAF: () => fn.remove("iframe"),
customTitle: () => fn.dt({
t: fn.title(" - 7mmtv.sx", 1)
}),
hide: ".ut1_img_content_js,.ut_cg1_top",
category: "hcomic"
}, {
name: "18H",
url: {
h: ["18h.mm-cg.com"],
st: "Large_cgurl"
},
imgs: () => _unsafeWindow.Large_cgurl,
button: [4],
insertImg: ["#show_cg_html", 2],
customTitle: () => fn.title("-", 1),
hide: ".ut1_img_content",
category: "hcomic"
}, {
name: "H 次元",
host: ["h-ciyuan.com"],
reg: /^https?:\/\/h-ciyuan\.com\/\d+\/\d+\/.+\//,
include: "a[data-fancybox],.rl-gallery-container a",
imgs: "a[data-fancybox],.rl-gallery-container a",
thums: "a[data-fancybox] img,.rl-gallery-container a img",
button: [4],
insertImg: [
[".entry-content,.rl-gallery-container", 2], 2
],
next: ".nav-previous>a",
prev: ".nav-next>a",
customTitle: ".post-title",
category: "hcomic"
}, {
name: "淫漫画",
host: ["www.yinmh.com", "www.yinmh.top", "www.yinmh.xyz"],
reg: /^https?:\/\/www\.yinmh\.(com|top|xyz)\/\d+\.html$/,
imgs: () => {
fn.showMsg(DL.str_05, 0);
return fn.fetchDoc(siteUrl).then(dom => fn.gae(".left>.image img.lazy", dom).map(e => e.getAttribute("img") ?? e.src));
},
button: [4],
insertImg: [".left>.image", 2],
customTitle: ".box>h1",
category: "hcomic"
}, {
name: "爱漫画网 閱讀頁",
host: ["www.iimhw.com", "iimhw.com", "518lebook.buzz"],
url: () => fn.checkUrl({
e: "a[title=爱漫画网],a[title=漫画猫]",
p: "/chapter"
}) || fn.curl(/^https?:\/\/518lebook\.buzz\/\?novel\d+\/chapter/),
imgs: () => fn.gae(".chapter-content img"),
button: [4],
insertImg: [".chapter-content", 2],
next: "a#next_chap[href$=html]",
prev: "a#prev_chap[href$=html]",
customTitle: [".truyen-title", ".chapter-title"],
hide: "#goTop~div[class][style]",
category: "hcomic"
}, {
name: "爱漫画网 目錄頁",
url: () => fn.checkUrl({
e: ["a[title=爱漫画网],a[title=漫画猫]", "#list-chapter"],
p: "/novel"
}) || fn.curl(/^https?:\/\/518lebook\.buzz\/\?novel\d+\/$/),
box: ["#list-chapter", 2],
init: () => fn.getNP("#list-chapter .list-chapter>li", "//div[@id='pagination']//a[text()='Next'][@href]", null, "#pagination"),
imgs: () => {
let links = fn.gau("#list-chapter .list-chapter a");
return fn.getImgA(".chapter-content img", links);
},
button: [4],
insertImg: ["box", 3],
customTitle: "h1>a[title]>span",
hide: "#goTop~div[class][style]",
category: "hcomic"
}, {
name: "H漫車 閱讀頁",
host: ["www.hmanche.com"],
url: {
h: "hmanche",
p: "/chapter/"
},
imgs: () => fn.getImgSrcArr("picture img").map(src => src.replace(".thumb.jpg", "")),
button: [4],
insertImg: ["picture", 2],
autoDownload: [0],
next: "//a[span[text()='下一章']][contains(@href,'chapter')]",
prev: "//a[span[text()='上一章']]",
customTitle: () => fn.gae("h2").map(e => e.innerText).join(" "),
category: "hcomic"
}, {
name: "H漫車 目錄頁",
host: ["www.hmanche.com"],
url: {
h: "hmanche",
p: "/book/",
e: ["#chapterGroupListJsonAsc,#chapterGroupListAsc", "//li/a[contains(text(),'成人寫真')][not(@class)]"]
},
box: ["#chapterContentContainer~.module-title", 1],
imgs: () => {
let links = JSON.parse(document.querySelector("#chapterGroupListJsonAsc,#chapterGroupListAsc").value).flat().map(e => "/chapter/" + e.id);
return fn.getImgA("picture img", links, 0, [".thumb.jpg", ""]);
},
button: [4],
insertImg: ["box", 2],
customTitle: () => fn.getText([".book-info-value", ".book-title-name"]),
hide: ".sss-container",
category: "hcomic"
}, {
name: "H漫車 目錄頁",
host: ["www.hmanche.com"],
url: {
h: "hmanche",
p: "/book/",
e: "#chapterGroupListJsonAsc,#chapterGroupListAsc"
},
box: ["#chapterContentContainer~.module-title", 1],
imgs: () => {
let links = JSON.parse(document.querySelector("#chapterGroupListJsonAsc,#chapterGroupListAsc").value).flat().map(e => "/chapter/" + e.id);
return fn.getImgA("picture img", links, 0, [".thumb.jpg", ""]);
},
button: [4],
insertImg: ["box", 3],
customTitle: () => fn.getText([".book-info-value", ".book-title-name"]),
hide: ".sss-container",
category: "hcomic"
}, {
name: "丽图·污漫画",
host: ["litu100.xyz"],
reg: /^https?:\/\/litu\d+\.xyz\/comic\/id-\w+\/\d+\.html$/,
imgs: ".article.comic img",
button: [4],
insertImg: [".article.comic", 2],
autoDownload: [0],
next: "a.next",
prev: "a.prev",
customTitle: () => fn.dt({
s: ".breadcrumb span:nth-child(2)",
d: "首页"
}),
css: "body{overflow:unset!important}",
hide: ".banner_ad,.swal2-container,.article:has(.media),.jquery-modal.blocker.current,.push-top-container",
category: "hcomic"
}, {
name: "漫小肆",
host: ["www.mxsweb.cc"],
url: {
t: "漫小肆",
p: "chapter"
},
init: () => fn.remove("//body/div[div[@id][@style][a]]|//body/div[div[@id][@style]][a[@id][@style]]"),
imgs: "img[data-original]",
button: [4],
insertImg: [".comicpage,#cp_img", 2],
autoDownload: [0],
next: "//a[text()='下一章']",
prev: "//a[text()='上一章']",
customTitle: () => {
if (fn.ge(".title")) {
return fn.gt(".title");
} else {
return fn.ge("meta[name='Description']")?.content?.replace("当前阅读的是", "");
}
},
referer: "src",
hide: "h5[id]:has(h5[id]),.swiper-container",
category: "hcomic"
}, {
name: "Avbebe",
host: ["avbebe.com"],
link: "https://avbebe.com/archives/category/%e6%88%90%e4%ba%bah%e6%bc%ab%e7%95%ab",
reg: /^https?:\/\/avbebe\.com\/archives\/\d+/,
include: "//a[@rel='category tag' and text()='成人漫畫']",
imgs: ".elementor-widget-container>p>img,.content-inner>p>img",
button: [4],
insertImg: [
["//p[img]", 2, "//p[img]"], 2
],
customTitle: ".jeg_post_title",
fancybox: {
v: 3,
css: false
},
category: "hcomic"
}, {
name: "ACG漫画网",
host: ["acgmhx.com", "acgxmh.com", "acgsmh.com", "hentai-acg.com", "porn-comic.com"],
url: {
e: [".header>.header-con>.logo", ".manga-page,.main-picture"],
p: /^\/([\w-]+\/)?(h|hentai|cos|webtoon|western)\/\d+\.html$/
},
imgs: async () => {
await fn.getNP(".manga-page img,.main-picture img", "#pages span+a:not(.a1)", null, "#pages", 200);
return fn.gae(".manga-page img,.main-picture img");
},
button: [4],
insertImg: [".manga-page,.main-picture", 2],
autoDownload: [0],
next: ".next_pics>.fr>a[href$=html],.post-next a",
prev: ".next_pics>.fl>a[href$=html],.post-pre a",
customTitle: "h2.title,h1.title,.entry-header>h1",
hide: ".pre_picture,.next_picture,[class^=ad300],[class^=ad900]",
category: "hcomic"
}, {
name: "ACG漫画网",
host: ["www.acgnbus.com", "acgnbus.com"],
url: {
e: ["#page.site", ".main-picture"],
p: /^\/\w+\/\d+\.html$/,
d: "m"
},
imgs: async () => {
await fn.getNP(".main-picture", "#pages span+a:not(.a1)", null, "#pages", 200);
return fn.gae(".main-picture img");
},
button: [4],
insertImg: [".entry-content", 2],
next: ".post-next a",
prev: ".post-pre a",
customTitle: ".entry-header>h1",
hide: ".pre_picture,.next_picture,.tips,.adbox",
category: "hcomic"
}, {
name: "Naxter",
url: {
h: ["naxter.net"]
},
page: () => fn.clp("/gallery/"),
SPA: () => _this.page(),
observeURL: "nav",
init: () => _this.page() ? fn.wait(() => {
let [, , id] = fn.clp().split("/");
return !!id;
}) : void 0,
json: () => {
let [, , id] = fn.clp().split("/");
return fn.fetchDoc("/gallery/" + id).then(dom => JSON.parse(fn.gst("files", dom)));
},
imgs: () => {
if (_this.page()) {
fn.showMsg(DL.str_05, 0);
return _this.json().then(json => {
let {
props: {
pageProps: {
gallery: {
files,
originalTitle,
title
}
}
},
runtimeConfig: {
media: {
filesBaseUrl
}
}
} = json;
apiCustomTitle = originalTitle ? originalTitle : title;
thumbnailSrcArray = files.map(e => filesBaseUrl + "/media/" + e.id + "?size=preview&format=webp");
return files.map(e => filesBaseUrl + "/media/" + e.id);
});
} else {
return [];
}
},
capture: () => _this.imgs(),
category: "hcomic"
}, {
name: "HManga",
url: {
h: ["hmanga.world"]
},
page: () => fn.clp("/manga/"),
SPA: () => _this.page(),
observeURL: "nav",
json: () => {
let id = fn.clp().split("/").at(-1);
return fetch("/api/getdoujin?id=" + id).then(res => res.json());
},
imgs: () => {
if (_this.page()) {
fn.showMsg(DL.str_05, 0);
return _this.json().then(json => {
let {
baseurl,
page,
titles: {
english,
original
}
} = json;
apiCustomTitle = original ? original : english;
return page.map((e, i) => baseurl + (i + 1) + "." + e);
});
} else {
return [];
}
},
capture: () => _this.imgs(),
hide: "div[style]:has(>div[id*='_ad_'])",
category: "hcomic"
}, {
name: "H-Comic",
url: {
t: "H-Comic",
h: "h-comic.com",
e: "body[data-theme='h-comic-blue-theme']"
},
page: () => ["/comics/", "/1"].every(e => fn.clp(e)),
SPA: () => _this.page(),
observeURL: "nav",
json: () => fn.fetchDoc(fn.clp()).then(dom => {
let code = fn.gst("num_pages", dom);
siteJson.env = fn.TextToObject(code, "env:");
let a = code.indexOf("data:");
let b = code.indexOf("[", a);
let c = code.lastIndexOf("],") + 1;
let data = code.slice(b, c);
data = fn.run(data);
return data.find(d => !!d?.data?.comic);
}),
imgs: () => {
if (_this.page()) {
fn.showMsg(DL.str_05, 0);
return _this.json().then(json => {
let {
data: {
comic: {
num_pages,
media_id,
comic_source,
title: {
japanese,
english,
pretty
}
}
}
} = json;
apiCustomTitle = japanese ?? english ?? pretty;
return fn.arr(num_pages, (v, i) => `${siteJson.env.PUBLIC_IAMGE_SERVER_URL}/${comic_source}/${media_id}/pages/${i + 1}`);
});
} else {
return [];
}
},
capture: () => _this.imgs(),
category: "hcomic"
}, {
name: "NiceCat",
url: {
h: "web.nicecat.cc"
},
page: () => fn.clp("/comic/book/reader/"),
data: () => {
let id = fn.clp().split("/").at(-1);
return fn.fetchDoc("/comic/info/" + id).then(dom => (doc = dom));
},
SPA: () => _this.page() ? true : (siteJson.imageData = null) && false,
observeURL: "nav",
init: () => {
if (!isAddAjaxHooker) {
isAddAjaxHooker = true;
const ajaxHooker = addAjaxHookerLibrary();
ajaxHooker.filter([{
url: "/api/ComicOrder/getComicOrder"
}]);
ajaxHooker.hook(request => {
//console.log(request);
request.response = res => {
if (res.status === 200 && request.url.includes("/api/ComicOrder/getComicOrder")) {
let json = JSON.parse(res.responseText);
//console.log("imageData", json);
siteJson.imageData = json.data.imageData;
}
}
});
}
return _this.page() ? fn.showMsg(DL.str_05, 0).then(() => _this.data().then(() => fn.wait(() => isArray(siteJson.imageData)))).then(() => fn.hideMsg()) : void 0;
},
imgs: () => _this.page() ? siteJson.imageData.map(e => e.imageUrl) : [],
capture: () => _this.imgs(),
customTitle: () => {
if (!_this.page()) return null;
let ele = fn.ge(".pc-mode", doc);
let [a, b] = fn.gae("span", ele).map(e => e.textContent);
return b || a;
},
category: "hcomic"
}, {
name: "摸摸漫画",
host: ["mmnaz.xyz", "ainuc.live", "nefoa.live", "mhmvisq.fun"],
url: {
t: "摸摸漫画"
},
page: () => fn.clp(/^\/comics\/\d+\/\d+$/),
SPA: () => _this.page(),
observeURL: "head",
data: () => {
fn.showMsg(DL.str_05, 0);
let [, , mid, cid] = fn.clp().split("/");
let res_a = fetch("/api/comic/chapter", {
"headers": {
"content-type": "application/json"
},
"body": `{\"id\":${Number(mid)},\"chapter\":${Number(cid)}}`,
"method": "POST"
}).then(res => res.json()).then(json => (siteJson = json));
let res_b = fn.fetchDoc(fn.clp()).then(dom => (doc = dom));
return Promise.all([res_a, res_b]).then(() => fn.hideMsg());
},
init: () => _this.page() ? _this.data() : void 0,
imgs: () => {
if (!_this.page()) return [];
fn.showMsg(DL.str_05, 0);
let fetchNum = 0;
let [, , mid, cid] = fn.clp().split("/");
let srcs = fn.arr(siteJson.pages, (v, i) => `https://themose.xyz/comic/${mid}/${cid}/${i + 1}.jpg`);
return srcs.map(src => fetch(src).then(res => res.text()).then(text => {
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${srcs.length}`, 0);
return fn.dataURLtoBlobURL(`data:image/jpeg;base64,${text}`);
}));
},
repeat: 1,
autoDownload: [0],
next: () => {
if (siteJson?.hadNext) {
let [, , , cid] = fn.clp().split("/");
return fn.clp().replace(/\d+$/, "") + (Number(cid) + 1);
}
return null;
},
prev: 1,
customTitle: () => {
if (!_this.page()) return null;
let text = doc.title;
let i = text.indexOf("漫画");
let mn = text.slice(0, i);
return mn + " - " + siteJson.title;
},
category: "hcomic"
}, {
name: "隐秘漫画",
host: ["yinmimh.com"],
url: {
t: "隐秘漫画",
p: "/comic/"
},
imgs: () => {
fn.showMsg(DL.str_05, 0);
let fetchNum = 0;
let srcs = fn.getImgSrcArr("#comic img");
return srcs.map(src => fetch(src).then(res => res.text()).then(text => {
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${srcs.length}`, 0);
return fn.dataURLtoBlobURL(`data:image/jpeg;base64,${text}`);
}));
},
autoDownload: [0],
next: "//span[text()='下一章']",
prev: "//span[text()='上一章']",
customTitle: () => fn.title(" - 隐秘漫画"),
category: "hcomic"
}, {
name: "紳士漫畫 圖片清單頁",
link: "https://wnacg.date/,https://wnacg01.org/",
//第3方API直接取得"寫真 & Cosplay"分類一整頁的畫廊資料
//https://meoden.net/gallery?page=1&site=WN&siteTag=
//https://meoden.net/api/gallery/wnacg?page=1
url: {
t: ["紳士漫畫", "绅士漫画"],
p: "/photos-index-aid-"
},
init: () => {
fn.remove(".sh,.dlh,div:not([id],[class],[style]):has(>a>img[alt]),iframe");
fn.remove("//body/div[a[img]] | //div[@class='Introduct']/a[div[img]] | //div[a[img[@alt='Game Tip']]]");
fn.addMutationObserver(() => fn.remove(".sh,.dlh,div:not([id],[class],[style]):has(>a>img[alt]),iframe"));
},
imgs: () => {
fn.showMsg(DL.str_05, 0);
let [galleryId] = fn.lp.match(/\d+/);
let galleryUrl = `/photos-gallery-aid-${galleryId}.html`;
return fetch(galleryUrl).then(res => res.text()).then(text => {
text = text.replaceAll("\\", "").replaceAll("fast_img_host+", "");
let s = text.indexOf("[{");
let e = text.indexOf(";", s);
text = text.slice(s, e);
let array = fn.run(text);
return array.map(e => e.url).filter(e => !e.includes("/themes/"));
});
},
button: [4],
insertImg: [
[".gallary_wrap,.Introduct", 0, ".gallary_wrap>.cc"], 2
],
customTitle: () => fn.dt({
d: / - 紳士漫畫.*$| - 绅士漫画.*$|-紳士漫畫.*$|-绅士漫画.*$/
}),
category: "hcomic"
}, {
name: "紳士漫畫 下拉閱讀頁",
url: {
t: ["紳士漫畫", "绅士漫画"],
p: /^\/photos-(slide|slidelow|list|slist)-aid-\d+\.html$/
},
init: () => {
fn.remove("div[align=center],#control_block,#img_load");
fn.addMutationObserver(() => fn.remove("div[align=center],#control_block,#img_load"));
},
imgs: () => _unsafeWindow.imglist.map(e => e.url).filter(e => !e.includes("/themes/")),
button: [4],
insertImg: ["#img_list", 2],
customTitle: () => fn.dt({
d: " - 列表"
}),
hide: "div[align=center],#control_block,#img_load",
category: "hcomic"
}, {
name: "紳夜漫畫/工口動漫",
host: ["syacomic.com"],
url: {
h: "syacomic",
t: ["紳夜漫畫", "工口動漫"]
},
page: () => fn.clp("/comic/detail/"),
json: () => {
fn.showMsg(DL.str_05, 0);
let [id] = fn.clp().match(/\d+/);
return fetch(`https://api.nftbaoyi.com/comic/${id}`).then(res => res.json()).then(json => {
siteJson = json;
debug("\n此頁JSON資料\n", siteJson);
apiCustomTitle = siteJson.name;
fn.hideMsg();
});
},
SPA: () => _this.page(),
observeURL: "head",
init: () => _this.page() ? _this.json() : void 0,
imgs: () => _this.page() ? fn.wait(() => isArray(siteJson.book_pages)).then(() => siteJson.book_pages.map(e => e.img_url)) : [],
button: [4],
insertImgBF: () => fn.waitEle(".grid img").then(() => fn.createImgBox(".grid", 1, 1200)),
insertImg: [
["box", 0, ".grid,a.justify-center,div:has(>a.block),div:has(>.custom-pagination)"], 2
],
customTitle: () => _this.page() ? fn.wait(() => isString(siteJson.name)).then(() => siteJson.name) : [],
hide: "body>ins,div:not([id],[class]):has(div.items-center)",
category: "hcomic"
}, {
name: "嗶咔漫畫PICACG",
url: {
h: ["manhuabika.com", "manhuapica.com"],
p: "/pchapter/",
s: "chapter=",
d: "pc"
},
imgs: () => {
const {
jQuery: $,
getTimeOnece,
cid,
chapter,
catMaxPage: max,
ProxyBaseUrl,
postHeader,
getsignature,
getS3ProxySet
} = _unsafeWindow;
fn.showMsg(DL.str_05, 0);
let fetchNum = 0;
const get = (page) => new Promise(resolve => {
const setTime = getTimeOnece();
const mothod = "GET";
const pathname = "comics/" + cid + "/order/" + chapter + "/pages?page=" + page;
$.ajax({
type: mothod,
contentType: "application/json; charset=UTF-8",
crossBrowser: true,
url: ProxyBaseUrl + pathname,
beforeSend: (request) => {
$.each(postHeader(setTime, pathname, mothod), (idx, obj) => request.setRequestHeader(obj.name, obj.value));
request.setRequestHeader("signature", getsignature(pathname, setTime, mothod));
request.setRequestHeader("image-quality", "original");
},
success: resolve
});
}).then(json => {
const {
ep: {
title
},
pages
} = json.data;
if (page == 1) {
customTitle += " " + title;
debug(`\n自定義標題:${customTitle}`);
}
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${max}`, 0);
const proxy = getS3ProxySet();
return pages.docs.map(e => proxy + e.media.path);
});
let resArr = fn.arr(max, (v, i) => get(i + 1));
return Promise.all(resArr).then(data => data.flat());
},
autoDownload: [0],
next: () => {
const {
chapter,
maxchapter
} = _unsafeWindow;
if (chapter < maxchapter) {
let url = new URL(fn.url);
url.searchParams.set("chapter", chapter + 1)
return url.href;
}
return null;
},
prev: 1,
customTitle: () => {
const {
jQuery: $,
getTimeOnece,
cid,
ProxyBaseUrl,
postHeader,
getsignature
} = _unsafeWindow;
return new Promise(resolve => {
const setTime = getTimeOnece();
const mothod = "GET";
const pathname = "comics/" + cid;
$.ajax({
type: mothod,
contentType: "application/json; charset=UTF-8",
crossBrowser: true,
url: ProxyBaseUrl + pathname,
beforeSend: (request) => {
$.each(postHeader(setTime, pathname, mothod), (idx, obj) => request.setRequestHeader(obj.name, obj.value));
request.setRequestHeader("signature", getsignature(pathname, setTime, mothod));
},
success: resolve
});
}).then(json => {
const {
author,
title
} = json.data.comic;
if (author) {
if (title.includes(author)) {
return title;
}
return `[${author}] ${title}`;
} else {
return title;
}
});
},
category: "hcomic"
}, {
name: "喜漫漫画",
url: {
h: ["www.favcomic.com", "www.favcomic.net"],
p: "/chapter/"
},
imgs: "#content img",
next: () => {
let next = fn.ge("img[alt=下一话][onclick]");
return next ? next.getAttribute("onclick").split("'")[1] : null;
},
prev: "img[alt=上一话][onclick]",
customTitle: () => fn.dt({
d: "全集"
}),
category: "hcomic"
}, {
name: "Comics",
url: {
h: ["pixiv.app"]
},
page: () => fn.clp("/comics/"),
wait: () => fn.waitEle([".bg-slate-100 img,.shadow-md img", "main h1", "footer[class]"]),
SPA: () => _this.page(),
observeURL: "loop",
init: () => _this.page() ? _this.wait() : void 0,
imgs: () => _this.page() ? fn.gae(".bg-slate-100 img,.shadow-md img") : [],
capture: () => _this.imgs(),
customTitle: () => _this.page() ? fn.gt("main h1") : null,
hide: ".overflow-hidden:has(iframe[src*=ads])",
category: "hcomic"
}, {
name: "日韩漫画/歪歪漫画",
host: ["www.diyihm.com", "www.lltoon.com", "www.rrtoon.com", "wwtoon.com", "www.zztoon.com", "www.vvtoon.com", "www.fftoon.com", "www.wwtoon.com", "www.niumh.com"],
link: "https://hm8.in,hstoon.com",
url: {
t: ["第一漫画", "歪歪漫画", "第一韩漫", "太极漫画网"],
p: /^\/view\/\d+\/\d+$/,
d: "m"
},
init: () => {
try {
let code = fn.gst("$(document).ready");
let objStr = code.match(/window\.\w+\s?=\s?([^;]+)/)[1];
let json = JSON.parse(objStr);
debug("\n此頁JSON資料\n", json);
siteJson = json;
} catch {}
},
imgs: async () => {
if (isArray(siteJson?.volume?.pages) && siteJson?.volume?.pages?.length > 0) {
return siteJson.volume.pages;
} else if (fn.ge("//a[text()='本章已分页']")) {
fn.showMsg(DL.str_01, 0);
let arr = [];
let src;
let page = 1;
let loop = true;
const getData = () => fn.fetchDoc(location.href + "/" + page).then(dom => {
fn.showMsg(`${DL.str_02}${page}/???`, 0);
const srcs = fn.getImgSrcArr(".charpetBox img", dom);
for (src of srcs) {
if (arr.includes(src)) {
loop = false;
return;
} else {
arr.push(src);
}
}
});
while (loop) {
await getData();
page++;
}
return arr;
} else {
return fn.gae(".charpetBox img");
}
},
button: [4, "24%", 3],
insertImg: [".charpetBox", 2],
autoDownload: [0],
next: "#loadNextChapter",
prev: "#loadPrevChapter",
customTitle: () => {
if (siteJson?.volume?.title) {
return siteJson.comic.title + " - " + siteJson.volume.title;
} else {
return fn.gt(".BarTit");
}
},
hide: "body>div[class][style]:first-of-type,body>div[class][style*='display: block; width: 100%; height: 128.75px;'],.letchepter[style*='20px'],#FullPictureLoadGoToLastImage~*:not([id^='Full'],[class^='Full'],[id^='pv-'],[class^='pv-'],#comicRead,#fab,*[class^=fancybox])",
category: "hcomic"
}, {
name: "顶点韩漫/红本子漫画",
link: "https://mh4.top,aetoon.com",
host: ["mgtoon.com", "hktoon.com", "www.redbz.com"],
url: {
t: ["顶点韩漫", "红本子漫画"],
p: /^\/view\/\d+\/\d+$/,
d: "m"
},
init: () => fn.waitVar("chapter_id").then(() => (siteJson = Object.entries(_unsafeWindow).filter(([k, v]) => !!v?.comic)[0][1])),
imgs: () => siteJson.volume.pages,
button: [4, "24%", 3],
insertImg: [".charpetBox", 2],
autoDownload: [0],
next: "#loadNextChapter",
prev: "#loadPrevChapter",
customTitle: () => {
let {
comic: {
title: mn
},
volume: {
title: cn
}
} = siteJson;
return cn.includes(mn) ? cn : mn + " - " + cn;
},
fancybox: {
blacklist: 1
},
hide: "body>div[class][style]",
category: "hcomic"
}, {
name: "头牌漫画网/顶点漫画/第一漫画网",
link: "https://xs8.me/,https://mh8.in/",
host: ["dmmtu.com", "dmmpic.com", "dymmt.com", "kkmnt.com", "mmxzt.com"],
url: {
t: ["头牌漫画网", "顶点漫画", "顶点韩漫", "第一漫画网"],
p: /^\/chapter\/\d+\.html$/
},
init: async () => {
const last = dom => !fn.ge(".mip-box-body img", dom);
await fn.getNP(".mip-box-body img", "//a[text()='下一页']", last, ".info");
},
box: [".info", 2],
imgs: ".mip-box-body img",
button: [4],
insertImg: [
["box", 0, ".mip-box-body>img"], 2
],
autoDownload: [0],
next: () => {
if ("nextid" in _unsafeWindow && _unsafeWindow.nextid != 0) {
return fn.dir(fn.lp) + _unsafeWindow.nextid + ".html";
}
return null;
},
prev: 1,
customTitle: ".mip-box-heading",
fancybox: {
blacklist: 1
},
hide: "body>div[class][style]",
category: "hcomic"
}, {
name: "松鼠症倉庫 閱讀頁",
host: ["ahri8.com"],
url: {
e: "//div[@id='logo-group']//a[contains(text(),'松鼠症倉庫') or contains(text(),'松鼠症仓库')]",
p: "readOnline",
cookie: "token"
},
imgs: () => {
const {
Original_Image_List,
HTTP_IMAGE
} = _unsafeWindow;
return Original_Image_List.map(e => HTTP_IMAGE + e.new_filename + "_w1500." + e.extension);
},
button: [4],
insertImg: ["#Big_Image", 2],
customTitle: () => fn.dt({
s: ".page-header",
d: "線上閱讀"
}),
hide: "#content>.col-lg-12,[id^=read_online_ads_area],#Big_Image~*",
category: "hcomic"
}, {
name: "松鼠症倉庫 詳情頁",
host: ["ahri8.com"],
url: {
e: "//div[@id='logo-group']//a[contains(text(),'松鼠症倉庫') or contains(text(),'松鼠症仓库')]",
p: "/post",
s: "ID=",
cookie: "token"
},
init: () => {
let e = fn.ge("//a[text()='預覽圖片']");
e.innerText = "圖片";
},
imgs: async () => {
let url = fn.gu("#more-information1 a:has(i.fa-book)");
await fn.getCode(url, {
mode: "dom",
key: "Original_Image_List"
});
const {
Original_Image_List,
HTTP_IMAGE
} = _unsafeWindow;
return Original_Image_List.map(e => HTTP_IMAGE + e.new_filename + "_w1500." + e.extension);
},
button: [4],
insertImg: ["#more-information1>div:has(img)", 2],
category: "hcomic"
}, {
name: "Caitlin.top/Ahri Gallery分機 閱讀頁",
host: [
"caitlin.top",
"ahri-gallery-lzgwo.top",
"ahri-gallery-20250322.top",
"ahri-gallery-ya48mscet5-2024-09-29.top",
"ahri-gallery-zix3l9mzfj-2024-09-01.top",
"ahri-gallery-scggiba9-2024-06-29.top",
"ahri-gallery-xfjd-2024-04-25.top",
"ahri-gallery-jq5s6-2024-04-29.top",
"xayahentai.com",
"xayahentai-hrr2q.top",
"xr2ggt95ie0202.top",
"lux-hentai.com",
"dvamh.top",
"dvamh-vzwp7.top",
"dvamh-di4nn.top",
"dvamh-gasje.top",
"zeri-m.top"
],
url: {
h: /caitlin|ahri|hentai|dvamh|zeri/,
p: "index",
s: "/read",
cookie: "token"
},
imgs: () => {
const {
Image_List,
IMAGE_SERVER,
image_server_id,
IMAGE_FOLDER
} = _unsafeWindow;
let counter = 0;
let srcArr = [];
for (let Image of Image_List) {
let ext = fn.ex(Image.extension.toLowerCase());
let src = IMAGE_SERVER[image_server_id][counter] + IMAGE_FOLDER + Image.sort + "." + ext;
srcArr.push(src);
counter += 1;
if (counter >= Object.keys(IMAGE_SERVER[image_server_id]).length) {
counter = 0;
}
}
return srcArr;
},
button: [4],
insertImg: ["#Big_Image", 2],
customTitle: "#content .d,.gallery_title",
hide: "#content>.col-lg-12,[id^=read_online_ads_area],#Big_Image~*",
category: "hcomic"
}, {
name: "Caitlin.top/Ahri Gallery分機 詳情頁",
url: {
h: /caitlin|ahri|hentai|dvamh|zeri/,
p: "index",
s: "article",
cookie: "token"
},
init: () => {
if (fn.ge("//a[text()='Read']")) {
fn.createImgBox(".container:has(.gallery_card)");
} else {
fn.createImgBox("#more-information1>div.row:has(img),div[id='2div'],#default-tab-thumbnail", 2);
}
_unsafeWindow.onscroll = null;
},
imgs: async () => {
let url;
if (fn.ge("//a[text()='Read']")) {
url = fn.gu("//a[text()='Read']");
} else if (fn.ge("a:has(.fa-eye)")) {
url = fn.gu("a:has(.fa-eye)");
} else {
url = fn.gu("#more-information1 a:has(i.fa-book)");
}
await fn.getCode(url, {
mode: "dom",
key: "Image_List"
});
const {
Image_List,
IMAGE_SERVER,
image_server_id,
IMAGE_FOLDER
} = _unsafeWindow;
let counter = 0;
let srcArr = [];
for (let Image of Image_List) {
let ext = fn.ex(Image.extension.toLowerCase());
let src = IMAGE_SERVER[image_server_id][counter] + IMAGE_FOLDER + Image.sort + "." + ext;
srcArr.push(src);
counter += 1;
if (counter >= Object.keys(IMAGE_SERVER[image_server_id]).length) {
counter = 0;
}
}
return srcArr;
},
button: [4],
insertImg: [
["box", 0, "#more-information1>div.row:has(img),div[id='2div'],#default-tab-thumbnail"], 2
],
customTitle: () => fn.getText([".row>.col-xs-12>h2", "div.name>h2", ".gallery_title", ".gallery_title2", "div[id='1div'] .h2", ".app-content .page-header"]),
category: "hcomic"
}, {
name: "蚂蚁搬运网/紳士泛漫畫",
links: [
"https://www.antbyw.com/plugin.php?id=jameson_manhua",
"https://itsacg.top/"
],
url: {
h: ["www.antbyw.com", /itsacg\./],
s: "=read",
st: "urls",
d: "pc"
},
imgs: () => {
let pages = fn.ge("//a[text()='无分页阅读']");
if (pages) {
fn.showMsg(DL.str_05, 0);
let url = fn.gu("//a[text()='无分页阅读']");
return fn.fetchDoc(url).then(dom => {
let code = fn.gst("urls", dom);
return fn.TextToArray(code, "urls");
});
}
let code = fn.gst("urls");
return fn.TextToArray(code, "urls");
},
button: [4],
insertImg: [".uk-zjimg", 2],
autoDownload: [0],
next: "//a[contains(text(),'下一章')]",
prev: "//a[contains(text(),'上一章')]",
chapters: {
url: "//a[text()='[目录]']",
target: ".muludiv a[href]",
sort: "r"
},
customTitle: () => {
if (fn.lh.includes("antbyw")) {
let eles = fn.gae(".uk-breadcrumb li");
return eles?.at(-2)?.innerText + " - " + eles?.at(-1)?.innerText;
} else {
let ct = fn.gt(".uk-breadcrumb>li:nth-child(4)");
let nt = fn.gt(".uk-breadcrumb>li:nth-child(5)");
if (ct.includes("|")) {
ct = ct.split("|")[0].trim();
}
ct = ct.replace(/【.+】/g, "").trim();
if (nt === "阅读浏览") {
return ct;
} else {
return ct + " - " + nt;
}
}
},
category: "comic"
}, {
name: "蚂蚁搬运网M",
url: {
h: "www.antbyw.com",
s: "=read",
st: "urls",
d: "m"
},
imgs: () => {
let code = fn.gst("urls");
return fn.TextToArray(code, "urls");
},
button: [4],
insertImg: ["#img_list", 2],
insertImgAF: () => fn.hideEle("#img_load"),
next: () => {
let next = fn.ge("//a[text()='下一章']");
if (next) {
let [id] = fn.attr("//a[text()='下一章']", "onclick").match(/\d+/);
if (Number(id)) {
let searchParams = new URLSearchParams(fn.ls);
searchParams.set("zjid", id);
return fn.lp + "?" + searchParams.toString();
}
return null;
}
return null;
},
prev: 1,
customTitle: [".title a", ".title span"],
category: "comic"
}, {
name: "紳士泛漫畫M",
url: {
h: /itsacg\./,
s: "=read",
st: "urls",
d: "m"
},
imgs: () => {
let pages = fn.ge("//a[text()='无分页阅读模式']");
if (pages) {
fn.showMsg(DL.str_05, 0);
let url = fn.gu("//a[text()='无分页阅读模式']");
return fn.fetchDoc(url).then(dom => {
let code = fn.gst("urls", dom);
return fn.TextToArray(code, "urls");
});
}
let code = fn.gst("urls");
return fn.TextToArray(code, "urls");
},
button: [4],
insertImg: [
[".zjimg", 1, ".zjimg"], 2
],
customTitle: "#comicName",
category: "hcomic"
}, {
name: "ACG糖",
host: ["acgotang.com"],
url: {
e: "//div[@class='content']//a[text()='ACG糖']",
p: /^\/\w+\/\w+\.html$/
},
imgs: () => {
let max = fn.gt("//a[text()='下一页']", 2);
return fn.getImgO(".manga-picture img", max, 5);
},
button: [4],
insertImg: [".manga-page", 2],
autoDownload: [0],
next: ".next-toon a",
prev: ".pre-toon a",
customTitle: ".title",
category: "hcomic"
}, {
name: "Roku Hentai",
host: ["rokuhentai.com"],
reg: /^https?:\/\/rokuhentai\.com\/\w+$/,
include: ".site-page-card__media",
imgs: () => {
fn.showMsg(DL.str_05, 0);
let url = fn.url + "/0";
return fn.fetchDoc(url).then(dom => fn.getImgSrcArr(".site-reader__image", dom));
},
button: [4],
insertImg: [
[".site-manga-info+.mdc-layout-grid", 2], 2
],
customTitle: () => fn.title(" - Roku Hentai"),
hide: ".site-bottom-ad-slot",
category: "hcomic"
}, {
name: "Roku Hentai",
host: ["rokuhentai.com"],
reg: /^https?:\/\/rokuhentai\.com\/\w+\/\d+$/,
imgs: ".site-reader__image",
button: [4],
insertImg: [".site-reader", 2],
customTitle: () => fn.title(" - Roku Hentai"),
css: ".site-reader--right-to-left,.site-reader--left-to-right{overflow-x:auto !important;overflow-y:auto !important}.site-reader{padding-bottom:0px !important}.site-reader{display:block !important}",
hide: ".site-bottom-ad-slot",
category: "hcomic"
}, {
name: "177 漫画/XXIAV寫真館",
url: {
h: [/177pic/, "www.xxiav.com"],
p: /^\/html\/\d+\/\d+\/\d+\.html$/
},
imgs: () => fn.getImg(".single-content img[data-lazy-src]", (fn.gt(".page-links>*:last-child", 2) || 1), 10),
button: [4],
insertImg: [".single-content", 2],
autoDownload: [0],
next: "a[rel=prev]",
prev: 1,
customTitle: ".entry-title",
category: "hcomic"
}, {
name: "18H 宅宅愛動漫",
host: ["18h.animezilla.com"],
reg: /^https?:\/\/18h\.animezilla\.com\/manga\/\d+/,
imgs: () => {
let max = Number(fn.gu(".last")?.split("/")?.at(-1)) || 1;
return fn.getImgO("#comic", max, "4", null, 0, ".entry-title,.wp-pagenavi", siteUrl, 0);
},
button: [4],
insertImg: ["#page-current", 1],
customTitle: () => fn.dt({
s: "h1.entry-title",
d: /\s?\[\d+P\](\s?-\s?\d+\/\d+\s?)?/i
}),
category: "hcomic"
}, {
name: "色漫网",
url: {
h: "www.cartoon18.com",
p: "/v/",
e: ".title+div>a.btn-info"
},
box: [".row.mb-4", 2],
imgs: () => {
fn.showMsg(DL.str_05, 0);
let urls = fn.gau(".title+div>a.btn-info");
return fn.getImgA("img[data-src],#lightgallery a,.gallary a", urls, 2000);
},
button: [4],
insertImg: ["box", 3],
fancybox: {
v: 3,
css: false
},
hide: "#chromeModal,.modal-backdrop",
category: "hcomic"
}, {
name: "色漫网",
url: {
h: "www.cartoon18.com",
p: "/v/",
e: ".title+div>a>i.fa-play"
},
imgs: () => {
fn.showMsg(DL.str_05, 0);
let url = fn.gu(".title+div>a");
return fn.fetchDoc(url).then(dom => fn.ge("img[data-src]", dom) ? fn.gae("img[data-src]", dom) : fn.gae("#lightgallery a,.gallary a", dom));
},
button: [4],
insertImg: ["//div[a[img]]", 2],
insertImgAF: (parent) => {
parent.className = "";
let modalOpen = fn.ge(".modal-open");
if (modalOpen) modalOpen.classList.remove("modal-open");
},
fancybox: {
v: 3,
css: false
},
hide: "#chromeModal,.modal-backdrop",
category: "hcomic"
}, {
name: "色漫网",
host: ["www.cartoon18.com"],
reg: /^https?:\/\/www\.cartoon18\.com\/([\w-]+\/)?story\/\d+\/full/,
imgs: () => fn.ge("img[data-src]") ? fn.gae("img[data-src]") : fn.gae("#lightgallery a,.gallary a"),
button: [4],
insertImg: ["#lightgallery,.gallary", 2],
autoDownload: [0],
next: "//a[text()='下一話']",
prev: "//a[text()='上一話']",
fancybox: {
v: 3,
css: false
},
category: "hcomic"
}, {
name: "H漫 閱讀頁",
host: ["hman91.com"],
url: {
t: "H漫",
p: "/manga-read/",
ee: ".page-title"
},
imgs: "#main .content img",
button: [4],
insertImg: [".content center:has(>div>img)", 2],
autoDownload: [0],
next: "//a[text()='下一章'][@href]",
prev: "//a[text()='上一章'][@href]",
customTitle: ["#main h1", "#main h2"],
category: "hcomic"
}, {
name: "H漫 目錄頁",
url: {
t: "H漫",
p: "/manga-read/"
},
box: [".module-list[id]", 2],
imgs: () => {
let links = fn.gau(".module-tab~.module-blocklist a");
return fn.getImgA("#main .content img", links);
},
button: [4],
insertImg: ["box", 3],
customTitle: ".page-title",
category: "hcomic"
}, {
name: "开心看漫画 閱讀頁",
host: ["kxmanhua.com"],
url: {
t: "开心看漫画",
p: "/detail/"
},
imgs: ".blog__details__content img",
button: [4],
insertImg: [".blog__details__content", 2],
endColor: "white",
autoDownload: [0],
next: "//a[text()='下一话'][@href]",
prev: "//a[text()='上一话'][@href]",
customTitle: () => fn.ge("meta[name='manga-name']").content + " - " + fn.ge("meta[name='chap-title']").content,
hide: ".fixed-ads,.ad-banner,.blog__details__content~*",
category: "hcomic"
}, {
name: "开心看漫画 目錄頁",
url: {
t: "开心看漫画",
p: "/manga/"
},
box: [".anime__details__episodes", 2],
imgs: () => {
let links = fn.gau(".chapter_list a").reverse();
return fn.getImgA(".blog__details__content img", links);
},
button: [4],
insertImg: ["box", 3],
customTitle: ".anime__details__title>h3",
hide: ".ad-banner",
category: "hcomic"
}, {
name: "凹凸漫/X漫/肉漫天堂 閱讀頁",
host: ["atm166.org", "xman8.org", "rmtt7.com"],
url: {
t: ["凹凸漫", "X漫", "肉漫天堂"],
p: "read/",
e: [
"center>h1",
"center>h2"
]
},
init: () => fn.clearAllTimer(),
imgs: "img.lazyload[data-original]",
button: [4],
insertImg: ["center:has(>div>img.lazyload[data-original])", 2],
autoDownload: [0],
next: "//a[text()='下一章']",
prev: "//a[text()='上一章']",
customTitle: ["center>h1", "center>h2"],
category: "hcomic"
}, {
name: "凹凸漫/X漫/肉漫天堂 目錄頁",
url: {
t: ["凹凸漫", "X漫", "肉漫天堂"],
p: "detail/",
e: ".playlist_full"
},
init: () => {
fn.clearAllTimer();
if ("showlist" in _unsafeWindow) {
_unsafeWindow.showlist();
}
},
box: [".hot_banner", 2],
imgs: () => {
let links = fn.gau(".playlist_full .content_playlist a");
return fn.getImgA("img.lazyload[data-original]", links);
},
button: [4],
insertImg: ["box", 3],
customTitle: "h1.title",
category: "hcomic"
}, {
name: "韓漫射/绅士同人H漫",
url: {
h: ["h-webtoon.com", "h-doujinshi.xyz"]
},
init: "setTimeout(()=>{fn.gae('.g1-nav-single a').forEach(e=>{e.removeAttribute('target')})},2000)",
imgs: ".g1-content-narrow p img",
button: [4],
insertImg: [".g1-content-narrow", 2],
autoDownload: [0],
next: "#content .g1-teaser-next",
prev: "#content .g1-teaser-prev",
customTitle: "h1.entry-title",
hide: "#simple-banner,.touchy-wrapper,.touchy-wrapper~*:not([id^='Full'],[class^='Full'],[id^='pv-'],[class^='pv-'],[id^='pagetual'],[class^='pagetual'],#comicRead,#fab,*[class^=fancybox]),.code-block,#secondary",
category: "hcomic"
}, {
name: "18H漫画",
host: ["18hmanga.com", "18hmanga.cyou"],
reg: /^https?:\/\/(18hmanga\.(com|cyou))\/[^\/]+\/$/,
init: () => fn.remove(".code-block,#secondary,body>div[id][class][style]"),
imgs: ".entry-content>img,.entry-content>p>img,.entry-content>div>img",
button: [4],
insertImg: [".entry-content", 2],
autoDownload: [0],
next: "#content .g1-teaser-prev",
prev: "#content .g1-teaser-next",
customTitle: ".entry-title",
css: ".g1-column-2of3{width:100%!important}",
category: "hcomic"
}, {
name: "18H漫画",
url: {
h: "18hmanga",
e: "//a[contains(text(),'Read More')]"
},
init: () => fn.remove("body>div[id][class][style]"),
imgs: () => {
fn.showMsg(DL.str_01, 0);
let fetchNum = 0;
let resArr = fn.gau("//a[contains(text(),'Read More')]").map((url, i, arr) => {
return fn.fetchDoc(url).then(dom => {
fn.showMsg(`${DL.str_02}${fetchNum+=1}/${arr.length}`, 0);
return fn.gae(".entry-content>img,.entry-content>p>img,.entry-content>div>img", dom);
});
})
return Promise.all(resArr).then(arr => arr.flat());
},
button: [4],
insertImg: [
["#primary", 0], 2
],
customTitle: ".g1-breadcrumbs-item>span[itemprop=name]",
category: "hcomic"
}, {
name: "老司機禁漫 目錄頁",
host: ["laosiji6.com", "laosijix.org"],
url: {
h: "laosiji",
p: /^\/comic\/\d+$/i
},
box: [".detail", 2],
imgs: () => {
let links = fn.gau(".vol-item a").reverse();
return fn.getImgA("img.lazy", links);
},
button: [4],
insertImg: [
["box", 0], 3
],
customTitle: ".detail h1",
category: "hcomic"
}, {
name: "老司機禁漫 閱讀頁",
host: ["laosiji6.com", "laosijix.org"],
url: {
h: "laosiji",
p: /^\/comic\/\d+\/\w+$/i
},
box: ["img.lazy", 1],
imgs: "img.lazy",
button: [4],
insertImg: [
["box", 0, "img.lazy"], 2
],
insertImgAF: () => {
if (nextLink && !fn.ge("//a[text()='章節目錄']")) {
fn.addUrlHtml(nextLink, ".container-fluid", 2);
fn.css(".positionFooter{display:none!important;}");
}
},
autoDownload: [0],
next: () => {
let chapterId = fn.lp.split("/").at(-1);
let comicUrl = fn.gu(".breadcrumb-item:nth-child(2)>a");
let nextXPath = `//div[div[div[label[span[a[contains(@href,'${chapterId}')]]]]]]/preceding-sibling::div[1]//a`;
return fn.fetchDoc(comicUrl).then(dom => {
let next = fn.ge(nextXPath, dom, dom);
return next ? next.href : null;
});
},
prev: 1,
customTitle: [".breadcrumb-item:nth-child(2) a", ".breadcrumb-item.active"],
category: "hcomic"
}, {
name: "COMIC18",
host: ["www.comic18.cc"],
reg: /^https?:\/\/www\.comic18\.cc\/\w+\/\d+\.html$/,
init: () => fn.waitEle(".article-body>img").then(e => fn.createImgBox(e, 1)),
imgs: ".article-body>img",
button: [4],
insertImg: [
["box", 0, ".article-body>img"], 2
],
autoDownload: [0],
next: "a.entry-page-prev[href$=html]",
prev: "a.entry-page-next[href$=html]",
customTitle: ".detail-title",
category: "hcomic"
}, {
name: "18漫畫",
host: ["18mh.org"],
reg: [
/^https?:\/\/badynews\.com\/[^\/]+$/i,
/^https?:\/\/18mh\.org\/manga\/[\w-]+\/[\d-]+/
],
init: async () => {
await fn.waitEle(".touch-manipulation img");
fn.remove(".flex.flex-row.space-x-2.px-2.py-4");
},
imgs: ".touch-manipulation img",
button: [4],
insertImg: [".touch-manipulation", 2],
autoDownload: [0],
next: "#nextChapterLink",
prev: "#preChapterLink",
customTitle: ["ol.inline-flex>li:nth-child(2) a", "ol.inline-flex>li:nth-child(3) a"],
category: "hcomic"
}, {
name: "热漫画",
url: {
t: ["Rehanman", "rehanman"],
h: "rehanman.com"
},
page: () => fn.clp("/webtoon/"),
SPA: () => _this.page(),
observeURL: "head",
imgs: () => {
if (!_this.page()) return [];
let [, , id] = fn.clp().split("/");
let body = {
query: "\n query entry($id: ID, $inputs: InputEntries) {\n entry (_id: $id, inputs: $inputs ){\n _id, \n title,\n alt_title,\n description,\n title_normalized,\n adult,\n released_year,\n status,\n thumbnail,\n type,\n authors { name },\n genres { name },\n created_date,\n modified_date,\n rating,\n rating_votes,\n views,\n volumes { id, chapters_count }\n entries_data { _id, chapters {name, title, index, images}, volume_name }\n entries_setting { _id, premium, entryId, isHide, countRead }\n }\n }\n",
variables: {
inputs: {
title_normalized: id
}
}
};
fn.showMsg(DL.str_05, 0);
return fetch("https://api.rehanman.com/manga-graphql", {
"headers": {
"content-type": "application/json"
},
"body": JSON.stringify(body),
"method": "POST"
}).then(res => res.json()).then(json => {
apiCustomTitle = json.data.entry.title;
return json.data.entry.entries_data.chapters.map(e => e.images).flat().map(e => "https://img.rehanman.com/uploads/data/china18sky/" + e);
});
},
capture: () => _this.imgs(),
category: "hcomic"
}, {
name: "NyaHentai",
url: {
h: ["nyahentai.re", "shikotch.in", "doujinantena.top"],
p: ["/re", "/comic/"]
},
imgs: "#post-comic img",
button: [4],
insertImg: ["#post-comic", 2],
customTitle: "#post-data h1",
hide: "[id*='_ad_'],div:has(>iframe),[id^='bnc_ad'],[class*='-ads-']",
category: "hcomic"
}, {
name: "Hitomi.la",
url: {
h: ["hitomi.la"]
},
page: () => !!fn.ge("#read-online-button[href^='/reader/']:not([style])"),
SPA: () => _this.page(),
observeURL: "loop",
imgs: () => {
if (!_this.page()) return [];
fn.showMsg(DL.str_05, 0);
let url = fn.gu("#read-online-button");
return fn.iframeVar(url, "galleryinfo").then(w => {
fn.hideMsg();
const {
galleryinfo,
url_from_url_from_hash,
our_galleryinfo
} = w;
apiCustomTitle = fn.dt({
t: galleryinfo.title,
d: "| Hitomi.la"
});
thumbnailSrcArray = fn.gae(".gallery-preview img").map(e => e.dataset.src ?? e.src);
return galleryinfo.files.map((e, i) => url_from_url_from_hash(galleryinfo.id, our_galleryinfo[i], hitomi_img_type));
});
},
button: [4],
insertImgBF: () => fn.createImgBox(".content", 2),
insertImg: ["box", 2],
insertImgAF: () => fn.hideEle(".thumbnail-list,.simplePagerNav"),
hide: "div:has(>[data-cl-spot]),div:has(>ins)",
category: "hcomic"
}, {
name: "NyaHentai/Joy Hentai/Hitomi/HitomiKR",
url: {
h: ["nyaa.fan", "joyhentai.red", "hitomi.si", "hitomikr.org", "hitomi.jp.net"]
},
page: () => ["/post/", "/g/", "/mangazine/"].some(p => fn.clp(p)),
SPA: () => _this.page(),
observeURL: "head",
data: () => fn.showMsg(DL.str_05, 0).then(() => {
let [id] = fn.clp().match(/\d+$/);
let res_a = fetch(`/spa/manga/${id}`).then(res => res.json());
let res_b = fetch(`/spa/manga/${id}/read`).then(res => res.json());
return Promise.all([res_a, res_b]).then(([a, b]) => {
siteJson = {
...a,
...b
};
fn.hideMsg();
});
}),
init: () => _this.page() ? _this.data() : void 0,
imgs: () => {
if (!_this.page()) return [];
let {
preview_imgs: {
pages
},
chapter_detail: {
server,
chapter_content
},
detail: {
manga_name
}
} = siteJson;
thumbnailSrcArray = Object.values(pages).flat();
let temp = fn.html(chapter_content);
return fn.gae(".chapter-img canvas[data-srcset],.chapter-img img[data-url]", temp).map(e => server + (e.dataset.srcset || e.dataset.url));
},
capture: () => _this.imgs(),
customTitle: () => _this.page() ? siteJson.detail.manga_name : null,
category: "hcomic"
}, {
name: "HentaiCamp",
url: {
h: ["hentaicamp.com"]
},
page: () => fn.clp("/hc/") && fn.clp()?.split("/")?.length === 3,
SPA: () => _this.page(),
observeURL: "head",
data: () => fn.showMsg(DL.str_05, 0).then(() => {
let url = `https://api.hentaicamp.com/api${fn.clp()}/load-more-images?show_all=true`;
let res_a = fetch(url).then(res => res.json()).then(json => (siteJson = json));
let res_b = fn.fetchDoc(fn.clp()).then(dom => (doc = dom));
return Promise.all([res_a, res_b]).then(() => fn.hideMsg());
}),
init: () => _this.page() ? _this.data() : void 0,
imgs: () => {
if (!_this.page()) return [];
let s = "https://api.hentaicamp.com/storage/";
thumbnailSrcArray = siteJson.images.map(e => s + e.small_image_path);
return siteJson.images.map(e => s + e.image_path);
},
capture: () => _this.imgs(),
customTitle: () => _this.page() ? fn.gt(".card-title", 1, doc) : null,
category: "hcomic"
}, {
name: "Hentaiser",
url: {
h: ["app.hentaiser.com"]
},
page: () => fn.clp("/book/"),
SPA: () => _this.page(),
observeURL: "head",
data: () => fn.showMsg(DL.str_05, 0).then(() => {
let [, , id] = fn.clp().split("/");
let res_a = fetch("https://api.hentaiser.com/1.3/books/" + id).then(res => res.json());
let res_b = fetch("https://api.hentaiser.com/1.3/books/" + id + "/pages").then(res => res.json());
return Promise.all([res_a, res_b]).then(([a, b]) => {
siteJson = {
...a,
...b
};
fn.hideMsg();
});
}),
init: () => _this.page() ? _this.data() : void 0,
imgs: () => {
if (!_this.page()) return [];
let {
host,
pages
} = siteJson;
return pages.map(e => host + e);
},
button: [4],
insertImgBF: () => fn.waitEle("#detailsSection").then(e => fn.createImgBox(e, 2)),
insertImg: ["box", 2],
capture: () => _this.imgs(),
customTitle: () => _this.page() ? siteJson.title : null,
category: "hcomic"
}, {
name: "KOMI",
url: {
h: ["komi.la"]
},
page: () => fn.clp("/manga/"),
SPA: () => _this.page(),
observeURL: "nav",
data: () => fn.showMsg(DL.str_05, 0).then(() => {
let [, , id] = fn.clp().split("/");
let url = "/api/galleries/" + id;
return fetch(url).then(res => res.json()).then(json => (siteJson = json) && fn.hideMsg());
}),
init: () => _this.page() ? _this.data() : void 0,
imgs: () => {
if (!_this.page()) return [];
return siteJson.images.map(e => e.url);
},
capture: () => _this.imgs(),
customTitle: () => _this.page() ? siteJson.title : null,
category: "hcomic"
}, {
name: "Doujin.sexy",
url: {
h: ["doujin.sexy"]
},
page: () => fn.clp("/read/"),
SPA: () => _this.page(),
observeURL: "head",
data: () => fn.showMsg(DL.str_05, 0).then(() => {
let [, , id] = fn.clp().split("/");
let url = `https://api.doujin.sexy/v3/album/${id}/pages?token=OJ9X057amA`;
return fetch(url).then(res => res.json()).then(json => (siteJson = json) && fn.hideMsg());
}),
init: () => _this.page() ? _this.data() : void 0,
imgs: () => {
if (!_this.page()) return [];
return siteJson.data.pages.map(e => e.sizes.full);
},
capture: () => _this.imgs(),
customTitle: () => _this.page() ? siteJson.data.title : null,
category: "hcomic"
}, {
name: "app.rule34.dev",
url: {
h: ["app.rule34.dev"]
},
page: () => fn.clp("/manga/g/"),
SPA: () => _this.page(),
observeURL: "nav",
data: () => fn.showMsg(DL.str_05, 0).then(() => fn.fetchDoc(fn.clp()).then(dom => {
doc = dom;
let code = fn.gst("pageProps", dom);
let json = JSON.parse(code);
siteJson = json.props.pageProps;
fn.hideMsg();
})),
init: () => _this.page() ? _this.data() : void 0,
imgs: () => {
if (!_this.page()) return [];
let {
pages: {
host,
pages
}
} = siteJson
return pages.map(e => host + e);
},
capture: () => _this.imgs(),
customTitle: () => _this.page() ? fn.getText("#__next h1", doc) : null,
category: "hcomic"
}, {
name: "PornComicsHD",
url: {
h: ["porncomicshd.com"]
},
page: () => ["/hd-porn-comics/", "/comics-porno-hd/", "/quadrinhos-porno-hd/", "/porno-comics-hd/"].some(p => fn.clp(p)),
SPA: () => _this.page(),
observeURL: "head",
imgs: () => fn.gae("app-comic-reader img"),
customTitle: () => fn.gt("app-comic-page h1") || fn.ge("app-comic-reader img")?.alt,
category: "hcomic"
}, {
name: "хентай манга",
host: ["a1.nude-moon.mom"],
url: {
e: "//div[text()='хентай манга']",
p: "/online/"
},
imgs: ".page__player img",
button: [4],
insertImg: [".page__player", 2],
customTitle: ".page__main h1",
category: "hcomic"
}, {
name: "Хентай-тян!",
host: ["hentaichan.live", "xxl.hentaichan.live", "hentaichan.pro", "x.hentaichan.pro", "hentai-chan.pro", "x4.h-chan.me"],
url: {
e: ["#thumbs img"],
p: "/online/",
s: "cacheId"
},
box: ["#thumbs", 1],
imgs: () => {
thumbnailSrcArray = fn.getImgSrcArr("#thumbs img");
return thumbnailSrcArray.map(e => e.replace("_thumbs", ""));
},
button: [4],
insertImg: ["box", 2],
insertImgAF: () => fn.hideEle("#thumbs"),
customTitle: ".manga-title",
category: "hcomic"
}, {
name: "Хентай-тян!",
url: {
h: "hentaichan.lat",
p: "/online/"
},
imgs: ".page__player img",
button: [4],
insertImg: [".page__player", 2],
customTitle: ".page__main h1",
category: "hcomic"
}, {
name: "HentaiFC閱讀頁",
url: {
h: "hentaifc.com",
p: /^\/e\/\d+\/c/
},
box: ["#chapter", 2, 1200],
init: () => fn.wait((_, w) => {
if (isArray(w?.ytaw)) {
let [e] = w.ytaw;
if (e?.startsWith("http")) {
return true;
}
}
return false;
}),
imgs: () => _unsafeWindow.ytaw,
button: [4],
insertImg: ["box", 2],
insertImgAF: () => fn.hideEle("#chapter"),
category: "hcomic"
}, {
name: "HentaiFC圖片清單頁",
url: {
h: "hentaifc.com",
p: /^\/e\/\d+$/
},
box: [".thumbs", 2],
imgs: () => {
fn.showMsg(DL.str_05, 0);
thumbnailSrcArray = fn.getImgSrcArr(".thumbs img");
let url = fn.gu("//div[@class='thumbs']/a[text()=' Read Online']");
return fn.iframe(url, {
waitVar: "ytaw",
cb: (dom, frame) => fn.wait(() => {
if (isArray(frame?.ytaw)) {
let [e] = frame.ytaw;
if (e?.startsWith("http")) {
return true;
}
}
return false;
})
}).then(w => w?.frame?.ytaw || []);
},
button: [4],
insertImg: ["box", 2],
customTitle: ".info .meta .value",
category: "hcomic"
}, {
name: "HentaiThai",
url: {
h: "hentaithai.com"
},
imgs: "#part-image img",
button: [4],
insertImg: ["#part-image", 2],
customTitle: "#doujin-detail h1",
category: "hcomic"
}, {
name: "เทพโดจิน",
url: {
h: "lnwdoujin.com",
e: "#comic-reader-zone"
},
imgs: () => Object.values(JSON.parse(document.querySelector("#comic-reader-zone").getAttribute("img-code"))).map(e => {
if (e?.sizes?.full?.includes("hentaithai")) {
return "https://lnwdoujin.com/showimg.php?url=" + e.sizes.full;
} else {
return e?.sizes?.full;
}
}),
button: [4],
insertImg: [".entry-content", 2],
customTitle: "#main h1",
category: "hcomic"
}, {
name: "HO5HO",
url: {
h: "www.ho5ho.com",
st: "chapter_preloaded_images"
},
imgs: () => _unsafeWindow.chapter_preloaded_images,
button: [4],
insertImg: [".entry-content", 2],
customTitle: ".breadcrumb>li:nth-child(2)",
category: "hcomic"
}, {
name: "成人漫画 圖片清單頁",
host: ["bad.news"],
link: "https://bad.news/mh",
reg: /^https?:\/\/bad\.news\/mh\/\w+\/id-\d+$/,
imgs: () => {
let link = [fn.gu("a.post-thumb")];
return fn.getImgA("img.img-responsive", link);
},
thums: "img.img-responsive",
button: [4],
insertImg: [
["//div[div[article[div[div[a[img[@class='img-responsive']]]]]]]", 2], 2
],
category: "hcomic"
}, {
name: "成人漫画 閱讀頁",
host: ["bad.news"],
link: "https://bad.news/mh",
reg: /^https?:\/\/bad\.news\/mh\/view\/id-\d+/,
imgs: ".img-responsive",
button: [4],
insertImg: ["//div[img[@class='img-responsive']]", 2],
category: "hcomic"
}, {
name: "H漫画",
host: ["a.123548.xyz"],
url: {
e: "//div[@class='logo']/a[text()='H漫画']",
p: "/e/action/ShowInfo.php"
},
imgs: ".entry img",
button: [4],
insertImg: [".entry", 1],
autoDownload: [0],
next: "//p[contains(text(),'上一')]/a",
prev: "//p[contains(text(),'下一')]/a",
customTitle: ".contitle",
category: "hcomic"
}, {
name: "JComic",
host: ["jcomic.net"],
reg: /^https?:\/\/jcomic\.net\/page\/[^\/]+$/,
imgs: ".comic-view,.comic-thumb",
button: [4],
insertImg: ["//div[img[@class='img-responsive comic-thumb']]", 2],
customTitle: "//ol/li[2]/a",
category: "hcomic"
}, {
name: "JComic",
host: ["jcomic.net"],
reg: /^https?:\/\/jcomic\.net\/page\/[^\/]+\/[0-9\.]+$/,
imgs: ".comic-view,.comic-thumb",
button: [4],
insertImg: ["//div[img[@class='img-responsive comic-thumb']]", 2],
autoDownload: [0],
next: () => {
let next = fn.ge("//a[button[text()='下一章']]");
return next && next.href != siteUrl ? next.href : null;
},
prev: 1,
customTitle: ["//ol/li[2]/a", "//ol/li[3]"],
category: "hcomic"
}, {
name: "一之涩漫画/哈塔兹漫画/布罗塔漫画/物二漫画",
url: {
h: [
"1zse.com",
"hatazi.com",
"www.bulota.com",
/52216\d\.xyz$/
],
p: /^\/index\.php\/\d+\.html/
},
init: () => {
fn.addMutationObserver(() => fn.remove("#eruda,.__chobitsu-hide__,#lightboxOverlay,#lightbox"));
fn.clearAllTimer();
},
imgs: () => fn.getImg(".context img", fn.gt(".pages").match(/\d+/g)[1], 7),
button: [4],
insertImg: [".context", 2],
autoDownload: [0],
next: ".post-previous a",
prev: ".post-next a",
customTitle: () => fn.dt({
s: "#content h1",
d: /\[\d+P\]|〈|〉/gi
}),
hide: "body>*:not(#head,.container,#footer,#tbox,[id^='Full'],[class^='Full'],[id^='pv-'],[class^='pv-'],#comicRead,#fab,*[class^=fancybox])",
category: "hcomic"
}, {
name: "那露漫画",
host: ["naluhd.com"],
reg: /^https?:\/\/naluhd\.com\/index\.php\/\d+\.html/,
imgs: () => fn.getImgA(".article-content img", "a.post-page-numbers"),
button: [4],
insertImg: [".article-content", 2],
autoDownload: [0],
next: "//a[p[text()='上一篇'] and not(starts-with(@href,'java'))]",
prev: "//a[p[text()='下一篇'] and not(starts-with(@href,'java'))]",
customTitle: ".article-title>a",
category: "hcomic"
}, {
name: "最新韩漫网",
host: ["www.manhuazuixin.com"],
reg: /^https?:\/\/www\.manhuazuixin\.com\/chapter_\d+\.html/,
include: ".rd-article-wr,.comic-list",
imgs: ".rd-article-wr img,.comic-list img",
button: [4],
insertImg: [".rd-article-wr,.comic-list", 2],
autoDownload: [0],
next: ".j-rd-next,.next-btn",
prev: ".j-rd-prev,.prev-btn",
customTitle: ".comic-title>a,.comic-name,.mip-shell-header-title",
category: "hcomic"
}, {
name: "韩国a漫 閱讀頁",
host: ["www.hanguoaman.com"],
reg: /^https?:\/\/www\.hanguoaman\.com\/read\/\d+\.html$/,
imgs: ".container img",
button: [4],
insertImg: [".container", 2],
autoDownload: [0],
next: "//a[text()='下一章'][starts-with(@href,'/')]",
prev: "//a[text()='上一章'][starts-with(@href,'/')]",
customTitle: () => fn.dt({
d: / - 韩国.+$/
}),
category: "hcomic"
}, {
name: "韩国a漫 目錄頁",
host: ["www.hanguoaman.com"],
reg: /^https?:\/\/www\.hanguoaman\.com\/aman\//,
box: [".stui-pannel:last-of-type", 1],
imgs: () => {
let links = fn.gau(".stui-content__playlist a");
return fn.getImgA(".container img", links);
},
button: [4],
insertImg: ["box", 3],
customTitle: "h1.title",
category: "hcomic"
}, {
name: "韩漫天下",
host: ["manhuatianxia.com", "www.manhuatianxia.com"],
reg: /^https?:\/\/(www\.)?manhuatianxia\.com\/index\.php\/chapter\/\d+$/,
imgs: "#manga-imgs img,#BookText img",
button: [4],
insertImg: ["#manga-imgs,#BookText", 2],
autoDownload: [0],
next: "//a[text()='下一话' or text()='下一章'][starts-with(@href,'/')]",
prev: "//a[text()='上一话' or text()='上一章'][starts-with(@href,'/')]",
customTitle: () => fn.dt({
d: "韩漫 "
}),
category: "hcomic"
}, {
name: "韩漫在线",
host: ["hanmanol.com", "www.hanmanol.com"],
url: {
e: "a[title=韩漫在线]",
p: /^\/index\.php\/chapter-\d+\.html$/
},
imgs: ".content_read #content img,.chapter_content img",
button: [4],
insertImg: [".content_read #content,.chapter_content", 2],
autoDownload: [0],
next: "//a[text()='下一章'][starts-with(@href,'/')] | //a[div[span[contains(text(),'下一篇')]]][starts-with(@href,'/')]",
prev: "//a[text()='上一章'][starts-with(@href,'/')] | //a[div[span[contains(text(),'上一篇')]]][starts-with(@href,'/')]",
customTitle: () => fn.dt({
d: "在线观看 "
}),
category: "hcomic"
}, {
name: "九妖漫画",
host: ["lifantt.com", "9yaomh.cc"],
url: {
t: "九妖漫画网",
p: "/chapter/"
},
imgs: ".rd-article-wr img,.comic-list img",
button: [4],
insertImg: [".rd-article-wr,.comic-list", 2],
autoDownload: [0],
next: ".j-rd-next,.next-btn",
prev: ".j-rd-prev,.prev-btn",
customTitle: () => fn.title(" - 九妖漫画网"),
hide: "[class^=ad],.m-hm-ad1,p.result",
category: "hcomic"
}, {
name: "韩漫库/腐漫屋",
host: ["se8.us", "fumanwu.org"],
url: {
t: ["韩漫库", "腐漫屋"],
p: "/chapter/"
},
imgs: ".rd-article-wr img,.comic-list img,.episode-detail img",
button: [4],
insertImg: [".rd-article-wr,.comic-list,.episode-detail", 1],
autoDownload: [0],
next: ".j-rd-next,.next-btn,a.next[href^='/']",
prev: ".j-rd-prev,.prev-btn,a.prev[href^='/']",
customTitle: async () => {
if (fn.ge(".rd-article-wr")) {
return fn.gt(".read__crumb").replace("首页 ", "").replace(" ", " - ");
} else {
try {
return _unsafeWindow.shareArr[0].match(/《([^》]+)/)[1] + " - " + fn.gt(".comic-name");
} catch {
let url = fn.gu("//a[contains(text(),'全集')]");
let comicName = await fn.fetchDoc(url).then(dom => fn.gt("h1.title", 1, dom));
return comicName + " - " + fn.gt(".center-title");
}
}
},
hide: "body>ins,div[id^='show']",
category: "hcomic"
}, {
name: "日漫之家",
host: ["rimanzhijia.com"],
reg: /^https?:\/\/rimanzhijia\.com\/index\.php\/chapter\/\d+/,
imgs: "#comic_pic",
button: [4],
insertImg: [
["#comic_pic", 2, "#comic_pic"], 2
],
autoDownload: [0],
next: "//a[contains(text(),'下一章')][starts-with(@href,'/')]",
prev: "//a[contains(text(),'上一章')][starts-with(@href,'/')]",
customTitle: () => fn.gt(".bo_tit").replace(">", "-"),
css: ".bo_nav{width:97%!important;padding:10px!important}",
hide: "img[src*='/ad']",
category: "hcomic"
}, {
name: "最新韩漫网M",
host: ["www.zuixinhanman.com", "www.xinhanman.com"],
reg: /^https?:\/\/www\.(zui)?xinhanman\.com\/chapter_\d+\.html/,
delay: 300,
imgs: "#comic_pic",
button: [4],
insertImg: [
[".bo_tit", 2, "#comic_pic"], 2,
],
autoDownload: [0],
next: "//a[contains(text(),'下一章')][contains(@href,'html')]",
prev: "//a[contains(text(),'上一章')][contains(@href,'html')]",
customTitle: ".mip-shell-header-title",
fancybox: {
blacklist: 1
},
category: "hcomic"
}, {
name: "韩漫100",
host: ["hanman100.com"],
reg: /^https?:\/\/hanman100\.com\/index\.php\/chapter-\d+\.html/,
box: ["#all", 2],
imgs: "#img-content img,.comic-list img",
button: [4, "24%", 4],
insertImg: [
["box", 0, "#all"], 2
],
autoDownload: [0],
next: ".pnext.next+a[href$=html],.next-btn",
prev: 1,
customTitle: () => fn.dt({
s: "h1.text-center,.comic-name",
d: "漫画 "
}),
hide: "#left,#right",
category: "hcomic"
}, {
name: "51漫画/爱漫画",
host: ["51comic.org", "aicomic.org"],
reg: [
/^https?:\/\/aicomic\.org\/index\.php\/chapter\/\d+/,
/^https?:\/\/51comic\.org\/chapter\/\d+/
],
init: () => fn.addMutationObserver(() => fn.remove("//div[div[text()='x']]")),
imgs: () => fn.ge(".rd-article-wr") ? fn.gae(".rd-article-wr img") : fn.gae(".comic-list img:not([src$='empty.png'])"),
button: [4],
insertImg: [".rd-article-wr,.comic-list", 1],
autoDownload: [0],
next: ".j-rd-next:not([style]):not(.hide),.next-btn",
prev: ".j-rd-prev,.prev-btn",
customTitle: () => fn.ge(".rd-article-wr") ? fn.gt(".j-comic-title") + " - " + fn.gt(".comic-title>a").replace(/\d+p/i, "") : _unsafeWindow.shareArr[0].match(/《([^》]+)/)[1] + " - " + fn.gt(".comic-name").replace(/\d+p/i, ""),
hide: ".image-container",
category: "hcomic"
}, {
name: "特漫网",
host: ["www.44te.com"],
url: {
t: "特漫网",
p: "/chapter/"
},
imgs: ".comicpage img:not([src*='/banner/']),#cp_img img:not([src*='/banner/'])",
button: [4],
insertImg: [".comicpage,#cp_img", 2],
autoDownload: [0],
next: "//a[@href and not(starts-with(@href,'java')) and text()='下一章']",
prev: "//a[@href and not(starts-with(@href,'java')) and text()='上一章']",
customTitle: () => fn.title(/无删减/, 1),
hide: "body>div[style^=background],[id^=ad]",
category: "hcomic"
}, {
name: "91禁漫",
host: ["www.91jinman.com"],
reg: /^https?:\/\/www\.91jinman\.com\/\d+\.html/,
imgs: ".wp-posts-content img",
button: [4],
insertImg: [".wp-posts-content", 2],
autoDownload: [0],
next: "//a[p[text()='上一篇']]",
prev: "//a[p[text()='下一篇']]",
customTitle: ".article-title",
css: ".wp-posts-content{max-height:unset!important}",
category: "hcomic"
}, {
name: "鸟鸟韩漫 閱讀頁",
host: ["nnhanman6.com"],
url: {
h: "nnhanman",
p: "chapter",
e: ".BarTit>h1"
},
imgs: "img[data-original]",
button: [4],
insertImg: ["//td[img] | //div[@class='view-imgBox']", 2],
autoDownload: [0],
next: "#k_Pic_nextArr",
prev: 1,
customTitle: () => fn.gt(".BarTit>h1").replace(" - 第1章", ""),
category: "hcomic"
}, {
name: "鸟鸟韩漫 目錄頁",
host: ["nnhanman6.com"],
url: {
h: "nnhanman",
p: "/comic/",
e: ".Introduct_Sub"
},
box: [".txtDesc", 2],
imgs: () => {
let links = fn.gau("#list a").reverse();
return fn.getImgA("img[data-original]", links);
},
button: [4],
insertImg: ["box", 3],
customTitle: ".Introduct_Sub h1",
category: "hcomic"
}, {
name: "A漫 閱讀頁",
host: ["aman8.org"],
url: {
t: "A漫",
h: "aman",
p: "/manhuaview/"
},
imgs: ".conch-ctwrap-auto img",
button: [4],
insertImg: [".conch-ctwrap-auto>center>div[style]", 2],
autoDownload: [0],
next: "//a[text()='下一章']",
prev: "//a[text()='上一章']",
customTitle: ["h1", "h2"],
category: "hcomic"
}, {
name: "A漫 目錄頁",
url: {
t: "A漫",
h: "aman",
p: "/manhuaview/",
e: "#hl-plays-list"
},
box: [".hl-list-wrap", 2],
imgs: () => {
let links = fn.gau("#hl-plays-list a");
return fn.getImgA(".conch-ctwrap-auto img", links);
},
button: [4],
insertImg: ["box", 3],
customTitle: ".hl-dc-title",
category: "hcomic"
}, {
name: "漫香阁",
host: ["xn--wgv69rba1382b.com", "韩漫日漫.com"],
url: {
t: "漫香阁",
p: /^\/content-[\w-]+\.html$/
},
imgs: "#contentimg img",
button: [4],
insertImg: ["#contentimg", 2],
customTitle: ".services-desc",
category: "hcomic"
}, {
name: "亲亲漫画",
host: ["m.qinqinmanhua.xyz"],
reg: /^https?:\/\/m\.qinqinmanhua\.xyz\/view\/\d+\.html/,
imgs: ".showimg img",
autoDownload: [0],
next: ".BtnBox>.next[href*=view]",
prev: ".BtnBox>.prev[href*=view]",
customTitle: () => document.title.match(/《(.+)》/)[1],
category: "hcomic"
}, {
name: "狮城漫画",
host: ["hdcomic.com"],
reg: /^https?:\/\/hdcomic\.com\/chapter\/\d+/,
init: () => fn.clearAllTimer(),
imgs: ".comicpage img,#cp_img img",
button: [4],
insertImg: [".comiclist,#cp_img", 2],
autoDownload: [0],
next: "//a[text()='下一章'][@href]",
prev: "//a[text()='上一章'][@href]",
customTitle: () => fn.title(/免费阅读-狮城漫画|在线阅读-狮城漫画/).replace(/\s-\s\(\d+P\)-高清全集/i, ""),
category: "hcomic"
}, {
name: "韩漫连连看",
host: ["www.hmkll.com"],
url: {
t: "韩漫连连看",
p: "/chapter/"
},
init: () => fn.clearAllTimer(),
imgs: ".comicpage img,#cp_img img",
button: [4],
insertImg: [".comiclist,#cp_img", 2],
autoDownload: [0],
next: "//a[text()='下一章'][@href]",
prev: "//a[text()='上一章'][@href]",
customTitle: () => fn.title(/免费阅读-连连看.+|免费在线看.+/).replace(/\s-\s\(\d+P\)-高清全集/i, ""),
category: "hcomic"
}, {
name: "18H汉化漫画 介紹頁",
host: ["manhua.sexbook.top", "18manga.top", "mt91.top", "kk4.top", "9xh.top", "v-m.top", "cr8.top"],
url: {
e: "//ul[@class='nav-main']//a[text()='18H汉化漫画'] | //a[text()='很色情的漫画'] | //a[text()='涩涩汉化漫画']",
p: "/cont.php",
s: "?id="
},
imgs: () => {
let [max] = fn.gt("#td-Act+#td-Series,.meta+.meta .rounded-button99").match(/\d+/);
let [, dir, , ex] = fn.gu("#content-id a,.article-tabs-content a:has(img)").match(/^(.+\/)(\d+)(\.\w+)$/);
return fn.arr(max, (v, i) => dir + (i + 1) + ex);
},
button: [4],
insertImg: [
[".content", 0, ".article-content>a,.article-tabs-content a:has(img)"], 2
],
endColor: "white",
customTitle: () => {
let text = fn.gt(".article-content>h3,.article-title");
if (text.includes("|")) {
text = text.split("|")[1];
}
return fn.dt({
t: text,
d: [
"很色情的漫画-"
]
});
},
fancybox: {
blacklist: 1
},
css: ".single .content{margin-right:0px!important;}",
hide: ".sidebar,.modown-ad",
category: "hcomic"
}, {
name: "18H汉化漫画 閱讀頁",
host: ["manhua.sexbook.top", "18manga.top", "mt91.top", "kk4.top", "9xh.top", "v-m.top", "cr8.top"],
url: {
e: "//ul[@class='nav-main']//a[text()='18H汉化漫画'] | //a[text()='很色情的漫画'] | //a[text()='涩涩汉化漫画']",
p: "/imgs.php",
s: "?id="
},
imgs: async () => {
let next = fn.ge("li.active+li");
let [, dir, , ex] = fn.gu("#imgs>a").match(/^(.+\/)(\d+)(\.\w+)$/);
if (next) {
let last = fn.ge("//a[contains(text(),'最大頁') or contains(text(),'最大页')]");
let lastDoc = await fn.fetchDoc(last);
let key = "decodeBinaryString";
let code = fn.gst(key, lastDoc);
let s = code.lastIndexOf(key);
let e = code.indexOf(";", s);
let lastFn = code.slice(s, e);
let html = fn.run(lastFn);
let tempDoc = fn.doc(html);
let urls = fn.gau("a", tempDoc).filter(url => url.includes(ex));
let lastA = urls.at(-1);
let [, max] = lastA.match(/(\d+)\.\w+$/);
return fn.arr(max, (v, i) => dir + (i + 1) + ex);
} else {
return fn.gau("#imgs>a").filter(url => url.includes(ex));
}
},
button: [4],
insertImg: ["#imgs", 2],
endColor: "white",
customTitle: ".article-content>h3,.article-title",
fancybox: {
blacklist: 1
},
css: ".single .content{margin-right:0px!important;}",
hide: ".sidebar,.modown-ad",
category: "hcomic"
}, {
name: "hanime1",
host: ["hanime1.biz", "ani02.xyz", "anime01.xyz"],
url: {
e: ["//a[contains(text(),'anime1')][@href='/home']", ".blog"],
p: /^\/book\/\d+$/
},
init: async () => {
fn.ge(".blog").scrollIntoView({
block: "end"
});
await fn.delay(2000);
},
imgs: async () => {
await fn.waitEle(".blog_section img[title]:not([src*=cover])");
thumbnailSrcArray = fn.getImgSrcArr(".blog_section img[title]:not([src*=cover])");
return thumbnailSrcArray.map(e => e.replace(/t(\d+\.\w+)$/, "$1"));
},
button: [4],
insertImg: [
[".mb-0.m-0>.blog_section", 2], 2
],
customTitle: ".blog_section h1,.blog_section h3",
hide: ".blog_section.max-w-7xl.mx-auto.rounded-sm.p-2.pb-3,.flex.flex-row.flex-wrap.items-center.text-center.justify-center",
category: "hcomic"
}, {
name: "JavABC",
host: ["javabc.club"],
reg: /^https?:\/\/javabc\.club\/chapter\/\d+$/i,
include: "#enc_img img",
init: () => {
fn.clearAllTimer();
fn.remove("//div[@class='comicpage']/a[img] | //div[@class='comicpage']/div[script] | //div[@id='cp_img']/a[img] | //div[@id='cp_img']/div[script]");
},
imgs: async () => {
await fn.getNP("#enc_img>div,#enc_img>img", "//a[text()='下一页'][@href]", null, ".fanye,.view-bottom-bar");
return fn.gae("#enc_img img");
},
button: [4],
insertImg: ["#enc_img", 2],
customTitle: () => {
if (fn.ge(".comic-name")) {
return fn.gt(".comic-name");
} else {
let code = fn.gst("bookInfo");
let bookInfo = fn.TextToObject(code, "bookInfo");
return bookInfo.book_name;
}
},
css: "img{opacity:1!important;}",
category: "hcomic"
}, {
name: "桃心漫画",
host: ["txcomic.com"],
reg: /^https?:\/\/txcomic\.com\/chapter\/\d+$/i,
include: "#enc_img img",
init: () => fn.remove("//div[@class='comicpage']/a[img] | //div[@class='comicpage']/div[script] | //div[@id='cp_img']/a[img] | //div[@id='cp_img']/div[script]"),
imgs: "#enc_img img",
button: [4],
insertImg: ["#enc_img", 2],
autoDownload: [0],
next: "//a[text()='下一章'][@href]",
prev: "//a[text()='上一章'][@href]",
customTitle: () => {
if (fn.ge(".title")) {
return fn.gt(".title");
} else {
let code = fn.gst("bookInfo");
let bookInfo = fn.TextToObject(code, "bookInfo");
return bookInfo.book_name + " - " + bookInfo.chapter_name;
}
},
hide: "#pubcdnModal",
category: "hcomic"
}, {
name: "有色漫画网",
host: ["yousemanhua.com"],
reg: /^https?:\/\/yousemanhua\.com\/index\.php\/chapter\/\d+$/i,
imgs: "img[data-original]:not([data-original*='empty.png'])",
button: [4],
insertImg: [".rd-article-wr,.chapter_content", 2],
autoDownload: [0],
next: "//a[contains(@class,'j-rd-next')][@_href] | //a[div[span[contains(text(),'下一篇')]]]",
prev: "//a[contains(@class,'j-rd-prev')][@_href] | //a[div[span[contains(text(),'上一篇')]]]",
customTitle: async () => {
if (fn.ge(".read__crumb")) {
let arr = fn.gt(".read__crumb").split(" ");
return arr[1] + " - " + arr[2];
} else {
let dom = await fn.fetchDoc(fn.gu(".nav_left>a"));
return fn.title(" - 有色漫画", 0, dom) + " - " + fn.title(" - 有色漫画");
}
},
category: "hcomic"
}, {
name: "漫画大叔",
url: {
h: "manhuadashu.xyz",
p: "/chapter/"
},
button: [4],
imgs: ".comiclist img,#cp_img img",
insertImg: [".comiclist,#cp_img", 2],
autoDownload: [0],
next: "//a[text()='下一章'][@href]",
prev: "//a[text()='上一章'][@href]",
customTitle: () => {
let code = fn.gst("bookInfo");
let bookInfo = fn.TextToObject(code, "bookInfo");
return bookInfo.book_name + " - " + bookInfo.chapter_name;
},
category: "hcomic"
}, {
name: "XXcomic",
url: {
h: "www.xxcomic.com",
p: "/album/"
},
button: [4],
imgs: () => {
fn.showMsg(DL.str_05, 0);
let fetchNum = 0;
let [id] = fn.lp.match(/\d+/);
let max = fn.attr(".pager a", "title").match(/\d+/g).at(-1);
let resArr = fn.arr(max, (v, i) => {
if (i == 0) {
return fn.fetchDoc(fn.lp).then(dom => {
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${max}`, 0);
return fn.ge(".entry-content", dom).innerHTML;
});
} else {
return fetch(`/wp-admin/admin-ajax.php?action=theme_page_nagination_ajax&post-id=${id}&page=${i + 1}`).then(res => res.json()).then(json => {
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${max}`, 0);
return json.content;
});
}
});
return Promise.all(resArr).then(htmls => {
let dom = fn.doc(htmls.join(""));
return [...dom.images];
});
},
insertImg: [".entry-content", 2],
customTitle: ".entry-title",
category: "hcomic"
}, {
name: "LXMANGA",
host: ["lxmanga.info"],
reg: /^https?:\/\/lxmanga\.\w+\/[\w-]+\/[\w-]+\/[\w-]+/i,
include: "//nav[li[span[starts-with(text(),'Danh')]]]",
imgs: "#image-container",
button: [4],
insertImg: [
["#image-container", 1, "#image-container"], 2
],
autoDownload: [0],
next: "//a[button[span[text()='Chương sau']]][not(starts-with(@href,'javascript'))]",
prev: "//a[button[span[text()='Chương trước']]][not(starts-with(@href,'javascript'))]",
customTitle: () => fn.title(" - ", 3),
category: "hcomic"
}, {
host: ["kkcomic.vip", "51man.vip", "www.51comic.org", "book.51comic.org", "18comic.top", "www.18comic.bar", "www.yumanse.com", "91manwu.com", "maozhuamcn.com"],
url: () => {
let check = fn.checkUrl({
e: [".hl-logo-black", ".hl-logo-white"],
p: "/artdetail"
});
return check ? fn.waitEle(".hl-article-title,.hl-show").then(() => !fn.ge(".hl-comic-box.hl-show")) : false;
},
init: () => fn.remove(".container:has(>#homeBannerWrap)"),
imgs: ".hl-article-box img",
button: [4],
insertImg: [".hl-article-box", 2],
autoDownload: [0],
next: "//a[@class='hl-next'] | //a[span[text()='下一話']]",
prev: "//a[@class='hl-prev'] | //a[span[text()='上一話']]",
customTitle: () => {
if (fn.ge(".hl-mob-title")) {
return fn.gt(".conch-head-1>.hl-mob-title") + " - " + fn.gt(".conch-head-2>.hl-mob-title");
} else {
return fn.gt(".hl-article-title");
}
},
category: "hcomic"
}, {
name: "污污漫畫",
host: ["www.55comic.com", "www.comicbox.xyz", "www.wuwucomic.xyz"],
reg: /^https?:\/\/(www\.55comic\.com|www\.comicbox\.xyz|www\.wuwucomic\.xyz)\/chapter\/\d+$/i,
include: ".comiclist",
init: () => fn.remove("//div[div[@class='CarouselView center']]"),
imgs: async () => {
let arr = [];
await fn.aotoScrollEles({
ele: ".comiclist div[data-src]",
cb: (ele) => {
let canvas = fn.ge("canvas", ele);
if (canvas) {
arr.push(canvas.toDataURL("image/jpeg"));
return true;
}
return false;
}
});
return arr.map(e => fn.dataURLtoBlobURL(e));
},
button: [4],
insertImg: [".comicpage", 0],
autoDownload: [0],
next: "//a[text()='下一章']",
prev: "//a[text()='上一章']",
customTitle: ".title",
category: "hcomic"
}, {
name: "污污漫畫M",
host: ["www.55comic.com", "www.comicbox.xyz", "www.wuwucomic.xyz"],
reg: /^https?:\/\/(www\.55comic\.com|www\.comicbox\.xyz|www\.wuwucomic\.xyz)\/chapter\/\d+$/i,
include: "#cp_img",
imgs: async () => {
let arr = [];
await fn.aotoScrollEles({
ele: ".cropped[data-src]",
cb: (ele) => {
let canvas = fn.ge("canvas", ele);
if (canvas) {
arr.push(canvas.toDataURL("image/jpeg"));
return true;
}
return false;
},
top: 1
});
return arr.map(e => fn.dataURLtoBlobURL(e));
},
button: [4],
insertImg: ["#cp_img", 0],
autoDownload: [0],
next: "//a[text()='下一章']",
prev: "//a[text()='上一章']",
customTitle: () => fn.title(" - 污污漫畫"),
category: "hcomic"
}, {
name: "污漫天堂",
host: ["wumtt.com"],
url: {
e: ".logo>a[title='污漫天堂']",
p: "/mangaread/"
},
imgs: ".content>center>div>img",
button: [4],
insertImg: [".content>center>div:has(>img)", 2],
autoDownload: [0],
next: "//a[text()='下一章']",
prev: "//a[text()='上一章']",
customTitle: () => fn.dt({
s: ".content h1",
d: [
"《",
"》"
]
}) + " - " + fn.gt(".content h2"),
category: "hcomic"
}, {
name: "污污漫书",
host: "www.55comics.xyz",
url: {
t: "污污漫书",
p: /\/\d+\.html$/,
e: ".scramble-page img"
},
imgs: async () => {
if (fn.ge(".pagination li.active")) {
let max = fn.gt("//li[a[text()='下一页»' or text()='下一頁»' or text()='Next»']]", 2);
let links = fn.arr(max, (v, i) => i == 0 ? fn.url : fn.url + "?p=" + (i + 1));
return fn.getImgA(".scramble-page img", links);
} else {
await fn.getNP(".scramble-page", "//li/a[text()='下一页»' or text()='下一頁»' or text()='Next»']", null, ".pagination");
return fn.gae(".scramble-page img");
}
},
button: [4],
insertImg: [
[".scramble-page", 2, ".scramble-page"], 2
],
insertImgAF: () => {
let arr = ["//div[div[@class='ads']]", "//div[ul[ul[@class='pagination']]]"];
fn.remove(arr);
},
autoDownload: [0],
next: "//a[text()='下一话»' or text()='下一話»']",
prev: "//a[text()='上一话»' or text()='上一話»']",
customTitle: () => {
let str = fn.gt(".chapter-left h1");
let strArr = str.split(">");
strArr = strArr.map(str => str.trim());
return strArr[2] + " - " + strArr[3];
},
observerClick: "#chk_cover",
hide: ".row:has(>.ads),.row:has(>.stui_md)",
category: "hcomic"
}, {
name: "污污漫书",
url: {
t: "污污漫书",
h: /www\.55comics\./
},
observerClick: "#chk_cover",
hide: ".row:has(>.ads)",
category: "ad"
}, {
name: "tooncn",
url: {
h: ["tooncn.net"],
e: ".entry-title"
},
imgs: "#readerarea img",
button: [4],
insertImg: ["#readerarea", 2],
autoDownload: [0],
next: ".ch-next-btn:not(.disabled)",
prev: ".ch-prev-btn:not(.disabled)",
customTitle: () => {
let eles = fn.gae(".ts-breadcrumb a span");
return eles?.at(-2)?.innerText + " - " + eles?.at(-1)?.innerText;
},
category: "hcomic"
}, {
name: "涩涩漫画",
host: ["sscomic.top"],
url: {
t: "涩涩漫画",
p: "/chapter/",
e: "#comic-data"
},
imgs: () => JSON.parse(document.getElementById("comic-data").textContent).filter(Boolean),
button: [4],
insertImg: ["#pic-list", 2],
autoDownload: [0],
next: () => {
let code = fn.gst("var xlink");
let a = code.indexOf("var xlink");
let b = code.indexOf("=", a);
let c = code.indexOf(";", b);
code = code.slice(b + 1, c);
return code.includes("chapter") ? code.replace(/[\s'"]/g, "") : null;
},
prev: 1,
customTitle: () => {
let url = fn.gu("a:has(.button-image-category)");
let id = fn.lp.split("/").at(-1);
return fn.fetchDoc(url).then(dom => {
let n = dom.querySelector(".comic_name").innerText;
let c = [...dom.querySelectorAll(".chapter-list a")].find(a => a.href.endsWith(id)).innerText;
return n + " - " + c;
});
},
hide: ".exoAds,.exoAdb,.exoAdl,ins",
category: "hcomic"
}, {
name: "涩涩漫画",
url: {
t: "涩涩漫画",
h: ["sscomic.top"]
},
hide: ".exoAds,.exoAdb,.exoAdl,ins",
category: "ad"
}, {
name: "Manhuascan.us",
url: {
h: "manhuascan.us",
p: "/manga/"
},
imgs: "#readerarea img",
button: [4],
insertImg: ["#readerarea", 2],
next: ".section_button a:has(>.fa-angle-right)",
prev: ".section_button a:has(>.fa-angle-left)",
chapters: {
wait: ["#chapter option[value^=http]"],
sort: "r"
},
customTitle: () => fn.title(" - Manhuascan.us"),
category: "comic"
}, {
name: "Mangago",
host: ["mangago.me", "mangago.zone", "youhim.me"],
url: {
h: /mangago|youhim/,
p: /^\/read-manga\/|^\/chapter\//,
st: "imgsrcs"
},
decrypt: str => {
let CryptoJS = _unsafeWindow.CryptoJS;
let key = CryptoJS.enc.Hex.parse("e11adc3949ba59abbe56e057f20f883e");
let iv = CryptoJS.enc.Hex.parse("1234567890abcdef1234567890abcdef");
let opinion = {
iv,
padding: CryptoJS.pad.ZeroPadding
};
return CryptoJS.AES.decrypt(str, key, opinion).toString(CryptoJS.enc.Utf8).split(",");
},
getSrcs: (scripts) => scripts.map(script => {
let code = script.textContent;
let s = code.indexOf("'") + 1;
let e = code.indexOf("'", s);
code = code.slice(s, e);
return _this.decrypt(code);
}).flat(),
init: () => {
fn.clearAllTimer();
return fn.waitVar(["jQuery", "CryptoJS", "imgsrcs"]).then(() => _unsafeWindow.jQuery(document).off("keydown"));
},
box: ["#pic_container", 1, 1000],
imgs: () => {
if (fn.lp.startsWith("/chapter/")) {
let links = fn.gau("#pagenavigation a,#dropdown-menu-page a");
links = links.filter((url, i) => {
if (i == 0) return true;
let p = url.split("/").at(-2);
return ["1", "6"].some(n => p.endsWith(n));
});
return fn.getEle(links, "//script[contains(text(),'imgsrcs')]").then(scripts => _this.getSrcs(scripts));
} else if ((isMobileDeviceUA || isM) && fn.lp.startsWith("/read-manga/")) {
return fn.showMsg(DL.str_05, 0).then(() => fn.xhrDoc(fn.url, {
headers: {
"User-Agent": PC_UA
}
}).then(dom => {
let script = fn.ge("//script[contains(text(),'imgsrcs')]", dom);
let scripts = [script];
return _this.getSrcs(scripts);
}));
} else {
return _this.decrypt(_unsafeWindow.imgsrcs);
}
},
button: [4],
insertImg: [
["box", 0, "#pic_container"], 2
],
insertImgAF: (parent) => {
fn.remove(".addtoalbum,.page_select,#pagenavigation,div:has(>img[onclick]),.btn-group:has(#dropdown-menu-page),.subnav-wrapper .pager");
if (nextLink) {
fn.addUrlHtml(nextLink, parent, 1, DL.str_143, 9);
}
},
endColor: "white",
autoDownload: [0],
getNext: id => {
let chapters = fn.gae(".chapter a");
let c_chapter = chapters.find(a => a.href.includes(`/${id}/`));
let next = c_chapter?.parentElement?.nextElementSibling?.firstElementChild;
return next ? next.href : null;
},
next: () => {
if ("next_c_url" in _unsafeWindow) {
if (["/read-manga/", "/chapter/"].some(s => _unsafeWindow.next_c_url.includes(s))) {
return _unsafeWindow.next_c_url;
}
}
if (fn.lp.startsWith("/chapter/")) {
let cid = fn.lp.split("/").at(-2);
return _this.getNext(cid);
} else {
if (isM) {
let cid = fn.lp.split("/").at(-3);
return _this.getNext(cid);
} else {
return fn.gu("//p[contains(text(),'Next Chapter:')]/a");
}
}
},
prev: 1,
chapters: {
target: "ul.chapter a"
},
customTitle: () => {
if (isM) {
return fn.gt("#series") + " - " + fn.gt("#series+a");
} else {
let url = fn.gu(".widepage a");
return fn.fetchDoc(url).then(dom => fn.ge(".rating_wrap a", dom)?.title.replace("Peole who read ", "") + " - " + fn.gt("#dropdown-chapter-page"));
}
},
css: "#FullPictureLoadMainImgBox img[id^=page]{width:auto;height:auto;max-width:100%}",
fancybox: {
blacklist: 1
},
category: "comic"
}, {
name: "MangaDex",
url: {
h: "mangadex.org",
e: "link[title=MangaDex]",
d: "pc"
},
page: () => fn.clp("/chapter/"),
wait: () => fn.wait((d) => d.title != "" && !d.title.includes("Loading")),
json: () => fn.showMsg(DL.str_05, 0).then(() => fn.clp().split("/").at(2)).then(id => fetch(`https://api.mangadex.org/at-home/server/${id}?forcePort443=false`).then(res => res.json()).then(json => (siteJson = json) && fn.hideMsg())),
SPA: () => _this.page() ? true : (siteJson = {}) && false,
observeURL: "head",
init: () => _this.page() ? _this.json().then(() => _this.wait()).then(() => fn.showMsg(DL.str_04, 0)).then(() => fn.waitEle("#chapter-selector li[data-value]")).then(() => fn.hideMsg()) : _this.wait(),
imgs: () => {
if (!_this.page()) return [];
let {
baseUrl,
chapter: {
data,
hash
}
} = siteJson;
return data.map(e => baseUrl + "/data/" + hash + "/" + e);
},
capture: () => _this.imgs(),
autoDownload: [0],
next: async () => {
if (_this.page()) {
let id = fn.clp().split("/").at(-1);
let chapters = await fn.waitEle(["#chapter-selector li[data-value]"]);
let c_chapter = chapters.find(e => e.dataset.value == id);
let next = c_chapter?.previousElementSibling;
return next ? fn.dir(fn.clp()) + next.dataset.value : null;
}
return null;
},
prev: 1,
chapters: {
target: "#chapter-selector li[data-value]",
cb: (text, e) => ({
text,
url: fn.dir(fn.clp()) + e.dataset.value
}),
sort: "r"
},
customTitle: async () => {
if (!_this.page()) return null;
await _this.wait();
let text = fn.dt({
d: [
/^[\d\s\|]+/,
" - MangaDex"
]
});
let textArr = text.split(" - ");
return textArr[1] + " - " + textArr[0];
},
category: "comic"
}, {
name: "NamiComi",
url: {
h: "namicomi.com",
e: "meta[content=NamiComi]",
d: "pc"
},
page: () => fn.clp("/chapter/"),
c_id: () => fn.clp().split("/").at(3),
json: () => fn.showMsg(DL.str_05, 0).then(() => fetch(`https://api.namicomi.com/images/chapter/${_this.c_id()}?newQualities=true`).then(res => res.json()).then(json => (siteJson = json) && fn.hideMsg())),
SPA: () => _this.page() ? true : (siteJson = {}) && false,
observeURL: "head",
id: () => fn.clp().split("/").at(-1),
init: () => _this.page() ? _this.json().then(() => fn.showMsg(DL.str_04, 0)).then(() => fn.waitEle(`select.relative option[value="${_this.id()}"]`)).then(() => fn.hideMsg()) : void 0,
imgs: () => {
if (!_this.page()) return [];
let chapter_id = _this.c_id();
let {
data: {
baseUrl,
hash,
}
} = siteJson;
let data;
let quality;
let keys = ["source", "high", "medium", "low"];
for (let k of keys) {
if (Array.isArray(siteJson.data[k])) {
data = siteJson.data[k];
quality = k;
break;
}
}
return data.map(e => baseUrl + "/chapter/" + chapter_id + "/" + hash + `/${quality}/` + e.filename);
},
capture: () => _this.imgs(),
autoDownload: [0],
next: async () => {
if (_this.page()) {
let id = _this.id();
let chapters = await fn.waitEle(["select.relative option"]);
let c_chapter = chapters.find(e => e.value == id);
let next = c_chapter?.previousElementSibling;
return next ? fn.dir(fn.clp()) + next.value : null;
}
return null;
},
prev: 1,
chapters: {
target: "//div[h2[text()='Chapter']]//option",
cb: (text, v) => ({
text,
url: fn.dir(fn.clp()) + v
}),
sort: "r"
},
customTitle: () => {
if (!_this.page()) return null;
let text = fn.dt({
d: [
/ - NamiComi.+$/
]
});
let textArr = text.split(" - ");
return textArr[1] + " - " + textArr[0];
},
category: "comic"
}, {
name: "BATOTO V2",
link: "https://rentry.co/batoto",
url: {
e: "meta[property='og:site_name'][content=Batoto]",
p: "/chapter/",
st: "imgHttps"
},
imgs: () => {
let code = fn.gst("imgHttps");
return fn.TextToArray(code, "imgHttps");
},
button: [4],
insertImg: ["#viewer", 2],
endColor: "white",
autoDownload: [0],
next: "//a[span[text()='Next Chapter ▶']]",
prev: "//a[span[text()='◀ Prev Chapter']]",
chapters: {
node: "optgroup[label=Chapters]",
target: "option",
cb: (t, v) => ({
text: t,
url: fn.dir(fn.url) + v
})
},
customTitle: () => {
let id = fn.lp.split("/").at(-1);
let chapters = fn.gae("optgroup[label=Chapters] option");
let chapterName = chapters.find(e => e.value == id).innerText;
let magaName = fn.gt(".nav-title>a");
return magaName + " - " + chapterName.replaceAll("\n", "").replace(/\s{2,10}/, "");
},
category: "comic"
}, {
name: "BATOTO V3",
url: {
t: "Bato.To",
p: "/title/",
e: "astro-island[props*=imageFiles]"
},
imgs: () => JSON.parse(JSON.parse(fn.attr("astro-island[props*=imageFiles]", "props")).imageFiles.find(isString)).map(([, url]) => url),
button: [4],
insertImgBF: () => fn.waitEle("div[name='image-item'] img"),
insertImg: ["div[name='image-item']", 2],
autoDownload: [0],
next: "//a[span[text()='Next Chapter ▶']]",
prev: "//a[span[text()='◀ Prev Chapter']]",
chapters: {
node: "optgroup[label=Chapters]",
target: "option"
},
customTitle: () => fn.title(" - Read Free Manga Online at Bato.To"),
hide: ".max-w-screen-2xl:has(button.btn-info)",
category: "comic"
}, {
name: "BATOTO DEV",
host: ["bato.si"],
url: {
e: ["//p[contains(text(),'BATO.TO')]", "script[type='qwik/json']", ".select.select-sm"],
p: "/title/"
},
box: [".grid:has(div[data-name='image-item'])", 1],
imgs: "div[data-name='image-item'] img",
button: [4],
insertImg: ["box", 2],
insertImgAF: () => fn.hideEle(".grid:has(div[data-name='image-item'])"),
autoDownload: [0],
next: "//a[span[text()='Next Chapter']]",
prev: "//a[span[text()='Prev Chapter']]",
chapters: {
wait: () => fn.waitEle(`.select.select-sm option[value="${fn.lp}"]`),
node: ".select.select-sm",
target: "option"
},
customTitle: () => fn.title(" - Read Free Manga Online"),
category: "comic"
}, {
name: "Dynasty Reader",
url: {
h: "dynasty-scans.com",
p: "/chapters/",
e: "#reader"
},
imgs: () => _unsafeWindow.pages.map(e => fn.lo + e.image),
button: [4],
insertImg: ["#reader", 2],
insertImgAF: (parent) => {
if (nextLink) {
fn.addUrlHtml(nextLink, parent, 1, DL.str_143, 4);
}
},
autoDownload: [0],
next: "#next_link",
prev: 1,
chapters: {
url: "#chapter-title a",
target: ".chapter-list a.name"
},
customTitle: () => fn.title("Dynasty Reader » "),
category: "comic"
}, {
name: "Top Manhua/Toonily/Manga-shi/ManhwaZ/Mangaclash/MANGAGG/Asura Scan/Kissmanga/TMO Manga/MangaLector",
url: {
h: ["manhuatop.org", "www.topmanhua.fan", "toonily.com", "manhwaz.com", "toonclash.com", "mangagg.com", "asurascan.me", "manhuaplus.com", "kissmanga.in", "tmomanga.com", "mangalector.com", "cocomic.co"],
p: ["/chapter", "/glava", "/c-", "/capitulo", "-capitulo-"],
e: ".reading-content img"
},
imgs: () => fn.gae(".reading-content img").filter(e => !e.closest("a[href*='/t.me/'],.banner")),
button: [4],
box: [".read-container,#chapter_content", 2],
insertImg: ["box", 2],
insertImgAF: () => fn.hideEle(".read-container,#chapter_content"),
endColor: () => fn.ge(".text-ui-light") ? "white" : "black",
autoDownload: [0],
next: "a.next_page",
prev: "a.prev_page",
chapters: {
wait: ".single-chapter-select option[data-redirect],.single-chapter-select option[value]",
node: ".single-chapter-select",
target: "option",
cb: (t, v, e) => ({
text: e.text,
url: ("redirect" in e.dataset) ? e.dataset.redirect : v
}),
sort: "r"
},
customTitle: () => {
let eles = fn.gae(".breadcrumb li");
return eles?.at(-2)?.innerText?.trim() + " - " + eles?.at(-1)?.innerText?.trim();
},
category: "comic"
}, {
name: "Dragon Tea",
host: ["dragontea.ink"],
url: {
t: "Dragon Tea",
p: "/chapter-"
},
init: () => fn.addMutationObserver(() => fn.remove("div[style*='2147483647'],iframe[style*='none'],.body-top-ads")),
imgs: ".reading-content img",
button: [4],
insertImg: [".reading-content", 2],
endColor: () => fn.ge(".text-ui-light") ? "white" : "black",
autoDownload: [0],
next: "a.next_page",
prev: "a.prev_page",
chapters: {
wait: ".single-chapter-select option[data-redirect]",
node: ".single-chapter-select",
target: "option[data-redirect]",
cb: (t, v, e) => ({
text: e.text,
url: e.dataset.redirect
}),
sort: "r"
},
customTitle: () => {
let e = fn.ge("#chapter-heading");
if (e) {
return e.innerText;
} else {
let eles = fn.gae(".breadcrumb li");
return eles?.at(-2)?.innerText?.trim() + " - " + eles?.at(-1)?.innerText?.trim();
}
},
category: "comic"
}, {
name: "巴卡漫画",
host: ["bakamh.app", "bakamh.com", "bakamh.ru"],
url: {
t: "bakamh巴卡漫画",
p: "/c-"
},
imgs: ".read-container img",
button: [4],
insertImg: [".read-container", 2],
endColor: () => fn.ge(".text-ui-light") ? "white" : "black",
autoDownload: [0],
next: "a.next_page",
prev: "a.prev_page",
customTitle: () => {
let e = fn.ge("#chapter-heading");
if (e) {
return e.innerText;
} else {
let eles = fn.gae(".breadcrumb li");
return eles?.at(-2)?.innerText?.trim() + " - " + eles?.at(-1)?.innerText?.trim();
}
},
category: "comic"
}, {
name: "Hiperdex/MangaRead/LHTranslation/MANHUAUS.COM/Setsu Scans/ToonGod/Manga Online Team/Harem de Kira/Manhwa Crush",
url: {
h: [
"hiperdex.com",
"hiperdex.tv",
"www.mangaread.org",
"lhtranslation.net",
"manhuaus.com",
"setsuscans.com",
"www.toongod.org",
"manytoon.com",
"harimanga.me",
"mangaonlineteam.com",
"haremscann.es",
"lectormanga.top",
"brmangas.top",
"manhwacrush.me"
],
p: /^\/(manga|comic|webtoon|serie)\//
},
imgs: ".wp-manga-chapter-img",
button: [4],
box: [".read-container", 2],
insertImg: ["box", 2],
insertImgAF: () => fn.hideEle(".read-container"),
endColor: () => fn.ge(".text-ui-light") ? "white" : "black",
autoDownload: [0],
next: "a.next_page",
prev: "a.prev_page",
chapters: {
wait: ".single-chapter-select option[data-redirect]",
node: ".single-chapter-select",
target: "option[data-redirect]",
cb: (t, v, e) => ({
text: e.text,
url: e.dataset.redirect
}),
sort: "r"
},
customTitle: () => {
let t_s = "#chapter-heading,#chapter_header h1";
if (fn.ge(t_s)) {
return fn.gt(t_s);
}
let eles = fn.gae(".breadcrumb li");
return eles?.at(-2)?.innerText?.trim() + " - " + eles?.at(-1)?.innerText?.trim();
},
hide: "#pageloader,[id^=teaser]",
category: "comic"
}, {
name: "mangaita/scanita",
url: {
h: ["mangaita.io", "scanita.top"],
p: "/scan/"
},
init: () => {
let a = fn.ge("//a[text()='Torna al manga']");
return fn.fetchDoc(a).then(dom => (siteJson.chapterList = fn.gae(".chapters-list a", dom).reverse()));
},
box: [".row:has(.book-page):not(.justify-content-center)", 1],
imgs: async () => {
await fn.getNP(".row:has(.book-page):not(.justify-content-center)", ".btn-navigation.btn-next", null, ".row:has(.btn-navigation):not(.justify-content-center)");
return fn.gae(".book-page img");
},
insertImg: [
["box", 0, ".row:has(.book-page):not(.justify-content-center)"], 2
],
next: () => {
let id = fn.lp.split("/").at(-1);
let urls = siteJson.chapterList.map(a => a.href);
let index = urls.findIndex(u => u.endsWith(id));
let next = urls[index + 1];
return isString(next) ? next : null;
},
prev: 1,
chapters: () => siteJson.chapterList.map(a => ({
text: fn.dt({
t: a.firstElementChild.firstElementChild.firstChild.textContent
}),
url: a.href
})),
button: [4],
customTitle: () => fn.dt({
s: ".container h3",
d: " - page 1"
}),
category: "comic"
}, {
name: "KaliScan",
url: {
h: ["kaliscan.io"],
p: "/chapter",
st: "chapterId"
},
imgs: () => fn.showMsg(DL.str_05, 0).then(() => fn.fetchDoc("/service/backend/chapterServer/?server_id=1&chapter_id=" + _unsafeWindow.chapterId).then(dom => fn.gae(".chapter-image", dom))),
button: [4],
insertImg: ["#chapter-images", 2],
autoDownload: [0],
next: "#btn-next",
prev: "#btn-prev",
chapters: {
api: () => "/service/backend/chapterList/?manga_id=" + _unsafeWindow.bookId,
target: "#chapter-list option",
sort: "r"
},
customTitle: () => fn.ge(".chapter-info h1").textContent,
category: "comic"
}, {
name: "Manga-Bay",
url: {
h: "manga-bay.org",
p: "/reader/",
st: "window.__DATA__"
},
init: () => {
let code = fn.gst("__DATA__");
let s = code.indexOf("{");
let e = code.lastIndexOf("}") + 1;
code = code.slice(s, e);
siteJson = fn.run(code);
},
imgs: () => siteJson.images,
button: [4],
insertImg: [".reader-view", 2],
insertImgAF: (parent) => {
if (nextLink) {
fn.addUrlHtml(nextLink, parent, 1, DL.str_143, 8);
}
},
autoDownload: [0],
next: () => {
let next = String(siteJson.next);
return next.includes("/reader/") ? next : null;
},
prev: () => {
let prev = String(siteJson.prev);
return prev.includes("/reader/") ? prev.replace(/#.+$/, "") : null;
},
chapters: () => {
let dir = fn.dir(fn.url);
return siteJson.chapters.map(({
id,
title
}) => ({
text: title,
url: dir + id
})).reverse();
},
customTitle: () => fn.dt({
d: ["Read", "manga online for free"]
}),
hide: ".nav__pages,.nav__paginate",
category: "comic"
}, {
name: "Mangakakalot/MangaHub",
url: {
h: ["mangakakalot.fun", "mangahub.io", "mangahub.us"],
},
page: () => fn.clp("/chapter/"),
json: () => fn.showMsg(DL.str_05, 0).then(() => {
let x = fn.lh == "mangakakalot.fun" ? "mn01" : "m01";
let mhub_access = fn.cookie("mhub_access");
let [, , slug, number] = fn.clp().split("/");
number = number.replace("chapter-", "");
let api = "https://api.mghcdn.com/graphql";
let headers = {
"content-type": "application/json",
"x-mhub-access": mhub_access
};
let data = {
query: `{chapter(x:${x},slug:"${slug}",number:${number}){id,title,mangaID,number,slug,pages,manga{id,title,slug}}}`,
};
return fetch(api, {
headers,
"body": JSON.stringify(data),
"method": "POST"
}).then(res => res.json()).then(json => {
data = {
query: `{chaptersByManga(mangaID:${json.data.chapter.mangaID}){number,title}}`,
};
return fetch(api, {
headers,
"body": JSON.stringify(data),
"method": "POST"
}).then(res => res.json()).then(chaptersJson => {
json = json.data.chapter;
Reflect.set(json, "chapters", chaptersJson.data.chaptersByManga);
return (siteJson = json) && fn.hideMsg();
});
});
}),
SPA: () => _this.page() ? true : (siteJson = {}) && false,
observeURL: "head",
init: () => _this.page() ? _this.json() : void 0,
imgs: () => {
if (!_this.page()) return [];
let {
p,
i: images
} = JSON.parse(siteJson.pages);
return images.map(e => `https://imgx.mghcdn.com/${p + e}`);
},
capture: () => _this.imgs(),
autoDownload: [0],
next: () => {
if (!_this.page()) return null;
let index = siteJson.chapters.findIndex(e => e.number == siteJson.number);
let next = siteJson.chapters[index + 1];
return isObject(next) ? fn.clp().replace(/[\d\.]+$/, "") + next.number : null;
},
prev: ".previous:not(.disabled) a",
chapters: {
wait: ["ul[aria-labelledby='select-chapter'] a"]
},
customTitle: () => {
if (!_this.page()) return null;
let {
manga: {
title: mt
},
title: ct
} = siteJson;
return mt + " - " + ct;
},
category: "comic"
}, {
name: "VyManga",
host: ["vymanga.com"],
url: {
h: ["summonersky.com", "burgerpixel.net"]
},
imgs: ".carousel-item img",
autoDownload: [0],
next: "a#navbar-chapter-control-next",
prev: "a#navbar-chapter-control-prev",
chapters: {
node: ".select-chapter",
target: "option",
sort: "r"
},
checkCurrentChapter: (url, text) => {
let c_t = fn.gt(".select-chapter [selected]");
return c_t == text;
},
customTitle: () => fn.ge("#chapter-info")?.textContent,
category: "comic"
}, {
name: "MangaNato/MangaKakalot/MangaNelo/Mangabat",
host: ["www.manganato.gg", "www.natomanga.com", "www.mangakakalot.gg", "www.nelomanga.com", "www.mangabats.com"],
url: {
t: ["MangaNato", "MangaKakalot", "MangaNelo", "Mangabat"],
p: "/chapter",
st: "chapterImages"
},
SPA: true,
imgs: ".container-chapter-reader img",
autoDownload: [0],
next: ".btn-navigation-chap a.next",
prev: ".btn-navigation-chap a.back",
chapters: {
node: ".navi-change-chapter",
target: "option",
cb: (t, v, e) => ({
text: t,
url: e.dataset.c
}),
sort: "r"
},
customTitle: ".info-top-chapter h2",
hide: ".banner-cus",
category: "comic"
}, {
name: "Mangakakalot",
host: ["mangakakalot.to"],
url: {
t: "Mangakakalot",
p: "/read/",
e: "#reading"
},
imgs: () => {
let id = fn.attr("#reading", "data-reading-id");
let type = fn.attr("#reading", "data-reading-type");
return fn.fetchDoc(`/ajax/manga/images?id=${id}&type=${type}`).then(dom => fn.gae(".card-wrap[data-url]", dom));
},
capture: () => _this.imgs(),
autoDownload: [0],
current: () => fn.ge(".select-reading [selected]"),
next: () => {
let next = _this.current()?.previousElementSibling;
return isEle(next) ? next.value : null;
},
prev: () => {
let prev = _this.current()?.nextElementSibling;
return isEle(prev) ? prev.value : null;
},
chapters: {
node: ".select-reading",
target: "option",
sort: "r"
},
customTitle: ".reading-info h2",
category: "comic"
}, {
name: "Слив манги для вас",
url: {
h: "mangabuff.ru",
p: "/manga/"
},
imgs: async () => {
let srcs = fn.getImgSrcArr(".reader__pages img");
let [src] = srcs;
fn.showMsg(DL.str_56, 0);
let status = await fn.xhrHEAD(src).then(res => res.status);
fn.hideMsg();
if (status === 200) {
return srcs;
} else {
let host = new URL(src).origin;
let newHost;
if (src.includes("https://custom.mangabuff.ru")) {
newHost = "https://c3.mangabuff.ru";
} else if (src.includes("https://c2.mangabuff.ru")) {
newHost = "https://custom.mangabuff.ru";
} else if (src.includes("https://img.mangabuff.ru")) {
newHost = "https://img2.mangabuff.ru";
} else if (src.includes("https://img2.mangabuff.ru")) {
newHost = "https://img.mangabuff.ru";
}
return newHost ? srcs.map(e => e.replace(host, newHost)) : srcs;
}
},
button: [4],
insertImg: [".reader__pages", 2],
autoDownload: [0],
next: "//a[contains(text(),'След.')]",
prev: "//a[contains(text(),'Пред.')]",
chapters: {
node: ".reader-chapters",
target: "a",
sort: "r"
},
customTitle: ".reader__controls",
hide: ".reader__top-a",
category: "comic"
}, {
name: "MangaMen",
url: {
h: "mangamen.ru",
st: ["__DATA__", "__pg"]
},
init: () => {
let code = fn.gst("__DATA__");
let a = code.indexOf("__DATA__");
let b = code.indexOf("{", a);
let c = code.indexOf(";", b);
siteJson.data = fn.run(code.slice(b, c));
a = code.indexOf("__info");
b = code.indexOf("{", a);
c = code.indexOf(";", b);
siteJson.info = fn.run(code.slice(b, c));
code = fn.gst("__pg");
siteJson.pg = fn.TextToArray(code, "__pg");
},
imgs: () => siteJson.pg.map(e => e.u),
button: [4],
insertImgBF: () => fn.waitEle(".reader-view div[page] img[alt]"),
insertImg: [".reader-view", 2],
autoDownload: [0],
next: () => {
let next = siteJson?.info?.next?.url;
return String(next)?.split("/")?.length > 2 ? next : null;
},
prev: () => {
let prev = siteJson?.info?.prev?.url;
return String(prev)?.split("/")?.length > 2 ? prev.replace(/\?.+$/, "") : null;
},
chapters: {
target: ".reader-chapters-list a",
sort: "r"
},
customTitle: () => siteJson.info.current.title + " - " + siteJson.data.chapters.find(e => e.id == siteJson.info.current.id).title,
hide: ".ads,.comment__dropdown",
category: "comic"
}, {
name: "Mangahub",
url: {
h: "mangahub.ru",
p: "/read/"
},
imgs: ".reader-viewer-img",
autoDownload: [0],
next: "a[data-target='reader-area.chapterNext']",
prev: "a[data-target='reader-area.chapterPrev']",
chapters: {
api: () => {
let m_id = fn.attr("history-progress", "object-id");
let c_id = fn.attr("history-progress", "item-id");
return `/read/${m_id}/chapters?translationId=${c_id}`;
},
target: "a",
sort: "r"
},
customTitle: () => fn.gt(".reader-info a.text-truncate").split("/")[0] + " - " + fn.gt(".reader-header .text-truncate"),
category: "comic"
}, {
name: "ReManga",
url: {
h: ["remanga.org"]
},
page: () => fn.clp(/^\/manga\/[^\/]+\/\d+/),
json: () => fn.showMsg(DL.str_05, 0).then(() => fn.fetchDoc(fn.clp()).then(dom => {
let code = [...dom.scripts].find(s => !s.textContent.includes("self.__next_f.push") && ["chapter", "content_type", "pages", "server"].every(key => s.textContent.includes(key)))?.textContent;
//debug("code", code);
let a_i = code.indexOf("({") + 1;
let b_i = code.lastIndexOf("})") + 1;
let key_code = code.slice(a_i, b_i);
//debug("key_code", key_code);
let json = JSON.parse(key_code).queries.find(({
queryHash
}) => queryHash?.includes("chapter-detail")).state.data.json;
siteJson = json;
debug("\n此頁JSON資料\n", siteJson);
if (siteJson?.pages?.length == 0) return;
return fn.showMsg(DL.str_04, 0).then(() => fn.waitEle("div[data-sentry-element=ReaderContainer] img", 600).then(e => {
if (isEle(e)) {
siteJson.host = new URL(e.src).host;
}
})).then(() => fn.hideMsg());
})),
SPA: () => _this.page() ? true : (siteJson.host = null) && false,
observeURL: "loop",
init: () => _this.page() ? _this.json() : void 0,
imgs: () => {
if (!_this.page() || !isArray(siteJson.pages)) return [];
let srcs = siteJson.pages.flat().map(e => e.link);
if (!siteJson.host) return srcs;
let [src] = srcs;
let host = new URL(src).host;
return srcs.map(e => e.replace(host, siteJson.host));
},
capture: () => _this.imgs(),
autoDownload: [0],
next: () => {
if (!_this.page()) return null;
let dir = fn.dir(fn.clp());
let next = siteJson?.next?.id;
return isNumber(next) ? dir + next : null;
},
prev: 1,
chapters: () => {
let dir = fn.dir(fn.clp());
return fetch(`https://api.remanga.org/api/titles/chapters/?branch_id=${siteJson.branch_id}&user_data=0`).then(res => res.json()).then(json => {
let chapters = json.content.sort((a, b) => a.index - b.index);
return chapters.map(({
chapter,
id
}) => ({
text: `Глава ${chapter}`,
url: dir + id
}));
});
},
category: "comic"
}, {
name: "MangaLib",
url: {
h: ["mangalib.org", "mangalib.me"],
p: "/read/"
},
init: () => {
const ajaxHooker = addAjaxHookerLibrary();
ajaxHooker.filter([{
type: "xhr",
url: "/chapter?"
}]);
ajaxHooker.hook(request => {
request.response = res => {
if (!("srcs" in siteJson)) {
siteJson.srcs = res.response.data.pages.map(e => e.url);
}
};
});
return fn.showMsg(DL.str_04, 0).then(() => fn.waitEle("main div[data-page] img", 200, doc, ".vk_cm").then(() => fn.hideMsg()));
},
imgs: () => {
if (fn.ge(".vk_cm")) return [];
let [src] = fn.getImgSrcArr("main div[data-page] img");
let host = new URL(src).origin;
return siteJson.srcs.map(e => host + e);
},
capture: () => _this.imgs(),
autoDownload: [0],
next: () => fn.gu("a:has(.fa-chevron-right):not([aria-current])"),
prev: 1,
chapters: () => {
let [, , id] = fn.clp().split("/");
return fetch(`https://api.cdnlibs.org/api/manga/${id}/chapters`, {
"headers": {
"client-time-zone": "Asia/Taipei",
"content-type": "application/json"
}
}).then(res => res.json()).then(json => json.data.map(({
volume,
number
}) => ({
text: `Том ${volume} Глава ${number}`,
url: `/ru/${id}/read/v${volume}/c${number}`
})));
},
customTitle: () => fn.gt("#app a .u8_vb") + " -" + fn.gt("#app a [data-media-down]"),
category: "comic"
}, {
name: "МангаПоиск",
url: {
h: ["mangapoisk.io"]
},
page: () => fn.clp("/chapter/"),
json: () => fn.showMsg(DL.str_05, 0).then(() => fn.fetchDoc(fn.clp()).then(dom => {
let pageData = fn.ge("#app[data-page]", dom).dataset.page;
let json = JSON.parse(pageData);
debug("\n此頁JSON資料\n", json);
siteJson = {
manga: json.props.manga.data,
chapter: json.props.chapter.data
}
}).then(() => fn.hideMsg())),
SPA: () => _this.page() ? true : (siteJson = {}) && false,
observeURL: "nav",
init: () => _this.page() ? _this.json() : void 0,
imgs: () => _this.page() ? siteJson.chapter.pages.map(e => e.link) : [],
capture: () => _this.imgs(),
//insertImgBF: () => fn.waitEle("#page-content div:has(>.page-image)"),
//button: [4],
//insertImg: ["#page-content div:has(>.page-image)", 2],
autoDownload: [0],
next: () => _this.page() && siteJson?.chapter?.nextChapter?.link ? siteJson.chapter.nextChapter.link : null,
prev: 1,
chapters: () => {
let [, , m_id] = fn.clp().split("/");
return fetch(`/manga/${m_id}/chapterSelector/${siteJson.chapter.id}`).then(res => res.json()).then(json => json.chapters.map(({
title,
link
}) => ({
text: title,
url: link
})).reverse());
},
customTitle: () => {
if (!_this.page()) return null;
let {
manga: {
title: n
},
chapter: {
title: c
},
} = siteJson;
return n + " - " + c;
},
category: "comic"
}, {
name: "YomiRaw",
url: {
h: ["yomiraw.com"]
},
page: () => fn.clp("/chapters/"),
json: () => fn.showMsg(DL.str_05, 0).then(() => fn.fetchDoc(fn.clp()).then(dom => {
doc = dom;
let pageData = fn.ge("#app[data-page]", dom).dataset.page;
let json = JSON.parse(pageData);
siteJson = json.props;
}).then(() => fn.hideMsg())),
SPA: () => _this.page() ? true : (siteJson = {}) && false,
observeURL: "nav",
init: () => _this.page() ? _this.json() : void 0,
imgs: () => {
if (!_this.page()) return [];
return fn.waitEle("img[alt^='Page'][src^='http']").then(img => {
let dir = fn.dir(img.src);
let file_name = img.src.split("/").at(-1);
let [num_str] = file_name.match(/\d+/);
let num_str_length = num_str.length;
let file_name_templet = file_name.replace(num_str, "{num}");
return fn.arr(siteJson.pages.length, (v, i) => {
if (num_str_length > 1) {
return `${dir}${file_name_templet.replace("{num}", String(i + 1).padStart(num_str_length, "0"))}`;
}
return `${dir}${file_name_templet.replace("{num}", i + 1)}`;
});
});
},
capture: () => _this.imgs(),
autoDownload: [0],
next: () => {
if (!_this.page()) return null;
let next = siteJson?.nextChapter?.slug;
return next ? fn.dir(fn.clp()) + next : null;
},
prev: 1,
chapters: () => {
let dir = fn.dir(fn.clp());
return siteJson.allChapters.map(({
title,
slug
}) => ({
text: title,
url: `${dir}${slug}`
}));
},
customTitle: () => {
if (!_this.page()) return null;
let {
chapter: {
manga: {
name
},
title
}
} = siteJson;
return name + " - " + title;
},
category: "comic"
}, {
name: "Weeb Central",
url: {
h: "weebcentral.com",
p: "/chapters/"
},
init: () => {
let chapters_url = fn.attr("button[hx-get]", "hx-get");
let p_a = fn.fetchDoc(chapters_url).then(dom => {
let button = fn.ge("#selected_chapter", dom);
siteJson.next = button?.previousElementSibling;
siteJson.prev = button?.nextElementSibling;
siteJson.chapterList = fn.gae("button,a", dom);
});
let p_b = fn.waitEle("main section img[alt^=Page]").then(() => fn.createImgBox("section:has(img[alt^=Page])", 1));
return Promise.all([p_a, p_b]);
},
imgs: () => fn.gae("main section img[alt^=Page]"),
button: [4],
insertImg: [
["box", 0, "section:has(img[alt^=Page])"], 2
],
endColor: "white",
autoDownload: [0],
next: () => {
let next = siteJson.next;
return isEle(next) ? next.href : null;
},
prev: () => {
let prev = siteJson.prev;
return isEle(prev) ? prev.href : null;
},
chapters: () => siteJson.chapterList.map(e => {
let url;
if (e.tagName == "BUTTON") {
url = fn.curl();
} else {
url = e.href;
}
return {
text: e.innerText.trim(),
url
}
}).reverse(),
customTitle: () => fn.title(" | Weeb Central"),
category: "comic"
}, {
name: "YuKomik",
url: {
h: "yukomik.com",
},
imgs: ".min-h-screen div[q\\:key] img",
button: [4],
insertImg: [".min-h-screen .min-h-screen", 2],
endColor: "white",
autoDownload: [0],
next: "//a[text()='Next ']",
prev: "//a[text()=' Prev']",
chapters: {
url: "a:has(h1[itemprop])",
target: "//div[h1[span[text()='Chapter']]]//a",
textNode: "p",
sort: "r"
},
customTitle: [".min-h-screen h1", ".min-h-screen h2"],
category: "comic"
}, {
name: "MangaPark",
host: ["mangapark.net", "mangapark.com", "mangapark.to", "parkmanga.com"],
url: {
t: "Share Any Manga on MangaPark",
p: ["chapter", "/title/"],
e: "select.select",
st: "image_server"
},
imgs: () => JSON.parse(fn.gst("image_server")).objs.filter(e => {
try {
return e.startsWith("http") && fn.isImage(e) && !["/thumb/", "/ampi/", "/mpim/", "/mpav/"].some(t => e.includes(t));
} catch {
return false;
}
}),
button: [4],
insertImgBF: () => fn.waitEle("[data-name='image-item'] img"),
insertImg: ["div:has(>div[data-name='image-item'])", 2],
autoDownload: [0],
next: "//a[span[text()='Next Chapter']]",
prev: "//a[span[text()='Prev Chapter']]",
chapters: {
wait: "select[on\\:change] option[value^='/title/']",
node: "select[on\\:change]",
target: "option"
},
customTitle: () => fn.title(" - Share Any Manga on MangaPark"),
category: "comic"
}, {
name: "MangaHere/Manga Fox 分頁模式",
url: {
h: ["www.mangahere.cc", "fanfox.net"],
p: "/manga/",
e: ".cp-pager-list span",
},
imgs: () => {
let code = fn.gst("imagecount");
let imagecount = fn.numVar(code, "imagecount");
let croot = fn.dir(fn.lp);
let chapterid = fn.numVar(code, "chapterid");
let fetchNum = 0;
let keyE = fn.ge("#dm5_key");
let key = keyE.value;
let resArr = fn.arr(imagecount, (v, i) => {
let searchParams = new URLSearchParams({
cid: chapterid,
page: i + 1,
key: key
});
let api = `${croot}chapterfun.ashx?${searchParams}`;
return fetch(api).then(res => res.text()).then(res => {
fn.showMsg(`${DL.str_06}(${fetchNum+=1}/${imagecount})`, 0);
let text = fn.parseCode(res);
let pix = fn.textVar(text, "pix");
let pvalue = fn.TextToArray(text, "pvalue");
return pix + pvalue[0];
});
});
return Promise.all(resArr);
},
button: [4],
insertImg: [".reader-main", 2],
endColor: "white",
autoDownload: [0],
next: "//a[text()='Next Chapter']",
prev: "//a[text()='Pre chapter']",
chapters: {
target: ".reader-header-title-list a"
},
customTitle: () => fn.ge("meta[name='og:title']")?.content?.split(" - ")[1]?.replace(/Read | Online/g, ""),
hide: ".ad-reader,.pager-list-left>span",
category: "comic"
}, {
name: "MangaHere/Manga Fox 條漫模式",
url: {
h: ["www.mangahere.cc", "fanfox.net"],
p: "/manga/",
e: ".cp-pager-list",
},
init: () => fn.waitEle(".reader-main img"),
imgs: () => fn.gae(".reader-main img"),
button: [4],
insertImg: [".reader-main", 2],
endColor: "white",
autoDownload: [0],
next: "//a[text()='Next Chapter']",
prev: "//a[text()='Pre chapter']",
chapters: {
target: ".reader-header-title-list a"
},
customTitle: () => fn.ge("meta[name='og:title']")?.content?.split(" - ")[1]?.replace(/Read | Online/g, ""),
hide: ".ad-reader",
category: "comic"
}, {
name: "MangaHere/Manga Fox M",
url: {
h: ["m.mangahere.cc", "m.fanfox.net"],
p: ["/manga/", "/roll_manga/"],
e: "#viewer"
},
init: () => {
let url = fn.url.replace("/manga/", "/roll_manga/");
return fn.fetchDoc(url).then(dom => {
siteJson.srcs = fn.getImgSrcArr("#viewer img", dom);
let btn = fn.ge(".roll-pagebtn", dom);
if (btn) {
tempEles.push(btn);
let next = fn.ge("//a[text()='Next Chapter']", btn);
if (next) {
tempNextLink = next.href;
}
}
});
},
imgs: () => siteJson.srcs,
button: [4, "24%", 1],
insertImg: ["#viewer", 2],
endColor: "white",
insertImgAF: (parent) => {
if (tempEles.length > 0 && !fn.ge(".roll-pagebtn")) {
parent.after(...tempEles);
}
fn.remove(".pager,.mangaread-page");
},
next: () => tempNextLink,
prev: 1,
customTitle: () => {
if (fn.lh.includes("fanfox")) {
return document.title + fn.gt(".mangaread-title");
} else {
let code = fn.gst("addHistory");
let json = fn.TextToObject(code, "addHistory");
let ch = fn.gt(".return-title");
return json.name + " - " + ch;
}
},
category: "comic"
}, {
name: "MangaHere/Manga Fox M",
url: {
h: ["newm.mangahere.cc", "newm.fanfox.net"],
p: "/manga/",
e: ".read-bottom-bar"
},
imgs: () => {
if (fn.ge(".read-bottom-bar-block.control-right")) {
let code = fn.gst("imagecount");
let imagecount = fn.numVar(code, "imagecount");
let croot = fn.dir(fn.lp);
let chapterid = fn.numVar(code, "chapterid");
let fetchNum = 0;
let resArr = fn.arr(imagecount, (v, i) => {
let searchParams = new URLSearchParams({
cid: chapterid,
page: i + 1,
key: ""
});
let api = `${croot}chapterfun.ashx?${searchParams}`;
return fetch(api).then(res => res.text()).then(res => {
fn.showMsg(`${DL.str_06}(${fetchNum+=1}/${imagecount})`, 0);
let text = fn.parseCode(res);
let pix = fn.textVar(text, "pix");
let pvalue = fn.TextToArray(text, "pvalue");
return pix + pvalue[0];
});
});
return Promise.all(resArr);
} else {
return fn.gae(".read-img-bar img");
}
},
button: [4, "24%"],
insertImg: [".read-img-bar", 2],
insertImgAF: (parent) => {
fn.run("jQuery('.read-img-bar').off()")
if (nextLink) {
fn.addUrlHtml(nextLink, parent, 1, DL.str_143, 5);
}
},
next: "//a[div[p[text()='Next Chapter']]][not(starts-with(@href,'java'))]",
prev: "//a[div[p[text()='Last Chapter' or text()='Prev Chapter']]][not(starts-with(@href,'java'))]",
customTitle: () => fn.ge("meta[name='og:title']")?.content?.split(" - ")[1]?.replace(/Read | Online/g, ""),
css: "#FullPictureLoadOptionsButtonParentDiv{margin-top:50px;}",
hide: "div:has(>[id^=mc])",
category: "comic"
}, {
name: "Sen Manga",
url: {
h: ["raw.senmanga.com"]
},
page: () => fn.clp(/^\/[\w-]+\/[\d\.-]+$/),
json: () => fn.showMsg(DL.str_05, 0).then(() => {
let p = fn.clp().split("/");
let m = p.at(-2);
let c = p.at(-1);
let r = m + "-chapter-" + c;
return fetch("/api/read/" + r).then(res => res.json()).then(json => (siteJson = json) && fn.hideMsg());
}),
SPA: () => _this.page() ? true : (siteJson = {}) && false,
observeURL: "nav",
init: () => _this.page() ? _this.json() : void 0,
imgs: () => _this.page() ? siteJson.pages : [],
capture: () => _this.imgs(),
autoDownload: [0],
next: () => _this.page() && siteJson?.nextChapter ? fn.clp().replace(/[\d\.-]+$/, "") + siteJson.nextChapter : null,
prev: 1,
chapters: () => siteJson.series.chapterList.map(({
title,
url
}) => ({
text: title,
url
})).reverse(),
customTitle: () => {
if (!_this.page()) return null;
return siteJson.series.title + " - Chapter " + siteJson.chapter;
},
category: "comic"
}, {
name: "Sen Manga",
url: {
h: "www.senmanga.com",
},
page: () => fn.clp("/read/"),
json: () => fn.fetchDoc(fn.clp()).then(dom => JSON.parse(dom.querySelector("#__NEXT_DATA__").textContent).props.pageProps.chapter).then(pageJson => {
return fetch(`/api/title/${pageJson.series.id}/chapters`).then(res => res.json()).then(chaptersJson => {
Reflect.set(pageJson, "chapters", chaptersJson.data);
debug("\n此頁JSON資料\n", pageJson);
return pageJson;
});
}),
SPA: () => _this.page() ? true : (siteJson = {}) && false,
observeURL: "head",
init: () => _this.page() ? fn.showMsg(DL.str_05, 0).then(() => _this.json().then(json => (siteJson = json) && fn.hideMsg())) : void 0,
imgs: () => _this.page() ? siteJson.pageList.url.map(url => "/api/proxy?imageUrl=" + url) : [],
capture: () => _this.imgs(),
autoDownload: [0],
next: () => {
if (!_this.page()) return null;
let cid = fn.clp().split("/").at(-1);
let c_chapter = siteJson.chapters.find(e => e.id == cid);
let _language = c_chapter.language.name;
let languageChapters = siteJson.chapters.filter(e => e.language.name == _language);
let index = languageChapters.findIndex(e => e.id == cid);
let next = languageChapters[index + 1];
return isObject(next) ? "/read/" + next.id : null;
},
prev: 1,
chapters: () => {
let cid = fn.clp().split("/").at(-1);
let c_chapter = siteJson.chapters.find(e => e.id == cid);
let _language = c_chapter.language.name;
let languageChapters = siteJson.chapters.filter(e => e.language.name == _language);
return languageChapters.map(({
full_title,
id
}) => ({
text: full_title,
url: "/read/" + id
}));
},
customTitle: () => _this.page() ? siteJson.series.title + " - " + siteJson.full_title : null,
category: "comic"
}, {
name: "NiAdd",
host: ["www.niadd.com"],
url: {
st: "NiaddChpPageCtrl",
p: "/statuses/"
},
imgs: () => {
let code = fn.gst("all_imgs_url");
return fn.TextToArray(code, "all_imgs_url");
},
button: [4],
insertImg: ["#viewer", 2],
endColor: "white",
insertImgAF: (parent) => {
if (nextLink) {
fn.addUrlHtml(nextLink, parent, 1, DL.str_143, 5);
}
},
autoDownload: [0],
next: () => {
let code = fn.gst("next_page_url");
let next = fn.textVar(code, "next_page_url ");
return next === "https://www.niadd.com/" ? null : next;
},
prev: 1,
customTitle: () => fn.gt(".title>a:last-child") + " - " + fn.gt(".title>a"),
hide: ".ads_margin,center:has(>script),.mangaread-pagenav>select~*,.site-content>footer",
category: "comic"
}, {
name: "NiAdd",
link: "https://niadd.com/original/10070490/chapters.html",
url: {
h: "niadd.com",
p: "/chapter/",
e: ["#viewer", ".pic_box", ".tool", "img[id^='manga_pic']", ".manga-name"]
},
imgs: () => {
let max = fn.gt(".tool>a").match(/\d+/g).at(-1);
let links = fn.arr(max, (v, i) => i == 0 ? fn.url : fn.url.replace(/\/$/, "") + `-${i + 1}.html`);
return fn.getImgA("img[id^='manga_pic']", links);
},
button: [4],
insertImg: [".pic_box", 2],
insertImgAF: (parent) => {
if (nextLink) {
fn.addUrlHtml(nextLink, parent, 1, DL.str_143, 5);
}
},
endColor: "white",
autoDownload: [0],
next: () => {
let select = fn.ge(".mangaread-pagenav>select");
let chapters = fn.gae("option", select);
let c_chapter = chapters.find(e => e.value == fn.url);
let next = c_chapter?.previousElementSibling;
return next ? next.value : null;
},
prev: 1,
customTitle: () => fn.dt({
s: ".manga-name",
d: [
/[\s\/]$/,
"(mitaku.net) "
]
}),
hide: ".option-item~*",
category: "comic"
}, {
name: "MangaHasu",
url: {
h: "mangahasu.me",
e: "#loadchapter"
},
imgs: ".img-chapter .img img",
button: [4],
insertImg: [".img-chapter .img", 2],
endColor: "white",
autoDownload: [0],
next: "//a[text()='Next']",
prec: "//a[text()='Prev']",
chapters: {
node: "//div[span[text()='Select Chapter:']]",
target: "option",
sort: "r"
},
customTitle: ".div-title-chapter h1",
category: "comic"
}, {
name: "MangaFire",
url: {
h: ["mangafire.to"]
},
page: () => fn.clp("/read/"),
get_chapters: () => {
let headers = new Headers({
"Accept": "application/json, text/javascript, */*; q=0.01",
"X-Requested-With": "XMLHttpRequest",
});
let [, , id, lang] = fn.clp().split("/");
id = id.split(".").at(-1);
return fetch(`/ajax/read/${id}/chapter/${lang}`, {
headers
}).then(res => res.json()).then(json => {
let temp = fn.html(json.result.html);
siteJson.chapterList = fn.gae("a[data-id]", temp);
});
},
SPA: () => _this.page() ? true : (siteJson = {}) && false,
observeURL: "head",
init: () => _this.page() ? _this.get_chapters() : void 0,
imgs: () => {
if (!_this.page()) return [];
fn.showMsg(DL.str_05, 0);
let c = fn.clp().split("/").at(-1);
let cc = siteJson.chapterList.find(a => a.href.includes(c));
let headers = new Headers({
"Accept": "application/json, text/javascript, */*; q=0.01",
"X-Requested-With": "XMLHttpRequest",
});
return fetch(`/ajax/read/chapter/${cc.dataset.id}`, {
headers
}).then(res => res.json()).then(json => json.result.images.map(arr => arr.find(e => e.startsWith("http"))));
},
capture: () => _this.imgs(),
autoDownload: [0],
next: () => {
if (!_this.page()) return null;
let c = fn.clp().split("/").at(-1);
let index = siteJson.chapterList.findIndex(a => a.href.includes(c));
let next = siteJson.chapterList[index - 1];
return isEle(next) ? next.href : null;
},
prev: 1,
chapters: () => siteJson.chapterList.map(a => {
let [text] = a.innerText.split(":");
return {
text,
url: a.href
}
}).reverse(),
customTitle: () => _this.page() ? fn.title(/ - Read Manga Online| \| Read Online on MangaFire|Manga, /g) : null,
category: "comic"
}, {
name: "Mangapill",
url: {
h: ["www.mangapill.com", "mangapill.com"],
p: "/chapters/"
},
imgs: "chapter-page img",
button: [4],
insertImg: ["div:has(>chapter-page)", 2],
autoDownload: [0],
next: "a[data-hotkey=ArrowRight]",
prev: "a[data-hotkey=ArrowLeft]",
chapters: {
api: () => {
let [id] = fn.lp.match(/\d+/);
return `/manga/${id}/chapters`;
},
target: "a",
sort: "r"
},
customTitle: "h1#top",
hide: ".flex.items-center.justify-between:has(svg[data-remove-flyer])",
category: "comic"
}, {
name: "MangaTown",
url: {
h: ["www.mangatown.com", "m.mangatown.com"],
p: "/manga/",
e: "#top_chapter_list"
},
init: async () => {
if (fn.lh.startsWith("m.")) {
await fn.waitEle("#top_chapter_list option");
fn.gae("#top_chapter_list option").forEach(e => {
let url = e.value;
if (url.includes("//manga")) {
url = url.replace("https://m.mangatown.com/", "");
}
if (!url.endsWith("/")) {
url = url + "/";
}
e.value = url;
});
}
},
imgs: () => {
if (fn.ge("#viewer .image")) {
return fn.gae("#viewer .image");
}
let max;
if (fn.lh.startsWith("m.")) {
max = fn.gae(".ch-select option").length;
} else {
max = _unsafeWindow.total_pages;
}
let links = fn.arr(max, (v, i) => i == 0 ? fn.lp : fn.lp + `${i + 1}.html`);
return fn.getImgA("#image", links);
},
button: [4],
insertImg: ["#viewer", 2],
endColor: "white",
insertImgAF: (parent) => {
if (nextLink) {
fn.addUrlHtml(nextLink, parent, 1, DL.str_143, 6);
}
document.onkeyup = null;
},
autoDownload: [0],
current: () => {
let chapters = fn.gae("#top_chapter_list option");
let c_chapter = chapters.find(e => e.value == fn.lp);
return c_chapter;
},
next: () => {
let next = _this.current()?.nextElementSibling;
return next ? next.value : null;
},
prev: () => {
let prev = _this.current()?.previousElementSibling;
return prev ? prev.value : null;
},
chapters: {
target: "#top_chapter_list option"
},
customTitle: () => {
if (fn.lh.startsWith("m.")) {
return fn.dt({
s: ".title>a",
d: " Page 1"
});
} else {
return fn.dt({
d: [
/.+- Read/,
"Online - Page 1",
]
});
}
},
hide: ".page_select,div[style]:has(>.page_select),.ch-select,#pager",
category: "comic"
}, {
name: "MangaHome",
url: {
h: "www.mangahome.com",
p: "/manga/",
e: "#viewer"
},
init: () => fn.waitEle("#readChapterLists a"),
imgs: () => {
const {
imagecount,
chapter_id
} = _unsafeWindow;
let fetchNum = 0;
let resArr = fn.arr(imagecount, (v, i) => {
let searchParams = new URLSearchParams({
cid: chapter_id,
page: i + 1,
key: ""
});
let api = `chapterfun.ashx?${searchParams}`;
return fetch(api).then(res => res.text()).then(res => {
fn.showMsg(`${DL.str_06}(${fetchNum+=1}/${imagecount})`, 0);
let text = fn.parseCode(res);
let [, pix] = text.match(/pix="([^"]+)/);
let [, pvalue] = text.match(/pvalue=([^;]+)/);
pvalue = JSON.parse(pvalue);
return pix + pvalue[0];
});
});
return Promise.all(resArr);
},
button: [4],
insertImg: ["#viewer", 2],
endColor: "white",
insertImgAF: () => fn.run("$('body').off()"),
autoDownload: [0],
next: "//a[text()='Next Chapter']",
prev: "//a[text()='Prev Chapter']",
chapters: {
target: "#readChapterLists a"
},
customTitle: () => fn.dt({
d: [
/.+- Read/,
"Online - Page 1",
]
}),
hide: ".mangaread-pagenav",
category: "comic"
}, {
name: "Asura Scans",
url: {
h: "asuracomic.net",
p: "/chapter/"
},
init: () => fn.waitEle("img[alt*='chapter']"),
imgs: () => fn.gae("img[alt*='chapter']"),
button: [4],
insertImg: ["div:has(>div>div>img[alt*='chapter'])", 2],
endColor: "white",
autoDownload: [0],
next: "//a[div[h2[text()='Next']]]",
prev: "//a[div[h2[text()='Prev']]]",
chapters: {
url: "h2+p a",
target: "//div[a[div[h3[text()='First Chapter']]]]/following-sibling::div//a",
textNode: "h3",
cb: (text, u) => ({
text,
url: [...new Set(u.split("/"))].join("/")
}),
sort: "r"
},
customTitle: "h2.text-xl",
hide: "#header-ads,.bg-gradient-to-br",
category: "comic"
}, {
name: "Comick",
url: {
h: ["comick.io"]
},
page: () => fn.clp("-chapter-"),
json: () => fn.showMsg(DL.str_05, 0).then(() => fn.clp().split("/").at(-1).split("-").at(0)).then(id => fetch(`https://api.comick.io/chapter/${id}`).then(res => res.json()).then(json => (siteJson = json) && fn.hideMsg())),
SPA: () => _this.page() ? true : (siteJson = {}) && false,
observeURL: "nav",
init: () => _this.page() ? _this.json() : void 0,
imgs: () => _this.page() ? siteJson.chapter.md_images.map(({
b2key
}) => `https://meo.comick.pictures/${b2key.slice(0, b2key.lastIndexOf(".")) + "-m.jpg"}`) : [],
capture: () => _this.imgs(),
autoDownload: [0],
next: () => _this.page() && siteJson?.next?.href ? siteJson.next.href : null,
prev: 1,
chapters: () => {
let dir = fn.dir(fn.clp());
return siteJson.chapters.map(({
chap,
hid,
lang
}) => ({
text: `Ch ${chap}`,
url: `${dir}${hid}-chapter-${chap}-${lang}`
})).reverse();
},
customTitle: () => {
if (!_this.page()) return null;
let textArr = siteJson.seoTitle.split(" - ");
return textArr[1] + " - " + textArr[0];
},
category: "comic"
}, {
name: "MangaDemon",
url: {
h: ["www.demonicscans.org", "demonicscans.org"],
p: "/chapter/"
},
box: [".main-width .chapter-info", 1],
imgs: ".imgholder:not([src*='free_ads'])",
button: [4],
insertImg: [
["box", 0, ".main-width>*:not(#FullPictureLoadMainImgBox,.chapter-info,center)"], 2
],
autoDownload: [0],
next: "a.nextchap",
prev: "a.prevchap",
chapters: {
node: ".chapters-nav select",
target: "option"
},
checkCurrentChapter: (url) => {
let cid = fn.lp.split("/").at(-2);
let uid = fn.getUSP("chapter", location.origin + url);
return cid == uid;
},
hide: "#teaser3",
category: "comic"
}, {
name: "Night Scans/Terco Scans/Lua Scans/Rizz Fables/Lectormiau/Mangagojo/Cosmic Scans Indonesia/Kiryuu/KumoPoi/Three daos",
url: {
h: [
"nightsup.net",
"tercomoon.xyz",
"tecno-moon.xyz",
"luascans.com",
"rizzfables.com",
"leemiau.com",
"mangagojo.com",
"rawkuma.net",
"lc3.cosmicscans.asia",
/kiryuu/,
"kumopoi.org",
"mangakita.id",
"threedaos.zdrz.xyz"
]
},
init: () => fn.addMutationObserver(() => fn.remove("#radio_content,#teaserbottom")),
imgs: "#readerarea img[class*='wp-image'],#readerarea .ts-main-image,#readerarea img[loading],#readerarea .chapter-img,#readerarea img[src*='/chapter'],#readerarea img[src*='/Chapter']",
button: [4],
insertImg: ["#readerarea", 2],
endColor: () => fn.ge(".darkmode") ? "white" : "black",
autoDownload: [0],
next: "a.ch-next-btn",
prev: "a.ch-prev-btn",
chapters: {
wait: "#chapter option[data-id]",
node: "#chapter",
target: "option[data-id]",
sort: "r"
},
checkCurrentChapter: (url, text) => {
let ct = fn.gt("#chapter [selected]");
return ct == text;
},
hide: ".ver-src.chapter,.blox,div[style]:has(>div>script),div:has(.adblock_title),div:has(.vast-blocker)",
customTitle: ".entry-title",
category: "comic"
}, {
name: "Three daos AAD",
url: {
h: "threedaos.zdrz.xyz"
},
hide: "#gusmdm,div:has(.adblock_title),div:has(.vast-blocker)",
category: "ad"
}, {
name: "Sektekomik",
url: {
h: ["sektekomik.id"]
},
imgs: ".read-img>img",
button: [4],
insertImg: [".read-img", 2],
autoDownload: [0],
next: ".text-right a.nav-chap",
prev: ".text-left a.nav-chap",
chapters: {
url: ".breadcrumb__links a",
urlIndex: 1,
target: "#chapterList a"
},
customTitle: ".container h3",
category: "comic"
}, {
name: "Kingsmanga",
url: {
h: "www.kingsmanga.net"
},
imgs: ".post-content img",
button: [4],
insertImg: [".post-content", 2],
autoDownload: [0],
next: ".reader-content a[rel=next]",
prev: ".reader-content a[rel=prev]",
chapters: {
url: "#breadcrumbs a",
urlIndex: 2,
target: ".table-bordered a",
cb: (t, u) => ({
text: t.trim().match(/[\d\.]+$/)[0],
url: u
}),
sort: "r"
},
customTitle: "h1.entry-title",
category: "comic"
}, {
name: "MangaToons",
url: {
h: "mangatoon.mobi",
p: "/watch/",
e: ".episode",
ee: ".new-episode-lock"
},
init: () => fn.waitEle(".pictures img:not(.cover)"),
imgs: ".pictures img:not(.cover)",
button: [4],
insertImg: [".pictures", 2],
autoDownload: [0],
next: ".page-icons-next",
prev: ".page-icons-prev",
chapters: {
url: ".top-left a",
target: ".episode-content-asc .episodes-wrap-new a.episode-item-new",
textNode: ".episode-title-new:not(.episode-number)"
},
customTitle: [".title", ".episode"],
category: "comic"
}, {
name: "MangaGeko",
url: {
h: "www.mgeko.cc",
p: "/reader/"
},
init: () => fn.addMutationObserver(() => fn.remove("#radio_content")),
imgs: "#chapter-reader img",
button: [4],
insertImg: ["#chapter-reader", 2],
autoDownload: [0],
next: ".chnav.next[href^='/reader/']",
prev: ".chnav.prev[href^='/reader/']",
chapters: {
node: ".chapternav select",
target: "option",
cb: (t, v, e) => ({
text: t.replace("-eng-li", ""),
url: e.value ? v : fn.lp
}),
sort: "r"
},
customTitle: () => fn.title("Manga: "),
hide: "center:has(>#chapter-reader)>*:not(#chapter-reader),.chapternav+div[style]",
category: "comic"
}, {
name: "Flame Comics",
url: {
h: ["flamecomics.xyz"]
},
json: () => fn.showMsg(DL.str_05, 0).then(() => fn.fetchDoc(fn.clp()).then(dom => {
let code = fn.gt("#__NEXT_DATA__", 1, dom);
let json = JSON.parse(code);
siteJson = json.props.pageProps;
debug("\n此頁JSON資料\n", json);
fn.hideMsg();
})),
page: () => fn.clp(/^\/series\/\w+\/\w+/),
SPA: () => _this.page() ? true : (siteJson = {}) && false,
observeURL: "nav",
init: () => _this.page() ? _this.json().then(() => {
fn.waitEle("div:not([id],[class],[style]):has(iframe[title='ad-iframe'])", 30).then(e => e?.remove());
}) : void 0,
imgs: () => {
if (!_this.page()) return [];
let cdn = "https://cdn.flamecomics.xyz/uploads/images/series";
let {
chapter: {
series_id,
images,
token,
release_date,
title,
chapter_title,
chapter
}
} = siteJson;
apiCustomTitle = title + " - " + (chapter_title ?? "Chapter " + Number(chapter));
return Object.values(images).map(({
name
}) => `${cdn}/${series_id}/${token}/${name}?${release_date}`);
},
capture: () => _this.imgs(),
autoDownload: [0],
next: () => {
if (!_this.page()) return null;
let {
next,
chapter: {
series_id
}
} = siteJson;
return next ? `/series/${series_id}/${next}` : null;
},
prev: 1,
chapters: {
api: () => `/series/${siteJson.chapter.series_id}`,
target: ".mantine-ScrollArea-viewport a",
textNode: "p",
sort: "r"
},
hide: "div[class^='Radio_radio_content'],div:not([id],[class],[style]):has(iframe)",
category: "comic"
}, {
name: "Hive Toon/Vortex Scans",
url: {
h: ["www.hivetoons.org", "hivetoons.org", "www.vortexscans.org", "vortexscans.org"]
},
data: () => fn.showMsg(DL.str_05, 0).then(() => fn.fetchDoc(fn.clp()).then(dom => (doc = dom))).then(() => fn.hideMsg()),
page: () => fn.clp("/chapter"),
SPA: () => _this.page(),
observeURL: "nav",
init: () => _this.page() ? _this.data() : void 0,
imgs: () => {
if (!_this.page()) return [];
let code = fn.gst('\\"images\\"', doc);
if (!code) return [];
code = code.replaceAll("\\", "");
return fn.TextToArray(code, '"images":').map(e => e.url);
},
capture: () => _this.imgs(),
autoDownload: [0],
next: () => {
if (!_this.page()) return null;
let code = fn.gst('\\"nextChapter\\":{', doc);
if (!code) return null;
code = code.replaceAll("\\", "");
let {
slug
} = fn.TextToObject(code, "nextChapter");
return fn.dir(fn.clp()) + slug;
},
prev: 1,
chapters: () => {
let url = fn.lo + fn.ge("main a", doc).pathname;
let dir = fn.dir(fn.clp());
return fn.fetchDoc(url).then(dom => {
let code = fn.gst('\\"chapters\\"', dom);
code = code.replaceAll("\\", "");
return fn.TextToArray(code, '"chapters":').map(({
slug,
number
}) => ({
text: `Chapter ${number}`,
url: `${dir}${slug}`
})).reverse();
});
},
customTitle: () => _this.page() ? fn.title(/ - Void Scans hivetoon| - Vortex Scans/, 0, doc) : null,
hide: "#radio_content",
category: "comic"
}, {
name: "NineManga",
url: {
h: "ninemanga.com",
p: "/chapter/"
},
imgs: () => {
let page = fn.ge("#page,.sl-page");
let links = fn.gae("option", page).map(e => e.value);
return fn.getImgA(".manga_pic", links);
},
button: [4],
insertImg: ["center:has(>.viwer),.image-box", 2],
insertImgAF: (parent) => {
if (nextLink) {
fn.addUrlHtml(nextLink, parent, 1, DL.str_143, 3);
}
},
autoDownload: [0],
next: () => {
let next = fn.ge("//select[@id='chapter' or @class='sl-chap']/option[@selected]/preceding-sibling::option[1]");
return next ? next.value : null
},
prev: "//select[@id='chapter' or @class='sl-chap']/option[@selected]/following-sibling::option[1]",
chapters: () => {
let [, e] = fn.gae(".subgiude a");
let name = fn.gt(e).toLowerCase();
let node = fn.ge(".readpage select");
const capitalizeFirstLetter = (str) => str.charAt(0).toUpperCase() + str.slice(1);
return fn.gae("option", node).map(o => ({
text: capitalizeFirstLetter(o.innerText.toLowerCase().replace(name, "").trim()),
url: o.value
})).reverse();
},
customTitle: () => fn.dt({
d: /page 1.+$/
}),
category: "comic"
}, {
name: "M440.in",
url: {
h: ["m440.in"],
p: "/manga/"
},
imgs: "#all img",
button: [4],
insertImg: ["#ppp", 2],
autoDownload: [0],
next: () => _unsafeWindow.next_chapter ? _unsafeWindow.next_chapter : null,
prev: () => _unsafeWindow.prev_chapter ? _unsafeWindow.prev_chapter : null,
chapters: {
target: "#chapter-list .dropdown-menu a",
sort: "r"
},
checkCurrentChapter: (url) => {
let cid = fn.url.split("/").at(5);
let uid = url.split("/").at(5);
return cid == uid;
},
customTitle: () => fn.dt({
d: [
" - Pág. 1",
" - M440.in"
]
}),
category: "comic"
}, {
name: "ReadComicsOnline",
url: {
h: ["www.readcomicsonline.ru", "readcomicsonline.ru"],
p: "/comic/"
},
imgs: "#all img",
button: [4],
insertImg: [".imagecnt", 2],
autoDownload: [0],
next: () => _unsafeWindow.next_chapter ? _unsafeWindow.next_chapter : null,
prev: () => _unsafeWindow.prev_chapter ? _unsafeWindow.prev_chapter : null,
chapters: {
target: "#chapter-list .dropdown-menu a",
cb: (t, url) => ({
text: t.slice(0, t.indexOf(":")),
url
}),
sort: "r"
},
customTitle: () => fn.dt({
d: " - Page 1"
}),
category: "comic"
}, {
name: "Mangamovil",
url: {
h: ["mangamovil.net"],
p: "/capitulo/",
st: "video"
},
imgs: () => {
let f = fn.html(_unsafeWindow.video[0]);
return fn.gae("img", f);
},
button: [4],
insertImg: ["#video-content", 2],
autoDownload: [0],
next: "a:has(.fa-angle-double-right)",
prev: "a:has(.fa-angle-double-left)",
chapters: {
url: "//a[contains(text(),'capítulos')]",
target: "ul.list-group a",
textNode: ".sa-series-link__number",
cb: (t, url) => ({
text: t.replace(".00", "").replace(".50", ".5").replace(".60", ".6"),
url
}),
sort: "r"
},
customTitle: ".container h1",
category: "comic"
}, {
name: "Omega Scans",
host: ["www.omegascans.org"],
url: {
h: [/^(www\.)?omegascans\.org$/]
},
page: () => fn.clp("/chapter"),
SPA: () => _this.page(),
observeURL: "gm",
init: () => _this.page() ? fn.waitEle("#content .container img:not(.rounded)") : void 0,
imgs: () => _this.page() ? fn.gae("#content .container img:not(.rounded)") : [],
capture: () => _this.imgs(),
autoDownload: [0],
next: "a:has(>button>.fa-chevron-right)",
prev: "a:has(>button>.fa-chevron-left)",
chapters: () => {
let [, , id] = fn.clp().split("/");
let dir = fn.dir(fn.clp());
return fetch(`https://api.omegascans.org/chapter/all/${id}`).then(res => res.json()).then(array => array.map(({
chapter_name,
chapter_slug
}) => ({
text: chapter_name,
url: dir + chapter_slug
})).reverse());
},
customTitle: () => _this.page() ? fn.dt({
d: [" - Reaper Scans", " - Omega Scans"]
}) : null,
category: "comic"
}, {
name: "ZeroScans",
url: {
h: ["zscans.com"]
},
page: () => fn.clp(/^\/comics\/[\w-]+\/\d+$/),
json: () => fn.showMsg(DL.str_05, 0).then(() => fn.fetchDoc(fn.clp()).then(dom => {
let code = fn.gst("__ZEROSCANS__", dom);
let json = fn.parseCode(code);
[siteJson] = json.data;
debug("\n此頁JSON資料\n", siteJson);
fn.hideMsg();
})),
SPA: () => _this.page() ? true : (siteJson = {}) && false,
observeURL: "nav",
init: () => _this.page() ? _this.json() : void 0,
imgs: () => _this.page() ? siteJson.current_chapter.high_quality : [],
capture: () => _this.imgs(),
autoDownload: [0],
next: () => {
if (!_this.page()) return null;
let {
current_chapter: {
comic_slug
},
nav: {
next
}
} = siteJson;
return isObject(next) ? `/comics/${comic_slug}/${next.id}` : null;
},
prev: 1,
chapters: () => {
let dir = fn.dir(fn.clp());
return siteJson.chapter_list.map(({
id,
name
}) => ({
text: `Chapter ${name}`,
url: dir + id
}));
},
customTitle: () => _this.page() ? fn.waitEle(".v-breadcrumbs").then(e => fn.dt({
t: fn.gt(e),
d: "Comics"
})) : null,
category: "comic"
}, {
name: "RawUwU/Rawdevart",
url: {
h: ["rawuwu.net", "rawdevart.art"]
},
page: () => fn.clp("/read/"),
SPA: () => _this.page(),
observeURL: "head",
data: () => fn.showMsg(DL.str_05, 0).then(() => fn.fetchDoc(fn.clp()).then(dom => {
let mid = fn.ge("#manga-id", dom).value;
let [cid] = fn.clp().match(/[\d\.]+$/);
return fetch(`/spa/manga/${mid}/${cid}`).then(res => res.json()).then(json => (siteJson = json));
})),
init: () => _this.page() ? _this.data() : void 0,
imgs: () => {
if (!_this.page()) return [];
debug("json", siteJson)
let {
chapter_detail: {
server,
chapter_content
}
} = siteJson;
let f = fn.html(chapter_content);
return fn.gae(".chapter-img canvas[data-srcset]", f).map(e => server + e.dataset.srcset);
},
button: [4],
insertImg: [".chapter-imgs", 2],
autoDownload: [0],
next: () => {
if (!_this.page()) return null;
return siteJson?.next?.startsWith("/read/") ? siteJson.next : null;
},
prev: 1,
chapters: () => {
let temp = fn.html(siteJson.options);
return fn.gae("option", temp).map(o => ({
text: o.innerText.trim(),
url: o.value
})).reverse();
},
customTitle: () => {
if (!_this.page()) return null;
let {
chapter_detail: {
manga_name,
chapter_number
}
} = siteJson;
return manga_name.trim() + " - Chapter " + chapter_number;
},
category: "comic"
}, {
name: "AnimeBbg",
url: {
h: ["animebbg.net"],
p: "/capitulo/link/"
},
imgs: ".itemList .js-lbImage",
button: [4],
insertImg: [".itemList", 2],
autoDownload: [0],
next: ".albumLinksNav-right a:has(.fa-arrow-right)",
prev: ".albumLinksNav-left a:has(.fa-arrow-left)",
chapters: () => {
let a = fn.ge("//a[contains(text(),'Capítulos')]");
return fn.fetchDoc(a).then(dom => {
const get = (_dom) => fn.gae(".structItem-title a", _dom).map(a => ({
text: a.innerText.trim().replace(".00", "").replace(".50", ".5").replace(".60", ".6"),
url: a.href
}));
let pages = fn.ge(".pageNav-jump--next", dom);
if (pages) {
let doms = [dom];
let max = Number(pages.previousElementSibling.lastElementChild.innerText) - 1;
let links = fn.arr(max, (v, i) => `${a.href}?page=${i + 2}`);
let resArr = links.map(link => fn.fetchDoc(link));
return Promise.all(resArr).then(res => {
doms = [...doms, ...res];
return doms.map(page_dom => get(page_dom)).flat();
});
}
return get(dom);
});
},
customTitle: () => {
let text = fn.gt(".p-title-value");
let [c, m] = text.split("-").map(e => e.trim());
return m + " - " + c.replace(".00", "").replace(".50", ".5").replace(".60", ".6");
},
fetch: 0,
category: "comic"
}, {
name: "InManga",
url: {
h: "inmanga.com",
p: /^\/ver\/manga\//
},
init: async () => {
await fn.waitVar("pageController");
await fn.waitEle("#ChapList option:checked");
_unsafeWindow.jQuery(document).off();
_unsafeWindow.jQuery(document.body).off();
},
imgs: () => {
let options = fn.gae("#PageList option");
return options.map((e, i) => _unsafeWindow.pageController._containers.pageUrl.replace("pageNumber", i).replace("identification", e.value));
},
button: [4],
insertImg: ["div:has(>a.NextPage)", 2],
insertImgAF: () => {
fn.ge(".chapterControlsContainer.hidden")?.classList.remove("hidden");
fn.remove(".pageSourceContainer");
},
autoDownload: [0],
chapterUrl: (option) => _unsafeWindow.pageController._containers.chapterUrl.replace("chapterNumber", option.innerText.replace(".", "-")).replace("identification", option.value),
current: () => fn.ge("#ChapList option:checked"),
next: () => {
let next = _this.current()?.nextElementSibling;
return next ? _this.chapterUrl(next) : null;
},
prev: () => {
let prev = _this.current()?.previousElementSibling;
return prev ? _this.chapterUrl(prev) : null;
},
chapters: {
node: "#ChapList",
target: "option",
cb: (text, v, e) => ({
text,
url: _this.chapterUrl(e)
})
},
checkCurrentChapter: (url, text) => {
let ct = fn.gt("#ChapList [selected]");
return ct == text;
},
customTitle: () => fn.dt({
d: " Online - InManga"
}),
category: "comic"
}, {
name: "MangaOni",
url: {
h: ["manga-oni.com"],
p: "/lector/"
},
init: async () => {
await fn.waitVar("hojas");
await fn.waitEle("#c_list option:checked");
fn.ge("#c_list")?.dispatchEvent(new Event("mouseover"));
await fn.delay(200, 0);
await fn.waitEle("#c_list option:checked");
document.body.onkeydown = null;
},
imgs: () => {
let {
dir,
hojas
} = _unsafeWindow;
return hojas.map(e => dir + e);
},
button: [4],
insertImg: ["#slider", 2],
endColor: "white",
insertImgAF: (parent) => {
if (nextLink) {
fn.addUrlHtml(nextLink, parent, 1, DL.str_143, 6);
}
fn.remove("#right")
},
autoDownload: [0],
current: () => {
let chapters = fn.gae("#c_list option");
let c_chapter = chapters.find(e => e.value == _unsafeWindow.url_lector);
return c_chapter;
},
next: () => {
let next = _this.current()?.previousElementSibling;
return next ? next.value : null;
},
prev: () => {
let prev = _this.current()?.nextElementSibling;
return prev ? prev.value : null;
},
chapters: {
target: "#c_list option",
sort: "r"
},
checkCurrentChapter: (url) => {
let cid = fn.url.split("/").at(5);
let uid = url.split("/").at(5);
return cid == uid;
},
customTitle: () => fn.dt({
d: " — Manga en línea | MangaOni"
}),
category: "comic"
}, {
name: "Raw Lazy",
host: ["rawlazy.io"],
url: {
t: "Manga Raw",
p: "/manga-chapter/",
st: "var zing"
},
imgs: async () => {
if (fn.ge(".z_content img")) {
return fn.gae(".z_content img");
} else if (fn.gst("chapter_id")) {
fn.showMsg(DL.str_05, 0);
let code = fn.gst("data:");
let obj_a = fn.TextToObject(code, "data:", 2);
code = fn.gst("var zing");
let obj_b = fn.TextToObject(code, "zing");
let json = {
...obj_a,
...obj_b
};
let page = 1;
let img_index = 0;
let loop = true;
let html = "";
const getData = () => {
let params = new URLSearchParams({
nonce: json.nonce,
action: json.action,
_action: json._action,
p: json.p,
img_index,
chapter_id: json.chapter_id
}).toString();
return fetch("/wp-admin/admin-ajax.php", {
"headers": {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8"
},
"body": params,
"method": "POST"
}).then(res => res.json()).then(json => {
fn.showMsg(`${DL.str_06}${page}/???`, 0);
img_index = json.img_index;
html += json.mes;
if (json?.going != 1) {
loop = false;
}
});
};
while (loop) {
await getData();
page++;
}
return [...fn.doc(html).images];
} else {
return [];
}
},
button: [4],
insertImg: [".entry-content", 2],
insertImgAF: () => fn.hideEle(".br-content"),
autoDownload: [0],
next: "//a[text()='次の章 →']",
prev: "//a[text()='← 前の章']",
chapters: {
target: ".chapters-list a",
textNode: "span",
sort: "r"
},
customTitle: () => fn.dt({
d: " | Manga Raw"
}),
category: "comic"
}, {
name: "KLManga",
host: ["klz9.com", "klto9.com", "jestful.net", "hachiraw.win", "cmoa1.top"],
url: {
t: [" - KL", " - KT9", " - JF", "- Hachiraw", "- CMOA"],
st: "load_image"
},
box: ["#list-imga", 2],
imgs: () => {
fn.showMsg(DL.str_05, 0);
let code = fn.gst("load_image");
let cid = Number(code.match(/\d+/));
return fn.fetchDoc(`/${fn.generateRandomString(30, 1)}.iog?cid=${cid}`).then(dom => fn.gae("img[alt^=Page]", dom));
},
button: [4],
insertImg: ["box", 2],
insertImgAF: () => fn.hideEle("#list-imga"),
endColor: "white",
autoDownload: [0],
current: () => fn.ge(".select-chapter option[selected]"),
next: () => {
let next = _this.current()?.previousElementSibling;
return next ? fn.dir(fn.url) + next.value : null;
},
prev: () => {
let prev = _this.current()?.nextElementSibling;
return prev ? fn.dir(fn.url) + prev.value : null;
},
chapters: {
wait: "#chap_list .current",
target: "#chap_list a",
sort: "r"
},
customTitle: () => fn.dt({
s: ".breadcrumb",
d: "Home Manga List"
}),
category: "comic"
}, {
name: "Weloma/WeloveManga",
url: {
h: ["weloma.art", "welovemanga.one"],
e: ".chapter-content"
},
box: [".chapter-content:not([id])", 1, 1280],
imgs: () => fn.showMsg(DL.str_05, 0).then(() => fn.fetchDoc(fn.lp).then(dom => fn.gae(".chapter-content img[data-img]", dom).map(e => atob(e.dataset.img)))),
button: [4],
insertImg: ["box", 2],
insertImgAF: () => fn.hideEle(".chapter-content:not([id])"),
endColor: "white",
autoDownload: [0],
current: () => fn.ge(".select-chapter option[selected]"),
next: () => {
let next = _this.current()?.previousElementSibling;
return next ? next.value : null;
},
prev: () => {
let prev = _this.current()?.nextElementSibling;
return prev ? prev.value : null;
},
chapters: {
wait: "#chap_list .current",
target: "#chap_list a",
sort: "r"
},
customTitle: () => fn.dt({
s: ".breadcrumb",
d: "Home List manga"
}),
category: "comic"
}, {
name: "NicoManga",
url: {
h: ["nicomanga.com"],
},
page: () => fn.clp("/read-"),
SPA: () => _this.page(),
observeURL: "nav",
init: () => _this.page() ? fn.fetchDoc(fn.clp()).then(dom => (doc = dom)) : void 0,
imgs: () => {
if (_this.page()) {
fn.showMsg(DL.str_05, 0);
let code = fn.gst("loadImagesChapter", doc);
let [id] = code.match(/\d+/);
let api = "/app/manga/controllers/cont.imgsList.php?cid=" + id;
return fn.fetchDoc(api).then(dom => [...dom.images].map(e => e.dataset.srcset));
}
return [];
},
button: [4],
insertImgBF: () => fn.waitEle("#listImgs img").then(() => fn.createImgBox("#listImgs", 2)),
insertImg: ["box", 2],
insertImgAF: () => fn.hideEle("#listImgs"),
autoDownload: [0],
next: "a:has(i.next:not(.disabled))",
prev: "a:has(i.prev:not(.disabled))",
chapters: () => {
let url_templet = fn.clp().replace(/([\d\.]+)(\.html)$/, "{num}$2");
return fn.gae("#chapterListContainer button", doc).map(b => ({
text: b.innerText.trim(),
url: url_templet.replace("{num}", b.dataset.chapter)
})).reverse();
},
customTitle: () => {
if (_this.page()) {
let eles = fn.gae(".breadcrumb-item", doc);
return eles?.at(-2)?.innerText?.trim() + " - " + eles?.at(-1)?.innerText?.trim();
}
return null;
},
category: "comic"
}, {
name: "RawKuro",
url: {
h: ["rawkuro.net", "manga1000.top", "mangakoma01.top", "kakuyomu.in", "mangakoma01.net", "www.raw1001.net", "raw1001.net", "www.manhuaplus.org", "manhuaplus.org"],
st: "CHAPTER_ID"
},
box: ["#chapterContent,#image_container", 2],
imgs: () => {
fn.showMsg(DL.str_05, 0);
let code = fn.gst("CHAPTER_ID");
let cid = fn.numVar(code, "CHAPTER_ID");
return fetch(`/ajax/image/list/chap/${cid}`, {
"headers": {
"accept": "application/json, text/javascript, */*; q=0.01",
"x-requested-with": "XMLHttpRequest"
},
"body": null,
"method": "POST"
}).then(res => res.json()).then(json => {
let dom = fn.doc(json.html);
if (fn.ge(".separator", dom)) {
let divs = fn.gae(".separator", dom).sort((a, b) => a.dataset.index - b.dataset.index);
return divs.map(e => e.firstElementChild.href).filter(e => !e.includes("rawwkuro.jpg"));
} else {
return fn.gae(".page-chapter img:not([data-original$='rawwkuro.jpg'])", dom);
}
});
},
button: [4],
insertImg: ["box", 2],
insertImgAF: () => fn.hideEle("#chapterContent,#image_container"),
endColor: "white",
autoDownload: [0],
next: "a.nextBtn[href*='/'],a.a_next[href*='/']",
prev: "a.prevBtn[href*='/'],a.a_prev[href*='/']",
chapters: {
node: ".nPL_select",
target: "option",
sort: "r"
},
customTitle: "main h1",
category: "comic"
}, {
name: "RawOtaku/JManga/JP Raw",
host: ["rawotaku.org", "jmanga.dev", "jpraw.xyz"],
url: {
t: ["RawOtaku", "jmanga", "JP Raw"],
h: [/^rawotaku/, /^jmanga/, /^jpraw/]
},
page: () => fn.clp("/read/"),
SPA: () => _this.page(),
observeURL: "gm",
init: () => _this.page() ? fn.waitEle(["#images-content .page-read", ".chapter-item.active"]) : void 0,
imgs: () => {
if (!_this.page()) return [];
let id = fn.ge(".chapter-item.active").dataset.id;
fn.showMsg(DL.str_05, 0);
return fetch(`/json/chapter?mode=vertical&id=${id}`, {
"headers": {
"accept": "application/json, text/javascript, */*; q=0.01",
"x-requested-with": "XMLHttpRequest"
}
}).then(res => res?.json()).then(json => {
fn.hideMsg();
return isObject(json) ? [...fn.doc(json.html).images] : [];
});
},
capture: () => _this.imgs(),
autoDownload: [0],
next: "//li[contains(@class,'chapter-item active')]/preceding-sibling::li[1]/a",
prev: ".chapter-item.active+li>a",
chapters: {
target: "#ja-chapters a",
textNode: ".name",
sort: "r"
},
customTitle: () => _this.page() ? fn.dt({
t: fn.gt(".manga-name") + " - " + fn.gt("#dropdown-chapters button")
}) : null,
category: "comic"
}, {
name: "ZonaTMO",
url: {
h: ["zonatmo.com"],
p: ["/viewer/", "/news/"]
},
init: () => (document.onkeydown = null),
imgs: () => {
if (!!fn.gst("dirPath")) {
let {
dirPath,
images
} = _unsafeWindow;
return images.map(e => dirPath + e);
} else {
return fn.gae(".viewer-container .viewer-img");
}
},
button: [4],
insertImg: [".viewer-container", 2],
insertImgAF: () => fn.remove(".container:has(#viewer-pages-select)"),
autoDownload: [0],
next: () => {
let next = fn.ge(".chapter-next a");
return next ? fetch(next).then(res => res.url) : null;
},
prev: () => {
let prev = fn.ge(".chapter-prev a");
return prev ? fetch(prev).then(res => res.url) : null;
},
chapters: {
url: "a[title=Volver]",
target: ".list-group-item[data-index]",
textNode: "h4",
urlNode: "a.btn",
sort: "r"
},
checkCurrentChapter: (url, text) => {
let [h2t_num] = fn.gt("#app h2").match(/[\d\.]+/);
let [ct_num] = text.match(/[\d\.]+/);
return h2t_num == ct_num;
},
customTitle: () => {
let text = fn.gt("h1") + " - " + fn.gt("h2");
return fn.dt({
t: text,
d: /Subido por:.+$/
});
},
category: "comic"
}, {
name: "ManhwaWeb",
url: {
h: ["www.manhwaweb.com", "manhwaweb.com"],
p: "/leer/"
},
init: () => {
let slug = fn.lp.replace("/leer", "");
let res_a = fetch(`https://manhwawebbackend-production.up.railway.app/chapters/see${slug}`).then(res => res.json());
let res_b = fetch(`https://manhwawebbackend-production.up.railway.app/chapters/seeprevpost${slug}`).then(res => res.json());
return Promise.all([res_a, res_b]).then(([a, b]) => {
siteJson = {
...a,
...b
};
debug("\n此頁JSON資料\n", siteJson);
});
},
imgs: () => siteJson.chapter.img,
button: [4],
insertImgBF: () => fn.waitEle(".flex-col.justify-center.items-center img"),
insertImg: [".flex-col.justify-center.items-center", 2],
insertImgAF: () => fn.remove("//div[div[div[span[text()='AD']]]]"),
endColor: "white",
autoDownload: [0],
next: () => siteJson.chapterSiguiente?.startsWith("http") ? siteJson.chapterSiguiente : null,
prev: () => siteJson.chapterAnterior?.startsWith("http") ? siteJson.chapterAnterior : null,
chapters: () => fetch(`https://manhwawebbackend-production.up.railway.app/manhwa/see/${siteJson.real_id}`).then(res => res.json()).then(json => json.chapters.map(({
chapter,
link
}) => ({
text: `Capitulo ${chapter}`,
url: link
}))),
customTitle: () => fn.dt({
d: " manhwa - ManhwaWeb"
}),
category: "comic"
}, {
name: "MangaKatana",
url: {
h: ["www.mangakatana.com", "mangakatana.com"],
p: "/manga/"
},
init: async () => {
await fn.waitVar("dimension_imgs");
_unsafeWindow.jQuery(document).off();
},
box: ["#imgs", 1],
imgs: "#imgs div[id^=page] img",
button: [4],
insertImg: [
["box", 0, "#imgs"], 2
],
endColor: "white",
autoDownload: [0],
next: "a.nav_button.next[href^=http]",
prev: "a.nav_button.prev[href^=http]",
chapters: {
node: "select[name=chapter_select]",
target: "option",
cb: (text, v) => ({
text,
url: fn.dir(fn.url) + v
}),
sort: "r"
},
customTitle: () => fn.dt({
s: ".uk-breadcrumb",
d: "Home"
}),
category: "comic"
}, {
name: "LeerCapitulo",
host: ["www.leercapitulo.co"],
reg: /^https?:\/\/www\.leercapitulo\.co\/leer\/.+/,
init: () => fn.waitEle("#page_select"),
imgs: () => fn.gae("#page_select option").map(e => e.value),
button: [4],
insertImg: [".each-page", 2],
autoDownload: [0],
next: "a.next",
prev: "a.pre",
chapters: {
node: "select[rel='chap-select']",
target: "option",
sort: "r"
},
customTitle: ".bodycontainer h1",
category: "comic"
}, {
name: "OlympusBiblioteca",
url: {
h: ["olympusbiblioteca.com"],
},
page: () => fn.clp("/capitulo/") && fn.clp("/comic-"),
SPA: () => _this.page(),
observeURL: "head",
json: () => {
fn.showMsg(DL.str_05, 0);
let [, , c_id, m_id] = fn.clp().split("/");
m_id = m_id.replace("comic-", "");
return fetch(`/api/capitulo/${m_id}/${c_id}?type=comic`).then(res => res.json()).then(json => {
siteJson = json;
debug("\n此頁JSON資料\n", siteJson);
fn.hideMsg();
});
},
init: () => _this.page() ? _this.json() : void 0,
imgs: () => _this.page() ? siteJson.chapter.pages : [],
capture: () => _this.imgs(),
autoDownload: [0],
chapter_url: (id) => fn.clp().split("/").with(2, id).join("/"),
next: () => {
let next = siteJson?.next_chapter?.id;
return next ? _this.chapter_url(next) : null;
},
prev: () => {
let prev = siteJson?.prev_chapter?.id;
return prev ? _this.chapter_url(prev) : null;
},
chapters: () => {
let m_id = fn.clp().split("/").at(-1).replace("comic-", "");
const get_json = (id, p) => fetch(`https://dashboard.olympusbiblioteca.com/api/series/${id}/chapters?page=${p}&direction=asc&type=comic`).then(res => res.json());
const get_c = (json) => json.data.map(({
id,
name
}) => ({
text: `Capítulo ${name}`,
url: `/capitulo/${id}/comic-${m_id}`
}));
return get_json(m_id, 1).then(json => {
if (json.meta.last_page > 1) {
let jsons = [json];
let resArr = fn.arr(json.meta.last_page - 1, (v, i) => get_json(m_id, i + 2));
return Promise.all(resArr).then(res => {
jsons = [...jsons, ...res];
return jsons.map(j => get_c(j)).flat();
});
}
return get_c(json);
});
},
customTitle: () => {
if (_this.page()) {
let {
comic: {
name: m
},
chapter: {
name: c
}
} = siteJson;
return `${m} - Capítulo ${c}`;
}
return null;
},
category: "comic"
}, {
name: "KuManga",
url: {
h: "www.kumanga.com",
p: "/manga/leer/"
},
init: () => fn.waitEle("#lector img").then(() => fn.clearAllTimer(3)).then(() => {
let control = fn.gae("select.form-control").at(1);
siteJson.chapterList = fn.gae("option", control);
}),
imgs: () => _unsafeWindow.pUrl.map(e => e.imgURL),
button: [4],
insertImg: ["#lector", 2],
autoDownload: [0],
current: () => {
let id = fn.lp.split("/").at(-1);
let c_chapter = siteJson.chapterList.find(e => e.value == id);
return c_chapter;
},
next: () => {
let next = _this.current()?.nextElementSibling;
return next ? "/manga/leer/" + next.value : null;
},
prev: () => {
let prev = _this.current()?.previousElementSibling;
return prev ? "/manga/leer/" + prev.value : null;
},
chapters: () => siteJson.chapterList.map(o => ({
text: o.innerText.trim(),
url: "/manga/leer/" + o.value
})),
customTitle: ".container h2",
category: "comic"
}, {
name: "Dream-Manga",
url: {
h: "dream-manga.com",
p: "/reader/"
},
init: () => fn.waitEle([".header__post-title", ".chapter__selector-trigger__title"]),
box: [".reader-view", 2, 1200],
imgs: () => _unsafeWindow.__DATA__.images,
button: [4],
insertImg: ["box", 2],
insertImgAF: () => fn.hideEle(".reader-view,.nav"),
autoDownload: [0],
next: () => {
let next = _unsafeWindow?.__DATA__?.next;
return next?.includes("/reader/") ? next : null;
},
prev: () => {
let prev = _unsafeWindow?.__DATA__?.prev;
return prev?.includes("/reader/") ? prev.replace(/#.+$/, "") : null;
},
chapters: () => {
let dir = fn.dir(fn.url);
return _unsafeWindow?.__DATA__?.chapters.map(({
id,
title
}) => ({
text: title,
url: dir + id
})).reverse();
},
customTitle: [".header__post-title", ".chapter__selector-trigger__title"],
category: "comic"
}, {
name: "OkHentai",
url: {
h: ["okhentai.net"],
p: "/gallery/",
e: ".gallery_thumb"
},
imgs: () => {
let links = fn.gau(".gallery_thumb a");
return fn.getImgA("#gimg", links);
},
thums: ".gallery_thumb img",
button: [4],
insertImg: ["#list_pages", 2],
customTitle: () => fn.getText(["#info h2", "#info h1"]),
category: "hcomic"
}, {
name: "N站模板無變數圖名隨機",
url: {
h: ["hentaivsmanga.com", "savehentai.info", "www.hentaihardcore.net", "hentai4all.com"],
e: "#thumbnail-container"
},
imgs: () => {
let links = fn.gau("#thumbnail-container a");
return fn.getImgA("#image-container img", links);
},
thums: "#thumbnail-container img",
button: [4],
insertImg: ["#thumbnail-container", 2],
customTitle: () => fn.getText(["#info h2", "#info h1"]),
category: "hcomic"
}, {
name: "N站模板無變數無縮略圖",
host: ["multi-manga.today", "hmanga.today", "w1.multi-manga.com"],
url: {
h: /multi|manga/,
e: ".logo img[src*='hitomila']"
},
imgs: "#thumbnail-container img",
button: [4],
insertImg: ["#thumbnail-container", 2],
customTitle: () => fn.getText(["#info h2", "#info h1"]),
category: "hcomic"
}, {
name: "N站模板無變數無縮略圖",
host: ["nhentai.online", "hentaiyaoi.net", "nhentaiyaoi.net", "hentaibl.com", "nhentai.net.br"],
url: {
h: "hentai",
e: ".post-titulo,.tituloOriginal"
},
imgs: ".post-fotos img",
button: [4],
insertImg: [".post-fotos", 2],
customTitle: () => fn.getText([".tituloOriginal", ".post-titulo"]),
hide: ".anuncios,#onesignal-slidedown-container,.floating-button",
category: "hcomic"
}, {
name: "嗨皮漫畫閱讀",
enable: 0,
url: {
h: ["m.happymh.com", "hihimanga.com"],
p: "/mangaread/",
ee: ".captcha-area"
},
getHeaders: () => ({
"headers": {
"accept": "application/json, text/plain, */*",
"x-requested-id": new Date().getTime(),
"x-requested-with": "XMLHttpRequest"
}
}),
fetchJson: (url = siteUrl) => {
let mangaCode = new URL(url).pathname.split("/").at(-1);
let api = `/v2.0/apis/manga/reading?code=${mangaCode}&v=v3.1818134`;
return fetch(api, _this.getHeaders()).then(res => res.json());
},
init: async () => {
let json = await _this.fetchJson();
debug("\n此頁JSON資料\n", json);
siteJson = json;
fn.picPreload(_this.imgs(json), _this.customTitle(json));
return fn.waitEle("#root footer button[data-href^='/manga']");
},
imgs: (json = siteJson) => {
if (json.status == 0) {
let srcs = json.data.scans.map(({
url
}) => url.replace(/\?q=\d+$/, ""));
if (srcs.length == 2 && ("next_cid" in json.data)) {
srcs = srcs.slice(0, -1);
}
if (srcs.length > 2 && ("next_cid" in json.data)) {
srcs = srcs.slice(0, -2);
}
return srcs;
} else {
return [];
}
},
referrerpolicy: "origin",
button: [4],
insertImg: ["//article[div[contains(@id,'imageLoader')]]", 3],
autoDownload: [0],
next: () => {
let next = fn.ge("//article//button[text()='下一话' or text()='下一話'][starts-with(@data-href,'/mangaread/')]");
return next ? next.dataset.href : null;
},
prev: "//article//button[text()='上一话' or text()='上一話'][starts-with(@data-href,'/mangaread/')]",
chapters: () => new Promise(resolve => {
let dir = fn.dir(fn.url);
let chapterListData = [];
let page = 1;
const get = () => {
const params = new URLSearchParams({
code: siteJson.data.manga_code,
cid: siteJson.data.id,
page,
order: "desc"
}).toString();
return fetch("/v2.0/apis/manga/chapterByPage?" + params, _this.getHeaders()).then(res => res.json()).then(json => {
if (json?.msg === "success") {
chapterListData = chapterListData.concat(json.data.items);
if (json?.data?.isEnd == 1 || chapterListData.length >= json?.data?.total) {
chapterListData = chapterListData.map(({
chapterName,
codes
}) => ({
text: chapterName.trim(),
url: dir + codes
})).reverse();
resolve(chapterListData);
} else {
page++;
return get();
}
} else {
resolve([]);
console.error("獲取章節列表資料錯誤");
}
}).catch(error => {
resolve([]);
console.error("獲取章節列表資料錯誤", error);
});
};
get();
}),
preloadNext: async () => {
let json = await _this.fetchJson(nextLink);
json.status == 0 ? fn.picPreload(_this.imgs(json), _this.customTitle(json), "next") : debug("預讀下一頁失敗");
},
customTitle: (json = siteJson) => json.data.manga_name + " - " + json.data.chapter_name,
category: "comic"
}, {
name: "COLAMANHUA", //方向鍵上一章下一章、反反偵錯,下載需先手動觸發全部載入圖片,圖址如為blob函式會使用到canvas需要繪製過程會有點卡。
url: {
h: "www.colamanga.com",
p: /^\/manga-.+\.html$/,
d: "pc"
},
init: async () => {
await fn.waitEle(".mh_comicpic img[src]");
const {
__cr,
__cad,
mh_info
} = _unsafeWindow;
const [value_a, value_b] = __cad.getCookieValue();
const pageCountKey = value_b + String(mh_info.pageid);
const pageCount = Number(fn.cookie(pageCountKey) || "0");
siteJson.images = fn.arr(pageCount, (v, i) => __cr.getPicUrl(i + 1));
debug("images", siteJson.images);
fn.clearAllTimer(1);
const [src] = siteJson.images;
if (autoScrollAllElement === 1 && src.includes(".enc.")) _this.scrollEle();
},
imgs: async () => {
let [src] = siteJson.images;
if (src.includes(".enc.")) {
let insufficient_quantity = false;
let current_total = fn.gae(".mh_comicpic img[src]").length;
if (current_total < siteJson.images.length) {
insufficient_quantity = true;
}
if (insufficient_quantity || options.autoDownload == 1 || options.shadowGallery == 1 || options.mobileGallery == 1) {
await _this.scrollEle();
}
return fn.imgBlobUrlArr(".mh_comicpic img[src^=blob]");
}
return siteJson.images;
},
button: [4],
insertImg: ["#mangalist", 0],
scrollEle: () => fn.aotoScrollEles({
ele: ".mh_comicpic",
cb: (ele) => isEle(fn.ge("img[src]", ele)),
time: 10000,
top: 1,
end: (sn) => sn > siteJson.images.length
}),
autoDownload: [0],
next: "//a[text()='下一章']",
prev: "//a[text()='上一章']",
chapters: {
url: ".mh_readtitle .read_page_link",
target: ".all_data_list a",
sort: "r"
},
customTitle: () => fn.title(" COLAMANGA", 1),
fetch: 1,
css: ".mh_wrap{width:100%!important;min-width:100%!important}",
category: "comic"
}, {
name: "COLAMANHUA 目錄連結新分頁開啟",
reg: /^https?:\/\/www\.colamanga\.com\/manga-\w+\/$/,
openInNewTab: ".all_data_list a:not([target=_blank])",
category: "none"
}, {
name: "8Comic無限動漫",
host: ["www.8comic.com"],
url: {
t: "無限動漫",
p: "/online/",
i: 0
},
frameCode: `
if ("xx" in window) {
const {
su,
ti,
nn,
mm,
xx
} = window;
const getSrc = (code) => {
const a = code.substring(15);
const b = window[code.substring(0, 5)];
const c = window[code.substring(5, 10)];
const d = window[code.substring(10, 15)];
const src = "https://img" + su(b, 0, 1) + ".8comic.com/" + su(b, 1, 1) + "/" + ti + "/" + c + "/" + nn(a) + "_" + su(d, mm(a), 3) + ".jpg";
return src;
};
const html = decodeURIComponent(xx);
const codes = html.matchAll(/\\ss="([^"]+)"/g);
const srcs = [...codes].map(([, code]) => {
if (code.startsWith("//")) {
return window.location.protocol + code;
} else if (code.length >= 16 && code.length <= 18 && /\\d{1,3}/.test(code.substring(15))) {
return getSrc(code);
} else {
return null;
}
});
window.newImgs = srcs;
const url = reurl("ch", ni);
if (url == document.URL) {
window.nextLink = null;
} else {
window.nextLink = url;
}
}
`,
init: async () => {
await fn.waitVar(["xx", "su", "ti", "nn", "mm", "reurl"]);
await fn.waitEle("#comics-pics img");
fn.script(_this.frameCode, 0, 1);
fn.createImgBox(".pinch-zoom-container", 2);
},
imgs: () => _unsafeWindow.newImgs,
button: [4],
insertImg: [
["box", 0, ".pinch-zoom-container"], 2
],
autoDownload: [0],
next: () => _unsafeWindow.nextLink,
prev: "#prevvol",
customTitle: () => fn.dt({
s: "#pt"
}),
preloadNext: () => {
if (!!_unsafeWindow.nextLink) {
fn.iframe(_unsafeWindow.nextLink, {
waitVar: ["xx", "su", "ti", "nn", "mm"],
cb: (dom, frame) => {
fn.script(_this.frameCode, 0, 1, dom);
fn.picPreload(frame.newImgs, fn.dt({
t: fn.gt("#pt", 1, dom)
}), "next");
}
});
}
},
infiniteScroll: true,
category: "comic"
}, {
name: "8Comic無限動漫 自動翻頁",
url: {
t: "無限動漫",
p: "/online/",
i: 1
},
frameCode: `
if ("xx" in window) {
const {
su,
ti,
nn,
mm,
xx
} = window;
const getSrc = (code) => {
const a = code.substring(15);
const b = window[code.substring(0, 5)];
const c = window[code.substring(5, 10)];
const d = window[code.substring(10, 15)];
const src = "https://img" + su(b, 0, 1) + ".8comic.com/" + su(b, 1, 1) + "/" + ti + "/" + c + "/" + nn(a) + "_" + su(d, mm(a), 3) + ".jpg";
return src;
};
const html = decodeURIComponent(xx);
const codes = html.matchAll(/\\ss="([^"]+)"/g);
const srcs = [...codes].map(([, code]) => {
if (code.startsWith("//")) {
return window.location.protocol + code;
} else if (code.length >= 16 && code.length <= 18 && /\\d{1,3}/.test(code.substring(15))) {
return getSrc(code);
} else {
return null;
}
});
window.newImgs = srcs;
const url = reurl("ch", ni);
if (url == document.URL) {
window.nextLink = null;
} else {
window.nextLink = url;
}
}
`,
init: async () => {
await fn.waitVar(["xx", "su", "ti", "nn", "mm", "reurl"]);
await fn.waitEle("#comics-pics img");
fn.script(_this.frameCode, 0, 1);
let tE = fn.createImgBox(".pinch-zoom-container", 2);
fn.remove(".pinch-zoom-container");
let imgs = fn.createImgArray(frameWindow.newImgs);
fragment.append(...imgs);
tE.append(fragment);
await fn.lazyload();
},
autoPager: {
mode: 1,
waitEle: "#comics-pics img",
ele: () => fn.createImgArray(frameWindow.newImgs),
pos: ["#FullPictureLoadMainImgBox", 0],
observer: "#FullPictureLoadMainImgBox>img",
next: () => frameWindow.nextLink,
title: (dom, frame) => {
if (isM) {
return "第" + frame.ch + "集";
} else {
return fn.dt({
t: fn.gt("#pt", 1, dom)
});
}
},
re: "#pt",
aF: () => (_unsafeWindow.ch = frameWindow.ch),
preloadNextPage: () => {
if (!!frameWindow.nextLink) {
fn.iframe(frameWindow.nextLink, {
waitVar: ["xx", "su", "ti", "nn", "mm"],
cb: (dom, frame) => {
fn.script(_this.frameCode, 0, 1, dom);
fn.picPreload(frame.newImgs, _this.autoPager.title(dom, frame), "next");
}
});
}
}
},
category: "comic autoPager"
}, {
name: "Mangabz",
url: {
h: "mangabz.com",
p: "/m",
e: ".container",
i: 0
},
init: () => fn.MangabzUI(),
imgs: (dom = document, msg = 1) => fn.MXY_getSrcs(dom, msg),
button: [4],
insertImg: ["#cp_img", 2],
endColor: "white",
autoDownload: [0],
next: "//a[img[contains(@src,'xiayizhang')]][starts-with(@href,'/m')]",
prev: "//a[img[contains(@src,'shangyizhang')]][starts-with(@href,'/m')]",
chapters: {
url: ".top-title a",
target: "#chapterlistload a",
sort: "r"
},
customTitle: (dom = document) => fn.title("_", 2, dom).replace("漫畫", ""),
preloadNext: async (nextDoc) => fn.picPreload(await fn.MXY_getSrcs(nextDoc, 0), _this.customTitle(nextDoc), "next"),
css: "body{overflow:unset!important}",
hide: "a[href^='j']",
infiniteScroll: true,
category: "comic"
}, {
name: "Mangabz 自動翻頁",
url: {
h: "mangabz.com",
p: "/m",
e: ".container",
i: 1
},
getSrcs: (dom, msg = 0) => fn.MXY_getSrcs(dom, msg),
getImgs: async (dom = document) => {
let srcs = await _this.getSrcs(dom);
return fn.createImgArray(srcs);
},
init: async () => {
fn.MangabzUI();
fn.showMsg(DL.str_135, 0);
await _this.getImgs().then(async imgs => {
let tE = fn.ge("#cp_img");
tE.innerHTML = "";
fragment.append(...imgs);
tE.append(fragment);
fn.hideMsg();
await fn.lazyload();
});
},
autoPager: {
ele: (dom) => _this.getImgs(dom),
pos: ["#cp_img", 0],
observer: "#cp_img>img",
next: "//a[img[contains(@src,'xiayizhang')]][starts-with(@href,'/m')]",
re: ".container",
title: (dom) => {
let code = fn.gst("MANGABZ_CTITLE", dom);
return fn.textVar(code, "MANGABZ_CTITLE");
},
preloadNextPage: 1
},
css: "body{overflow:unset!important}",
hide: "a[href^='j']",
category: "comic autoPager"
}, {
name: "Xmanhua",
url: {
h: "xmanhua.com",
p: "/m",
e: ".reader-bottom-page-list",
i: 0
},
init: () => fn.XmanhuaUI(),
imgs: (dom = document, msg = 1) => fn.MXY_getSrcs(dom, msg),
button: [4],
insertImg: ["#cp_img", 2],
endColor: "white",
autoDownload: [0],
next: "//a[img[contains(@src,'reader-bottom-right-2')]][starts-with(@href,'/m')]",
prev: "//a[img[contains(@src,'reader-bottom-right-1')]][starts-with(@href,'/m')]",
chapters: {
url: ".reader-title a[title]",
target: "#chapterlistload a",
sort: "r"
},
customTitle: (dom = document) => fn.title("_", 2, dom).replace("漫畫", ""),
preloadNext: async (nextDoc) => fn.picPreload(await fn.MXY_getSrcs(nextDoc, 0), _this.customTitle(nextDoc), "next"),
css: ".reader-img-con{padding:64px 0 50px !important;}",
hide: ".relative>a",
infiniteScroll: true,
category: "comic"
}, {
name: "Xmanhua 自動翻頁",
url: {
h: "xmanhua.com",
p: "/m",
e: ".reader-bottom-page-list",
i: 1
},
getSrcs: (dom, msg = 0) => fn.MXY_getSrcs(dom, msg),
getImgs: async (dom = document) => {
let srcs = await _this.getSrcs(dom);
return fn.createImgArray(srcs);
},
init: async () => {
fn.XmanhuaUI();
fn.showMsg(DL.str_135, 0);
await _this.getImgs().then(async imgs => {
let tE = fn.ge("#cp_img");
tE.innerHTML = "";
fragment.append(...imgs);
tE.append(fragment);
fn.hideMsg();
await fn.lazyload();
});
},
autoPager: {
ele: (dom) => _this.getImgs(dom),
pos: ["#cp_img", 0],
observer: "#cp_img>img",
next: "//a[img[contains(@src,'reader-bottom-right-2')]][starts-with(@href,'/m')]",
re: ".container",
title: (dom) => {
let code = fn.gst("XMANHUA_CTITLE", dom);
return fn.textVar(code, "XMANHUA_CTITLE");
},
preloadNextPage: 1
},
css: ".reader-img-con{padding:64px 0 50px !important;}",
hide: ".relative>a",
category: "comic autoPager"
}, {
name: "YYMANGA",
url: {
h: "yymanhua.com",
p: "/m",
e: ".reader-bottom-page-list",
i: 0
},
init: () => fn.XmanhuaUI(),
imgs: (dom = document, msg = 1) => fn.MXY_getSrcs(dom, msg),
button: [4],
insertImg: ["#cp_img", 2],
endColor: "white",
autoDownload: [0],
next: "//a[img[contains(@src,'reader-bottom-right-2')]][starts-with(@href,'/m')]",
prev: "//a[img[contains(@src,'reader-bottom-right-1')]][starts-with(@href,'/m')]",
chapters: {
url: ".reader-title a[title]",
target: "#chapterlistload a",
sort: "r"
},
customTitle: (dom = document) => fn.title("_", 2, dom).replace("漫畫", ""),
preloadNext: async (nextDoc) => fn.picPreload(await fn.MXY_getSrcs(nextDoc, 0), _this.customTitle(nextDoc), "next"),
css: ".reader-img-con{padding:64px 0 50px !important;}",
hide: ".relative>a",
infiniteScroll: true,
category: "comic"
}, {
name: "YYMANGA 自動翻頁",
url: {
h: "yymanhua.com",
p: "/m",
e: ".reader-bottom-page-list",
i: 1
},
getSrcs: (dom, msg = 0) => fn.MXY_getSrcs(dom, msg),
getImgs: async (dom = document) => {
let srcs = await _this.getSrcs(dom);
return fn.createImgArray(srcs);
},
init: async () => {
fn.XmanhuaUI();
fn.showMsg(DL.str_135, 0);
await _this.getImgs().then(async imgs => {
let tE = fn.ge("#cp_img");
tE.innerHTML = "";
fragment.append(...imgs);
tE.append(fragment);
fn.hideMsg();
await fn.lazyload();
});
},
autoPager: {
ele: (dom) => _this.getImgs(dom),
pos: ["#cp_img", 0],
observer: "#cp_img>img",
next: "//a[img[contains(@src,'reader-bottom-right-2')]][starts-with(@href,'/m')]",
re: ".container",
title: (dom) => {
let code = fn.gst("YYMANHUA_CTITLE", dom);
return fn.textVar(code, "YYMANHUA_CTITLE");
},
preloadNextPage: 1
},
css: ".reader-img-con{padding:64px 0 50px !important;}",
hide: ".relative>a",
category: "comic autoPager"
}, {
name: "DM5/極速 分頁模式",
host: ["www.dm5.com", "m.dm5.com", "www.dm5.cn", "m.dm5.cn", "en.dm5.com", "cnc.dm5.com", "hk.dm5.com", "cnc.dm5.com", "www.1kkk.com", "m.1kkk.com", "tel.1kkk.com", "en.1kkk.com", "cnc.1kkk.com", "hk.1kkk.com"],
url: {
h: [/dm5/, /1kkk/],
p: /^\/(m|ch|vol|other)/,
e: "#chapterpager",
i: 0
},
imgs: (dom = document, msg = 1) => fn.DM5_getSrcs(dom, msg),
button: [4],
insertImg: ["#cp_img", 2],
autoDownload: [0],
next: "//a[text()='下一章']",
prev: "//a[text()='上一章']",
chapters: {
url: ".view-btn-back",
target: ".view-win-list a",
sort: "r"
},
customTitle: (dom = document) => fn.title("_", 2, dom),
topButton: true,
css: "body{overflow:unset!important}",
hide: ".view-ad,.view-mask",
infiniteScroll: true,
category: "comic"
}, {
name: "DM5/極速 分頁模式 自動翻頁",
url: {
h: [/dm5/, /1kkk/],
p: /^\/(m|ch|vol|other)/,
e: "#chapterpager",
i: 1
},
getSrcs: (dom, msg = 0) => fn.DM5_getSrcs(dom, msg),
getImgs: async (dom = document) => {
let srcs = await _this.getSrcs(dom);
return fn.createImgArray(srcs)
},
init: async () => {
fn.showMsg(DL.str_135, 0);
await _this.getImgs().then(async imgs => {
let tE = fn.ge("#cp_img");
tE.innerHTML = "";
fragment.append(...imgs);
tE.append(fragment);
fn.hideMsg();
await fn.lazyload();
});
},
autoPager: {
ele: (dom) => _this.getImgs(dom),
pos: ["#cp_img", 0],
observer: "#cp_img>img",
next: "//a[text()='下一章']",
re: ".active.right-arrow,.view-paging",
title: (dom) => fn.gt(".title", 1, dom).replace("首页 ", "").replace(/\s+/g, " ").trim(),
hide: ".view-comment"
},
css: "body{overflow:unset!important}",
hide: "a[href^='javascript:Show'],.chapterpager,.view-ad,.view-mask",
category: "comic autoPager"
}, {
name: "DM5/極速 條漫模式",
url: {
h: [/dm5/, /1kkk/],
p: /^\/(m|ch|vol|other)/,
i: 0
},
imgs: "#barChapter>img",
button: [4],
insertImg: ["#barChapter", 2],
autoDownload: [0],
next: "//a[text()='下一章']",
prev: "//a[text()='上一章']",
chapters: {
url: ".view-btn-back",
target: ".view-win-list a",
sort: "r"
},
customTitle: (dom = document) => fn.title("_", 2, dom),
css: "body{overflow:unset!important}",
infiniteScroll: true,
category: "comic"
}, {
name: "DM5/極速 條漫模式 自動翻頁",
url: {
h: [/dm5/, /1kkk/],
p: /^\/(m|ch|vol|other)/,
e: "#barChapter",
i: 1
},
getSrcs: (dom) => fn.gae("img.load-src[data-src]", dom).map(e => e.dataset.src),
getImgs: (dom = document) => {
let srcs = _this.getSrcs(dom);
return fn.createImgArray(srcs);
},
init: async () => {
let imgs = _this.getImgs();
let tE = fn.ge("#barChapter");
tE.innerHTML = "";
fragment.append(...imgs);
tE.append(fragment);
await fn.lazyload();
},
autoPager: {
ele: (dom) => _this.getImgs(dom),
pos: ["#barChapter", 0],
observer: "#barChapter>img",
next: "//a[text()='下一章']",
re: ".view-paging",
title: (dom) => fn.gt(".title", 1, dom).replace("首页 ", "").replace(/\s+/, " ").trim(),
hide: ".view-comment"
},
css: "body{overflow:unset!important}",
category: "comic autoPager"
}, {
name: "DM5/極速/Mangabz/Xmanhua/yymanhua/漫画人/漫本 手機版",
host: ["m.dm5.com", "m.1kkk.com", "www.mangabz.com", "mangabz.com", "www.xmanhua.com", "xmanhua.com", "www.yymanhua.com", "yymanhua.com", "www.manben.com", "www.manhuaren.com"],
url: {
h: /dm5|1kkk|mangabz|xmanhua|yymanhua|manhuaren|manben/,
p: /^\/(m|ch|vol|other)?[-_0-9]+\//,
st: "newImgs",
i: 0
},
init: async () => {
await fn.waitVar("newImgs");
if (fn.gae(".view-bottom-bar>li").length == 4) {
fn.css(".view-bottom-bar>li:nth-child(n+2):nth-child(-n+3){display:none!important}.view-bottom-bar li{width:50%!important}");
}
let b = fn.ge("body.viewbody");
if (fn.lh.includes("mangabz") && b) {
b.innerHTML = b.innerHTML.replace("<!--", "").replace("-->", "");
fn.ge(".top-bar-tool").removeAttribute("style");
fn.ge(".bottom-bar").removeAttribute("style");
const showtoolbar = () => document.body.classList.toggle("toolbar");
document.addEventListener('click', showtoolbar);
}
},
imgs: () => _unsafeWindow.newImgs,
button: [4],
insertImg: ["#cp_img,.main_img,#comicContain,.comic-list", 2],
autoDownload: [0],
next: () => {
let next = fn.ge("//a[text()='下一章'] | //a[img[@alt='下一章']]");
if (next) return /pushHistory/.test(next.href) ? location.origin + next.href.split("'")[1] : next.href;
return null;
},
prev: "//a[text()='上一章'] | //a[img[@alt='上一章']]",
chapters: {
url: "//a[p[text()='目录']]",
target: ".detail-list-select a",
sort: "r"
},
customTitle: (dom = document) => {
let host = fn.lh;
if (/dm5|manhuaren|1kkk|mangabz|xmanhua|yymanhua/.test(host) && !/sixmanhua/.test(host)) {
return fn.title("_", 2, dom);
} else if (/sixmanhua/.test(host)) {
return fn.title("_", 3, dom);
} else if (/manben/.test(host)) {
if (fn.ge("#comicTitle")) {
return fn.gt("#chapter", 1, dom) + " " + fn.gt(".title-comicHeading", 1, dom);
} else {
return fn.title(" ", 2, dom);
}
}
},
preloadNext: (nextDoc, obj) => {
if (!/dm5|1kkk|manhuaren/.test(fn.lh)) {
let code = fn.gst("newImgs", nextDoc);
fn.script(code, 0, 1);
fn.picPreload(_unsafeWindow.newImgs, obj.customTitle(nextDoc), "next");
}
},
infiniteScroll: true,
category: "comic"
}, {
name: "DM5/極速/Mangabz/Xmanhua/yymanhua/漫画人/漫本 手機版 自動翻頁",
url: {
h: /dm5|1kkk|mangabz|xmanhua|yymanhua|manhuaren|manben/,
p: /^\/(m|ch|vol|other)?[-_0-9]+\//,
st: "newImgs",
i: 1
},
getSrcs: (dom) => {
let code = fn.gst("newImgs", dom);
let text = fn.parseCode(code);
return fn.TextToArray(text, "newImgs");
},
getImgs: (dom = document) => {
let srcs = _this.getSrcs(dom);
return fn.createImgArray(srcs);
},
init: async () => {
let imgs = _this.getImgs();
let tE = fn.ge("#cp_img");
tE.innerHTML = "";
fragment.append(...imgs);
tE.append(fragment);
await fn.lazyload();
if (fn.gae(".view-bottom-bar>li").length == 4) {
fn.css(".view-bottom-bar>li:nth-child(n+2):nth-child(-n+3){display:none!important}.view-bottom-bar li{width:50%!important}");
}
let b = fn.ge("body.viewbody");
if (fn.lh.includes("mangabz") && b) {
b.innerHTML = b.innerHTML.replace("<!--", "").replace("-->", "");
fn.ge(".top-bar-tool").removeAttribute("style");
fn.ge(".bottom-bar").removeAttribute("style");
const showtoolbar = () => document.body.classList.toggle("toolbar");
document.addEventListener('click', showtoolbar);
}
},
autoPager: {
ele: (dom) => _this.getImgs(dom),
pos: ["#cp_img", 0],
observer: "#cp_img>img",
next: (dom) => {
let next = fn.ge("//a[text()='下一章'] | //a[img[@alt='下一章']]", dom, dom);
if (next) {
let url = /pushHistory/.test(next.href) ? fn.lo + next.href.split("'")[1] : next.href;
if (!/-end/.test(url)) {
return url;
}
}
return null;
},
re: ".view-fix-top-bar-title,.top-title,.view-bottom-bar,.view-fix-bottom-bar,.bottom-bar-tool",
title: (dom) => {
let tt = fn.gt(".top-title", 1, dom);
if (fn.lh.includes("xmanhua") && tt) {
return tt.replaceAll("?", "-").replace("XManhua-", "");
} else if (fn.lh.includes("mangabz") && tt) {
return tt.replaceAll("?", "-").replace("Mangabz-", "");
} else if (fn.lh.includes("yymanhua") && tt) {
return tt.replaceAll("?", "-").replace("YYManhua-", "");
}
return dom.title.replace(/,?_在线漫画.+/, "").replace("漫画", "").replace(/^[^_]+_/, "");
},
bF: (dom) => {
let b = fn.ge("body.viewbody", dom);
if (fn.lh.includes("mangabz") && b) {
b.innerHTML = b.innerHTML.replace("<!--", "").replace("-->", "");
}
},
preloadNextPage: (dom) => {
if (!/dm5|1kkk/.test(fn.lh)) {
let next = _this.autoPager.next(dom);
if (next) {
fn.fetchDoc(next).then(_dom => fn.picPreload(_this.getSrcs(_dom), _this.autoPager.title(_dom), "next"));
}
}
}
},
category: "comic autoPager"
}, {
name: "再漫画",
url: {
h: "manhua.zaimanhua.com",
d: "pc"
},
page: () => fn.dlp("/view/"),
SPA: () => _this.page(),
observeURL: "gm",
json: () => {
fn.showMsg(DL.str_05, 0);
let [, , , comic_id, chapter_id] = fn.clp().split("/");
siteJson.comic_id = comic_id;
siteJson.chapter_id = chapter_id;
let res_a = fetch(`/api/v1/comic2/chapter/detail?comic_id=${comic_id}&chapter_id=${chapter_id}`).then(res => res.json()).then(json => {
let {
page_url,
page_url_hd,
title: chapter_title
} = json.data.chapterInfo;
siteJson.srcs = page_url_hd ?? page_url;
siteJson.chapter_title = chapter_title;
});
let res_b = fetch(`/api/v1/comic2/comic/detail?id=${comic_id}`).then(res => res.json()).then(json => {
let _chapters = [];
let {
id,
chapterList,
title: comic_title
} = json.data.comicInfo;
siteJson.comic_id = id;
siteJson.comic_title = comic_title;
chapterList.forEach(e => {
if (e.title == "单行本") {
_chapters[0] = e;
} else if (e.title == "连载") {
_chapters[1] = e;
} else if (e.title == "番外篇") {
_chapters[2] = e;
} else {
_chapters[3] = e;
}
});
_chapters = _chapters.filter(Boolean);
siteJson.chapters = _chapters.map(e => e.data.reverse()).flat();
});
return Promise.all([res_a, res_b]).then(() => {
debug("\n此頁JSON資料\n", siteJson);
fn.hideMsg();
});
},
init: () => _this.page() ? _this.json() : void 0,
imgs: () => _this.page() ? siteJson.srcs : [],
capture: () => _this.imgs(),
autoDownload: [0],
next: () => {
if (!_this.page()) return null;
let index = siteJson.chapters.findIndex(e => e.chapter_id == siteJson.chapter_id);
let next = siteJson.chapters[index + 1];
let dir = fn.dir(fn.clp());
return isObject(next) ? dir + next.chapter_id : null;
},
prev: 1,
chapters: () => siteJson.chapters.map(({
chapter_id,
chapter_title
}) => ({
text: chapter_title,
url: fn.dir(fn.clp()) + chapter_id
})),
category: "comic"
}, {
name: "再漫画M",
url: {
h: "m.zaimanhua.com",
d: "m"
},
page: () => fn.clp("/pages/comic/page"),
json: () => {
fn.showMsg(DL.str_05, 0);
let url = fn.curl();
let comic_id = fn.getUSP("comic_id", url);
let chapter_id = fn.getUSP("chapter_id", url);
siteJson.comic_id = comic_id;
siteJson.chapter_id = chapter_id;
let res_a = fetch(`/api/app/v1/comic/chapter/${comic_id}/${chapter_id}?_v=15`).then(res => res.json()).then(json => {
let {
page_url,
page_url_hd,
title: chapter_title
} = json.data.data;
siteJson.srcs = page_url_hd ?? page_url;
siteJson.chapter_title = chapter_title;
});
let res_b = fetch(`/api/app/v1/comic/detail/${comic_id}?_v=15`).then(res => res.json()).then(json => {
let _chapters = [];
let {
id,
chapters,
title: comic_title
} = json.data.data;
siteJson.comic_id = id;
siteJson.comic_title = comic_title;
chapters.forEach(e => {
if (e.title == "单行本") {
_chapters[0] = e;
} else if (e.title == "连载") {
_chapters[1] = e;
} else if (e.title == "番外篇") {
_chapters[2] = e;
} else {
_chapters[3] = e;
}
});
_chapters = _chapters.filter(Boolean);
siteJson.chapters = _chapters.map(e => e.data.reverse()).flat();
});
return Promise.all([res_a, res_b]).then(() => {
debug("\n此頁JSON資料\n", siteJson);
fn.hideMsg();
});
},
SPA: () => _this.page() ? true : (siteJson = {}) && false,
observeURL: "nav",
init: () => _this.page() ? _this.json() : void 0,
imgs: () => _this.page() ? siteJson.srcs : [],
capture: () => _this.imgs(),
next: () => {
if (!_this.page()) return null;
let index = siteJson.chapters.findIndex(e => e.chapter_id == siteJson.chapter_id);
let next = siteJson.chapters[index + 1];
return isObject(next) ? `/pages/comic/page?comic_id=${siteJson.comic_id}&chapter_id=${next.chapter_id}&chapter_name=${next.chapter_title}` : null;
},
prev: 1,
chapters: () => siteJson.chapters.map(({
chapter_id,
chapter_title
}) => ({
text: chapter_title,
url: `/pages/comic/page?comic_id=${siteJson.comic_id}&chapter_id=${chapter_id}&chapter_name=${chapter_title}`
})),
checkCurrentChapter: (url) => {
let cid = fn.getUSP("chapter_id", fn.curl());
let uid = fn.getUSP("chapter_id", location.origin + url);
return cid == uid;
},
customTitle: () => _this.page() ? siteJson.comic_title + " - " + siteJson.chapter_title : null,
css: ".top_nav{z-index: 999999999!important}",
category: "comic"
}, {
name: "漫畫狗",
url: {
h: "dogemanga.com",
p: "/p/",
e: ".site-reader"
},
imgs: () => fn.gae(".site-reader__image").map(e => e.dataset.pageImageUrl),
button: [4, "24%", 1],
insertImgBF: () => fn.ge(".site-reader").setAttribute("class", "imgBox"),
insertImg: [".imgBox", 2],
insertImgAF: () => {
fn.addUrlHtml(location.origin, ".imgBox", 1, "首頁");
if (nextLink) fn.addUrlHtml(nextLink, ".imgBox", 1);
},
autoDownload: [0],
current: () => fn.ge(".site-selector[data-kind=publication] [selected]"),
next: () => {
let next = _this.current()?.previousElementSibling;
return next ? next.value : null;
},
prev: () => {
let prev = _this.current()?.nextElementSibling;
return prev ? prev.value : null;
},
chapters: {
url: ".site-navbar__title",
target: "#site-manga__tab-pane-all a",
sort: "r"
},
customTitle: () => fn.title(" - 漫畫狗"),
preload: 0,
css: ".imgBox{height:auto!important}",
hide: ".fixed-bottom",
category: "comic"
}, {
name: "Manhuagui看漫画M",
url: {
h: "m.manhuagui.com",
p: /^\/comic\/\d+\/\d+.html/,
i: 0
},
json: (dom = document) => fn.manhuaguiJson(dom),
init: () => {
siteJson = _this.json();
let nextE = fn.ge("a[data-action='chapter.next']");
let prevE = fn.ge("a[data-action='chapter.prev']");
let c_url = fn.ge("#mangaTitle a").href;
if (siteJson.nextId == 0) {
nextE.innerText = "目录";
nextE.href = c_url;
} else {
nextE.href = c_url + siteJson.nextId + ".html";
}
if (siteJson.prevId == 0) {
prevE.innerText = "目录";
prevE.href = c_url;
} else {
prevE.href = c_url + siteJson.prevId + ".html";
}
},
box: ["#manga", 2],
imgs: (json = siteJson) => json.images.map(e => `https://i.hamreus.com${e}?e=${json.sl.e}&m=${json.sl.m}`),
button: [4],
insertImg: ["box", 2],
insertImgBF: () => fn.waitEle("#manga img[src*=hamreus]"),
insertImgAF: () => fn.css("#manga{display:none!important;}"),
autoDownload: [0],
next: () => siteJson.nextId == 0 ? null : fn.gu("#mangaTitle a") + siteJson.nextId + ".html",
prev: "//a[text()='上一章']",
chapters: {
url: "#mangaTitle a",
target: "#chapterList a",
sort: "r"
},
customTitle: (dom = document) => fn.gt("#mangaTitle", 1, dom),
preloadNext: (nextDoc) => {
let json = _this.json(nextDoc);
let arr = _this.imgs(json);
fn.picPreload(arr, _this.customTitle(nextDoc), "next");
},
css: ".action-list li{width:50% !important}",
hide: "#action>ul>li:nth-child(n+2):nth-child(-n+3),.manga-page,.clickforceads",
infiniteScroll: true,
category: "comic"
}, {
name: "Manhuagui看漫画M 自動翻頁",
url: {
h: "m.manhuagui.com",
p: /^\/comic\/\d+\/\d+.html/,
i: 1
},
json: (dom = document) => fn.manhuaguiJson(dom),
getSrcs: (dom) => {
let json = _this.json(dom);
return json.images.map(e => `https://i.hamreus.com${e}?e=${json.sl.e}&m=${json.sl.m}`);
},
getImgs: (dom = document) => {
let srcs = _this.getSrcs(dom);
return fn.createImgArray(srcs);
},
init: async () => {
await fn.waitEle("#manga img[src*=hamreus]");
let imgs = _this.getImgs();
let tE = fn.ge("#manga");
tE.innerHTML = "";
fragment.append(...imgs);
tE.append(fragment);
await fn.lazyload();
},
autoPager: {
ele: (dom) => _this.getImgs(dom),
pos: ["#manga", 0],
observer: "#manga>img",
next: (dom, r = 1) => {
let json = _this.json(dom);
if (json.nextId == 0) {
if (r === 1) {
let e = fn.ge("a[data-action='chapter.next']");
e.href = fn.ge("#mangaTitle a").href;
e.innerText = "返回目录";
}
return null;
} else {
return fn.gu("#mangaTitle a") + json.nextId + ".html";
}
},
re: "#mangaTitle",
title: (dom) => fn.ge("#mangaTitle>a", dom)?.nextSibling?.data?.replace(/\s+/g, " ")?.trim(),
aF: (dom) => {
let json = _this.json(dom);
let cUrl = fn.gu("#mangaTitle a");
let ne = fn.ge("a[data-action='chapter.next']");
ne.href = cUrl + json.nextId + ".html";
let pe = fn.ge("a[data-action='chapter.prev']");
pe.href = cUrl + json.prevId + ".html";
},
preloadNextPage: 1
},
css: ".action-list li{width:50% !important}",
hide: "#action>ul>li:nth-child(n+2):nth-child(-n+3),.manga-page,.clickforceads",
category: "comic autoPager"
}, {
name: "Manhuagui看漫画M 点击查看下20条记录",
url: {
h: "m.manhuagui.com",
p: /^\/(update|list|rank|user)\//
},
loadMore: "#more:not([style*=none])>.more-go",
openInNewTab: "#detail a:not([target=_blank])",
category: "autoPager"
}, {
name: "Manhuagui看漫画",
host: ["www.manhuagui.com", "tw.manhuagui.com", "www.mhgui.com"],
url: {
h: /manhuagui|mhgui/,
p: /^\/comic\/\d+\/\d+.html/,
i: 0
},
init: "$(document).unbind('keydown')",
imgs: (dom = document) => {
let json = fn.manhuaguiJson(dom);
let domain = "https://i.hamreus.com";
return json.files.map(e => `${domain+json.path+e}?e=${json.sl.e}&m=${json.sl.m}`);
},
button: [4],
insertImg: ["#tbBox", 2],
autoDownload: [0],
next: () => {
const {
cInfo
} = _unsafeWindow;
return cInfo.nextId == 0 ? null : location.origin + "/comic/" + cInfo.bid + "/" + cInfo.nextId + ".html";
},
prev: "//a[text()='上一章']",
chapters: () => {
let a = fn.ge("#viewList");
return fn.fetchDoc(a).then(dom => fn.gae("[id^='chapter-list']", dom).reverse().map(list => {
let uls = fn.gae("ul", list);
return uls.map(ul => {
let lis = fn.gae("li", ul).reverse();
return lis.map(li => ({
text: li.firstElementChild.title,
url: li.firstElementChild.href
}));
});
}).flat(Infinity));
},
customTitle: (dom = document) => fn.gt("h1>a", 1, dom) + " - " + fn.gt("h2", 1, dom),
preloadNext: true,
css: ".tbCenter{max-width:1400px!important;width:auto!important;height:auto!important}",
infiniteScroll: true,
category: "comic"
}, {
name: "Manhuagui看漫画 自動翻頁",
url: {
h: /manhuagui|mhgui/,
p: /^\/comic\/\d+\/\d+.html/,
i: 1
},
json: (dom = document) => fn.manhuaguiJson(dom),
getSrcs: (dom) => {
let json = _this.json(dom);
let domain = "https://i.hamreus.com";
return json.files.map(e => `${domain+json.path+e}?e=${json.sl.e}&m=${json.sl.m}`);
},
getImgs: (dom = document) => {
let srcs = _this.getSrcs(dom);
return fn.createImgArray(srcs);
},
init: async () => {
let imgs = _this.getImgs();
let tE = fn.ge("#tbBox");
tE.innerHTML = "";
fragment.append(...imgs);
tE.append(fragment);
await fn.lazyload();
fn.run("$(document).unbind('keydown')");
},
autoPager: {
ele: (dom) => _this.getImgs(dom),
pos: ["#tbBox", 0],
observer: "#tbBox img",
next: (dom, r = 1) => {
let json = _this.json(dom);
let n = json.nextId;
if (n == 0) {
if (r === 1) {
fn.ge("#pagination").outerHTML = fn.ge(".main-btn").outerHTML;
}
return null;
} else {
return fn.url.replace(/\d+\.html$/, "") + n + ".html";
}
},
re: ".title h2",
title: (dom) => _this.json(dom).cname,
preloadNextPage: 1
},
css: ".tbCenter{max-width:1400px!important;width:auto!important;height:auto!important}",
hide: "#prev,#pageSelect,#next,.pager>*:not([onclick])",
category: "comic autoPager"
}, {
name: "包子漫画 閱讀",
host: ["cn.baozimh.com", "cn.webmota.com", "tw.baozimh.com", "tw.webmota.com", "www.baozimh.com", "www.webmota.com", "cn.kukuc.co", "tw.kukuc.co", "www.kukuc.co", "tw.czmanga.com", "cn.czmanga.com", "www.czmanga.com", "tw.dzmanga.com", "cn.dzmanga.com", "www.dzmanga.com", "tw.dociy.net", "cn.dociy.net", "www.dociy.net", "tw.twmanga.com", "cn.twmanga.com", "www.twmanga.com"],
url: {
t: "包子",
p: /^\/comic\/chapter\/[^/]+\/\w+\.html/i,
i: 0
},
init: async () => {
fn.addMutationObserver(() => fn.remove("div[id*='ads'],div[id='interstitial_fade'],iframe"));
fn.run("document.onkeydown=null");
await fn.getNP(".comic-contain>div:not(.mobadsq)", "//a[contains(text(),'下一頁') or contains(text(),'下一页')]", null, ".comic-chapter>.next_chapter,.bottom-bar-tool");
},
imgs: (dom = document) => [...new Set(fn.gae(".comic-contain amp-img", dom).map(e => e.dataset.src ?? e.getAttribute("src")))],
button: [4],
insertImg: [".comic-contain", 2],
autoDownload: [0],
next: "//div[@class='next_chapter']/a[contains(text(),'下一話') or contains(text(),'下一话')]",
prev: 1,
chapters: {
url: () => new URL(fn.gu("a.goto")).pathname,
target: "#chapter-items a,#chapters_other_list a",
cb: (text, u, a) => ({
text,
url: `${fn.dir(fn.clp())}0_${fn.getUSP("chapter_slot", a.href)}.html`
})
},
customTitle: (dom = document) => fn.title(" - ", 3, dom).replace(/\(\d+\/\d+\)/, ""),
preloadNext: true,
hide: "div[id*='ads'],div[id='interstitial_fade'],iframe,.chapter-main.scroll-mode~*:not(.next_chapter):not(.bottom-bar)",
infiniteScroll: true,
category: "comic"
}, {
name: "包子漫画 閱讀 自動翻頁",
url: {
t: "包子",
p: /^\/comic\/chapter\/[^/]+\/\w+\.html/i,
i: 1
},
getSrcs: (dom) => fn.gae(".comic-contain amp-img", dom).map(e => e.dataset.src ?? e.getAttribute("src")),
getImgs: (dom = document) => {
let srcs = _this.getSrcs(dom);
if (fn.ge(".FullPictureLoadImage")) {
let currentLastSrc = fn.gae(".FullPictureLoadImage").at(-1).dataset.src;
let nextFirstNum = Number(srcs[0].match(/(\d)\.\w+$/)[1]);
if (/\/(50|100|150|200|250|300)\.[a-z]{3,5}$/i.test(currentLastSrc) && nextFirstNum == 7 && nextFirstNum != 1) {
srcs = srcs.slice(4);
}
}
return fn.createImgArray(srcs);
},
init: async () => {
fn.addMutationObserver(() => fn.remove("div[id*='ads'],div[id='interstitial_fade'],iframe"));
fn.run("document.onkeydown=null");
let imgs = _this.getImgs();
let tE = fn.ge(".comic-contain");
tE.innerHTML = "";
fragment.append(...imgs);
tE.append(fragment);
await fn.lazyload();
},
autoPager: {
ele: (dom) => _this.getImgs(dom),
pos: [".comic-contain", 0],
observer: ".comic-contain img",
next: (dom) => {
let next = fn.ge("a#next-chapter", dom);
return next ? next.pathname : null;
},
re: "//div[@class='text']/span[@class='title'] | //div[@class='comic-chapter']/div[@class='next_chapter'] | //div[@class='bottom-bar-tool']",
title: (dom) => {
let titleText = fn.gt("span.title", 1, dom).replace(/\(\d\/\d+\)/, "");
return {
ok: /\/\d+_\d+\.html$/.test(nextLink),
text: titleText
}
},
hide: ".comic-chapter>.l-content",
preloadNextPage: 1
},
css: ".comic-contain{width: 100%;margin: 0 auto;max-width:970px;}",
hide: "div[id*='ads'],div[id='interstitial_fade'],iframe,.chapter-main.scroll-mode~*:not(.next_chapter,.bottom-bar,.l-content),.mobadsq",
category: "comic autoPager"
}, {
name: "包子漫画 展開目錄",
icon: 0,
key: 0,
url: {
t: "包子",
p: /^\/comic\/[-\w]+$/i
},
autoClick: ["#button_show_all_chatper", 1000],
category: "comic"
}, {
name: "包子漫画,連結新分頁開啟",
icon: 0,
key: 0,
url: {
t: "包子",
e: ".comics-card,.bookshelf-items"
},
openInNewTab: ".comics-card a:not([target=_blank]),.bookshelf-items a:not(.remove-img):not([target=_blank])",
category: "comic"
}, {
name: "Komiic",
enable: 0,
url: {
h: ["komiic.com"]
},
page: () => fn.clp("/chapter/"),
json: () => {
fn.showMsg(DL.str_05, 0);
let [, , mhId, , chapterId] = fn.clp().split("/");
siteJson = {
mhId,
chapterId
};
let c_body = {
operationName: "imagesByChapterId",
variables: {
chapterId: `${chapterId}`
},
query: "query imagesByChapterId($chapterId: ID!) {\n imagesByChapterId(chapterId: $chapterId) {\n id\n kid\n height\n width\n __typename\n }\n}\n"
};
let res_a = fetch("/api/query", {
"headers": {
"content-type": "application/json"
},
"body": JSON.stringify(c_body),
"method": "POST"
}).then(res => res.json());
let n_body = {
operationName: "chapterByComicId",
variables: {
comicId: `${mhId}`
},
query: "query chapterByComicId($comicId: ID!) {\n chaptersByComicId(comicId: $comicId) {\n id\n serial\n type\n dateCreated\n dateUpdated\n size\n __typename\n }\n}\n"
};
let res_b = fetch("/api/query", {
"headers": {
"content-type": "application/json"
},
"body": JSON.stringify(n_body),
"method": "POST"
}).then(res => res.json());
return Promise.all([res_a, res_b]).then(([a, b]) => {
siteJson.images = a.data.imagesByChapterId;
siteJson.chapterList = b.data.chaptersByComicId;
debug("\n此頁JSON資料\n", siteJson);
fn.hideMsg();
});
},
SPA: () => _this.page() ? true : (siteJson = {}) && false,
observeURL: "nav",
init: () => _this.page() ? _this.json() : void 0,
imgs: () => _this.page() ? siteJson.images.map(e => "https://komiic.com/api/image/" + e.kid) : [],
capture: () => _this.imgs(),
next: () => {
if (!_this.page()) return null;
let chapterList = siteJson.chapterList;
let index = chapterList.findIndex(e => e.id == siteJson.chapterId);
let next = chapterList[index + 1];
return isObject(next) ? fn.clp().replace(siteJson.chapterId, next.id) : null;
},
prev: 1,
chapters: () => {
let {
mhId,
chapterList,
} = siteJson;
return chapterList.map(({
id,
serial,
type
}) => ({
text: `第${serial}${type == "book" ? "卷" : "話"}`,
url: `/comic/${mhId}/chapter/${id}/images/all`
}));
},
customTitle: async () => {
if (!_this.page()) return null;
await fn.waitEle(".v-breadcrumbs");
let textArr = fn.gt(".v-breadcrumbs").split("\n");
return textArr[1] + " - " + textArr[2];
},
referer: "url",
category: "comic"
}, {
name: "LINE WEBTOON / 咚漫",
host: ["www.webtoons.com", "www.dongmanmanhua.cn"],
enable: 0,
url: {
h: /webtoons|dongmanmanhua/,
p: /^\/[^&]+&episode/
},
imgs: "._images[data-url]",
autoDownload: [0],
next: "//div[@class='episode_cont']//li[a[starts-with(@class,'on')]]/following-sibling::li[1]/a",
prev: "//div[@class='episode_cont']//li[a[starts-with(@class,'on')]]/preceding-sibling::li[1]/a",
customTitle: () => fn.title("|", 3).replace(/ - \d+/, "").replace("|", " - "),
category: "comic"
}, {
name: "LINE WEBTOON 目錄聚集所有章節",
enable: 0,
icon: 0,
key: 0,
url: {
h: "www.webtoons.com",
p: "/list"
},
init: "fn.getNP('._episodeItem',\"//div[@class='paginate']/a[span[@class='on']]/following-sibling::a[1]\",null,'.paginate',0,null,0)",
category: "comic"
}, {
name: "動漫狂",
host: ["www.cartoonmad.com", "cc.fun8.us"],
url: {
h: "cc.fun8.us",
p: "/post/",
ee: "#info table[align]",
i: 0
},
init: () => fn.cartoonmadUI(),
imgs: (dom = document) => {
let src = fn.src("img[onload],img[oncontextmenu]", dom);
let dir = fn.dir(src);
let max = fn.ge(".onpage", dom).parentNode.lastElementChild.previousElementSibling.innerText;
fn.remove("//tr[td[a[@class='onpage']]]");
return fn.arr(max, (v, i) => dir + String((i + 1)).padStart(3, "0") + ".jpg");
},
button: [4],
insertImg: ["//td[a[img[@oncontextmenu]]] | //td[a[img[@oncontextmenu]]]", 2],
autoDownload: [0],
next: "//td[@width='150' and a[img[@src='/image/rad.gif']]]/a | //a[b]",
prev: "//td[@width='150' and a[img[@src='/image/rad1.gif']]]/a",
chapters: () => {
let img = fn.ge("img[onload],img[oncontextmenu],.FullPictureLoadImage");
let src = img.dataset.src || img.src;
let comicId = new URL(src).pathname.split("/")[3];
return fn.xhrDoc(`https://www.cartoonmad.com/comic/${comicId}.html`, {
headers: {
"User-Agent": PC_UA
}
}).then(dom => {
let dir = fn.dir(fn.url);
return fn.gae("#info:has(table a) a", dom).map(a => {
let [id] = a.href.split("/").at(-1).match(/\d+/);
return {
text: a.innerText.trim(),
url: `${dir}${id}.html`
}
});
});
},
customTitle: async (dom = document) => {
let src = fn.ge("img[onload],img[oncontextmenu]", dom).src;
let comicId = new URL(src).pathname.split("/")[3];
let comicIdData = JSON.parse(localStorage.getItem("comicIdData")) ?? {};
if (comicIdData[comicId] === null || comicIdData[comicId] === undefined) {
if (/TW|HK/.test(language)) {
fn.showMsg("首次取得漫畫名稱", 0);
} else if (/zh/.test(language)) {
fn.showMsg("首次取得漫画名称", 0);
} else {
fn.showMsg("First time Get ComicName", 0);
}
let comicName = await fn.xhrDoc(`https://www.cartoonmad.com/comic/${comicId}.html`, {
headers: {
"User-Agent": PC_UA
}
}).then(comicDoc => fn.ge("meta[name=Keywords]", comicDoc).content.split(",")[0]);
comicIdData[comicId] = comicName;
localStorage.setItem("comicIdData", JSON.stringify(comicIdData));
return comicName + " - " + dom.title;
} else {
let comicName = comicIdData[comicId];
return comicName + " - " + dom.title;
}
},
preloadNext: true,
infiniteScroll: true,
category: "comic"
}, {
name: "動漫狂 自動翻頁",
url: {
h: "cc.fun8.us",
p: "/post/",
ee: "#info table[align]",
i: 1
},
getSrcs: (dom) => {
let src = fn.src("img[onload],img[oncontextmenu]", dom);
let dir = fn.dir(src);
let max = fn.ge(".onpage", dom).parentNode.lastElementChild.previousElementSibling.innerText;
return fn.arr(max, (v, i) => dir + String((i + 1)).padStart(3, "0") + ".jpg");
},
getImgs: (dom = document) => {
let srcs = _this.getSrcs(dom);
return fn.createImgArray(srcs);
},
init: async () => {
fn.cartoonmadUI();
let imgs = _this.getImgs();
let tE = fn.ge("//td[a[img[@oncontextmenu]]] | //td[a[img[@oncontextmenu]]]");
tE.innerHTML = "";
fragment.append(...imgs);
tE.append(fragment);
await fn.lazyload();
fn.remove("//tr[td[a[@class='onpage']]]");
},
autoPager: {
ele: (dom) => _this.getImgs(dom),
pos: ["//td[img]", 0],
observer: "//td[img]/img",
next: "//td[@width='150' and a[img[@src='/image/rad.gif']]]/a | //a[b]",
aF: (dom) => {
fn.gae("//tr[td[@bgcolor='#EAEAEA']] | //tr[td[@bgcolor='#EBEBEB']]").forEach(e => (e.innerHTML = fn.ge("//tr[td[@bgcolor='#EAEAEA']] | //tr[td[@bgcolor='#EBEBEB']]", dom, dom).innerHTML));
fn.remove("//td[div[@id='sidebar-follow']] | //td[ins[@class='adsbygoogle']] | //tr[td[script]] | //select");
},
preloadNextPage: 1
},
category: "comic autoPager"
}, {
name: "動漫啦",
enable: 0,
url: {
h: "www.dongman.la",
p: "/chapter/"
},
imgs: (link = siteUrl, msg = 1, request = 0) => {
let links = [link.replace("all.html", "") + "all.html"];
return fn.getImgA(".imgListBox img", links, 0, null, msg, request);
},
button: [4],
insertImg: [".imgListBox", 2],
autoDownload: [0],
next: "//a[label[text()='下一章']][contains(@href,'chapter')]",
prev: "//a[label[text()='上一章']][contains(@href,'chapter')]",
customTitle: (dom = document) => fn.attr("meta[name='description']", "content", dom),
preloadNext: async (nextDoc, obj) => fn.picPreload(await obj.imgs(nextLink, 0, 1), obj.customTitle(nextDoc), "next"),
css: ".mdui-col-xs-4{width:50%!important}",
hide: ".mdui-container .mdui-col-xs-4:nth-child(2)",
category: "comic"
}, {
name: "動漫啦M",
enable: 0,
url: {
h: "m.dongman.la",
p: "/chapter/",
},
imgs: ".chapter-images img",
button: [4],
insertImg: [".chapter-images", 2],
autoDownload: [0],
next: "//a[label[text()='下一章']][contains(@href,'chapter')]",
prev: "//a[label[text()='上一章']][contains(@href,'chapter')]",
customTitle: (dom = document) => dom.title,
preloadNext: true,
category: "comic"
}, {
name: "動漫戲說",
enable: 0,
url: {
h: "comic.acgn.cc",
p: "/view"
},
imgs: (dom = document) => fn.gae(".pic[_src][id]", dom).map(e => e.getAttribute("_src")),
button: [4],
insertImg: ["#pic_list", 2],
autoDownload: [0],
next: ".display_right>a",
prev: ".display_left>a",
customTitle: (dom = document) => fn.gt(".hotrmtexth1>a", 1, dom),
preloadNext: true,
hide: ".btn_wrap",
category: "comic"
}, {
name: "国漫吧",
host: ["www.guoman8.cc", "m.guoman8.cc"],
url: {
h: ".guoman8.",
p: /^\/\d+\/\d+\.html$/,
i: 0
},
init: () => setTimeout(() => fn.run("$(document).off()"), 5000),
json: (dom) => {
let code = fn.gst("eval", dom);
let s = code.indexOf("(");
let e = code.indexOf("{}))", s) + 5;
code = code.slice(s, e);
let objText = fn.run(code);
return fn.TextToObject(objText, "cInfo");
},
imgs: (dom = document) => {
let json = _this.json(dom);
const {
pageConfig
} = _unsafeWindow;
return json.fs.map(e => /^http/.test(e) ? e : "//" + pageConfig.host.auto[0] + e);
},
button: [4],
insertImg: ["//td[img[@id='manga']]", 2],
autoDownload: [0],
next: "a.nextC:not([href^=java])",
prev: ".prevC",
chapters: () => {
let a = fn.ge("#viewList,#mangaTitle a");
return fn.fetchDoc(a).then(dom => {
if (fn.lh.startsWith("m.")) {
return fn.gae("#chapterList a", dom).map(a => ({
text: a.title,
url: a.href
})).reverse();
}
let list = fn.ge(".chapter-list", dom);
let uls = fn.gae("ul", list);
return uls.map(ul => {
let lis = fn.gae("li", ul).reverse();
return lis.map(li => ({
text: li.firstElementChild.title,
url: li.firstElementChild.href
}));
}).flat(Infinity);
});
},
customTitle: (dom = document) => {
let json = _this.json(dom);
return json.btitle + " - " + json.ctitle;
},
preloadNext: true,
css: ".action-list li{width:50%!important}",
hide: "#action>ul>li:nth-child(n+2):nth-child(-n+3),.bd_960_90,body>section,#action~*:not(#pageNo),footer~*",
infiniteScroll: true,
category: "comic"
}, {
name: "国漫吧 自動翻頁",
url: {
h: ".guoman8.",
p: /^\/\d+\/\d+\.html$/,
i: 1
},
json: (dom) => {
let code = fn.gst("eval", dom);
let s = code.indexOf("(");
let e = code.indexOf("{}))", s) + 5;
code = code.slice(s, e);
let objText = fn.run(code);
return fn.TextToObject(objText, "cInfo");
},
getSrcs: (dom) => {
let json = _this.json(dom);
const {
pageConfig
} = _unsafeWindow;
return json.fs.map(e => /^http/.test(e) ? e : "//" + pageConfig.host.auto[0] + e);
},
getImgs: (dom = document) => {
let srcs = _this.getSrcs(dom);
return fn.createImgArray(srcs);
},
init: async () => {
let imgs = _this.getImgs();
let tE = fn.ge("//td[img[@id='manga']]");
tE.innerHTML = "";
fragment.append(...imgs);
tE.append(fragment);
await fn.lazyload();
setTimeout(() => fn.run("$(document).off()"), 5000);
},
autoPager: {
ele: (dom) => _this.getImgs(dom),
pos: ["//td[img]", 0],
observer: "//td[img]/img",
next: (dom, r = 1) => {
let nextE = fn.ge("a.nextC:not([href^=java])", dom);
if (nextE) {
return nextE.href;
} else {
if (r === 1) {
let curl = fn.lp.replace(/\d+\/$|\d+\.html$/, "");
let mn = fn.ge("a.nextC");
if (mn) {
mn.href = curl;
mn.innerText = "返回目录";
}
if (fn.lh === "www.guoman8.cc") {
mn.remove();
let pn = fn.ge("//a[text()='下一章']");
pn.setAttribute("onclick", "");
pn.href = fn.ge("//a[text()='返回目录']").pathname;
pn.innerText = "返回目录";
}
}
return null;
}
},
re: ".title h2,.main-btn,#mangaTitle,#action",
title: (dom) => _this.json(dom).ctitle,
preloadNextPage: 1
},
css: ".action-list li{width:50%!important}",
hide: "#imgLoading,#manga,.action,#action>ul>li:nth-child(n+2):nth-child(-n+3),.bd_960_90,body>section,#action~*:not(#pageNo,#FullPictureLoadMsg),footer~*:not(#FullPictureLoadMsg),#prev,#pageSelect,#next,#pager>*:not([onclick]),#pager>*[onclick*='next()'],.backToTop~div[style*='overflow']",
category: "comic autoPager"
}, {
name: "漫画456",
host: ["www.manhua456.com", "m.manhua456.com"],
enable: 0,
url: {
h: ".manhua456.com",
p: /^\/manhua\/\w+\/\d+\.html/
},
init: () => {
if (isPC) {
fn.run("setTimeout(()=>$(document).unbind('keyup') && $(document).unbind('keydown'),4000)");
}
let res_b = fn.fetchDoc(fn.url).then(dom => (doc = dom));
let res_a = fetch("/js/config.js").then(res => res.text()).then(text => {
let domain = String(fn.TextToArray(text, "domain"));
siteJson.domain = domain;
});
return Promise.all([res_a, res_b]);
},
imgs: (dom = doc) => {
let code = fn.gst("chapterImages", dom);
let chapterImages = fn.TextToArray(code, "chapterImages");
let chapterPath = fn.textVar(code, "chapterPath");
return chapterImages.map(e => e.startsWith("http") ? e : siteJson.domain + "/" + chapterPath + e);
},
button: [4],
insertImgBF: () => fn.waitEle("#images img"),
insertImg: ["#images", 2],
insertImgAF: () => fn.run("jQuery('#images').unbind('click')"),
autoDownload: [0],
next: () => {
let code = fn.gst("comicUrl", doc);
let comicUrl = fn.textVar(code, "comicUrl");
return fn.fetchDoc(new URL(comicUrl).pathname).then(dom => {
let chapters = fn.gau("ul[id^=chapter-list] a", dom);
let index = chapters.findIndex(url => url.includes(fn.lp.match(/\d+/g).at(-1)));
let next = chapters[index + 1];
return isString(next) ? next : null;
});
},
prev: "//a[text()='上一章']",
customTitle: (dom = doc) => {
let code = fn.gst("pageTitle", dom);
let pageTitle = fn.textVar(code, "pageTitle");
let [chapterName, comicName] = pageTitle.split(" - ");
return comicName + " - " + chapterName;
},
preloadNext: true,
mcss: ".action-list li{width:50% !important}",
hide: ".img_land_prev,.img_land_next,#action>ul>li:nth-child(n+2):nth-child(-n+3),.img_land_prev,.img_land_next,body>div[id]:has(>div[class][style]>div[style]),body>div:has(.swiper-slide)",
category: "comic"
}, {
name: "漫画1234",
host: ["www.amh1234.com", "m.amh1234.com"],
enable: 0,
url: {
t: "漫画1234",
p: /^\/comic\/\d+\/\d+\.html/,
st: "chapterImages"
},
init: () => {
let res_b = fn.fetchDoc(fn.url).then(dom => (doc = dom));
let res_a = fetch("/js/config.js").then(res => res.text()).then(text => {
let domain = String(fn.TextToArray(text, "domain"));
siteJson.domain = domain;
});
let res_c = fn.fetchDoc(_unsafeWindow.comicUrl).then(dom => {
let chapters = fn.gau('ul[id^=chapter-list] a', dom);
let index = chapters.findIndex(url => url.includes(fn.lp.match(/\d+/g).at(-1)));
siteJson.next = chapters[index + 1];
siteJson.prev = chapters[index - 1];
});
return Promise.all([res_a, res_b, res_c]).then(() => fn.run("$(document).unbind('keydown') && $(document).unbind('keyup')"));
},
imgs: (dom = doc) => {
let code = fn.gst("chapterImages", dom);
let chapterImages = fn.TextToArray(code, "chapterImages");
let chapterPath = fn.textVar(code, "chapterPath");
return chapterImages.map(e => e.startsWith("http") ? e : siteJson.domain + "/" + chapterPath + e);
},
button: [4],
insertImg: ["#images", 2],
insertImgAF: (parent) => {
fn.run("$('#images').unbind('click')");
if (nextLink) {
fn.addUrlHtml(nextLink, parent, 1, DL.str_143, 3);
}
},
autoDownload: [0],
next: () => isString(siteJson.next) ? siteJson.next : null,
prev: () => isString(siteJson.prev) ? siteJson.prev : null,
customTitle: (dom = doc) => {
let code = fn.gst("SinMH.initChapter", dom);
let [, chapterName, , comicName, ] = code.match(/SinMH.initChapter\(([^\)]+)\)/)[1].replaceAll('"', "").split(",");
return comicName + " - " + chapterName;
},
preloadNext: true,
css: ".action-list li{width:50% !important}",
hide: ".globalPadding,.img_info,#imgLoading,#loading,#action>ul>li:nth-child(n+2):nth-child(-n+3)",
category: "comic"
}, {
name: "92漫画/31漫画",
enable: 0,
url: {
h: ["www.92mh.com", "www.31mh.cc"],
p: [/^\/manhua\/\d+\/\d+\.html$/, /^\/comic\/\w+\/\d+\.html$/]
},
init: () => {
let res_a = fn.fetchDoc(fn.url).then(dom => (doc = dom)).then(() => {
try {
fn.run("$(document).unbind('keydown') && $(document).unbind('keyup') && $('#images').unbind('click')");
} catch {}
});
let code = fn.gst("comicUrl", doc);
let comicUrl = fn.textVar(code, "comicUrl");
let res_b = fn.fetchDoc(new URL(comicUrl).pathname).then(dom => {
let chapters = fn.gau("ul[id^=chapter-list] a", dom);
let index = chapters.findIndex(url => url.includes(fn.lp.match(/\d+/g).at(-1)));
siteJson.next = chapters[index + 1];
siteJson.prev = chapters[index - 1];
});
return Promise.all([res_a, res_b]);
},
imgs: (dom = doc) => {
let code = fn.gst("chapterImages", dom);
let chapterImages = fn.TextToArray(code, "chapterImages");
let chapterImageHost = fn.textVar(code, "chapterImageHost");
return chapterImages.map(e => e.startsWith("http") ? e : chapterImageHost + e);
},
button: [4],
insertImg: ["#images", 2],
autoDownload: [0],
next: () => isString(siteJson.next) ? siteJson.next : null,
prev: () => isString(siteJson.prev) ? siteJson.prev : null,
customTitle: (dom = doc) => {
let code = fn.gst("SinMH.initChapter", dom);
let [, chapterName, , comicName, ] = code.match(/SinMH.initChapter\(([^\)]+)\)/)[1].replaceAll('"', "").split(",");
return comicName + " - " + chapterName;
},
preloadNext: true,
hide: ".img_land_prev,.img_land_next",
category: "comic"
}, {
name: "92漫画M/31漫画M",
enable: 0,
url: {
h: ["m.92mh.com", "m.31mh.cc"],
p: [/^\/manhua\/\d+\/\d+\.html$/, /^\/comic\/\w+\/\d+\.html$/]
},
imgs: (url = fn.url, msg = 1) => {
if (msg == 1) fn.showMsg(DL.str_05, 0);
url = url.replace("/m.", "/www.");
return fn.xhrDoc(url, {
headers: {
"Referer": url,
"User-Agent": PC_UA
}
}).then(dom => {
let code = fn.gst("chapterImages", dom);
let chapterImages = fn.TextToArray(code, "chapterImages");
let chapterImageHost = fn.textVar(code, "chapterImageHost");
return chapterImages.map(e => e.startsWith("http") ? e : chapterImageHost + e);
});
},
button: [4],
insertImg: ["#images", 2],
autoDownload: [0],
next: () => {
let next = fn.ge("//a[text()='下一章'][contains(@href,'html')]");
return next ? next.href : null;
},
prev: 1,
customTitle: (dom = document) => fn.title("在线", 1, dom),
preloadNext: async nextDoc => fn.picPreload(await _this.imgs(nextLink, 0), _this.customTitle(nextDoc), "next"),
css: "body{padding:0!important}.action-list li{width:50% !important}",
hide: "div[style*='text-align: left;'],.UnderPage~*:not([id^='Full'],[class^='Full'],[id^='pv-'],[class^='pv-'],[id^='pagetual'],[class^='pagetual'],#comicRead,#fab,[class^=fancybox]),.action-list>ul>li:nth-child(n+2):nth-child(-n+3)",
category: "comic"
}, {
name: "优酷漫画",
host: ["www.ykmh.net", "m.ykmh.net"],
enable: 0,
url: {
h: ".ykmh.",
p: /^\/manhua\/\w+\/\d+\.html$/
},
init: () => {
let res_b = fn.fetchDoc(fn.url).then(dom => (doc = dom));
let res_a = fetch("/js/config.js").then(res => res.text()).then(text => {
let domain = String(fn.TextToArray(text, "domain"));
siteJson.domain = domain;
});
return Promise.all([res_a, res_b]).then(() => fn.run("$(document).unbind('keydown') && $(document).unbind('keyup') && $('#images').unbind('click')"));
},
imgs: (dom = doc) => {
let code = fn.gst("chapterImages", dom);
let chapterImages = fn.TextToArray(code, "chapterImages");
let chapterPath = fn.textVar(code, "chapterPath");
return chapterImages.map(e => e.startsWith("http") ? e : siteJson.domain + e);
},
button: [4],
insertImg: ["#images", 2],
autoDownload: [0],
next: () => {
let code = fn.gst("comicUrl", doc);
let comicUrl = fn.textVar(code, "comicUrl");
return fn.fetchDoc(new URL(comicUrl).pathname).then(dom => {
let chapters = fn.gau("ul[id^=chapter-list] a", dom);
if (isM) {
chapters = chapters.reverse();
}
let index = chapters.findIndex(url => url.includes(fn.lp.match(/\d+/g).at(-1)));
let next = chapters[index + 1];
return isString(next) ? next : null;
});
},
prev: 1,
customTitle: (dom = doc) => {
let code = fn.gst("pageTitle", dom);
let pageTitle = fn.textVar(code, "pageTitle");
let [chapterName, comicName] = pageTitle.split(" - ");
return comicName + " - " + chapterName;
},
preloadNext: true,
mcss: ".action-list li{width:50% !important}",
hide: ".img_land_prev,.img_land_next,.letchepter>div,.letchepter>section,#action>ul>li:nth-child(n+2):nth-child(-n+3)",
category: "comic"
}, {
name: "来漫画",
host: ["www.laimanhua88.com", "www.comemh8.com"],
url: {
h: [/^www\.(laimanhua|comemh)/],
p: "/kanmanhua/",
d: "pc",
i: 0
},
init: () => fn.clearAllTimer(),
box: ["#pic-list", 2],
imgs: () => {
const {
base64_decode,
picTree,
getpicdamin
} = _unsafeWindow;
return base64_decode(picTree).split("$qingtiandy$").map(e => getpicdamin() + e);
},
button: [4],
insertImg: [
["box", 0, "#pic-list"], 2
],
endColor: "white",
autoDownload: [0],
next: () => {
const {
nextUrlid
} = _unsafeWindow;
return nextUrlid == "" ? null : fn.gu("a#cartoon_url") + nextUrlid + ".html";
},
prev: ".btn-prev",
chapters: {
url: "a.big-link-back",
target: ".plist a",
sort: "r"
},
customTitle: (dom = document) => fn.title(",", 1, dom).replace("漫画", "").trim(),
preloadNext: (nextDoc, obj) => {
let code = fn.gst("picTree", nextDoc);
fn.script(code, 0, 1);
fn.picPreload(obj.imgs(), obj.customTitle(nextDoc), "next");
},
hide: "#loading,#pre-loading,.img_info,.blank20,#udbsdk_login",
infiniteScroll: true,
category: "comic"
}, {
name: "来漫画 自動翻頁",
url: {
h: /^www\.(laimanhua|comemh)/,
p: "/kanmanhua/",
e: "#pic-list",
d: "pc",
i: 1
},
getSrcs: (dom) => {
const {
base64_decode,
getpicdamin
} = _unsafeWindow;
let code = fn.gst("picTree", dom);
let base64Text = fn.textVar(code, "picTree");
return base64_decode(base64Text).split("$qingtiandy$").map(e => getpicdamin() + e);
},
getImgs: (dom = document) => {
let srcs = _this.getSrcs(dom);
return fn.createImgArray(srcs);
},
init: async () => {
fn.clearAllTimer();
let tE = fn.createImgBox("#pic-list", 2);
fn.remove("#pic-list");
let imgs = _this.getImgs();
fragment.append(...imgs);
tE.append(fragment);
await fn.lazyload();
},
autoPager: {
script: "//script[contains(text(),'picTree')]",
ele: (dom) => _this.getImgs(dom),
pos: ["#FullPictureLoadMainImgBox", 0],
observer: "#FullPictureLoadMainImgBox>img",
next: (dom) => {
let code = fn.gst("nextUrlid", dom);
let comicURL = fn.gu("#position a");
let [, cidText] = code.match(/nextUrlid[\s\=]+([^,;]+)/);
if (/\d+/.test(cidText)) {
let [cid] = cidText.match(/\d+/);
return comicURL + cid + ".html";
} else {
return null;
}
},
re: "#bottom_chapter",
title: (dom) => fn.gt("#position", 1, dom).replaceAll("\n", "").replaceAll(">", "").replace("漫画", "").trim(),
preloadNextPage: 1
},
css: ".subNav{margin: 4px auto!important;float:unset!important}",
hide: "#loading,#pre-loading,.img_info,.blank20,#udbsdk_login",
category: "comic autoPager"
}, {
name: "来漫画M",
host: ["m.laimanhua8.com", "m.laimanhua88.com", "m.comemh.com", "m.comemh8.com"],
url: {
h: [/^m\.(laimanhua|comemh)/],
p: "/kanmanhua/",
e: "#manga",
d: "m",
i: 0
},
init: () => fn.clearAllTimer(),
imgs: () => {
const {
mhInfo,
realurl
} = _unsafeWindow;
return mhInfo.images.map(e => realurl + mhInfo.path + e);
},
button: [4],
insertImg: ["#manga", 2],
autoDownload: [0],
next: () => {
const {
mhInfo
} = _unsafeWindow;
return mhInfo.nextUrlid == "" ? null : fn.gu("#mangaTitle>a") + mhInfo.nextUrlid + ".html";
},
prev: "//a[text()='上一章']",
customTitle: (dom = document) => fn.gt("#mangaTitle", 1, dom).replace(/\n/g, "").trim(),
chapters: {
url: "#mangaTitle a",
target: "#chapterList a",
sort: "r"
},
preloadNext: (nextDoc, obj) => {
let code = fn.gst("mhInfo", nextDoc);
fn.script(code, 0, 1);
fn.picPreload(obj.imgs(), obj.customTitle(nextDoc), "next");
},
css: ".action-list li{width:50% !important}",
hide: "#jusha1,#action>ul>li:nth-child(n+2):nth-child(-n+3)",
infiniteScroll: true,
category: "comic"
}, {
name: "来漫画M 自動翻頁",
url: {
h: [/^m\.(laimanhua|comemh)/],
p: "/kanmanhua/",
e: "#manga",
d: "m",
i: 1
},
json: (dom) => {
let code = fn.gst("mhInfo", dom);
return fn.TextToObject(code, "mhInfo");
},
getSrcs: (dom) => {
let json = _this.json(dom);
return json.images.map(e => _unsafeWindow.realurl + json.path + e);
},
getImgs: (dom = document) => {
let srcs = _this.getSrcs(dom);
return fn.createImgArray(srcs);
},
init: async () => {
fn.clearAllTimer();
let imgs = _this.getImgs();
let tE = fn.ge("#manga");
tE.innerHTML = "";
fragment.append(...imgs);
tE.append(fragment);
await fn.lazyload();
},
autoPager: {
script: "//script[contains(text(),'mhInfo')]",
ele: (dom) => _this.getImgs(dom),
pos: ["#manga", 0],
observer: "#manga>img",
next: (dom, r = 1) => {
let json = _this.json(dom);
let cUrl = fn.gu("#mangaTitle>a");
if (json.nextUrlid == "") {
if (r === 1) {
fn.remove("//li[a[text()='下一章']]");
let html = `<li><a href="${cUrl}">返回目录</a></li>`;
fn.ge("#action>ul").insertAdjacentHTML("beforeend", html);
}
return null;
} else {
return cUrl + json.nextUrlid + ".html";
}
},
title: (dom) => _this.json(dom).chapterTitle,
hide: "#slider",
preloadNextPage: 1
},
css: ".action-list li{width:50% !important}",
hide: "#jusha1,#action>ul>li:nth-child(n+2):nth-child(-n+3)",
category: "comic autoPager"
}, {
name: "来漫画",
host: ["www.laimanhua.org", "m.laimanhua.org"],
url: {
h: "laimanhua.org",
p: "/chapter/"
},
init: () => fn.waitEle(".imgbox img"),
imgs: (dom = document) => fn.getImgSrcArr(".imgbox img", dom),
button: [4],
insertImg: [".imgbox", 2],
autoDownload: [0],
next: "//a[text()='下一话']",
prev: "//a[text()='上一话']",
customTitle: (dom = document) => {
if (fn.lh.startsWith("m.")) {
let text = fn.ge("meta[name=keywords]", dom).content;
text = text.replace(/^[^,]+,/, "");
text = text.replace("漫画", " - ");
return fn.dt({
t: text,
d: "在线观看 - 来漫画"
});
} else {
return fn.dt({
t: fn.gt(".breadcrumb_crumbItem:nth-child(3)", 1, dom) + " - " + fn.gt(".breadcrumb_crumbItem:nth-child(4)", 1, dom)
});
}
},
frame: ".imgbox img",
preloadNext: true,
category: "comic"
}, {
name: "漫客栈",
enable: 0,
url: {
h: "www.mkzhan.com",
p: /^\/\d+\/\d+\.html/
},
fetchJson: async (lp = new URL(siteUrl).pathname) => {
let lps = lp.split("/");
let comic_id = lps[1];
let [chapter_id] = lps[2].match(/\d+/);
let apiUrl = `https://comic.mkzcdn.com/chapter/content/v1/?chapter_id=${chapter_id}&comic_id=${comic_id}&format=1&quality=1&type=1`;
return fetch(apiUrl).then(res => res.json());
},
init: async () => {
let json = await _this.fetchJson();
debug("\n此頁JSON資料\n", json);
siteJson = json;
},
imgs: (json = siteJson) => json.code == 302 ? [] : json.data.page.map(e => e.image),
insertImg: ["#pages-tpl", 2],
autoDownload: [0],
next: ".rd-aside a.j-rd-next",
prev: ".rd-aside a.j-rd-prev",
autoClick: "//div[@class='rd-aside__item j-rd-mod'][span[text()='卷轴']]",
customTitle: (dom = document) => fn.title(" - ", 1, dom),
preloadNext: async (nextDoc, obj) => {
let json = await obj.fetchJson(new URL(nextLink).pathname);
fn.picPreload(obj.imgs(json), obj.customTitle(nextDoc), "next");
},
category: "comic"
}, {
name: "好国漫",
host: ["www.haoguoman8.com", "m.haoguoman8.com"],
url: {
t: "好国漫",
p: /^\/\d+\/\d+\.html$/,
i: 0
},
json: (dom) => {
let code = fn.gst("params", dom);
let dataBase64 = fn.textVar(code, "params");
let dataJson = _unsafeWindow.CMS.chapter.decrypt(dataBase64);
return dataJson;
},
init: () => fn.wait(() => !!_unsafeWindow?.CMS?.chapter?.decrypt),
box: [".chapter-images", 2],
imgs: (dom = document) => {
let {
chapter_images,
images_domain
} = _this.json(dom);
return chapter_images.map(e => e.startsWith("http") ? e : images_domain + e);
},
button: [4],
insertImg: ["box", 2],
endColor: "white",
autoDownload: [0],
next: "a.j-chapter-next[href$=html]",
prev: "a.j-chapter-prev[href$=html]",
chapters: {
url: "a:has(.icon-chapter),.top-toolbar a",
target: ".comic-chapters a,.chapter-list a"
},
customTitle: (dom = document) => {
let {
comic_name,
chapter_title
} = _this.json(dom);
return comic_name + " - " + chapter_title;
},
preloadNext: true,
hide: ".chapter-images,#loading,ins",
infiniteScroll: true,
category: "comic"
}, {
name: "好国漫 自動翻頁",
url: {
t: "好国漫",
p: /^\/\d+\/\d+\.html$/,
i: 1
},
json: (dom = document) => {
let code = fn.gst("params", dom);
let dataBase64 = fn.textVar(code, "params");
let dataJson = _unsafeWindow.CMS.chapter.decrypt(dataBase64);
return dataJson;
},
getSrcs: (dom) => {
let json = _this.json(dom);
let {
chapter_images,
images_domain
} = json;
return chapter_images.map(e => e.startsWith("http") ? e : images_domain + e);
},
getImgs: (dom = document) => {
let srcs = _this.getSrcs(dom);
return fn.createImgArray(srcs);
},
init: async () => {
await fn.wait(() => !!_unsafeWindow?.CMS?.chapter?.decrypt);
let tE = fn.createImgBox(".chapter-images", 2);
let imgs = _this.getImgs();
fragment.append(...imgs);
tE.append(fragment);
await fn.lazyload();
},
autoPager: {
ele: (dom) => _this.getImgs(dom),
pos: ["#FullPictureLoadMainImgBox", 0],
observer: "#FullPictureLoadMainImgBox>img",
next: "a.j-chapter-next[href$=html]",
re: ".breadcrumb,.j-chapter-next,.j-chapter-prev,.chapter-next,.comic-name,.clearfix>li:not(.collect)",
title: (dom) => _this.json(dom).chapter_title,
preloadNextPage: 1
},
hide: ".chapter-images,#loading,ins,.chapter-read-pos",
category: "comic autoPager"
}, {
name: "漫画屋格式",
host: ["www.mhua5.com", "www.mhw1.com", "www.mh5.xyz", "www.umh5.com", "www.biqu8.xyz", "comics.veryim.com", "www.cuimanhua.com"],
enable: 0,
reg: [
/^https?:\/\/(www\.mhua5\.com|www\.mhw\d?\.com|www\.mh5\.xyz|www\.umh5\.com)\/index\.php\/chapter\/\d+/i,
/^https?:\/\/www\.manshiduo\.net\/chapter_\d+\.html$/i,
/^https?:\/\/www\.biqu8\.xyz\/index\.php\/chapter-\d+.html$/i,
/^https?:\/\/comics\.veryim\.com\/\w+\/\d+\/\d+\.html$/,
/^https?:\/\/(www\.cuimanhua\.com|manhuami\.cc)\/[-\d]+\.html$/
],
include: ".rd-article-wr",
init: "document.onkeydown=null",
imgs: (dom = document) => fn.getImgSrcArr("img[data-original]:not([data-original*='/template/pc/default/']),.lazy-read:not([data-original*='/template/pc/default/']),img[data-src]", dom),
button: [4],
insertImg: [".rd-article-wr", 2],
endColor: "white",
autoDownload: [0],
//next: ".btn--next-chapter,.rd-aside a.j-rd-next",
next: () => {
let next1 = fn.ge("a.j-rd-next[_href]:not([style])");
let next2 = fn.ge("a.j-rd-next[href]:not([href^=java])");
if (next1) {
let href = fn.attr("a.j-rd-next[_href]", "_href");
return href == "" ? null : location.origin + href;
} else if (next2) {
return next2.href;
}
return null;
},
prev: ".rd-aside a.j-rd-prev",
autoClick: "//div[@class='rd-aside__item j-rd-mod'][span[text()='卷轴']]",
customTitle: (dom = document) => {
if (/www\.mhua5\.com|www\.mhw\d\.com/.test(fn.lh)) {
return fn.title(" - 漫画屋", 0, dom).replace("-", " - ");
} else if (/www\.mh5\.xyz/.test(fn.lh)) {
return fn.attr("meta[name=description]", "content", dom).split(" - 漫画屋")[0].replace("当前阅读的是", "").replace("的", " - ");
} else if (/www\.umh5\.com|www\.biqug\.org/.test(fn.lh)) {
return fn.gt(".j-comic-title", 1, dom) + " - " + fn.gt(".last-crumb", 1, dom);
} else {
return fn.title(/下拉|在线/, 1, dom).replace("-", " - ").replace(/漫画|\[\d+P\]/i, "");
}
},
preloadNext: true,
category: "comic"
}, {
name: "漫画屋M格式",
host: ["m.mkzhan.com", "www.mhua5.com", "www.mhw1.com", "www.mh5.xyz", "www.umh5.com", "www.biqug.org", "wap.veryim.com", "shouji.veryim.com"],
enable: 0,
reg: [
/^https?:\/\/m\.mkzhan\.com\/\d+\/\d+\.html$/i,
/^https?:\/\/(www\.mhua5\.com|www\.mhw\d?\.com|www\.mh5\.xyz|www\.umh5\.com)\/index\.php\/chapter\/\d+/i,
/^https?:\/\/www\.biqug\.org\/index\.php\/chapter-\d+.html$/i,
/^https?:\/\/(wap|shouji)\.veryim\.com\/\w+\/\d+\/\d+\.html$/i,
/^https?:\/\/www\.51manhua\.buzz\/chapter\/\d+$/i
],
imgs: (dom = document) => fn.getImgSrcArr(".comic-page img,img[data-src],img[data-original]", dom),
autoDownload: [0],
next: async () => {
if (/www\.mhua5\.com|www\.mh5\.xyz|www\.umh5\.com|www\.mhw\d\.com|www\.biqug\.org|(www\.)?51manhua\.buzz/.test(fn.lh)) {
let next = fn.attr(".next-chapter", "_href");
return next !== "" ? location.origin + next : null;
} else if (/m\.mkzhan\.com/.test(fn.lh)) {
await fn.waitEle(".next-chapter[data-href]", 10)
let next = fn.ge(".next-chapter").dataset.href;
return next !== "" || next != 0 ? location.origin + next : null;
} else {
let next = fn.ge("//a[text()='下一章']");
return next ? next.href : null;
}
},
prev: 1,
customTitle: (dom = document) => {
if (/www\.mhua5\.com|www\.mh5\.xyz/.test(fn.lh)) {
return fn.title(" - 漫画屋", 0, dom).replace("-", " - ");
} else if (/m\.mkzhan\.com/.test(fn.lh)) {
return fn.title(" - 漫客栈", 0, dom).trim();
} else if (/www\.umh5\.com|www\.mhw\d\.com|www\.biqug\.org|m\.cuiman\.com|(www\.)?51manhua\.buzz/.test(fn.lh)) {
return _unsafeWindow.shareArr[0].match(/《([^》]+)/)[1] + " - " + fn.gt(".comic-name", 1, dom);
} else {
return fn.title(/下拉|在线/, 1, dom).trim().replace("-", " - ");
}
},
preloadNext: (nextDoc, obj) => fn.iframeDoc(nextLink, ".comic-page img,img[data-src],img[data-original],canvas[data-src]", 30000).then(nextIframeDoc => fn.picPreload(obj.imgs(nextIframeDoc), obj.customTitle(nextIframeDoc), "next")),
hide: "body>ins,#mainView>.read,.chapter-end .read,#chapter1,#chapter3,.cnt-4,.comic-list a,.chapter-end>a,div[style^=height],body>div[id][style]:has(>div[style]),.comic-list>div[id][style]:has(>div[style]),#mainView>div[id][style]:has(>div[style]),.chapter-end>div[id][style]:has(>div[style])",
category: "comic"
}, {
name: "韩漫天堂/猪猪漫画",
url: {
h: ["www.hmttmh.com", "cn.zhuzhumh.com", "w226.npdn.top", "w323.npdn.top"],
p: "/chapter/",
i: 0
},
cors: true,
init: async () => {
await fn.waitVar("newImgs");
_unsafeWindow.newImgs = [];
},
box: ["#comicContain", 2],
imgs: (dom = document) => {
let code = fn.gst("newImgs", dom);
let newImgsCode = fn.parseCode(code);
newImgsCode = fn.stringSlicer(newImgsCode, "newImgs=", "Utf8))");
let newImgsArr = fn.run(newImgsCode);
return newImgsArr;
},
button: [4],
insertImg: [
["box", 0, "#comicContain"], 2
],
autoDownload: [0],
next: "a:has(>img[alt=下一章])",
prev: "a:has(>img[alt=上一章])",
chapters: () => {
let url = fn.gu(".view_exit_logo");
let chapters = [];
return fn.xhrDoc(url).then(dom => {
chapters = fn.gae(".cy_plist a", dom).map(a => ({
text: a.innerText.trim(),
url: a.href
}));
let more_e = fn.ge("#zhankai", dom);
if (more_e) {
let origin = new URL(url).origin;
let {
id,
vid
} = more_e.dataset;
let api = `${origin}/api/bookchapter?id=${id}&id2=${vid}`;
return fn.xhr(api, {
responseType: "json"
}).then(array => {
let dir = fn.dir(fn.url);
let more = array.map(({
chapterid,
chaptername
}) => ({
text: chaptername,
url: `${dir}${chapterid}.html`
}));
chapters = [...chapters, ...more];
return chapters.reverse();
});
}
return chapters.reverse();
});
},
customTitle: (dom = document) => fn.ge("meta[itemprop=name]", dom)?.content + " - " + fn.ge("meta[itemprop=chaptername]", dom)?.content,
preloadNext: true,
infiniteScroll: true,
//css: "#FullPictureLoadMainImgBox{max-width: 800px;}",
category: "comic"
}, {
name: "韩漫天堂/猪猪漫画 自動翻頁",
url: {
h: ["www.hmttmh.com", "cn.zhuzhumh.com", "w226.npdn.top", "w323.npdn.top"],
p: "/chapter/",
e: "#comicContain",
i: 1
},
cors: true,
getSrcs: (dom) => {
let code = fn.gst("newImgs", dom);
let newImgsCode = fn.parseCode(code);
newImgsCode = fn.stringSlicer(newImgsCode, "newImgs=", "Utf8))");
return fn.run(newImgsCode);
},
getImgs: (dom = document) => {
let srcs = _this.getSrcs(dom);
return fn.createImgArray(srcs);
},
init: async () => {
await fn.waitVar("newImgs");
_unsafeWindow.newImgs = [];
let tE = fn.createImgBox("#comicContain", 2);
fn.remove("#comicContain");
let imgs = _this.getImgs();
fragment.append(...imgs);
tE.append(fragment);
await fn.lazyload();
},
autoPager: {
ele: (dom) => _this.getImgs(dom),
pos: ["#FullPictureLoadMainImgBox", 0],
observer: "#FullPictureLoadMainImgBox>img",
next: (dom) => {
let next = fn.ge("a:has(>img[alt=下一章])", dom);
if (next) {
let [, nextId] = next.href.match(/(\d+)\.html$/);
return fn.lp.replace(/(\d+)(\.html)$/, `${nextId}$2`);
} else {
return null;
}
},
re: ".main_control",
title: (dom) => fn.ge("meta[itemprop=chaptername]", dom)?.content,
preloadNextPage: 1
},
category: "comic autoPager"
}, {
name: "韩漫天堂M/猪猪漫画M",
url: {
h: ["www.hmttmh.com", "cn.zhuzhumh.com", "w226.npdn.top", "w323.npdn.top"],
p: "/chapter/",
i: 0
},
cors: true,
box: ["#mainView_img", 2],
imgs: (dom = document) => {
let code = fn.gst("original", dom);
code = fn.parseCode(code);
return code.match(/https?:\/\/[^/]+\/\w+\/\d+\/[\w-]+\.\w+/gi);
},
button: [4],
insertImg: [
["box", 0, "#mainView_img"], 2
],
insertImgAF: () => {
const $ = _unsafeWindow.jQuery;
$("#FullPictureLoadMainImgBox").click(() => {
$(".reader-footer").fadeToggle(300);
$(".van-nav-bar").fadeToggle(300);
});
},
autoDownload: [0],
next: ".end-itm.next>a",
prev: ".end-itm.prev>a",
customTitle: (dom = document) => fn.ge("#mainView_img img", dom)?.alt?.replace("-图1", ""),
preloadNext: true,
infiniteScroll: true,
fancybox: {
blacklist: 1
},
category: "comic"
}, {
name: "韩漫天堂M/猪猪漫画M 自動翻頁",
url: {
h: ["www.hmttmh.com", "cn.zhuzhumh.com", "w226.npdn.top", "w323.npdn.top"],
p: "/chapter/",
e: "#mainView_img",
i: 1
},
cors: true,
getSrcs: (dom) => {
let code = fn.gst("original", dom);
code = fn.parseCode(code);
return code.match(/https?:\/\/[^/]+\/\w+\/\d+\/[\w-]+\.\w+/gi);
},
getImgs: (dom = document) => {
let srcs = _this.getSrcs(dom);
return fn.createImgArray(srcs);
},
init: async () => {
const $ = _unsafeWindow.jQuery;
let tE = fn.createImgBox("#mainView_img", 2);
fn.remove("#mainView_img");
let imgs = _this.getImgs();
fragment.append(...imgs);
tE.append(fragment);
$("#FullPictureLoadMainImgBox").click(() => {
$(".reader-footer").fadeToggle(300);
$(".van-nav-bar").fadeToggle(300);
});
await fn.lazyload();
},
autoPager: {
ele: (dom) => _this.getImgs(dom),
pos: ["#FullPictureLoadMainImgBox", 0],
observer: "#FullPictureLoadMainImgBox>img",
next: (dom) => {
let next = fn.ge(".end-itm.next>a", dom);
if (next) {
let [, nextId] = next.href.match(/(\d+)\.html$/);
return fn.lp.replace(/(\d+)(\.html)$/, `${nextId}$2`);
} else {
return null;
}
},
re: ".end-btns",
title: (dom) => fn.ge("meta[itemprop=chaptername]", dom)?.content,
hide: ".comic-recommend",
preloadNextPage: 1
},
category: "comic autoPager"
}, {
name: "Godamanga.ART 英文漫画",
url: {
h: ["godamh.org"],
p: /^\/chapter\/\d+\.html$/i,
i: 0
},
init: async () => {
await fn.waitEle(".touch-manipulation img");
let setdata = JSON.parse(fn.cookie("setdata"));
let {
host,
ms,
cs
} = setdata;
let api = `${host}/chapter/getinfo?m=${ms}&c=${cs}`;
await fn.fetchDoc(api, {
cache: "no-cache"
}).then(dom => {
let obj = {
...fn.ge("#c-imagelist", dom).dataset,
...setdata
};
siteJson = obj;
});
},
imgs: () => fn.gae(".touch-manipulation img"),
button: [4],
insertImg: [".touch-manipulation", 2],
autoDownload: [0],
next: "#nextChapterLink",
prev: "#preChapterLink",
customTitle: () => siteJson.title + " - " + siteJson.ctitle,
preloadNext: (dom) => {
if ("next" in siteJson) {
//let api = `${siteJson.host}/chapter/getcontent?m=${siteJson.ms}&c=${siteJson.next}`;
let api = `${siteJson.host}/chapter/getinfo?m=${siteJson.ms}&c=${siteJson.next}`;
fn.fetchDoc(api, {
cache: "no-cache"
}).then(nextDom => {
let srcs = fn.getImgSrcArr(".touch-manipulation img", nextDom);
fn.picPreload(srcs, siteJson.nextt, "next");
});
}
},
infiniteScroll: true,
category: "comic"
}, {
name: "Godamanga.ART 自動翻頁",
url: {
h: ["godamh.org"],
p: /^\/chapter\/\d+\.html$/i,
i: 1
},
getData: () => {
let setdata = JSON.parse(fn.cookie("setdata"));
let {
host,
ms,
cs
} = setdata;
let api;
if ("next" in siteJson) {
api = `${host}/chapter/getinfo?m=${ms}&c=${siteJson.next}`;
} else {
api = `${host}/chapter/getinfo?m=${ms}&c=${cs}`;
}
return fn.fetchDoc(api, {
cache: "no-cache"
}).then(dom => {
let dataset = {
...fn.ge("#c-imagelist", dom).dataset
};
siteJson = dataset;
globalImgArray = fn.getImgSrcArr(".touch-manipulation img", dom);
customTitle = dataset.title + " - " + dataset.ctitle;
if ("next" in dataset) {
tempNextLink = `${host}/chapter/getinfo?m=${ms}&c=${dataset.next}`;
fn.fetchDoc(tempNextLink, {
cache: "no-cache"
}).then(nextDom => {
let srcs = fn.getImgSrcArr(".touch-manipulation img", nextDom);
fn.picPreload(srcs, dataset.nextt, "next");
});
} else {
tempNextLink = null;
}
});
},
init: async () => {
await _this.getData();
let imgs = fn.createImgArray(globalImgArray);
await fn.waitEle(".touch-manipulation img");
let tE = fn.createImgBox(".touch-manipulation", 2);
await fn.remove(".touch-manipulation");
fragment.append(...imgs);
tE.append(fragment);
await fn.lazyload();
},
autoPager: {
ele: () => fn.createImgArray(globalImgArray),
pos: ["#FullPictureLoadMainImgBox", 0],
observer: "#FullPictureLoadMainImgBox>img",
next: () => tempNextLink,
wait: () => _this.getData(),
title: () => customTitle,
hide: "div.justify-center:has(>.w-full),.pb-14",
history: 0
},
category: "comic autoPager"
}, {
name: "Godamanga.ART 英文漫画",
url: {
h: ["manhuascans.org"],
p: /^\/manga\/[\w-]+\/[\w-]+$/i,
e: "#chapterContent",
i: 0
},
xhrOptions: {
cache: "no-cache"
},
init: async () => await fn.waitEle(".touch-manipulation img"),
imgs: () => fn.gae(".touch-manipulation img"),
button: [4],
insertImg: [".touch-manipulation", 2],
autoDownload: [0],
next: "#nextChapterLink[href^='/manga/']",
prev: "#preChapterLink",
chapters: {
api: () => {
let id = fn.ge("#chapterContent").dataset.ms;
return `/manga/get?mid=${id}&mode=all`;
},
target: "#allchapterlist a",
cb: (t, url, e) => ({
text: e.dataset.ct,
url
})
},
customTitle: (dom = document) => fn.gt("ol.inline-flex>li:nth-child(2) a", 1, dom) + " - " + fn.gt("ol.inline-flex>li:nth-child(3) a", 1, dom),
preloadNext: (dom) => {
let dataE = fn.ge("#chapterContent", dom);
let ms = dataE.dataset.ms;
let cs = dataE.dataset.cs;
let ct = dataE.dataset.ct;
let host = dataE.dataset.host;
let api = `${host}/chapter/getcontent?m=${ms}&c=${cs}`;
fn.fetchDoc(api).then(nextDom => {
let srcs = fn.getImgSrcArr(".touch-manipulation img", nextDom);
fn.picPreload(srcs, ct, "next");
});
},
infiniteScroll: true,
category: "comic"
}, {
name: "Godamanga.ART 英文漫画 自動翻頁",
url: {
h: ["manhuascans.org"],
p: /^\/manga\/[\w-]+\/[\w-]+$/i,
e: "#chapterContent",
i: 1
},
xhrOptions: {
cache: "no-cache"
},
getSrcs: (dom) => {
let dataE = fn.ge("#chapterContent", dom);
let ms = dataE.dataset.ms;
let cs = dataE.dataset.cs;
let host = dataE.dataset.host;
let api = `${host}/chapter/getcontent?m=${ms}&c=${cs}`;
return fn.fetchDoc(api).then(apitDom => fn.getImgSrcArr(".touch-manipulation img", apitDom));
},
getImgs: async (dom = document) => {
let srcs = await _this.getSrcs(dom);
return fn.createImgArray(srcs);
},
init: async () => {
await fn.waitEle(".touch-manipulation img");
let imgs = await _this.getImgs();
let tE = fn.createImgBox(".touch-manipulation", 2);
fn.remove("//div[ins[@class='adsbygoogle']]");
await fn.remove(".touch-manipulation");
fragment.append(...imgs);
tE.append(fragment);
await fn.lazyload();
},
autoPager: {
ele: (dom) => _this.getImgs(dom),
observer: "#FullPictureLoadMainImgBox>img",
pos: ["#FullPictureLoadMainImgBox", 0],
next: "#nextChapterLink[href^='/manga/']",
title: (dom) => fn.ge("#chapterContent", dom).dataset.ct,
history: 0,
hide: "div.justify-center:has(>.w-full),.pb-14",
preloadNextPage: 1
},
category: "comic autoPager"
}, {
name: "GODA漫畫/包子漫畫",
url: {
h: [
"www.cocolamanhua.com",
"n.cocolamanhua.com",
"godamh.com",
"m.godamh.com",
"g-mh.org",
"m.g-mh.org",
"baozimh.org",
"m.baozimh.org",
"baozimh.one",
"m.baozimh.one",
"bzmh.org",
"m.bzmh.org",
"manhuafree.com"
],
p: /^\/manga\/[\w-]+\/[\w-]+$/i,
e: "#chapterContent",
i: 0
},
init: async () => {
fn.addMutationObserver(() => fn.remove("iframe,.bannersUite"));
await fn.waitEle(".touch-manipulation img");
fn.remove(["#noad-button,.absolute,.adshow", "//div[ins[@class='adsbygoogle']]"]);
let chapterDataE = fn.ge("#chapterContent");
let ms = chapterDataE.dataset.ms;
let cs = chapterDataE.dataset.cs;
let api = `https://api-get-v3.mgsearcher.com/api/chapter/getinfo?m=${ms}&c=${cs}`;
let fetchJson = await fetch(api, {
cache: "no-cache"
}).then(res => res.json());
siteJson = fetchJson;
},
imgs: (json = siteJson) => {
let {
line,
images
} = json.data.info.images;
let host = line === 2 ? "https://f40-1-4.g-mh.online" : "https://t40-1-4.g-mh.online";
return images.map(e => host + e.url);
},
button: [4],
insertImg: [".touch-manipulation", 2],
autoDownload: [0],
next: "#nextchaptera[href*='/manga/']",
prev: "#prevchaptera[href*='/manga/']",
chapters: () => {
let chapterDataE = fn.ge("#chapterContent");
let mid = chapterDataE.dataset.ms;
let api = `https://api-get-v3.mgsearcher.com/api/manga/get?mid=${mid}&mode=all`;
return fetch(api).then(res => res.json()).then(json => {
let dir = fn.dir(fn.url);
return json.data.chapters.map(d => {
let {
attributes: {
slug,
title
}
} = d;
return {
text: title,
url: dir + slug
}
});
});
},
customTitle: (json = siteJson) => json.data.info.mangatitle + " - " + json.data.info.title,
preloadNext: () => {
let next = siteJson.data.info?.next;
if (!!next) {
let chapterDataE = fn.ge("#chapterContent");
let ms = chapterDataE.dataset.ms;
let api = `https://api-get-v3.mgsearcher.com/api/chapter/getinfo?m=${ms}&c=${next}`;
fetch(api, {
cache: "no-cache"
}).then(res => res.json()).then(json => {
let srcs = _this.imgs(json);
let text = _this.customTitle(json);
fn.picPreload(srcs, text, "next");
});
}
},
hide: "iframe,.bannersUite,.w-full:has(>amp-ad),#noad-button,.absolute,.adshow",
infiniteScroll: true,
category: "comic"
}, {
name: "GODA漫畫/包子漫畫 自動翻頁",
url: {
h: [
"www.cocolamanhua.com",
"n.cocolamanhua.com",
"godamh.com",
"m.godamh.com",
"g-mh.org",
"m.g-mh.org",
"baozimh.org",
"m.baozimh.org",
"baozimh.one",
"m.baozimh.one",
"bzmh.org",
"m.bzmh.org",
"manhuafree.com"
],
p: /^\/manga\/[\w-]+\/[\w-]+$/i,
e: "#chapterContent",
i: 1
},
getApi: (mode = "current") => {
let chapterDataE = fn.ge("#chapterContent");
let ms = chapterDataE.dataset.ms
let cs = chapterDataE.dataset.cs
if (mode === "next") {
return `https://api-get-v3.mgsearcher.com/api/chapter/getinfo?m=${ms}&c=${siteJson.data.info.next}`;
} else {
return `https://api-get-v3.mgsearcher.com/api/chapter/getinfo?m=${ms}&c=${cs}`;
}
},
getSrcs: (json) => {
let {
line,
images
} = json.data.info.images;
let host = line === 2 ? "https://f40-1-4.g-mh.online" : "https://t40-1-4.g-mh.online";
return images.map(e => host + e.url);
},
getImgs: (json) => {
let srcs = _this.getSrcs(json);
return fn.createImgArray(srcs);
},
init: async () => {
fn.addMutationObserver(() => fn.remove("iframe,.bannersUite,.w-full:has(>amp-ad)"));
await fn.waitEle(".touch-manipulation img");
let api = _this.getApi();
let fetchJson = await fetch(api, {
cache: "no-cache"
}).then(res => res.json());
siteJson = fetchJson;
let imgs = _this.getImgs(fetchJson);
let tE = fn.createImgBox(".touch-manipulation", 2);
fn.remove(["#noad-button,.absolute,.adshow", "//div[ins[@class='adsbygoogle']]"]);
await fn.remove(".touch-manipulation");
fragment.append(...imgs);
tE.append(fragment);
await fn.lazyload();
},
autoPager: {
mode: "json",
ele: (json) => _this.getImgs(json),
observer: "#FullPictureLoadMainImgBox>img",
pos: ["#FullPictureLoadMainImgBox", 0],
next: async () => {
let next = siteJson?.data?.info?.next;
if (!!next) {
return _this.getApi("next");
} else {
return null;
}
},
title: (json) => json.data.info.title,
history: 0,
hide: ".justify-center:has(>.border-t),div:has(>.banners),div:has(>div>.cardlist)",
preloadNextPage: (json) => {
let next = json?.data?.info?.next || siteJson?.data?.info?.next;
if (next) {
let api = _this.getApi("next");
fetch(api, {
cache: "no-cache"
}).then(res => res.json()).then(json => {
let srcs = _this.getSrcs(json);
let text = _this.autoPager.title(json);
fn.picPreload(srcs, text, "next");
});
}
}
},
hide: "iframe,.bannersUite,.w-full:has(>amp-ad),#noad-button,.absolute,.adshow",
category: "comic autoPager"
}, {
name: "ゼロサムオンライン",
url: {
h: "zerosumonline.com"
},
data: () => {
fn.showMsg(DL.str_05, 0);
return fn.fetchDoc(fn.clp()).then(dom => {
let code = fn.gst("decodedChapterId", dom);
let [, id] = code.match(/decodedChapterId[\\\s"':]+(\d+)/);
return fetch(`https://api.zerosumonline.com/api/v1/viewer?chapter_id=${id}`, {
"body": null,
"method": "POST"
}).then(res => res.text()).then(text => (siteJson.data = text) && fn.hideMsg());
});
},
page: () => fn.clp("/episode/"),
SPA: () => _this.page() ? true : (siteJson = {}) && false,
observeURL: "nav",
init: () => _this.page() ? _this.data() : void 0,
imgs: () => _this.page() ? siteJson.data.match(/https?:\/\/\w+\.\w+\.com\/\w+\/\d+\/\d+\.\w+/gi) : [],
capture: () => _this.imgs(),
customTitle: () => {
if (!_this.page()) return null;
let textArr = document.title.split("|");
return textArr[1] + " - " + textArr[0];
},
category: "comic"
}, {
name: "マンガMeets",
url: {
h: "manga-meets.jp",
p: /^\/comics\/[\w-]+\/\d+$/i
},
init: () => {
let [, , mid, cid] = fn.lp.split("/");
let res_a = fetch(`/api/comics/${mid}/episodes.json`).then(res => res.json());
let res_b = fetch(`/api/comics/${mid}/episodes/${cid}/viewer.json`).then(res => res.json());
return Promise.all([res_a, res_b]).then(([a, b]) => {
siteJson = {
chapters: a.data,
...b
};
});
},
imgs: () => siteJson.episode_pages.map(e => e.image.original_url.replace("f_auto", "w_1080")),
capture: () => _this.imgs(),
next: () => {
let [, , mid, cid] = fn.lp.split("/");
let {
chapters,
sort_volume
} = siteJson;
if (chapters[sort_volume]?.id) {
return `/comics/${mid}/${(Number(cid) + 1)}`;
}
return null;
},
prev: 1,
customTitle: () => {
let {
comic: {
title
},
volume
} = siteJson;
return title + " - " + volume;
},
category: "comic"
}, {
name: "アルファポリス",
url: {
h: "www.alphapolis.co.jp",
p: /^\/manga\/official\/\d+\/\d+$/,
d: "pc"
},
init: () => fn.fetchDoc(fn.lp).then(dom => (doc = dom)),
imgs: () => {
let data = fn.attr("viewer-manga-horizontal", "v-bind:pages", doc);
let array = JSON.parse(data);
let srcs = array.filter(isString).filter(src => !src.includes("/white_page/"));
return srcs.map(e => e.replace(/\d+x\d+\.jpg/, "1080x1536.jpg"));
},
capture: () => _this.imgs(),
current: () => {
let menu = fn.ge("template", doc).content;
let episodes = fn.gae("template", menu).map(t => fn.gae(".episode-unit", t.content)).flat();
let cid = fn.lp.split("/").at(-1);
let c_episode = episodes.find(e => e.dataset.order == cid);
return c_episode;
},
next: () => {
let next = _this.current()?.previousElementSibling;
return next ? fn.dir(fn.lp) + next.dataset.order : null;
},
prev: () => {
let prev = _this.current()?.nextElementSibling;
return prev ? fn.dir(fn.lp) + prev.dataset.order : null;
},
customTitle: () => {
let menu = fn.ge("template", doc).content;
let tag = fn.ge("menu-official-content", menu);
return fn.attr(tag, "manga-title") + " - " + fn.attr(tag, "episode-title");
},
category: "comic"
}, {
name: "GANMA!(ガンマ)",
url: {
h: ["ganma.jp"]
},
page: () => fn.clp("/reader/"),
json: () => fn.showMsg(DL.str_05, 0).then(() => fn.fetchDoc(fn.clp()).then(dom => {
let textArr = dom.title.split(" - ");
customTitle = textArr[0] + " - " + fn.gt("h1.text-ellipsis", 1, dom);
let text = fn.gst("singleModeDisplayUnits", dom).replaceAll("\\", "");
siteJson.images = fn.TextToArray(text, '"singleModeDisplayUnits":');
fn.hideMsg();
})),
SPA: () => _this.page() ? true : (siteJson = {}) && false,
observeURL: "gm",
init: () => _this.page() ? _this.json() : void 0,
imgs: () => _this.page() ? siteJson.images.map(e => e.url.replaceAll("u0026", "&")) : [],
capture: () => _this.imgs(),
autoDownload: [0],
next: "//a[div[span[text()='次話']]]",
prev: 1,
category: "comic"
}, {
name: "ガンガンONLINE",
url: {
h: ["www.ganganonline.com"]
},
page: () => fn.clp("/chapter/"),
json: () => fn.showMsg(DL.str_05, 0).then(() => fn.fetchDoc(fn.clp()).then(dom => {
let code = fn.gst("pageProps", dom);
siteJson = JSON.parse(code);
})).then(() => fn.hideMsg()),
SPA: () => _this.page(),
observeURL: "head",
init: () => _this.page() ? _this.json() : void 0,
imgs: () => {
if (_this.page()) {
return siteJson.props.pageProps.data.pages.filter(obj => {
if (isObject(obj)) {
return ("image" in obj);
}
return false;
}).map(e => e.image.imageUrl);
}
return [];
},
capture: () => _this.imgs(),
autoDownload: [0],
next: () => {
if (_this.page()) {
let {
page,
props: {
pageProps: {
data: {
lastPage: {
nextChapterId
}
}
},
titleId
}
} = siteJson;
if (isNumber(nextChapterId)) {
page = page.replace("[titleId]", titleId);
page = page.replace("[chapterId]", nextChapterId);
return page;
}
return null;
}
return null;
},
prev: 1,
customTitle: () => {
if (_this.page()) {
let {
titleName,
chapterName
} = siteJson.props.pageProps.data;
return titleName + " - " + chapterName;
}
return null;
},
category: "comic"
}, {
name: "コミックDAYS 格式",
url: {
h: [
"comic-days.com",
"shonenjumpplus.com",
"kuragebunch.com",
"www.sunday-webry.com",
"tonarinoyj.jp",
"comic-gardo.com",
"comic-zenon.com",
"comic-trail.com",
"comic-action.com",
"magcomi.com",
"viewer.heros-web.com",
"feelweb.jp",
"comicborder.com",
"comic-ogyaaa.com",
"comic-earthstar.com",
"comic-seasons.com"
]
},
data: () => {
fn.showMsg(DL.str_05, 0);
return fn.fetchDoc(fn.clp()).then(dom => {
let json = JSON.parse(fn.ge("#episode-json", dom).dataset.value);
siteJson = json.readableProduct;
debug("\n此頁JSON資料\n", siteJson);
fn.hideMsg();
});
},
page: () => fn.clp("/episode/"),
SPA: () => _this.page(),
observeURL: "head",
init: () => _this.page() ? _this.data() : void 0,
imgs: async () => {
if (!_this.page() || !siteJson?.pageStructure?.pages) return [];
let urls = siteJson.pageStructure.pages.filter(obj => {
if (isObject(obj)) {
return ("src" in obj);
}
return false;
}).map(e => e.src);
let [url] = urls;
if (
url.includes("/original/") ||
isM && ["viewer.heros-web.com", "feelweb.jp"].some(h => fn.lh === h)
) {
return urls;
}
fn.showMsg(DL.str_53, 0);
let arr = [];
let fetchNum = 0;
for (const [index, url] of urls.entries()) {
let getRedraw = new Promise(async resolve => {
let error = false;
const blob = await fetch(url).then(res => res.blob());
const img = new Image();
await new Promise(load => {
img.onload = load;
img.onerror = () => {
error = true;
resolve(null);
}
img.src = URL.createObjectURL(blob);
});
if (error) return;
const imgWidth = img.naturalWidth;
const imgHeight = img.naturalHeight;
const canvas = new OffscreenCanvas(imgWidth, imgHeight);
const canvas_2d = canvas.getContext("2d");
const DIVIDE_NUM = 4;
const MULTIPLE = 8;
const cellWidth = Math.floor(canvas.width / (DIVIDE_NUM * MULTIPLE)) * MULTIPLE;
const cellHeight = Math.floor(canvas.height / (DIVIDE_NUM * MULTIPLE)) * MULTIPLE;
for (let e = 0; e < DIVIDE_NUM * DIVIDE_NUM; e++) {
const t = Math.floor(e / DIVIDE_NUM) * cellHeight;
const i = e % DIVIDE_NUM * cellWidth;
const r = Math.floor(e / DIVIDE_NUM);
const n = e % DIVIDE_NUM * DIVIDE_NUM + r;
const s = n % DIVIDE_NUM * cellWidth;
const o = Math.floor(n / DIVIDE_NUM) * cellHeight;
canvas_2d.drawImage(img, i, t, cellWidth, cellHeight, s, o, cellWidth, cellHeight);
}
URL.revokeObjectURL(img.src);
canvas.convertToBlob({
type: blob.type,
quality: 0.9
}).then(blob => {
fn.showMsg(`DrawImage ${fetchNum+=1}/${urls.length}`, 0);
resolve(URL.createObjectURL(blob));
});
});
arr.push(getRedraw);
await delay(100);
}
return arr;
},
capture: () => _this.imgs(),
autoDownload: [0],
next: () => {
if (!_this.page()) return null;
let next = siteJson?.nextReadableProductUri;
return next ? next : null;
},
prev: 1,
customTitle: () => {
if (!_this.page()) return null;
let {
series: {
title: m
},
title: c
} = siteJson
return (m == c) ? m : m + " - " + c;
},
category: "comic"
}, {
name: "ヤンチャンWeb 格式",
url: {
h: [
"youngchampion.jp",
"younganimal.com",
"bigcomics.jp",
"comicride.jp",
"kansai.mag-garden.co.jp",
"championcross.jp",
"comic.j-nbooks.jp",
"comic-growl.com",
"comicpash.jp",
"rimacomiplus.jp"
],
p: "/episodes/"
},
init: async () => {
let viewer = await fn.waitEle("#comici-viewer[comici-viewer-id]");
let id = fn.attr("#comici-viewer", "comici-viewer-id");
let apiDomain = viewer.dataset.apiDomain;
let res_a = fetch(`https://${apiDomain}/book/Info?comici-viewer-id=${id}`).then(res => res.json());
let res_b = fetch(`https://${apiDomain}/book/episodeInfo?comici-viewer-id=${id}`).then(res => res.json());
return Promise.all([res_a, res_b]).then(([res_a, res_b]) => {
siteJson = {
...res_a.result,
apiDomain,
chapters: res_b.result,
chapter: res_b.result.find(e => e.id === id)
};
debug("\n此頁JSON資料\n", siteJson);
});
},
imgs: async () => {
let userId = fn.gt("#login_user_id") || "0";
let {
id,
apiDomain,
chapter: {
page_count
}
} = siteJson
const pages = await fetch(`https://${apiDomain}/book/contentsInfo?user-id=${userId}&comici-viewer-id=${id}&page-from=0&page-to=${page_count}`).then(res => res.json()).then(json => json.result);
fn.showMsg(DL.str_53, 0);
let arr = [];
let fetchNum = 0;
for (const [index, page] of pages.entries()) {
let getRedraw = new Promise(async resolve => {
let error = false;
const {
imageUrl,
scramble,
height,
width
} = page;
const blob = await fetch(imageUrl).then(res => res.blob());
const img = new Image();
await new Promise(load => {
img.onload = load;
img.onerror = () => {
error = true;
resolve(null);
}
img.src = URL.createObjectURL(blob);
});
if (error) return;
const imgWidth = img.naturalWidth;
const imgHeight = img.naturalHeight;
const canvas = new OffscreenCanvas(imgWidth, imgHeight);
const canvas_2d = canvas.getContext("2d");
const dict = [];
const dictTemplete = JSON.parse("[[0,0],[0,1],[0,2],[0,3],[1,0],[1,1],[1,2],[1,3],[2,0],[2,1],[2,2],[2,3],[3,0],[3,1],[3,2],[3,3]]");
const scrambleOrders = JSON.parse(scramble);
for (let i = 0; i < dictTemplete.length; i++) {
dict.push(dictTemplete[scrambleOrders[i]]);
}
const pieceWidth = Math.floor(width / 4);
const pieceHeight = Math.floor(height / 4);
let dictCounter = 0;
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
const x = dict[dictCounter][0];
const y = dict[dictCounter][1];
canvas_2d.drawImage(img, pieceWidth * x, pieceHeight * y, pieceWidth, pieceHeight, pieceWidth * i, pieceHeight * j, pieceWidth, pieceHeight);
dictCounter++;
}
}
URL.revokeObjectURL(img.src);
canvas.convertToBlob({
type: blob.type,
quality: 0.9
}).then(blob => {
fn.showMsg(`DrawImage ${fetchNum+=1}/${pages.length}`, 0);
resolve(URL.createObjectURL(blob));
});
});
arr.push(getRedraw);
await delay(100);
}
return arr;
},
capture: () => _this.imgs(),
customTitle: () => {
let {
title,
chapter: {
name
}
} = siteJson;
return title + " - " + name;
},
category: "comic"
}, {
name: "WEBコミックガンマぷらす 格式",
url: {
h: [
"gammaplus.takeshobo.co.jp",
"storia.takeshobo.co.jp",
"webcomicgamma.takeshobo.co.jp",
"comic-meteor.jp",
"www.comic-valkyrie.com",
"comic-polaris.jp",
"televikun-super-hero-comics.com"
],
p: ["/_files/", "/ptdata/", "/samplebook/", "/rensai/"]
},
imgs: async () => {
fn.showMsg(DL.str_05, 0);
const baseURL = fn.url;
const datas = await fetch(fn.url).then(res => res.text()).then(text => {
let urls = text.match(/data\/\d+\.ptimg\.json/gm).map(json => baseURL + json);
let resArr = urls.map(url => fetch(url).then(res => res.json()));
return Promise.all(resArr);
});
fn.showMsg(DL.str_53, 0);
let arr = [];
let fetchNum = 0;
for (const [index, data] of datas.entries()) {
let getRedraw = new Promise(async resolve => {
let error = false;
const {
resources,
views
} = data;
const img = new Image();
await new Promise(load => {
img.onload = load;
img.onerror = () => {
error = true;
resolve(null);
}
img.src = `${baseURL}data/${resources.i.src}`;
});
if (error) return;
const imgWidth = views[0].width;
const imgHeight = views[0].height;
const canvas = new OffscreenCanvas(imgWidth, imgHeight);
const canvas_2d = canvas.getContext("2d");
const coords = views[0].coords.map(coord => {
const items = coord.match(/^([^:]+):(\d+),(\d+)\+(\d+),(\d+)>(\d+),(\d+)$/).map(Number);
return items.slice(2);
});
for (const [srcX, srcY, width, height, destX, destY] of coords) {
canvas_2d.drawImage(img, srcX, srcY, width, height, destX, destY, width, height);
}
URL.revokeObjectURL(img.src);
canvas.convertToBlob({
type: "image/jpeg",
quality: 0.9
}).then(blob => {
fn.showMsg(`DrawImage ${fetchNum+=1}/${datas.length}`, 0);
resolve(URL.createObjectURL(blob));
});
});
arr.push(getRedraw);
await delay(100);
}
return arr;
},
capture: () => _this.imgs(),
category: "comic"
}, {
name: "COMICリュウ",
url: {
h: ["www.comic-ryu.jp", "unicorn.comic-ryu.jp"],
p: /^\/\d+\/$/
},
imgs: () => fn.waitEle([".m-viewer-page-comic-img"]),
capture: () => _this.imgs(),
autoDownload: [0],
next: async () => {
await fn.waitEle(".m-viewer .m-viewer-page-comic-img");
let next = fn.ge(".is-link-next");
return next ? next.href : null;
},
prev: 1,
customTitle: [".m-viewer .sakuhin-article-title", ".m-viewer-title"],
gallery: 1,
category: "comic"
}, {
name: "マンガボックス",
url: {
h: "www.mangabox.me",
p: "/reader/"
},
imgs: () => fn.waitEle([".slides img:not(.link_page_image)"]).then(imgs => {
if (isM) {
return imgs.reverse();
}
return imgs;
}),
capture: () => _this.imgs(),
autoDownload: [0],
next: ".lastSlider_nextButton",
prev: 1,
customTitle: () => fn.waitEle("header h2,.episode_header_title").then(e => fn.gt(e)),
category: "comic"
}, {
name: "コミチ",
url: {
h: ["comici.jp"],
p: "/episodes/"
},
imgs: ".manga-area img[id][alt]",
autoDownload: [0],
next: ".mode-next a.ep-f-nav-link",
prev: ".mode-prev a.ep-f-nav-link",
customTitle: [".a-series-title", ".title-line2"],
category: "comic"
}, {
name: "少年エースplus",
url: {
h: ["web-ace.jp"],
p: "/episode/"
},
imgs: () => fetch(fn.lp + "json").then(res => res.json()),
capture: () => _this.imgs(),
autoDownload: [0],
next: ".viewerbtn_toNext a",
prev: ".viewerbtn_toBack a",
customTitle: ["#viewerPc h2", "#viewerPc span"],
category: "comic"
}, {
name: "やわらかスピリッツ",
url: {
h: ["yawaspi.com"],
p: "/comic/"
},
imgs: () => fn.waitEle([".vertical__inner ul li img"]),
capture: () => _this.imgs(),
autoDownload: [0],
next: "a.-next",
prev: "a.-prev",
customTitle: ["header h2", "header h3"],
category: "comic"
}, {
name: "Comic Top",
url: {
h: "comic-top.com",
p: "/viewer/",
s: "cid="
},
imgs: () => {
let code = fn.gst("chapter");
let [, text] = code.match(/chapter[\s=]+({[^;]+)/);
let json = JSON.parse(text);
return Object.values(json).map(e => e.image);
},
capture: () => _this.imgs(),
customTitle: [".manga-title", ".manga-episode"],
category: "comic"
}, {
name: "漫畫屋",
enable: 0,
url: {
h: "mh5.tw",
p: /^\/(series|seriesvip)-\w+-\d+-\d+/
},
imgs: () => {
let max;
/seriesvip/.test(siteUrl) ? max = fn.gt("a.cur~a:last-child") - 2 : max = fn.gt("a.cur~a:last-child") - 1;
return fn.getImgIframe(".ptview>img[alt]:not([style])", max, 13, ".setnmh-pagedos", 1000, 0);
},
insertImg: [".ptview", 1, 0],
autoDownload: [0],
next: "//a[text()='下一話']",
prev: "//a[text()='上一話']",
customTitle: () => {
let ele = fn.ge("h2");
return ele ? fn.gt("h1") + " - " + fn.gt("h2") : fn.gt(".setnmh-bookname>a:nth-child(5)") + " - " + fn.gt(".setnmh-bookname>a:nth-child(7)");
},
css: ".ptview>img{width:100%!important;height:auto!important;max-width:1000px!important;border:none!important;box-shadow:none!important;padding:0!important;margin:0 auto!important}",
category: "comic"
}, {
name: "山立漫畫/TVBS漫畫",
enable: 0,
url: {
h: ["www.setnmh.com", "www.tvbsmh.com"],
p: /^\/(series|seriesvip)-\w+-\d+-\d+-.+$/
},
imgs: () => {
let max;
/seriesvip/.test(siteUrl) ? max = fn.gt("a.cur~a:last-child") - 2 : max = fn.gt("a.cur~a:last-child") - 1;
return fn.getImgIframe(".ptview>img[alt]:not([style])", max, 13, ".setnmh-pagedos,.pagedosw", 1000, 0);
},
insertImg: [".ptview", 1, 0],
autoDownload: [0],
next: "//a[text()='下一話']",
prev: "//a[text()='上一話']",
customTitle: () => document.title.split(" - ")[0].replace(/正在觀看|(\d+P)/ig, "").replace(">", " - "),
css: ".ptview>img{width:100%!important;height:auto!important;max-width:1000px!important;border:none!important;box-shadow:none!important;padding:0!important;margin:0 auto!important}",
category: "comic"
}, {
name: "如漫画/读漫屋",
host: ["www.rumanhua.com", "rumanhua.com", "m.rumanhua.com", "www.rumanhua1.com", "rumanhua1.com", "m.rumanhua1.com", "www.dumanwu.com", "dumanwu.com", "m.dumanwu.com", "www.dumanwu1.com", "dumanwu1.com", "m.dumanwu1.com"],
url: {
h: [/rumanhua\d?\.com$/, /dumanwu\d?\.com$/],
p: /^\/\w+\/\w+\.html$/i,
st: "__c0rst96",
i: 0
},
init: () => fn.waitEle(".main_img img[data-src]"),
imgs: (dom = document) => fn.getImgSrcArr(".main_img img", dom),
button: [4],
insertImg: [".main_img", 2],
endColor: () => ["dumanwu.com", "m.dumanwu.com"].some(h => fn.lh === h) ? "white" : "black",
autoDownload: [0],
next: "a[href$=html]:has(>.folat-next1),a[href$=html]:has(>.i-rd-next)",
prev: "a[href$=html]:has(>.folat-prev1),a[href$=html]:has(>.i-rd-prev)",
chapters: () => {
let a = fn.ge(".headwrap a[title]~a[title],.chaphead-name a");
let chapters = [];
return fn.fetchDoc(a).then(dom => {
chapters = fn.gae(".chapterlistload a,.chaplist-box a", dom).map(a => ({
text: a.innerText.trim(),
url: a.href
}));
if (fn.ge(".chaplist-more", dom)) {
let [, id] = a.pathname.split("/");
return fetch("/morechapter", {
"headers": {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8"
},
"body": `id=${id}`,
"method": "POST"
}).then(res => res.json()).then(json => {
let more = json.data.map(({
chapterid,
chaptername
}) => ({
text: chaptername,
url: `${a.href}${chapterid}.html`
}));
chapters = [...chapters, ...more];
return chapters.reverse();
});
}
return chapters.reverse();
});
},
customTitle: (dom = document) => {
let text = fn.dt({
t: dom.title,
d: ["漫画 - 如漫画", "漫画 - 读漫屋"]
});
let textArr = text.split("_");
return textArr[1] + " - " + textArr[0];
},
frame: ".main_img img[data-src]",
preloadNext: true,
infiniteScroll: true,
category: "comic"
}, {
name: "如漫画/读漫屋 自動翻頁",
url: {
h: [/rumanhua\d?\.com$/, /dumanwu\d?\.com$/],
p: /^\/\w+\/\w+\.html$/i,
st: "__c0rst96",
i: 1
},
getSrcs: (dom) => fn.getImgSrcArr(".main_img img", dom),
getImgs: (dom = document) => fn.createImgArray(_this.getSrcs(dom)),
init: async () => {
await fn.waitEle(".main_img img[data-src]");
let imgs = _this.getImgs();
let tE = fn.ge(".main_img");
tE.innerHTML = "";
fragment.append(...imgs);
tE.append(fragment);
await fn.lazyload();
},
autoPager: {
mode: 1,
waitEle: ".main_img img[data-src]",
ele: (dom) => _this.getImgs(dom),
pos: [".main_img", 0],
observer: ".main_img>img",
next: "a[href$=html]:has(>.folat-next1),a[href$=html]:has(>.i-rd-next)",
re: ".footer-right>a,.main_control,.chaphead,.chapter-end,.chap-footer",
title: (dom) => {
let text = fn.dt({
t: dom.title,
d: " - 如漫画"
});
let textArr = text.split("_");
if (isM) {
return textArr[0];
} else {
return textArr[1] + " - " + textArr[0];
}
},
hide: ".mults,.like-more",
preloadNextPage: 1
},
hide: "a:has(>.end-novel)",
category: "comic autoPager"
}, {
name: "D漫画",
url: {
h: "www.dmanhua.com",
p: "/chapter/",
i: 0
},
imgs: (dom = document) => {
let code = fn.gst("pasd", dom);
let [num] = code.match(/\d+/);
let [, pasd] = code.match(/pasd[\s="]+([^"]+)/);
return fn.arr(num, (v, i) => pasd + (i + 1) + ".webp");
},
button: [4],
insertImg: [".images", 2],
autoDownload: [0],
next: "#nextChapter[href]",
prev: "//a[contains(@class,'nav-button')][contains(text(),'上')]",
chapters: () => {
let a = fn.ge("//a[text()='目录']");
let chapters = [];
return fn.fetchDoc(a).then(dom => {
let more_e = fn.ge(".load-more .button", dom);
if (more_e) {
let [id] = a.pathname.split("/").at(-1).match(/\d+/);
return fetch(`/comic/${id}`, {
"headers": {
"content-type": "application/json"
},
"body": "{}",
"method": "POST"
}).then(res => res.json()).then(json => {
let dir = fn.dir(fn.url);
chapters = json.data.chapters.map(({
chapterName,
contentId,
id
}) => ({
text: chapterName,
url: `${dir}${contentId}-${id}.html`
}));
return chapters.reverse();
});
}
chapters = fn.gae(".chapter-list a", dom).map(a => ({
text: a.innerText.trim(),
url: a.href
}));
return chapters.reverse();
});
},
customTitle: (dom = document) => {
let textArr = fn.ge("meta[name=keywords]", dom).content.replaceAll("\n", "").split(",");
return textArr[0] + " - " + textArr[1];
},
preloadNext: true,
infiniteScroll: true,
hide: "body>div[class][style^='position:fixed;']",
category: "comic"
}, {
name: "D漫画 自動翻頁",
url: {
h: "www.dmanhua.com",
p: "/chapter/",
i: 1
},
getSrcs: (dom = document) => {
let code = fn.gst("pasd", dom);
let [num] = code.match(/\d+/);
let [, pasd] = code.match(/pasd[\s="]+([^"]+)/);
return fn.arr(num, (v, i) => pasd + (i + 1) + ".webp");
},
getImgs: (dom = document) => {
let srcs = _this.getSrcs(dom);
return fn.createImgArray(srcs);
},
init: async () => {
let imgs = _this.getImgs();
let tE = fn.ge(".images");
tE.innerHTML = "";
fragment.append(...imgs);
tE.append(fragment);
await fn.lazyload();
},
autoPager: {
ele: (dom) => _this.getImgs(dom),
pos: [".images", 0],
observer: ".images>img",
next: "#nextChapter[href]",
re: "#leftNav,#rightNav,.footer-toolbar",
title: (dom) => {
let textArr = fn.ge("meta[name=keywords]", dom).content.replaceAll("\n", "").split(",");
if (isM) {
return textArr[1];
} else {
return textArr[0] + " - " + textArr[1];
}
},
preloadNextPage: 1
},
css: ".autoPagerTitle{width:100%}",
hide: "body>div[class][style^='position:fixed;']",
category: "comic autoPager"
}, {
name: "D漫画 AD",
url: {
h: "www.dmanhua.com"
},
hide: "body>div[class][style^='position:fixed;']",
category: "ad"
}, {
name: "漫画网",
host: ["www.manhua3.com"],
url: {
e: ["div.logo>a[title=漫画网]>img[alt=漫画网]", "#pics"],
p: /^\/[\d-]+\.html$/,
i: 0
},
box: ["#pics", 1],
imgs: (frame = _unsafeWindow) => frame.params.images,
button: [4],
insertImg: [
["box", 0, "#pics"], 2
],
autoDownload: [0],
next: "//a[text()='下一章'][starts-with(@href,'/')]",
prev: "//a[text()='上一章'][starts-with(@href,'/')]",
chapters: {
url: "//a[text()='返回详情']",
mode: "g",
target: ".module-play-list-content a"
},
customTitle: (dom = document) => fn.dt({
t: dom.title,
d: "在线阅读-漫画网"
}).replace("_", " - "),
preloadNext: (nextDoc, obj) => {
fn.iframeVar(nextLink, "params").then(w => {
let srcs = obj.imgs(w);
fn.picPreload(srcs, obj.customTitle(nextDoc), "next");
});
},
infiniteScroll: true,
mcss: ".main{padding:20px 0px 0!important}",
category: "comic"
}, {
name: "漫画网 自動翻頁",
url: {
e: ["div.logo>a[title=漫画网]>img[alt=漫画网]", "#pics"],
p: /^\/[\d-]+\.html$/,
i: 1
},
getSrcs: () => frameWindow.params.images,
getImgs: () => fn.createImgArray(_this.getSrcs()),
init: async () => {
let imgs = _this.getImgs();
let tE = fn.createImgBox("#pics", 1);
fragment.append(...imgs);
tE.append(fragment);
fn.remove("#pics");
await fn.lazyload();
},
autoPager: {
mode: 1,
waitEle: "#pics img",
ele: () => _this.getImgs(),
pos: ["#FullPictureLoadMainImgBox", 0],
observer: "#FullPictureLoadMainImgBox>img",
next: "//a[text()='下一章'][starts-with(@href,'/')]",
re: ".btn.paediy",
title: (dom) => {
let text = fn.dt({
t: dom.title,
d: "在线阅读-漫画网"
});
if (isM) {
return text.split("_")[1];
} else {
return text.replace("_", " - ");
}
},
preloadNextPage: 1
},
mcss: ".main{padding:20px 0px 0!important}",
category: "comic autoPager"
}, {
name: "36漫画",
url: {
h: "www.36mh.org",
p: /^\/manhua\/[\d-]+\.html$/,
d: "pc"
},
box: ["#images", 1],
imgs: (frame = _unsafeWindow) => frame.params.images,
button: [4, "24%", 3],
insertImg: [
["box", 0, "#images"], 2
],
autoDownload: [0],
next: "a[href$=html]:has(>img[alt=下一章])",
prev: "a[href$=html]:has(>img[alt=上一章])",
chapters: {
url: "a:has(img[alt=目录])",
target: "#chapterlistload a"
},
customTitle: (dom = document) => {
let text = fn.dt({
t: dom.title,
d: "漫画-36漫画"
});
let textArr = text.split("_");
return textArr[1] + " - " + textArr[0];
},
preloadNext: (nextDoc, obj) => {
fn.iframeVar(nextLink, "params").then(w => {
let srcs = obj.imgs(w);
fn.picPreload(srcs, obj.customTitle(nextDoc), "next");
});
},
category: "comic"
}, {
name: "36漫画M",
url: {
h: "m.36mh.org",
p: /^\/manhua\/[\d-]+\.html$/,
d: "m"
},
box: ["#cp_img", 1],
imgs: (frame = _unsafeWindow) => frame.params.images,
button: [4, "24%", 3],
insertImg: [
["box", 0, "#cp_img"], 2
],
autoDownload: [0],
next: "//li[p[text()='下一章']]/a",
prev: "//li[p[text()='上一章']]/a",
chapters: {
url: "//li[p[text()='章节']]/a",
target: ".chapterList a"
},
customTitle: (dom = document) => {
let text = fn.dt({
t: dom.title,
d: "漫画-36漫画"
});
let textArr = text.split("_");
return textArr[1] + " - " + textArr[0];
},
preloadNext: (nextDoc, obj) => {
fn.iframeVar(nextLink, "params").then(w => {
let srcs = obj.imgs(w);
fn.picPreload(srcs, obj.customTitle(nextDoc), "next");
});
},
hide: "body>div[id][style]:has(a>img),body>*[style*='100;']",
category: "comic"
}, {
name: "天天漫画",
host: ["www.ortzn.com", "m.ortzn.com"],
url: {
t: "天天漫画",
p: /^\/ttmanhua\/\d+\/\d+\.html$/
},
imgs: (dom = document) => fn.getImgSrcArr(".chapter-content img,.hide-scrollbars img", dom),
button: [4],
insertImg: [".chapter-content,.hide-scrollbars", 2],
next: "a[href$='html']:has(>.icon-xiayihua),a[href$=html]:has(>.icon-chapter-right)",
prev: "a[href$='html']:has(>.icon-shangyihua),a[href$=html]:has(>.icon-chapter-left)",
chapters: () => {
let [, , id] = fn.lp.split("/");
let api;
if (fn.lh.startsWith("m.")) {
api = `/ajax.php?chapter_list=1&aid=${id}`;
} else {
api = `/modules/article/ajax.php?act=chapterlist&aid=${id}`;
}
return fetch(api).then(res => res.json()).then(obj => {
let _array;
if (isObject(obj)) {
_array = obj.result;
} else {
_array = obj;
}
let dir = fn.dir(fn.url);
return _array.map(({
chapterid,
chaptername
}) => ({
text: chaptername,
url: `${dir}${chapterid}.html`
}));
});
},
customTitle: (dom = document) => fn.gt(".title a[title]", 1, dom) ?? fn.attr(".chapter-tool-box a", "alt", dom) + " - " + fn.gt(".title .active,h1.title", 1, dom),
preloadNext: true,
category: "comic"
}, {
name: "漫画站",
url: {
h: ["www.manhuazhan.com", "m.manhuazhan.com"],
p: "/chapter/"
},
init: () => fn.waitVar("newImgs"),
imgs: (w = _unsafeWindow) => w.newImgs.map(e => e.url),
button: [4],
insertImg: ["#ChapterContent,.chapter_content", 2],
autoDownload: [0],
next: "//a[text()='下一章'][starts-with(@href,'/')] | //a[div[span[contains(text(),'下一篇')]]][starts-with(@href,'/')]",
prev: "//a[text()='上一章'][starts-with(@href,'/')] | //a[div[span[contains(text(),'上一篇')]]][starts-with(@href,'/')]",
chapters: {
url: "//a[text()='目录'] | //a[div[span[contains(text(),'目录')]]]",
target: ".looplist a,.catalog_list a",
textNode: ".name"
},
customTitle: (dom = document) => {
if (fn.lh.startsWith("m.")) {
return fn.dt({
t: dom.title.replace("_", " - "),
d: ["漫画", "-漫画站"]
});
} else {
return fn.gt(".arthor", 1, dom) + " - " + fn.gt(".title", 1, dom);
}
},
preloadNext: (nextDoc, obj) => {
fn.iframeVar(nextLink, "newImgs").then(w => {
let srcs = obj.imgs(w);
fn.picPreload(srcs, obj.customTitle(nextDoc), "next");
});
},
category: "comic"
}, {
name: "喵趣漫画",
url: {
h: ["www.miaoqumh.org", "m.miaoqumh.org"],
p: ".html",
e: "#manga-imgs",
st: "DATA"
},
init: () => fn.waitVar("newImgs"),
imgs: (w = _unsafeWindow) => w.newImgs.map(e => e.url),
button: [4],
insertImg: ["#manga-imgs", 2],
autoDownload: [0],
next: "//a[text()='下一话' or text()='下一章'][starts-with(@href,'/')]",
prev: "//a[text()='上一话' or text()='上一章'][starts-with(@href,'/')]",
chapters: {
url: "//a[text()='目录'] | //a[@class='iconback']",
target: "#episodes a,.listbox a",
cb: (t, url, e) => ({
text: e?.title?.includes(":") ? e.title.split(":")[1] : t,
url
})
},
customTitle: (dom = document) => {
let textArr = dom.title.replace("-喵趣漫画", "").split("_");
return textArr[1] + " - " + textArr[0];
},
preloadNext: (nextDoc, obj) => {
fn.iframeVar(nextLink, "newImgs").then(w => {
let srcs = obj.imgs(w);
fn.picPreload(srcs, obj.customTitle(nextDoc), "next");
});
},
hide: "body>div[id][style]:has([style]):not(#manga-imgs)",
category: "comic"
}, {
name: "漫画屋/囧次元",
host: ["www.manhua55.com", "www.jiongcy.com"],
reg: [
/^https?:\/\/(www\.)?manhua55\.com\/chapter\/[\d-]+\.html$/,
/^https?:\/\/(www\.)?jiongcy\.com\/kan\/\d+\/\d+\.html$/
],
init: () => fn.wait(() => isArray(_unsafeWindow?.params?.images)),
box: [".chapter-main,.more-box", 1],
imgs: (frame = _unsafeWindow) => frame.params.images.map(src => {
if (frame.params.source_id == 12) {
src = "https://img1.baipiaoguai.org" + src;
}
return src;
}),
button: [4, "24%", 3],
insertImg: [
["box", 0, ".chapter-main,.more-box"], 2
],
autoDownload: [0],
next: "id('next-chapter') | //a[text()='下一章'][starts-with(@href,'/')]",
prev: "id('prev-chapter') | //a[text()='上一章'][starts-with(@href,'/')]",
chapters: {
url: "//a[text()='目录'] | //a[text()='详情']",
target: "#chapter-items a,.episode-box a"
},
customTitle: (dom = document) => fn.dt({
t: dom.title,
d: [",_在线漫画阅读_漫画屋", "漫画", /- 免费观看.+$/]
}).replace("_", " - "),
preloadNext: (nextDoc, obj) => {
fn.iframeVar(nextLink, "params").then(w => {
let srcs = obj.imgs(w);
fn.picPreload(srcs, obj.customTitle(nextDoc), "next");
});
},
category: "comic"
}, {
name: "爱淘漫画",
url: {
h: ["www.aitaocomic.com", "aitaocomic.com"]
},
page: () => fn.clp(/^\/detail\/\w+\/\d+/),
SPA: () => _this.page(),
observeURL: "nav",
json: () => {
fn.showMsg(DL.str_05, 0);
let cdn = "https://api-aitaocomic.nftbaoyi.com/comic/";
let [, , mid, cid] = fn.clp().split("/");
let res_a = fetch(`${cdn}${mid}`).then(res => res.json());
let res_b = fetch(`${cdn}${mid}/${cid}`).then(res => res.json());
return Promise.all([res_a, res_b]).then(([a, b]) => {
siteJson = {
...a.data,
...b.data
};
fn.hideMsg();
});
},
init: () => _this.page() ? _this.json() : void 0,
imgs: () => _this.page() ? siteJson.episode_all_images : [],
capture: () => _this.imgs(),
autoDownload: [0],
chapter_url: (num) => fn.dir(fn.clp()) + num,
next: () => {
if (_this.page()) {
let next = siteJson.next_episode_number;
return isNumber(next) ? _this.chapter_url(next) : null;
}
return null;
},
prev: () => {
if (_this.page()) {
let prev = siteJson.previous_episode_number;
return isNumber(prev) ? _this.chapter_url(prev) : null;
}
return null;
},
chapters: () => siteJson.episode_list.map(({
episode_name,
episode_number
}) => ({
text: episode_name,
url: _this.chapter_url(episode_number)
})),
customTitle: () => {
if (_this.page()) {
let {
name,
episode_name
} = siteJson;
return name + " - " + episode_name;
}
return null;
},
preloadNext: () => {
let [, , mid, cid] = nextLink.split("/");
fetch(`https://api-aitaocomic.nftbaoyi.com/comic/${mid}/${cid}`).then(res => res.json()).then(json => {
let {
episode_name,
episode_all_images
} = json.data;
fn.picPreload(episode_all_images, episode_name, "next");
});
},
category: "comic"
}, {
name: "风车漫画",
url: {
h: "www.fengchemh.com",
p: "/chapter/",
i: 0
},
box: [".more-box", 1],
imgs: (frame = _unsafeWindow) => frame.params.images,
button: [4],
insertImg: [
["box", 0, ".more-box"], 2
],
autoDownload: [0],
next: "//a[text()='下一章'][starts-with(@href,'/chapter/')]",
prev: "//a[text()='上一章'][starts-with(@href,'/chapter/')]",
chapters: {
url: "//a[text()='详情']",
target: ".episode-box a"
},
customTitle: (dom = document) => fn.dt({
t: dom.title,
d: "在线漫画阅读_风车漫画"
}).replace("_", " - "),
preloadNext: (nextDoc, obj) => {
fn.iframeVar(nextLink, "params").then(w => {
let srcs = obj.imgs(w);
fn.picPreload(srcs, obj.customTitle(nextDoc), "next");
});
},
infiniteScroll: true,
mcss: ".vod-list{padding:0!important;}",
category: "comic"
}, {
name: "风车漫画 自動翻頁",
url: {
h: "www.fengchemh.com",
p: "/chapter/",
i: 1
},
getSrcs: () => frameWindow.params.images,
getImgs: () => fn.createImgArray(_this.getSrcs()),
init: async () => {
let imgs = _this.getImgs();
let tE = fn.createImgBox(".more-box", 1);
fragment.append(...imgs);
tE.append(fragment);
fn.remove(".more-box");
await fn.lazyload();
},
autoPager: {
mode: 1,
waitEle: ".more-box img",
ele: () => _this.getImgs(),
pos: ["#FullPictureLoadMainImgBox", 0],
observer: "#FullPictureLoadMainImgBox>img",
next: "//a[text()='下一章'][starts-with(@href,'/chapter/')]",
re: ".vod-list .btn",
title: (dom) => {
let text = fn.dt({
t: dom.title,
d: "在线漫画阅读_风车漫画"
});
if (isM) {
return text.split("_")[1];
} else {
return text.replace("_", " - ");
}
},
preloadNextPage: 1
},
mcss: ".vod-list{padding:0!important;}",
category: "comic autoPager"
}, {
name: "歪瑞古德漫画",
host: ["www.veryim.com"],
url: {
t: "歪瑞古德漫画",
p: /^\/manhua\/\d+\/\d+\.html$/,
st: "qTcms_S_m_murl_e",
i: 0
},
init: () => fn.waitEle("div.chapter-image").then(() => fn.remove(".visible-xs")),
box: [".chapter-images", 1],
imgs: (dom = document) => fn.getImgSrcArr("div.chapter-image", dom),
button: [4],
insertImg: [
["box", 0, ".chapter-images"], 2
],
autoDownload: [0],
next: "#k_Pic_nextArr[href^='/']",
prev: "#k_Pic_backArr[href^='/']",
chapters: {
url: ".breadcrumb a",
urlIndex: 2,
target: ".list-charts a",
sort: "r"
},
customTitle: (dom = document) => {
let code = fn.gst("qTcms_S_m_name", dom);
let qTcms_S_m_name = fn.textVar(code, "qTcms_S_m_name");
let qTcms_S_m_playm = fn.textVar(code, "qTcms_S_m_playm");
return qTcms_S_m_name + " - " + qTcms_S_m_playm;
},
frame: "div.chapter-image",
preloadNext: true,
infiniteScroll: true,
mcss: ".container,.content-body{padding:0px !important}",
hide: "body>a[target]",
category: "comic"
}, {
name: "歪瑞古德漫画 自動翻頁",
url: {
t: "歪瑞古德漫画",
p: /^\/manhua\/\d+\/\d+\.html$/,
st: "qTcms_S_m_murl_e",
i: 1
},
getSrcs: (dom) => fn.getImgSrcArr("div.chapter-image", dom),
getImgs: (dom) => {
let srcs = _this.getSrcs(dom);
return fn.createImgArray(srcs);
},
init: async () => {
await fn.waitVar(["qt100", "params", "CMS"]);
fn.remove(".visible-xs");
let imgs = _this.getImgs();
let tE = fn.createImgBox(".chapter-images", 1);
fn.remove(".chapter-images");
fragment.append(...imgs);
tE.append(fragment);
await fn.lazyload();
},
autoPager: {
mode: 1,
waitEle: "div.chapter-image",
ele: (dom) => _this.getImgs(dom),
pos: ["#FullPictureLoadMainImgBox", 0],
observer: "#FullPictureLoadMainImgBox>img",
next: (dom, r = 1) => {
let n = fn.ge("#k_Pic_nextArr[href$='html']", dom);
if (n) {
return n.href;
} else {
if (r === 1) {
let n = fn.ge("#k_Pic_nextArr");
if (n) {
n.href = fn.lp.replace(/\d+\.html$/, "");
n.innerText = "返回目录";
}
}
return null;
}
},
re: ".breadcrumb,#gundong,.panel-heading:has(+.chaptera),.pager",
title: (dom) => {
let code = fn.gst("qTcms_S_m_name", dom);
let qTcms_S_m_name = fn.textVar(code, "qTcms_S_m_name");
let qTcms_S_m_playm = fn.textVar(code, "qTcms_S_m_playm");
if (isM) {
return qTcms_S_m_playm;
} else {
return qTcms_S_m_name + " - " + qTcms_S_m_playm;
}
},
lazyload: 0,
preloadNextPage: 1
},
css: ".container,.content-body{padding:0px !important}",
hide: "body>a[target]",
category: "comic autoPager"
}, {
name: "非常爱漫新站 AD",
url: {
h: "www.veryim.com"
},
init: () => fn.addMutationObserver(() => {
fn.gae(".visible-xs").forEach(e => {
if (e.innerText.includes("广而告之")) {
e.remove();
}
});
}),
hide: "body>a[target]",
category: "ad"
}, {
name: "漫画160",
host: ["www.mh160mh.com", "m.mh160mh.com"],
url: {
t: "漫画160",
p: "/kanmanhua/",
st: "qTcms_S_m_murl_e",
i: 0
},
init: () => fn.lh == "www.mh160mh.com" ? fn.wait(() => isFn(document?.onkeydown)).then(() => (document.onkeydown = null)) : void 0,
imgs: (dom = document) => {
const {
base64_decode,
f_qTcms_Pic_curUrl_realpic
} = _unsafeWindow;
let code = fn.gst("qTcms_S_m_murl_e", dom);
let qTcms_S_m_murl_e = fn.textVar(code, "qTcms_S_m_murl_e");
return base64_decode(qTcms_S_m_murl_e).split("$qingtiandy$").map(e => f_qTcms_Pic_curUrl_realpic(e));
},
button: [4],
insertImg: ["//td[//img[@onclick]] | //div[@class='UnderPage']", 2],
autoDownload: [0],
next: "#k_Pic_nextArr[href$='html']",
prev: "#k_Pic_backArr[href$='html']",
chapters: {
url: "#viewList,a.iconRet",
target: ".cy_plist a,.chapters a",
sort: "r"
},
customTitle: (dom = document) => {
let code = fn.gst("qTcms_S_m_name", dom);
let qTcms_S_m_name = fn.textVar(code, "qTcms_S_m_name");
let qTcms_S_m_playm = fn.textVar(code, "qTcms_S_m_playm");
return qTcms_S_m_name + " - " + qTcms_S_m_playm;
},
preloadNext: true,
infiniteScroll: true,
css: ".action-list li{width:50% !important}",
mcss: ".container,.content-body{padding:0px !important}",
hide: "body>a[target],#action>ul>li:nth-child(n+2):nth-child(-n+3)",
category: "comic"
}, {
name: "漫画160 自動翻頁",
url: {
t: "漫画160",
p: "/kanmanhua/",
st: "qTcms_S_m_murl_e",
i: 1
},
getSrcs: (dom) => {
const {
base64_decode,
f_qTcms_Pic_curUrl_realpic
} = _unsafeWindow;
let code = fn.gst("qTcms_S_m_murl_e", dom);
let qTcms_S_m_murl_e = fn.textVar(code, "qTcms_S_m_murl_e");
return base64_decode(qTcms_S_m_murl_e).split("$qingtiandy$").map(e => f_qTcms_Pic_curUrl_realpic(e));
},
getImgs: (dom = document) => {
let srcs = _this.getSrcs(dom);
return fn.createImgArray(srcs);
},
init: async () => {
if (fn.lh == "www.mh160mh.com") {
fn.wait(() => isFn(document?.onkeydown)).then(() => (document.onkeydown = null));
}
let imgs = _this.getImgs();
let tE = fn.createImgBox("//td[//img[@onclick]] | //div[@class='UnderPage']", 2);
fn.remove("//td[//img[@onclick]] | //div[@class='UnderPage']");
fragment.append(...imgs);
tE.append(fragment);
await fn.lazyload();
},
autoPager: {
script: "//script[contains(text(),'qTcms_S_m_murl_e')]",
ele: () => _this.getImgs(),
pos: ["#FullPictureLoadMainImgBox", 0],
observer: "#FullPictureLoadMainImgBox>img",
next: (dom, r = 1) => {
let n = fn.ge("#k_Pic_nextArr[href$='html']", dom);
if (n) {
return n.href;
} else {
if (r === 1) {
let n = fn.ge("#k_Pic_nextArr");
if (n) {
n.href = fn.lp.replace(/\d+\.html$/, "");
n.innerText = "返回目录";
if (fn.lh === "www.mh160mh.com") {
n.remove();
}
}
}
return null;
}
},
re: ".title,.main-btn,.breadcrumb,.BarTit,#action,.pager:not([id])",
title: (dom) => {
let code = fn.gst("qTcms_S_m_name", dom);
let qTcms_S_m_name = fn.textVar(code, "qTcms_S_m_name");
let qTcms_S_m_playm = fn.textVar(code, "qTcms_S_m_playm");
if (isM) {
return qTcms_S_m_playm;
} else {
return qTcms_S_m_name + " - " + qTcms_S_m_playm;
}
},
hide: "#m_r_bottom~.imgBox,.globalPadding",
lazyload: 0,
preloadNextPage: 1
},
css: ".action-list li{width:50% !important}",
mcss: ".container,.content-body{padding:0px !important}",
hide: "body>a[target],.main-btn #prev,.main-btn #k_next,#k_pageSelect,#action>ul>li:nth-child(n+2):nth-child(-n+3),li:has(>#prev),li:has(>.curPage),li:has(>#k_next)",
category: "comic autoPager"
}, {
name: "笨狗漫画",
enable: 0,
url: {
h: ["www.bengou.co", "m.bengou.co"],
p: /^\/\w+\/\w+\/\d+\.html$/
},
init: "document.onkeydown=null",
imgs: (dom = document) => {
const {
base64_decode,
f_qTcms_Pic_curUrl_realpic
} = _unsafeWindow;
let code = fn.gst("qTcms_S_m_murl_e", dom);
let qTcms_S_m_murl_e = fn.textVar(code, "qTcms_S_m_murl_e");
return base64_decode(qTcms_S_m_murl_e).split("$qingtiandy$").map(e => f_qTcms_Pic_curUrl_realpic(e));
},
button: [4],
insertImg: ["//td[img[@id='qTcms_pic']]", 2],
autoDownload: [0],
next: () => {
const {
qTcms_Pic_nextArr
} = _unsafeWindow;
return (!/^java/.test(qTcms_Pic_nextArr) && qTcms_Pic_nextArr !== "") ? qTcms_Pic_nextArr : null;
},
prev: 1,
customTitle: (dom = document) => {
let code = fn.gst("qTcms_S_m_name", dom);
let qTcms_S_m_name = fn.textVar(code, "qTcms_S_m_name");
let qTcms_S_m_playm = fn.textVar(code, "qTcms_S_m_playm");
return qTcms_S_m_name + " - " + qTcms_S_m_playm;
},
preloadNext: true,
css: ".action-list li{width:50% !important}",
hide: "#mypic_k0,.action-list>ul>li:nth-child(n+2):nth-child(-n+3)",
category: "comic"
}, {
name: "哔咔漫画",
enable: 0,
url: {
h: ["www.bikamanhua.com", "m.bikamanhua.com"],
p: /^\/[\d-]+\.html$/
},
imgs: "img.lazy-read",
button: [4],
insertImg: ["div:has(>div>img.lazy-read),.episode-detail", 2],
autoDownload: [0],
next: "//a[text()='下一章'] | //a[text()='下一话']",
prev: "//a[text()='上一章'] | //a[text()='上一话']",
customTitle: (dom = document) => fn.title(" - ", 3, dom),
preloadNext: true,
category: "comic"
}, {
name: "聚合漫画屋/酷看漫画/飞飞漫画/皮皮漫画/六漫画",
host: ["www.52hah.com", "www.kukanmanhua.org", "www.feifeimanhua.vip", "www.mh369.com", "www.un10000.net"],
url: {
t: ["聚合漫画屋", "酷看漫画", "飞飞漫画", "皮皮漫画", "六漫画"],
p: ["/chapter/", "/book/"],
d: "pc"
},
imgs: ".comiclist img[data-original]",
button: [4],
insertImg: [".comicpage", 2],
autoDownload: [0],
next: "//a[text()='下一章']",
prev: "//a[text()='上一章']",
chapters: {
target: ".mCustomScrollBox a"
},
customTitle: (dom = document) => fn.gt("h1.title", 1, dom),
preloadNext: (nextDoc, obj) => fn.iframeDoc(nextLink, ".comiclist img:not([src*=loading])", 30000).then(nextIframeDoc => fn.picPreload(fn.getImgSrcArr(obj.imgs, nextIframeDoc), obj.customTitle(nextIframeDoc), "next")),
category: "comic"
}, {
name: "聚合漫画屋M/酷看漫画M/飞飞漫画M/皮皮漫画M/六漫画M",
url: {
t: ["聚合漫画屋", "酷看漫画", "飞飞漫画", "皮皮漫画", "六漫画"],
p: ["/chapter/", "/book/"],
d: "m"
},
imgs: "#cp_img img",
button: [4],
insertImg: ["#cp_img", 2],
autoDownload: [0],
next: "//a[text()='下一章']",
prev: "//a[text()='上一章']",
customTitle: (dom = document) => {
let code = fn.gst("bookInfo", dom);
let bookInfo = fn.TextToObject(code, "bookInfo");
return bookInfo.book_name.replace(/_\d+$/, "") + " - " + bookInfo.chapter_name;
},
preloadNext: (nextDoc, obj) => fn.iframeDoc(nextLink, "#cp_img img[data-original]:not([src*=loading])", 30000).then(nextIframeDoc => fn.picPreload(fn.getImgSrcArr(obj.imgs, nextIframeDoc), obj.customTitle(nextIframeDoc), "next")),
category: "comic"
}, {
name: "白菜漫画",
url: {
h: "baicaimanhua.com",
p: "/mhread.php"
},
box: [".view-paging", 2],
imgs: ".comiclist img[data-original]",
button: [4],
insertImg: [
["box", 0, ".comicpage>div[style^=width],.comicpage>img[data-original]"], 2
],
autoDownload: [0],
next: "//a[text()='下一章']",
prev: "//a[text()='上一章']",
chapters: {
target: ".mCustomScrollBox a"
},
customTitle: (dom = document) => fn.dt({
t: fn.gt("h1.title", 1, dom)
}),
preloadNext: true,
category: "comic"
}, {
name: "白菜漫画M",
url: {
h: "baicaimanhua.com",
p: "/m/mh_read.php"
},
imgs: ".imagecj img",
button: [4],
insertImg: [".imagecj", 2],
insertImgAF: () => {
let $ = _unsafeWindow.jQuery;
$(".FullPictureLoadImage").click(() => {
if ($(".crt-bar").hasClass("flt")) {
$(".crt-bar").removeClass("flt");
$(".crt-bar").css("position", "absolute");
} else {
$(".crt-bar").addClass("flt");
$(".crt-bar").css("position", "fixed");
}
let node = $("#funcBox");
if (node.is(":hidden")) {
node.show();
} else {
node.hide();
}
});
},
autoDownload: [0],
next: "//a[text()='下一章' or text()='下一话'][not(starts-with(@href,'javascript'))]",
prev: "//a[text()='上一章' or text()='上一话'][not(starts-with(@href,'javascript'))]",
customTitle: (dom = document) => {
let textArr = dom.title.split("-");
return textArr[1] + " - " + textArr[2];
},
preloadNext: true,
fancybox: {
blacklist: 1
},
hide: ".read-article>div:has(>div[style*=float]),div[style^=line]",
category: "comic"
}, {
host: ["say-on.com", "ahgwyd.com", "www.jianyu120.com", "www.jiasenongye.com", "www.one-uplus.com", "www.qize-airline.com"],
url: {
st: [/(R|r)eadData/, "setComic"],
p: "/read/"
},
imgs: ".read-content img,#comicContainer img,.pic-ist img",
autoDownload: [0],
next: "//a[div[text()='下一话']][contains(@href,'/read/')] | //a[@class='page-next'][contains(@href,'/read/')] | //a[@id='nextButton'][contains(@href,'/read/')]",
prev: "//a[div[text()='上一话']][contains(@href,'/read/')] | //a[@class='page-prev'][contains(@href,'/read/')] | //a[@id='prevButton'][contains(@href,'/read/')]",
customTitle: () => {
let code = fn.gst(/readdata/i);
let object = fn.TextToObject(code, "eadData");
return object.comicName + " - " + object.readName;
},
category: "comic"
}, {
name: "我的漫畫",
url: {
h: "mycomic.com",
p: "/chapters/",
i: 0
},
init: () => fn.MyComicUI(),
box: ["div:has(>img.page)", 2],
imgs: "img.page",
button: [4],
insertImg: [
["box", 0, "div:has(>img.page)"], 2
],
insertImgAF: (p) => p.after(fn.ge("div:has(>div[data-flux-button-group])").cloneNode(true)),
autoDownload: [0],
next: {
s: "a[href*='chapters']",
t: "下一話"
},
prev: {
s: "a[href*='chapters']",
t: "上一話"
},
chapters: {
url: "[data-flux-breadcrumbs-item] a:not([aria-label])",
mode: "f",
target: "template[x-for='chapter in chapters']~a",
sort: "r"
},
customTitle: (dom = document) => fn.ge("img.page", dom).alt.replace(/:.+$/, ""),
preloadNext: true,
infiniteScroll: true,
hide: "div:has(>div>div>button[x-ref])",
mcss: ".p-6{padding:1.5rem 0}",
category: "comic"
}, {
name: "我的漫畫 自動翻頁",
url: {
h: "mycomic.com",
p: "/chapters/",
i: 1
},
getSrcs: (dom) => fn.getImgSrcArr("img.page", dom),
getImgs: (dom = document) => {
let srcs = _this.getSrcs(dom);
return fn.createImgArray(srcs);
},
init: async () => {
fn.MyComicUI();
let imgs = _this.getImgs();
let tE = fn.createImgBox("div:has(>img.page)", 2);
fragment.append(...imgs);
tE.append(fragment);
let e = fn.ge("div:has(>div[data-flux-button-group])").cloneNode(true);
tE.after(e);
await fn.remove("div:has(>img.page)");
await fn.lazyload();
},
autoPager: {
ele: (dom) => _this.getImgs(dom),
pos: ["#FullPictureLoadMainImgBox", 0],
observer: "#FullPictureLoadMainImgBox>img",
next: "//a[contains(text(),'下一話')][contains(@href,'chapters')]",
title: (dom) => {
let text = fn.ge("img.page", dom).alt.replace(/:.+$/, "");
if (isM) {
return text.split(" - ")[1];
} else {
return text;
}
},
re: "div[data-flux-breadcrumbs]",
aF: (dom) => {
let ne = fn.ge("div:has(>div[data-flux-button-group])", dom);
fn.gae("div:has(>div[data-flux-button-group])").forEach(ce => (ce.innerHTML = ne.innerHTML));
},
preloadNextPage: 1
},
hide: "div:has(>div>div>button[x-ref])",
mcss: ".p-6{padding:1.5rem 0}",
category: "comic autoPager"
}, {
name: "奇漫屋",
url: {
h: "www.mqzjw.com",
p: "/bookstt/",
i: 0
},
init: () => {
fn.addMutationObserver(() => fn.remove([
"//div[a[contains(text(),'下载')]]",
"//div[contains(text(),'下载')]",
"//div[contains(text(),'投诉邮箱')]",
"#alertBox",
"#xiazai"
]));
return fn.waitVar("CryptoJS");
},
imgs: () => fn.getMqzjwSrc(),
button: [4],
insertImg: [".comiclist", 2],
insertImgAF: () => {
let [id] = fn.gst("readPic").match(/\d+/);
fn.ge(".back").href = `/book/${id}.html`;
const {
jQuery: $
} = _unsafeWindow;
fn.run("jQuery(window).off()");
let lastScrollTop = 0;
document.addEventListener("scroll", event => {
const st = event.srcElement.scrollingElement.scrollTop;
if (st > lastScrollTop) {
$(".header").css("transform", "translateY(-100%)");
$(".bottom-bar").css("transform", "translateY(100%)");
lastScrollTop = st;
} else if (st < lastScrollTop - 20) {
$(".header").css("transform", "translateY(0%)");
$(".bottom-bar").css("transform", "translateY(0%)");
lastScrollTop = st;
}
});
if (isString(nextLink)) {
fn.addUrlHtml(nextLink, ".next_chapter", 1, "点击进入下一话");
}
fn.remove(".next_chapter");
},
autoDownload: [0],
next: () => {
let next = fn.ge(".j-rd-next[_href^='/bookstt/']");
return next ? next.getAttribute("_href") : null;
},
prev: ".j-rd-prev",
chapters: {
target: "#chapter-items a",
sort: "r"
},
customTitle: (dom = document) => {
let text = dom.title.replace("漫画-免费在线看漫画-奇漫屋", "");
let textArr = text.split("-");
return textArr[1] + " - " + textArr[0];
},
preloadNext: async (nextDoc) => {
let srcs = await fn.getMqzjwSrc(nextLink, 0);
fn.picPreload(srcs, _this.customTitle(nextDoc), "next");
},
fancybox: {
blacklist: 1
},
infiniteScroll: true,
css: "html{cursor:auto!important}",
category: "comic"
}, {
name: "奇漫屋 自動翻頁",
url: {
h: "www.mqzjw.com",
p: "/bookstt/",
i: 1
},
init: async () => {
fn.addMutationObserver(() => fn.remove([
"//div[a[contains(text(),'下载')]]",
"//div[contains(text(),'下载')]",
"//div[contains(text(),'投诉邮箱')]",
"#alertBox",
"#xiazai"
]));
await fn.waitVar("CryptoJS");
fn.showMsg(DL.str_135, 0);
await fn.getMqzjwSrc(fn.lp, 0).then(srcs => fn.createImgArray(srcs)).then(async imgs => {
let tE = fn.ge(".comiclist");
tE.innerHTML = "";
fragment.append(...imgs);
tE.append(fragment);
fn.ge(".j-rd-prev").outerHTML = fn.ge(".j-rd-prev").outerHTML;
fn.ge(".j-rd-next").outerHTML = fn.ge(".j-rd-next").outerHTML;
fn.ge(".j-rd-prev").href = fn.attr(".j-rd-prev[_href]", "_href");
fn.ge(".j-rd-next").href = fn.attr(".j-rd-next[_href]", "_href");
let [id] = fn.gst("readPic").match(/\d+/);
fn.ge(".back").href = `/book/${id}.html`;
fn.hideMsg();
await fn.remove(".next_chapter");
await fn.lazyload();
});
const {
jQuery: $
} = _unsafeWindow;
fn.run("jQuery(window).off()");
let lastScrollTop = 0;
document.addEventListener("scroll", event => {
const st = event.srcElement.scrollingElement.scrollTop;
if (st > lastScrollTop) {
$(".header").css("transform", "translateY(-100%)");
$(".bottom-bar").css("transform", "translateY(100%)");
lastScrollTop = st;
} else if (st < lastScrollTop - 20) {
$(".header").css("transform", "translateY(0%)");
$(".bottom-bar").css("transform", "translateY(0%)");
lastScrollTop = st;
}
});
},
autoPager: {
ele: () => fn.getMqzjwSrc(nextLink, 0).then(srcs => fn.createImgArray(srcs)),
pos: [".comiclist", 0],
observer: ".comiclist>img",
next: (dom) => {
let next = fn.ge(".j-rd-next[_href^='/bookstt/']", dom);
return next ? next.getAttribute("_href") : null;
},
title: (dom) => {
let text = dom.title.replace("漫画-免费在线看漫画-奇漫屋", "");
let textArr = text.split("-");
return isM ? textArr[0] : textArr[1] + " - " + textArr[0];
},
re: "span.title,.j-rd-prev[_href],.j-rd-next[_href]",
aF: (dom) => {
fn.ge(".j-rd-prev").href = fn.attr(".j-rd-prev[_href]", "_href", dom);
let nextE = fn.ge(".j-rd-next");
let next_url = fn.attr(".j-rd-next[_href]", "_href", dom);
if (next_url == "") {
nextE.href = fn.gu(".back");
fn.ge("span", nextE).innerText = "返回";
} else {
nextE.href = next_url;
}
},
preloadNextPage: async (dom) => {
let next = _this.autoPager.next(dom);
if (!!next) {
let srcs = await fn.getMqzjwSrc(next, 0);
fn.fetchDoc(next).then(nextDoc => fn.picPreload(srcs, _this.autoPager.title(nextDoc), "next"));
}
}
},
css: "html{cursor:auto!important}",
category: "comic autoPager"
}, {
name: "奇漫屋AD",
url: {
h: "www.mqzjw.com"
},
init: () => fn.addMutationObserver(() => fn.remove([
"//div[div[contains(text(),'下载')]]",
"//div[a[contains(text(),'下载')]]",
"#alertBox",
"#xiazai"
])),
category: "ad"
}, {
name: "嗶哩漫畫",
url: {
h: ["www.bilimanga.net", "www.bilicomic.net"],
p: "/read/",
st: "ReadParams"
},
imgs: "#acontentz img",
button: [4],
insertImg: ["#acontentz", 2],
endColor: "white",
autoDownload: [0],
next: () => {
let next = _unsafeWindow?.ReadParams?.url_next;
return isString(next) && next?.includes("/read/") ? next : null;
},
prev: 1,
chapters: {
url: () => {
let dir = fn.dir(fn.lp);
return dir + "catalog";
},
target: ".volume-chapters a"
},
customTitle: () => document.title.trim().slice(0, -5),
preload: 0,
fancybox: {
blacklist: 1
},
category: "comic"
}, {
name: "拷貝漫畫M SPA",
url: () => fn.checkUrl({
h: ["www.2025copy.com", "2025copy.com", "copy2000.site", "www.copy20.com", "copy20.com", "www.mangacopy.com", "mangacopy.com"],
i: 0,
d: "m"
}) && copymangaSPA_Mode == 1,
page: () => fn.clp("/h5/comicContent/"),
clearLoop: true,
json: (url = fn.clp(), msg = 1) => {
if (msg == 1) fn.showMsg(DL.str_05, 0);
let [name, id] = url.split("/").slice(3);
let api_a = `https://api.2025copy.com/api/v3/comic/${name}/chapter/${id}`;
//let api_b = `https://api.2025copy.com/api/v3/comic/${name}/chapter2/${id}`;
return fn.xhr(api_a, {
responseType: "json",
headers: {
"Referer": `https://${fn.lh}/comic/${name}/chapter/${id}`,
"User-Agent": PC_UA
}
});
},
SPA: () => _this.page() ? true : (siteJson = {}) && false,
observeURL: "nav",
init: () => _this.page() ? _this.json().then(json => (siteJson = json) && fn.hideMsg()) : (_unsafeWindow.aboutBlank = null),
imgs: (json = siteJson) => {
if (!_this.page()) return [];
const {
contents
} = json.results.chapter;
return contents.map(e => e.url);
/**
api_b 需要還原圖片順序
const srcs = [];
const {
words,
contents
} = json.results.chapter;
words.forEach((w, i) => (srcs[w] = contents[i].url));
return srcs;
*/
},
capture: () => _this.imgs(),
button: [4],
insertImgBF: () => fn.waitEle(".van-image__img").then(() => fn.createImgBox(".comicContentPopupImageList", 2)).then(() => fn.hideEle(".van-ovarlay,.van-toast:has(.van-loading)")),
insertImg: [
["box", 0, ".comicContentPopupImageList"], 2
],
insertImgAF: (p) => {
const addHtml = (url, text) => {
let str = `<div style="padding: 10px 0; text-align: center; font-size: initial !important;"><a href="${url}"style="width: 100%;font-size: 26px;line-height: 50px;height: 50px;text-align: center;">${text}</a></div>`;
p.insertAdjacentHTML("afterend", str);
};
let s = fn.clp().split("/").at(-2);
let url = `/h5/details/comic/${s}`;
let hUrl = `/h5/index`;
addHtml(hUrl, "首頁");
addHtml(url, "目錄");
if (nextLink) addHtml(nextLink, "點選進入下一話");
fn.hideEle(".comicFixed");
},
next: () => {
if (!_this.page()) return null;
let next = siteJson.results.chapter.next;
return next ? fn.dir(fn.clp()) + next : null;
},
prev: 1,
chapters: () => {
let name = fn.curl().split("/").at(5);
return axios.get(`https://api.2025copy.com/api/v3/comic/${name}/group/default/chapters?limit=500&offset=0`).then(json => {
let chapters = json.data.results.list;
return chapters.map(({
name,
comic_path_word,
uuid,
}) => ({
text: name,
url: `/h5/comicContent/${comic_path_word}/${uuid}`
}));
});
},
customTitle: (json = siteJson) => _this.page() ? json.results.comic.name + " - " + json.results.chapter.name : null,
preloadNext: () => {
_this.json(nextLink, 0).then(json => {
let srcs = _this.imgs(json);
let title = _this.customTitle(json);
fn.picPreload(srcs, title, "next");
});
},
fancybox: {
blacklist: 1
},
gallery: 0,
infiniteScroll: true,
category: "comic"
}, {
name: "拷貝漫畫",
url: {
t: ["拷貝漫畫", "拷贝漫画"],
p: /^\/comic\/\w+\/chapter\//,
st: "contentKey",
i: 0
},
delay: 300,
init: () => {
fn.copymangaUI();
let readHistoryData = localStorage.getItem("copymangaReadHistory");
let [, , comic, , chapter] = fn.lp.split("/");
let json;
readHistoryData ? json = JSON.parse(readHistoryData) : json = {};
json[comic] = chapter;
localStorage.setItem("copymangaReadHistory", JSON.stringify(json));
axios.get(`https://api.2025copy.com/api/v3/roasts?chapter_id=${chapter}&limit=100&offset=0&_update=true`).then(res => console.log("評論", res.data));
},
imgs: async (dom = document) => {
let code = fn.gst("contentKey", dom);
let [, key, , raw] = code.split("'");
let images = await fn.copymanga_decrypt_A(raw, key);
return images.map(({
url
}) => url.replace("800x.", "1500x."));
},
button: [4],
insertImg: [".comicContent-list", 2],
endColor: "white",
autoDownload: [0],
next: "//a[text()='下一話'][starts-with(@href,'/comic/')]",
prev: "//a[text()='上一話'][starts-with(@href,'/comic/')]",
chapters: () => {
let [, , comicName] = fn.lp.split("/");
return axios.get(`/comicdetail/${comicName}/chapters`, {
headers: {
"dnts": 1
}
}).then(json => {
let code = fn.gst("contentKey");
let [, key] = code.split("'");
let data = fn.copymanga_decrypt_B(json.data.results, key);
let chapters = data.groups.default.chapters;
let dir = fn.dir(fn.url);
return chapters.map(({
name,
id
}) => ({
text: name,
url: dir + id
}));
});
},
customTitle: (dom = document) => fn.dt({
t: dom.title,
d: / - 拷.+$/
}),
preloadNext: true,
hide: ".header+div[style],.comicContainerAds",
infiniteScroll: true,
category: "comic"
}, {
name: "拷貝漫畫 自動翻頁",
url: {
t: ["拷貝漫畫", "拷贝漫画"],
p: /^\/comic\/\w+\/chapter\//,
st: "contentKey",
i: 1
},
delay: 300,
getSrcs: async (dom) => {
let code = fn.gst("contentKey", dom);
let [, key, , raw] = code.split("'");
let images = await fn.copymanga_decrypt_A(raw, key);
return images.map(({
url
}) => url.replace("800x.", "1500x."));
},
getImgs: async (dom = document) => {
let srcs = await _this.getSrcs(dom);
return fn.createImgArray(srcs);
},
init: async () => {
fn.copymangaUI();
await _this.getImgs().then(async imgs => {
let tE = fn.ge(".comicContent-list");
tE.innerHTML = "";
fragment.append(...imgs);
tE.append(fragment);
await fn.lazyload();
});
fn.addMutationObserver(() => {
if (fn.ge("//li[img[@data-src]]")) {
fn.remove("//li[img[@data-src]]");
}
});
},
autoPager: {
ele: (dom) => _this.getImgs(dom),
pos: [".comicContent-list", 0],
observer: ".comicContent-list>img",
next: "//a[text()='下一話'][starts-with(@href,'/comic/')]",
re: ".header,.footer",
title: (dom) => fn.dt({
t: dom.title,
d: / - 拷.+$/
}),
preloadNextPage: 1
},
hide: ".header+div[style],.comicContainerAds",
category: "comic autoPager"
}, {
name: "拷貝漫畫 目錄頁",
url: {
t: ["拷貝漫畫", "拷贝漫画"],
p: /^\/comic\/\w+$/
},
delay: 300,
init: async () => {
await fn.waitEle(".tab-pane.show.active a");
const updateLastChapter = () => {
let [, , comic] = fn.lp.split("/");
let readHistoryData = localStorage.getItem("copymangaReadHistory");
if (!!readHistoryData) {
let json = JSON.parse(readHistoryData);
if (comic in json) {
let selector = `.tab-content a[href$="${json[comic]}"]`;
fn.gae(".lastchapter").forEach(a => a.classList.remove("lastchapter"));
fn.gae(selector).forEach(a => a.classList.add("lastchapter"));
setTimeout(() => {
let lastReadUrl = fn.lp + "/chapter/" + json[comic];
let lastText = fn.ge(".lastchapter").title;
let lastE = fn.ge("#lastRead");
if (!lastE && !fn.ge("//span[contains(text(),'最後閱讀')]")) {
let a = document.createElement("a");
a.id = "lastRead";
a.target = "_blank";
let tableRight = fn.ge(".table-default-right");
tableRight.insertAdjacentElement("afterbegin", a);
const span = document.createElement("span");
span.innerText = "最後閱讀:";
tableRight.insertAdjacentElement("afterbegin", span);
a.href = lastReadUrl;
a.innerText = lastText;
} else if (!!lastE) {
let a = lastE;
a.href = lastReadUrl;
a.innerText = lastText;
}
}, 200);
}
}
};
updateLastChapter();
document.addEventListener("visibilitychange", updateLastChapter);
if ("aboutBlank" in _unsafeWindow) _unsafeWindow.aboutBlank = null;
setTimeout(() => fn.clearAllTimer(3), 1000);
},
css: ".lastchapter{color:#fff !important;background:#1790E6}",
hide: ".comicDetailAds",
category: "none"
}, {
name: "拷貝漫畫M",
url: {
h: /2025copy|copy20|mangacopy/,
p: /^\/h5\/comicContent\/\w+\//,
i: 0
},
xhrJson: (url = siteUrl) => {
let [name, id] = new URL(url).pathname.split("/").slice(-2);
let api = `https://api.2025copy.com/api/v3/comic/${name}/chapter/${id}`;
return fn.xhr(api, {
responseType: "json",
headers: {
"Referer": `https://${fn.lh}/comic/${name}/chapter/${id}`,
"User-Agent": PC_UA
}
});
},
init: async () => {
fn.clearAllTimer(3);
if ("aboutBlank" in _unsafeWindow) _unsafeWindow.aboutBlank = null;
siteJson = await _this.xhrJson();
debug("\n此頁JSON資料\n", siteJson);
},
imgs: (json = siteJson) => {
const {
contents
} = json.results.chapter;
return contents.map(e => e.url);
},
button: [4],
insertImg: [".comicContentPopupImageList", 2],
insertImgAF: () => {
fn.hideEle(".van-ovarlay,.van-toast:has(.van-loading)");
const addHtml = (url, text) => {
let str = `<div style="padding: 10px 0; text-align: center; font-size: initial !important;"><a href="${url}"style="width: 100%;font-size: 26px;line-height: 50px;height: 50px;text-align: center;">${text}</a></div>`;
fn.ge(".comicContentPopupImageList").insertAdjacentHTML("afterend", str);
};
let s = siteUrl.split("/").at(-2);
let url = `/h5/details/comic/${s}`;
let hUrl = `/h5/index`;
addHtml(hUrl, "首頁");
addHtml(url, "目錄");
if (nextLink) addHtml(nextLink, "點選進入下一話");
fn.copymanga_M_UI(url, hUrl);
},
next: () => {
let next = siteJson.results.chapter.next;
return next ? siteUrl.replace(/[\w-]+$/, "") + next : null;
},
customTitle: (json = siteJson) => json.results.comic.name + " - " + json.results.chapter.name,
preloadNext: () => {
_this.xhrJson(nextLink).then(json => {
let srcs = _this.imgs(json);
let title = _this.customTitle(json);
fn.picPreload(srcs, title, "next");
});
},
css: ".comicControlBottom a:-webkit-any-link{color:white!important}.comicContentPopup .comicControlBottom .comicControlBottomBottom span{margin:0 1rem!important}",
hide: ".comicFixed,.comicControlBottom.hide",
fancybox: {
blacklist: 1
},
gallery: 0,
infiniteScroll: true,
category: "comic"
}, {
name: "拷貝漫畫M 自動翻頁",
url: {
h: /2025copy|copy20|mangacopy/,
p: /^\/h5\/comicContent\/\w+\//,
i: 1
},
getData: () => {
let [name, id] = new URL(document.URL).pathname.split("/").slice(-2);
let api = `https://api.2025copy.com/api/v3/comic/${name}/chapter/${id}`;
return fn.xhr(api, {
responseType: "json",
headers: {
"Referer": `https://${fn.lh}/comic/${name}/chapter/${id}`,
"User-Agent": PC_UA
}
}).then(json => {
let {
contents,
name,
next
} = json.results.chapter;
const images = contents.map(e => e.url);
if (!!next) {
next = fn.dir(document.URL) + next;
} else {
next = null;
}
siteJson = {
images,
name,
next
}
console.log("\n拷貝漫畫M_JSON\n", siteJson);
});
},
init: async () => {
fn.showMsg(DL.str_135, 0);
await _this.getData();
let imgs = fn.createImgArray(siteJson.images);
let tE = fn.ge(".comicContentPopupImageList");
tE.innerHTML = "";
fragment.append(...imgs);
tE.append(fragment);
fn.hideEle(".van-ovarlay,.van-toast:has(.van-loading)");
await fn.lazyload();
fn.clearAllTimer(3);
if ("aboutBlank" in _unsafeWindow) _unsafeWindow.aboutBlank = null;
fn.hideMsg();
const addHtml = (url, text) => {
let str = `<div style="padding: 0 0 12px; text-align: center;"><a href="${url}"style="width: 100%;font-size: 26px;line-height: 34px;height: 34px;text-align: center;">${text}</a></div>`;
fn.ge(".comicContentPopupImageList").insertAdjacentHTML("afterend", str);
};
let s = siteUrl.split("/").slice(-2);
let url = `https://${fn.lh}/h5/details/comic/${s[0]}`;
let hUrl = `https://${fn.lh}/h5/index`;
addHtml(hUrl, "首頁");
addHtml(url, "目錄");
fn.copymanga_M_UI(url, hUrl);
},
autoPager: {
ele: () => fn.createImgArray(siteJson.images),
pos: [".comicContentPopupImageList", 0],
observer: ".comicContentPopupImageList>img",
next: () => siteJson.next,
wait: () => _this.getData(),
title: () => siteJson.name
},
css: ".comicControlBottom a:-webkit-any-link{color:white!important}.comicContentPopup .comicControlBottom .comicControlBottomBottom span{margin:0 1rem!important}",
hide: ".comicFixed,.comicControlBottom.hide",
category: "comic autoPager"
}, {
name: "樱花漫画",
url: {
h: "yinghuamh.net",
p: /^\/comic\/\w+\/\d+\/\d+/
},
init: async () => {
await fn.waitVar("x_tokens");
fn.run("$(document).off()");
let lastScrollTop = 0;
document.addEventListener("scroll", event => {
let st = event.srcElement.scrollingElement.scrollTop;
if (st > lastScrollTop) {
fn.ge(".view-title").style.top = "-60px";
lastScrollTop = st;
} else if (st < lastScrollTop - 20) {
fn.ge(".view-title").style.top = "0px";
lastScrollTop = st;
}
});
},
imgs: () => {
const {
x_tokens,
Gm
} = _unsafeWindow;
return x_tokens.map(e => Gm.getImgUrl(Gm.fitImgUrl(e)));
},
button: [4],
insertImg: ["#all", 2],
endColor: "white",
autoDownload: [0],
next: "a.next_part:not([href^=java])",
prev: ".paginationContent>a:first-child:not([href^=java])",
chapters: {
url: "//a[text()='目录']",
target: "#comic-book-list a[title]",
sort: "r"
},
customTitle: () => {
const {
comic_name,
part_name
} = _unsafeWindow;
return comic_name + " - " + part_name;
},
preloadNext: () => {
fn.iframeVar(nextLink, "x_tokens").then(frame => {
const {
x_tokens,
Gm,
comic_name,
part_name
} = frame;
let srcs = x_tokens.map(e => Gm.getImgUrl(Gm.fitImgUrl(e)));
let text = comic_name + part_name;
fn.picPreload(srcs, text, "next");
});
},
category: "comic"
}, {
name: "看漫画",
host: ["www.kanman.com"],
enable: 0,
url: {
h: "www.kanman.com",
p: /^\/\d+\/[\w-]+\.html$/,
d: "pc"
},
init: async () => {
let [, comic_id, id] = fn.lp.split("/");
id = id.replace(".html", "");
let api = `/api/getchapterinfov2?product_id=1&productname=kmh&platformname=pc&comic_id=${comic_id}&chapter_newid=${id}&isWebp=1&quality=middle`;
await fetch(api).then(res => res.json()).then(json => (siteJson = json));
debug("\n此頁JSON資料\n", siteJson);
},
imgs: () => siteJson.data.current_chapter.chapter_img_list,
next: () => {
let {
comic_id,
next_chapter
} = siteJson.data;
if (next_chapter) {
return "/" + comic_id + "/" + next_chapter.chapter_newid + ".html";
}
return null;
},
prev: 1,
customTitle: () => siteJson.data.comic_name + " - " + siteJson.data.current_chapter.chapter_name,
category: "comic"
}, {
name: "zero搬运网",
host: ["www.zerobywtar.com"],
url: {
h: "www.zero",
p: "/plugin",
s: "a=read",
st: "listimg"
},
imgs: () => {
let code = fn.gst("listimg");
let dataArr = fn.TextToArray(code, "listimg");
return dataArr.map(e => e.file);
},
button: [4],
insertImg: [".uk-alert.uk-alert-danger.uk-text-center,.uk-zjimg", 3],
autoDownload: [0],
next: "//a[contains(text(),'下一章')]",
prev: "//a[contains(text(),'上一章')]",
chapters: {
url: "//a[text()='目录']",
target: "h3~[uk-grid] a"
},
customTitle: () => fn.title(" - zero搬运网"),
category: "comic"
}, {
name: "zero搬运网M",
url: {
h: "www.zero",
p: "/plugin",
s: "a=read",
d: "m"
},
imgs: () => {
let i = ".zjimg img";
if (fn.ge(i)) {
return fn.gae(i);
}
fn.showMsg(DL.str_05, 0);
return fn.xhrDoc(fn.url, {
headers: {
"User-Agent": PC_UA
}
}).then(dom => {
let code = fn.gst("listimg", dom);
let dataArr = fn.TextToArray(code, "listimg");
return dataArr.map(e => e.file);
});
},
button: [4],
insertImg: [".areadiv", 3],
autoDownload: [0],
next: "//a[contains(text(),'下一章')]",
prev: "//a[contains(text(),'上一章')]",
customTitle: () => fn.title(/_ zero搬运网.+/),
category: "comic"
}, {
name: "漫蛙", //方向鍵上一章下一章、清除擋廣告警告、向下滾動隱藏工具列、反反偵錯,,下載需先手動觸發全部載入圖片,函式使用到canvas需要繪製過程會有點卡。
host: ["manwa.me"],
link: "https://fuw11.cc/maKapG",
url: {
h: "manwa",
p: /^\/chapter\/\d+(\?img_host=\d)?$/
},
//delay: 1000,
init: async () => {
_unsafeWindow.Function.prototype.constructor = () => {};
//await fn.scrollEles(".img-content img", 200);
fn.css(".ad-area{opacity:0!important;}#cp_img>.two-ad-area:nth-child(1)>.ad-area,#cp_img>.two-ad-area:nth-child(2){display:none!important}");
fn.remove(".ad-area,body>div[id]:not([id^='pv-'],[class^='pv-'],[id^='pagetual'],[class^='pagetual'],#comicRead,#fab,[id^='FullPictureLoad'],[class^='FullPictureLoad'],[class^=fancybox])", 5000);
await fn.waitVar("jQuery");
const $ = _unsafeWindow.jQuery;
let lastScrollTop = 0;
document.addEventListener("scroll", event => {
let st = event.srcElement.scrollingElement.scrollTop;
if (st > lastScrollTop) {
$(".view-fix-top-bar").attr("style", "top: -60px;");
$(".view-fix-bottom-bar").attr("style", "bottom: -60px;");
$(".detail-comment-fix-bottom").hide("fast");
lastScrollTop = st;
} else if (st < lastScrollTop - 20) {
$(".view-fix-top-bar").attr("style", "top: 0px;");
$(".view-fix-bottom-bar").attr("style", "bottom: 0px;");
$(".detail-comment-fix-bottom").show("fast");
lastScrollTop = st;
}
});
await fn.waitEle(".content-img.lazy_img[src^=blob]");
if (autoScrollAllElement === 1) _this.scrollEle();
},
imgs: async () => {
if (options.autoDownload == 1 || options.shadowGallery == 1 || options.mobileGallery == 1) {
await _this.scrollEle();
}
return fn.imgBlobUrlArr(".content-img[src^=blob]");
},
scrollEle: () => fn.aotoScrollEles({
ele: ".img-content .content-img",
cb: (img) => /^blob/.test(img.src),
top: 1
}),
autoDownload: [0],
next: ".view-fix-bottom-bar-item-menu-next",
prev: ".view-fix-bottom-bar-item-menu-prev",
customTitle: () => fn.title("在线阅读", 1),
css: "body{padding-bottom:0px!important}div:has(>.view-fix-top-bar){z-index:1000!important}",
category: "comic"
}, {
name: "漫蛙選目錄展開全部章節",
url: {
h: "manwa",
p: /^\/book\/\d+$/
},
init: async () => {
_unsafeWindow.Function.prototype.constructor = () => {};
await fn.waitEle("#detail-list-select li");
await fn.waitVar(["titleSelect", "charpterMore"]);
EClick("//a[text()='目录']");
EClick("a.detail-list-more");
},
category: "none"
}, {
name: "漫蛙自動載入更多",
url: {
h: "manwa",
p: /^\/update$/
},
init: "Function.prototype.constructor=()=>{}",
observerClick: "#loadMore",
category: "autoPager"
}, {
name: "開車漫画",
host: ["18p.fun"],
reg: /^https?:\/\/(www\.)?(18p|gohaveababy|imynest|healthway|beforeout)\.[a-z]{2,5}\/(ForInject\/|Article\/|content\/)/,
imgs: async () => {
await fn.waitEle("//script[contains(text(),'_curChap')]");
if (fn.lh != "18p.fun") {
location.replace("https://18p.fun/ForInject/Chapter/?id=" + _unsafeWindow.$_curChap.id);
await delay(3000);
}
await fn.getNP("img[data-src].lazy:not(.demo-lazy)", "//a[@data-url and contains(text(),'下一頁')] | //a[@data-url and contains(text(),'下一章')]", null, "div[class^=picnext]");
return fn.gae("img[data-src].lazy:not(.demo-lazy)");
},
insertImg: ["div[class^=pictures]", 3],
endColor: "white",
category: "comic"
}, {
name: "開車漫画",
host: ["18p.fun"],
enable: 0,
icon: 0,
key: 0,
reg: /^https?:\/\/18p\.fun\//,
include: ".loadmore>button",
init: () => fn.addMutationObserver(() => fn.gae("img.lazy[src$=svg]").forEach(img => (img.src = img.dataset.src))),
observerClick: ".loadmore>button",
openInNewTab: "#itemlist li>a:not([target=_blank])",
css: ".loadmore{display:block!important}",
hide: ".page",
category: "comic"
}, {
name: "风之动漫",
url: {
h: ["www.fffdm.com", "manhua.fffdm.com"]
},
page: () => fn.clp(/^\/(manhua\/)?\d+\/[^/]+\/$/i),
json: () => {
let [mhId, mhcId] = fn.clp().split("/").slice(-3);
let api = `/api/manhua/${mhId}/${mhcId}`;
return fetch(api).then(res => res.json()).then(json => (siteJson = json));
},
SPA: () => _this.page() ? _this.json() : false,
observeURL: "nav",
init: () => {
if (_this.page()) return _this.json();
},
imgs: async () => {
if (!_this.page()) return [];
let hostArr = fn.gau("link[rel='dns-prefetch']");
let [firstPic] = siteJson.cont;
let testArr = hostArr.map(e => e + firstPic);
let ok = false;
let host;
fn.showMsg(DL.str_56, 0);
for (let [i, test] of testArr.entries()) {
let status = await fn.xhrHEAD(test).then(res => res.status);
if (status == 200) {
ok = true;
host = hostArr[i];
break;
}
}
return ok ? siteJson.cont.map(e => host + e) : [];
},
next: () => {
if (!_this.page()) return null;
let comicListUrl = decodeURIComponent(fn.clp().replace(/[^\/]+\/$/i, ""));
let chapter = decodeURIComponent(fn.clp().match(/[^\/]+\/$/)[0]);
let nextXPath = `//div[@id='content']/li[a[@href='${chapter}']]/preceding-sibling::li[1]/a`;
return fn.fetchDoc(comicListUrl).then(dom => {
let next = fn.ge(nextXPath, dom, dom);
return next ? comicListUrl + next.getAttribute("href") : null;
});
},
prev: 1,
customTitle: () => _this.page() ? fn.title("第1页 FFF风之动漫") : null,
fancybox: {
v: 3,
insertLibrarys: 1
},
category: "comic"
}, {
name: "漫画皮",
host: ["www.manhuapi.cc", "m.manhuapi.cc"],
url: {
h: "manhuapi",
p: "/chapter/"
},
init: "document.onkeydown=null && $('body').unbind()",
imgs: (dom = document) => fn.gae("option[jhc-data]", dom).map(e => e.getAttribute("jhc-data").replace("-mht.middle.webp", "")).map(e => e.replace(new URL(e).protocol, location.protocol)),
button: [4],
insertImg: [".mh_list,#content", 2],
autoDownload: [0],
next: "//a[text()='下一章'][contains(@href,'chapter')]",
prev: "//a[text()='上一章'][contains(@href,'chapter')]",
chapters: () => {
let a = fn.ge("//a[text()='作品目录'] | //a[text()='章节目录']");
if (fn.lh.startsWith("m.")) {
let chapters = [];
return fn.fetchDoc(a).then(dom => {
const get = (_dom) => fn.gae(".readlist a", _dom).map(a => ({
text: a.innerText.trim(),
url: a.href
}));
let pages = fn.ge(".hd-sel", dom);
if (pages) {
let doms = [dom];
let links = fn.gae("option[value]", pages).map(e => e.value);
let resArr = links.map(link => fn.fetchDoc(link));
return Promise.all(resArr).then(res => {
doms = [...doms, ...res];
return doms.map(page_dom => get(page_dom)).flat();
});
}
return get(dom);
});
}
return fn.fetchDoc(a).then(dom => fn.gae(".cy_plist~.cy_plist a", dom).map(a => ({
text: a.innerText.trim(),
url: a.href
})));
},
customTitle: (dom = document) => fn.attr("meta[name='keywords']", "content", dom).replace(",", " - "),
preloadNext: true,
hide: "#prePage,#nextPage,select[onchange],.jump-list,.apjg,a[href*=taobao],body>*[style*='z-index'][style*='2147483646']",
category: "comic"
}, {
name: "哈哈漫画",
url: {
h: "www.hahacomic.com",
p: /^\/manhua\/\d+\/\d+\.html/
},
imgs: "img[data-original]",
button: [4],
insertImg: [".chapter-images", 2],
autoDownload: [0],
next: "//a[label[text()='下一章'] and not(starts-with(@href,'java'))]",
prev: "//a[label[text()='上一章'] and not(starts-with(@href,'java'))]",
chapters: {
url: "//a[div[text()='返回漫画']]",
target: ".fm-chapter-list-wrap a",
sort: "r"
},
customTitle: (dom = document) => dom.title,
preloadNext: true,
category: "comic"
}, {
name: "土豪漫画",
url: {
h: "www.thmanhua.com",
p: "/chapter/"
},
imgs: ".more-box img",
button: [4],
insertImg: [".more-box", 2],
autoDownload: [0],
next: {
s: "a[href*=chapter]",
t: "下一章"
},
prev: {
s: "a[href*=chapter]",
t: "上一章"
},
chapters: {
url: "//a[text()='详情']",
target: "#chapterList a"
},
customTitle: [".btn+div+div", ".btn+div"],
preloadNext: true,
category: "comic"
}, {
name: "哈哈漫画 - 分類自動翻頁",
url: {
h: "www.hahacomic.com",
p: "/list/"
},
autoPager: {
ele: ".mdui-col-lg-2",
observer: ".mdui-col-lg-2",
next: (dom) => fn.ge("span.current+a", dom) ? siteUrl.replace(/\?page=\d+/, "") + "?page=" + fn.ge("span.current+a", dom).getAttribute("href").match(/\d+/)[0] : null,
re: ".pages",
pageNum: () => nextLink.match(/\d+$/)[0]
},
openInNewTab: ".mdui-col-lg-2>a",
category: "autoPager"
}, {
name: "轻之国度",
url: {
h: "www.lightnovel.us",
p: /^\/\w+\/detail\/\d+/
},
imgs: ".article-content img",
button: [4],
insertImg: [".article-content", 3],
customTitle: ".article-title",
category: "comic"
}, {
name: "微信公众号",
url: {
h: "mp.weixin.qq.com",
p: /^\/[^&]+&mid=\d+/
},
imgs: "img.js_insertlocalimg,img.wxw-img",
category: "comic"
}, {
name: "微信公众号",
url: {
h: "mp.weixin.qq.com",
s: "sn="
},
imgs: "img.js_insertlocalimg,img.wxw-img",
category: "comic"
}, {
name: "虎扑社区",
url: {
h: "bbs.hupu.com",
p: /^\/\d+\.html/
},
init: () => (siteJson = JSON.parse(fn.attr("#bbs-admin-main-post-container", "data-admininfo"))),
imgs: () => {
let data = JSON.parse(siteJson.format);
if (data.imgList) {
return data.imgList.map(e => e.remoteUrl);
} else if (data.jsonV3) {
return data.jsonV3.content.filter(item => item.type == "image").map(e => e.attrs.src);
} else {
return [];
}
},
customTitle: () => siteJson.postTitle,
category: "comic"
}, {
name: "微漫画 目錄頁",
host: ["medibang.com"],
url: {
h: "medibang.com",
p: "/book/",
d: "pc"
},
box: ["#contentsDetailShow"],
imgs: () => {
fn.showMsg(DL.str_05, 0);
let links;
let chapterIds;
if (fn.ge("a.btn_more")) {
links = fn.gau("a.btn_more").reverse();
chapterIds = links.map(url => url.split("/").at(-1));
} else {
links = fn.gau(".btn_book_read>a");
chapterIds = links.map(url => url.split("/").at(-2));
}
let resArr = [];
let fetchNum = 0;
for (let id of chapterIds) {
let res = fetch(`/api/book/fixedList2/${id}/?quality=pc`).then(res => res.json()).then(json => {
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${links.length}`, 0);
try {
let arr = [json.coverUrl];
json.chapterList[0].pageList.forEach(e => arr.push(e.publicBgImage));
return arr;
} catch (error) {
console.error(error);
return [];
}
});
resArr.push(res);
}
return Promise.all(resArr).then(data => data.flat());
},
button: [4],
insertImg: ["box", 3],
customTitle: ".box_data>h1.tit",
category: "comic"
}, {
name: "微漫画 閱讀頁",
host: ["medibang.com"],
url: {
h: "medibang.com",
p: "/viewer/",
d: "pc"
},
imgs: () => {
fn.showMsg(DL.str_05, 0);
let id = fn.lp.split("/").at(-2);
return fetch(`/api/book/fixedList2/${id}/?quality=pc`).then(res => res.json()).then(json => {
try {
let arr = [json.coverUrl];
json.chapterList[0].pageList.forEach(e => arr.push(e.publicBgImage));
return arr;
} catch (error) {
console.error(error);
return [];
}
});
},
capture: () => _this.imgs(),
hide: ".mdModal.mdWd1",
category: "comic"
}, {
name: "HachiRAW/JRAW",
url: {
h: ["hachiraw.net", "jraw.top"],
p: "/chapter"
},
box: ["#TopPage", 2, 1200],
imgs: () => fn.getImgSrcArr("#TopPage img").filter(e => e != "https://hachiraw.net/01.png"),
button: [4],
insertImg: ["box", 2],
insertImgAF: () => fn.hideEle("#TopPage"),
autoDownload: [0],
current: () => fn.ge("div:has(>.btn-success)"),
next: () => {
let next = _this.current()?.previousElementSibling?.firstElementChild;
return next ? next.href : null;
},
prev: () => {
let prev = _this.current()?.nextElementSibling?.firstElementChild;
return prev ? prev.href : null;
},
chapters: {
target: "#ChapterModal a",
sort: "r"
},
category: "comic"
}, {
name: "KKRAW",
url: {
h: ["kkraw.com"],
p: "/chapter"
},
box: [".more-box", 2],
imgs: ".more-box img",
button: [4],
insertImg: ["box", 2],
insertImgAF: () => fn.hideEle(".more-box"),
autoDownload: [0],
next: "//a[text()='次の章'][starts-with(@href,'/')]",
prev: "//a[text()='前の章'][starts-with(@href,'/')]",
customTitle: () => fn.title(" - 無料読み - Kkraw"),
category: "comic"
}, {
name: "SHINIGAMI",
url: {
h: ["shinigami-id.top"],
p: "/ch/"
},
imgs: ".read-img>img",
button: [4],
insertImg: [".read-img", 2],
autoDownload: [0],
next: "//a[contains(text(),'Next »')]",
prev: "//a[contains(text(),'« Prev')]",
customTitle: "section h3",
category: "comic"
}, {
name: "comic imgs",
host: ["www.manhuab.com", "www.manhua4.com"],
url: {
st: "var imgs",
e: [".info-title,.con_top", "#content"],
p: "/manhua/"
},
imgs: () => {
let f = fn.html(_unsafeWindow.imgs.join(""));
return fn.gae("img", f);
},
button: [4],
insertImg: ["#content", 2],
autoDownload: [0],
next: "//a[text()='下一章']",
prev: "//a[text()='上一章']",
customTitle: () => {
let texts = fn.gt(".info-title,.con_top").split(">").map(t => t.trim());
return texts.at(-2) + " - " + texts.at(-1);
},
category: "comic"
}, {
name: "九天AD",
url: {
e: ["#body-header-top", ".logo-pc", ".logo-moible"]
},
hide: "#installContainer",
category: "ad"
}, {
name: "漫畫類 自動展開目錄",
reg: [
/(mangabz|xmanhua|yymanhua|dm5|1kkk|manhuaren|manben|mkzhan)\.com\/[\w-]+\//,
/(m\.dmzj\.com|m\.gmh1234\.com)\/(info|comic)\/\d+\.html$/,
/(dgmanhua|acgwd|magayuan|manhua456|dashumanhua|shilunart|ruyanmh|mh160|szcdmj)\.(com|cc)\/(comic|manhua|manga|maga|kanmanhua|szcbook)\/[\w-]+\/?$/,
/www\.mhua5\.com\/[\w-]+\.html/,
/m\.guoman\.net\/comic\/\w+/,
/(www|m)\.77mh\.\w+\/colist_\d+\.html/,
/www\.manhw\.com\/index\.php\/comic\/\w+$/,
/rumanhua\d?\.com\/\w+\/$/i,
/dumanwu\d?\.com\/\w+\/$/i,
/haoguoman\.net\/\d+$/,
/^https?:\/\/www\.hmttmh\.com\/book\//,
/^https?:\/\/cn.zhuzhumh.com\/book\//,
],
init: async () => {
if (["www.magayuan.com", "m.magayuan.com"].some(h => h === fn.lh)) {
fn.css(".Introduct_Sub{background:url(https://m.idmzj.com/images/int_bg.png)!important;background-size:100% 100%!important}");
}
if (isM) {
if (["xmanhua", "yymanhua"].some(h => fn.lh.includes(h)) && fn.ge("//a[text()='章節']")) {
EClick("//a[text()='章節']");
}
}
if (fn.lh.includes("haoguoman")) {
setTimeout(() => {
EClick(".j-chapter-more");
}, 1500);
}
},
autoClick: [`
span.more,
a.detail-list-form-more,
a.detail-list-more,
.deatil-list-more>a,
.detail-more,
.moreChapter,
.show-more,
a#zhankai,
.gengduo_dt1>button,
.morechapter>button,
.gengduo_dt1>a,
.chapterList+.more,
li.add,a.extend,
a.action-collapse:not(.on),
.chapter__more .down,
.listmore,
.more.chapLiList-cont>a,
.m-load-more-sm>a,
.more>a,
.allmulu,
.show-more>a,
.morechp,
.nnmore>a,
.chaplist-more>button
`, 1500],
hide: ".comic-info-box+a,.cartoon-introduction.cmg,.cartoon-introduction+a,.msloga,.comic_intro>a,.Introduct+a,[class^='ad']",
category: "none"
}, {
name: "94i.in 自動簽到",
host: ["94i.in"],
reg: /^https?:\/\/94i\.in\//,
autoClick: "#pper_a:not([style='display: none;'])",
category: "none"
}, {
name: "Supjav 立即顯示影片縮圖",
host: ["supjav.com"],
delay: 300,
reg: /^https?:\/\/supjav\.com\/(zh\/|ja\/)?\d+\.html/,
init: async () => {
let t = fn.ge("title");
t.innerText = t.innerText.replace(/-\sSupjav.com.+/, "").trim();
let ele = "#vserver.play-button";
if (await fn.waitEle(ele)) EClick(ele);
},
category: "none"
}, {
name: "ouo.io 自動跳轉",
host: ["ouo.io"],
reg: /^https?:\/\/ouo\./,
init: async () => {
let ele = "#btn-main:not(.disabled)";
if (await fn.waitEle(ele)) EClick(ele);
},
category: "none"
}, {
name: "cuty.io 自動跳轉",
host: ["cuty.io"],
reg: /^https?:\/\/cutt?y\.(io|app)\/\w+/i,
init: async () => {
let ele = "//button[@id='submit-button' and text()= 'Continue' or text()= 'I am not a robot' or text()= 'Go ->']";
if (await fn.waitEle(ele)) EClick(ele);
},
category: "none"
}, {
name: "m.4khd.com 自動跳轉",
host: ["m.4khd.com"],
enable: 0,
url: {
h: "m.4khd.com",
p: /^\/\w+$|^\/link\/|^\/vip\//i
},
init: () => {
if (fn.ge("#content a[href*='reload']")) {
return location.reload();
}
if (fn.lp.includes("/vip/")) {
fn.css(FullPictureLoadStyle, "FullPictureLoadMainStyle");
fn.showMsg("系統錯誤,1秒後關閉。");
return setTimeout(() => window.close(), 1000);
}
const selector = "//a[text()='GET LINK']|//a[span[text()='GET LINK']]";
if (fn.ge(selector)) {
let url = fn.gu(selector);
EClick(selector);
ge("#cz").innerHTML = "▲";
ge("#zc_tiaozhuan").style.display = "block";
fn.clearAllTimer(3);
}
},
hide: "#divExoLayerWrapper,.exo-ipp,.exo_wrapper,div:has(>.centered-contai),.center-container,.centered-contai",
category: "none"
}, {
name: "4kup.net 自動跳轉",
host: ["4kup.net"],
reg: /^https?:\/\/4kup\.net\/getlink\/$/,
init: async () => {
let selectorArr = ["#output:not([style*=none]) button", "#gotolink:not([disabled])"];
for (let selector of selectorArr) {
await fn.waitEle(selector);
EClick(selector);
await delay(200);
}
},
category: "none"
}, {
name: "terabox.fun 自動跳轉",
host: ["terabox.fun"],
reg: /^https?:\/\/terabox\.fun\/slmiddlepage\//,
init: async () => {
let ele = ".btn.active";
setInterval(async () => {
if (await fn.waitEle(ele)) EClick(ele);
}, 1000);
},
category: "none"
}, {
name: "MediaFire 自動下載",
host: ["www.mediafire.com"],
reg: /^https?:\/\/www\.mediafire\.com\//,
autoClick: ".download_link:not(.started) #downloadButton",
category: "none"
}, {
name: "anonfiles 自動下載",
host: ["anonfiles.com"],
reg: /^https?:\/\/anonfiles\.com\//,
autoClick: ["#download-url"],
category: "none"
}, {
name: "letsupload 自動下載",
host: ["letsupload.cc"],
reg: /^https?:\/\/letsupload\.cc\//,
autoClick: ["#download-url"],
category: "none"
}, {
name: "stfly.me 半自動跳轉",
host: ["stfly.me"],
reg: () => fn.ge("img[src^='https://stfly.me/']") ? true : false,
init: async () => {
if (await fn.waitEle(".btn-captcha:not(.disable)")) setInterval(() => EClick(".btn-captcha:not(.disable)"), 3000);
},
category: "none"
}, {
name: "link1s 自動跳轉",
host: ["link1s.com"],
reg: () => fn.ge("a.site-logo[href='https://link1s.com/'],a.logo-image[href='https://link1s.com/']") ? true : false,
init: async () => {
if (await fn.waitEle("//button[@onclick='link1sgo()'] | //button[@id='link' and contains(@style,'none')] | //a[text()='Get Link']")) EClick("//button[@onclick='link1sgo()'] | //a[@id='link1s'] | //a[text()='Get Link']");
},
category: "none"
}, {
name: "Binto.click 自動跳轉",
host: ["binto.click"],
reg: () => /^https?:\/\/binto\.click\/\w+$/i.test(siteUrl) && fn.ge("#go-link"),
init: async () => {
if (await fn.waitEle("//a[text()='Get Link']")) location.href = fn.gu("//a[text()='Get Link']");
},
category: "none"
}, {
name: "網址清單新分頁開啟",
host: ["github.com"],
reg: [
/github\.com\/skofkyo\/AutoPager\/tree\/main\/CustomPictureDownload$/,
/github\.com\/skofkyo\/AutoPager\/blob\/main\/CustomPictureDownload\/README\.md$/
],
init: async () => await fn.waitEle(".markdown-body a"),
openInNewTab: ".markdown-body a[href]:not([target=_blank]):not([id])",
css: ".markdown-body a{text-decoration:none!important}",
category: "none"
}];
//const debug = (str, obj = "", title = "debug") => console.log(`%c[Full Picture Load] ${title}:`, "background-color: #C9FFC9;", str, obj);
function debug(str, obj = "", title = "debug") {
console.log(`%c[Full Picture Load] ${title}:`, "background-color: #C9FFC9;", str, obj);
}
function getType(object) {
try {
return Object.prototype.toString.call(object)?.replace("[object ", "")?.replace("]", "");
} catch {
return undefined;
}
}
function addElement(node, tag, attrs) {
const elem = document.createElement(tag);
Object.assign(elem, {
...attrs
});
node.appendChild(elem);
return elem;
}
const hasTouchEvent = ("ontouchstart" in _unsafeWindow);
const isM = ("ontouchstart" in _unsafeWindow);
const isMobileDeviceUA = ["Mobi", "Android", "iPhone", "iPad", "iPod", "BlackBerry", "IEMobile", "Opera Mini"].some(d => _unsafeWindow.navigator.userAgent.includes(d));
const isPC = !isMobileDeviceUA || !("ontouchstart" in _unsafeWindow);
const isCh = language.includes("zh") || language.includes("TW");
const isMobileEdge = ["Mobile", "EdgA"].every(t => _unsafeWindow.navigator.userAgent.includes(t));
const isMobileYandex = ["Mobile", "YaBrowser"].every(t => _unsafeWindow.navigator.userAgent.includes(t));
const isFirefox = _unsafeWindow.navigator.userAgent.includes("Firefox");
const isXBrowser = ("mbrowser" in _unsafeWindow) && !!_unsafeWindow?.mbrowser?.GM_xmlhttpRequest;
const isVia = ("via" in _unsafeWindow) && ("via_gm" in _unsafeWindow);
const isString = str => getType(str) === "String";
const isNumber = num => getType(num) === "Number";
const isBoolean = b => getType(b) === "Boolean";
const isRegExp = reg => getType(reg) === "RegExp";
const isObject = obj => getType(obj) === "Object";
const isArray = arr => getType(arr) === "Array";
const isSet = set => getType(set) === "Set";
const isFn = fn => getType(fn).endsWith("Function");
const isPromise = p => getType(p) === "Promise";
const isEle = e => (getType(e).startsWith("HTML") && getType(e).endsWith("Element")) || getType(e) === "DocumentFragment";
const isURL = (url) => {
if ("canParse" in URL) {
return URL.canParse(url);
}
try {
new URL(url);
return true;
} catch {
return false;
}
};
const cancelDefault = (event) => {
event.preventDefault();
event.stopPropagation();
};
const _GM_xmlhttpRequest = (() => isFn(GM_xmlhttpRequest) ? GM_xmlhttpRequest : GM.xmlHttpRequest)();
const _GM_openInTab = (() => isFn(GM_openInTab) ? GM_openInTab : GM.openInTab)();
const _GM_getValue = (() => isFn(GM_getValue) ? GM_getValue : GM.getValue)();
const _GM_setValue = (() => isFn(GM_setValue) ? GM_setValue : GM.setValue)();
const _GM_listValues = (() => isFn(GM_listValues) ? GM_listValues : GM.listValues)();
const _GM_deleteValue = (() => isFn(GM_deleteValue) ? GM_deleteValue : GM.deleteValue)();
const _GM_registerMenuCommand = (() => isFn(GM_registerMenuCommand) ? GM_registerMenuCommand : GM.registerMenuCommand)();
const _GM_unregisterMenuCommand = (() => isFn(GM_unregisterMenuCommand) ? GM_unregisterMenuCommand : GM.unregisterMenuCommand)();
const _GM_getResourceText = (() => isFn(GM_getResourceText) ? GM_getResourceText : GM.getResourceText)();
const _GM_addElement = (() => {
try {
return GM_addElement;
} catch {
return addElement;
}
})();
const UI_zIndex = Number(_GM_getValue("UI_zIndex", 2147483647));
const pageViewMode = _GM_getValue("pageViewMode", 0);
const ajaxHookerJS = _GM_getResourceText("ajaxHookerJS");
const CryptoJS_code = _GM_getResourceText("CryptoJS_code");
const JqueryJS = _GM_getResourceText("JqueryJS");
const FancyboxV5JS = _GM_getResourceText("FancyboxV5JS");
const FancyboxV5Css = _GM_getResourceText("FancyboxV5Css");
const FancyboxV3JS = _GM_getResourceText("FancyboxV3JS");
const FancyboxV3Css = _GM_getResourceText("FancyboxV3Css");
const ViewerJs = _GM_getResourceText("ViewerJs");
const ViewerJsCss = _GM_getResourceText("ViewerJsCss");
const addAjaxHookerLibrary = () => {
if (!("ajaxHooker" in _unsafeWindow)) {
_GM_addElement(document.body, "script", {
textContent: ajaxHookerJS
});
}
return _unsafeWindow.ajaxHooker;
};
const addCryptoJSLibrary = () => {
if (!("CryptoJS" in _unsafeWindow)) {
_GM_addElement(document.body, "script", {
textContent: CryptoJS_code
});
}
return _unsafeWindow.CryptoJS;
};
const addLibrarysV3 = async () => {
try {
const jsArr = [JqueryJS, FancyboxV3JS];
for (let [i, code] of jsArr.entries()) {
if (i == 0 && ("jQuery" in _unsafeWindow)) continue;
//fn.script(code, 0, 1);
_GM_addElement(document.body, "script", {
textContent: code
});
}
if ("fancybox" in siteData && siteData?.fancybox?.css !== false) {
fn.css(FancyboxV3Css, "FancyboxV3Css");
}
} catch (error) {
console.error("\naddLibrarysV3() 注入函式庫失敗", error);
}
};
const addLibrarysV5 = () => {
try {
const jsArr = [JqueryJS, FancyboxV5JS];
for (let [i, code] of jsArr.entries()) {
if (i == 0 && ("jQuery" in _unsafeWindow)) continue;
if (i == 1 && ("Fancybox" in _unsafeWindow)) return;
//fn.script(code, 0, 1);
_GM_addElement(document.body, "script", {
textContent: code
});
}
fn.css(FancyboxV5Css, "FancyboxV5Css");
} catch (error) {
console.error("\naddLibrarysV5() 注入函式庫失敗", error);
}
};
const FancyboxWheelValue = _GM_getValue("FancyboxWheel", 1);
let FancyboxWheel;
if (FancyboxWheelValue == 0) {
FancyboxWheel = "zoom";
} else {
FancyboxWheel = "slide";
}
const FancyboxSlideshowTimeout = Number(_GM_getValue("FancyboxSlideshowTimeout", 3));
const FancyboxSlideshowTimeoutNum = FancyboxSlideshowTimeout == 0 ? 500 : (FancyboxSlideshowTimeout * 1000);
const FancyboxSlideshowTransition = _GM_getValue("FancyboxSlideshowTransition", "fade") == "no" ? "false" : _GM_getValue("FancyboxSlideshowTransition", "fade");
const FancyboxAutoClose = _GM_getValue("FancyboxAutoClose", 1);
const FancyboxAutoNext = _GM_getValue("FancyboxAutoNext", 1);
let isOpenFancybox = false;
let FancyboxOptions;
let slideIndex = null;
if (isM) {
FancyboxOptions = {
Hash: false,
idle: false,
showClass: false,
hideClass: false,
Images: {
Panzoom: {
maxScale: 4
},
zoom: false
},
Slideshow: {
timeout: FancyboxSlideshowTimeoutNum,
},
Carousel: {
transition: FancyboxSlideshowTransition,
},
Thumbs: {
showOnStart: false
},
Toolbar: {
display: {
left: ["infobar"],
middle: ["flipX", "flipY"],
right: ["iterateZoom", "slideshow", "thumbs", "close"]
}
},
on: {
done: (fancybox, slide) => {
if (fancybox.isCurrentSlide(slide)) {
slideIndex = slide.index;
fn.scrollEvent(slideIndex);
} else {
fn.scrollEvent(fancybox.getSlide().index);
}
if (fancybox.carousel.page == 0 && (fancybox.carousel.prevPage == fancybox.carousel.pages.at(-1).index)) {
if (FancyboxAutoClose == 1) {
fancybox.close();
}
if (FancyboxAutoNext == 1) {
if (!!nextLink) {
fn.showMsg(DL.str_34.n);
setTimeout(() => (location.href = nextLink), 100);
}
}
}
},
close: fancybox => {
document.body.classList.remove("imgbox-show", "hide-scrollbar");
slideIndex = fancybox.getSlide().index;
fn.scrollEvent(slideIndex);
}
}
};
} else {
FancyboxOptions = {
Hash: false,
idle: false,
showClass: false,
hideClass: false,
wheel: FancyboxWheel,
Images: {
Panzoom: {
maxScale: 4
},
zoom: false
},
Slideshow: {
timeout: FancyboxSlideshowTimeoutNum,
},
Carousel: {
transition: FancyboxSlideshowTransition
},
Thumbs: {
showOnStart: false
},
Toolbar: {
display: {
left: ["infobar"],
middle: ["zoomIn", "zoomOut", "iterateZoom", "toggle1to1", "rotateCCW", "rotateCW", "flipX", "flipY", "fitX", "fitY", "reset"],
right: ["slideshow", "fullscreen", "thumbs", "close"]
}
},
on: {
done: (fancybox, slide) => {
isOpenFancybox = true;
if (fancybox.isCurrentSlide(slide)) {
slideIndex = slide.index;
fn.scrollEvent(slideIndex);
} else {
fn.scrollEvent(fancybox.getSlide().index);
}
if (fancybox.carousel.page == 0 && (fancybox.carousel.prevPage == fancybox.carousel.pages.at(-1).index)) {
if (FancyboxAutoClose == 1) {
fancybox.close();
}
if (FancyboxAutoNext == 1) {
if (!!nextLink) {
fn.showMsg(DL.str_34.n);
setTimeout(() => (location.href = nextLink), 100);
}
}
}
},
close: fancybox => {
document.body.classList.remove("imgbox-show", "hide-scrollbar");
slideIndex = fancybox.getSlide().index;
fn.scrollEvent(slideIndex);
setTimeout(() => {
isOpenFancybox = false;
}, 100);
}
}
};
}
const fancyboxBlackList = () => siteData.fancybox?.blacklist === 1;
//顯示語言
switch (language) {
case "TW":
case "zh-TW":
case "zh-HK":
case "zh-MO":
case "zh-Hant-TW":
case "zh-Hant-HK":
case "zh-Hant-MO":
DL = {
xchina_picnum_error: "圖片數量不符,請反饋。",
str_01: "獲取圖片元素中...",
str_02: "獲取圖片中 ",
str_03: "獲取圖片逾時",
str_04: "等待關鍵元素中...",
str_05: "獲取資料中...",
str_06: "獲取資料中 ",
str_07: "確認登錄狀態中...",
str_08: "獲取預覽圖中...",
str_09: "獲取最後一張圖...",
str_10: "是否複製連結至剪貼簿?",
str_11: "已複製連結至剪貼簿",
str_12: "只有複製連結功能",
str_13: "請輸入圖片抓取最大次數",
str_14: "獲取下一頁中...",
str_15: "獲取下一頁結束",
str_16: "獲取元素中...",
str_17: "獲取元素中 ",
str_18: "已聚集所有圖片",
str_19: "用來定位插入的元素不存在",
str_20: "沒有能插入的圖片",
str_21: "延遲",
str_22: "毫秒",
str_23: "第",
str_24: "張下載",
str_25: "完成",
str_26: "錯誤",
str_27: "下載失敗了",
str_28: "張",
str_29: "\n是否只保存目前下載成功的圖片?\n只要圖片不是100%掛掉,可以調低下載線程數或重新載入網頁後重新下載試試看,網站如有Cloudflare防火牆,需要自行取得Cookie,使用Set Cloudflare Clearance Cookies填入或更新Cookie。",
str_30: "圖片extension錯誤",
str_31: "壓縮進度: ",
str_32: "自動下載倒數",
str_33: "秒",
str_34: {
n: "nextJS前往下一頁",
p: "prevJS前往上一頁"
},
str_35: "已點擊下一頁",
str_36: "自動下載完畢",
str_37: "沒有下一頁元素",
str_38: "返回上一頁",
str_39: "已點擊上一頁",
str_40: "沒有上一頁元素",
str_41: "已取消",
str_42: "字數小於3已取消",
str_43: "下載失敗數據為空...",
str_44: "沒有任何圖片元素...",
str_45: "網址已複製",
str_46: "即將進行滾動...",
str_47: "左鍵:進行下載打包壓縮\n中鍵:匯出網址URLs.txt文件\n右鍵:複製圖片網址和標題或手動模式聚集所有圖片",
str_48: "下載&壓縮中請稍後再操作!",
str_49: "獲取圖片中請稍後再操作!",
str_50: "自訂網站收藏的網址在新分頁開啟",
str_51: "請輸入自訂壓縮檔資料夾名稱",
str_52: "聚圖數量",
str_53: "圖片繪製中...",
str_54: "403,未登錄網站?",
str_55: "下載載入中...",
str_56: "確認圖片狀態中...",
str_57: "自動翻頁載入中...",
str_58: "已到達最後一頁",
str_59: "沒有任何主體元素",
str_60: "圖片縮放",
str_61: "取消縮放",
str_62: "前往第一張圖",
str_63: "左鍵:前往最後一張圖\n右鍵:匯出網址URLs.txt文件",
str_64: "即將開始自動下載!!!",
str_65: "已停止自動下載!!!",
str_66: "💬 Greasy Fork 反饋",
str_67: "⚙️ 設定",
str_68: "當前(※全局)網站選項",
str_69: "顯示左下圖示按鈕",
str_70: "最大下載線程數:",
str_71: "下載後壓縮打包",
str_72: "壓縮檔副檔名:",
str_73: "自動下載",
str_74: "ESC鍵:可中斷自動下載\n快捷鍵 [ ctrl + . ]:開始自動下載或取消自動下載",
str_75: "自動下載倒數秒數:",
str_76: "啟用當前漫畫站點規則",
str_77: "自動進入畫廊需點擊主圖示按鈕",
str_78: "Fancybox&Viewer燈箱功能",
str_79: "頁面容器圖片縮放比例:",
str_80: "頁面容器圖片並排數量:",
str_81: "comic類固定為2,comic類並排後為右至左的漫讀模式,hcomic類也設定為2將套用。",
str_82: isM ? "取消" : "取消 (Esc)",
str_83: "重置設定",
str_84: "保存設定",
str_85: isM ? "腳本選項" : "腳本選項(*)",
str_86: isM ? "切換模式" : "切換模式(5)",
str_87: isM ? "比例縮放" : "比例縮放(-+)",
str_88: isM ? "取消縮放" : "取消縮放(.)",
str_89: "暫停自動翻頁",
str_90: "啟用自動翻頁",
str_91: "初始化設定",
str_92: "原始模式",
str_93: "並排模式",
str_94: "返回開頭了",
str_95: "前往下一集",
str_96: "已是最後一集",
str_97: "共",
str_98: "頁獲取出錯,建議反饋",
str_99: "重試第",
str_100: "次",
str_101: "網址.txt已匯出",
str_102: "格式轉換中...",
str_103: "頁面容器預設使用並排模式",
str_104: isM ? "匯出圖址" : "匯出圖址(7)",
str_105: isM ? "複製圖址" : "複製圖址(1)",
str_106: isM ? "分頁畫廊" : "分頁畫廊(8)",
str_107: isM ? "一鍵下載" : "一鍵下載(3)",
str_108: "※ 訊息提示顯示的位置:",
str_109: {
c: "置中",
ul: "左上",
ur: "右上",
ll: "左下",
lr: "右下",
},
str_110: "WEBP轉換為JPG",
str_111: "匯出",
str_112: "提示",
str_113: "滾動煞車:",
str_114: "E/EX-HENTAI 載入原始圖片連結",
str_115: "自動滾動至首張圖片",
str_116: "自動滾動所有惰性載入的圖片元素",
str_117: "顯示浮動選單",
str_118: "圖集標題已更新",
str_119: "Fancybox5滾輪圖片縮放",
str_120: "分頁畫廊使用Viewer插件",
str_121: "關閉頁面容器圖片導覽快捷鍵",
str_122: "此漫畫站使用無限滾動閱讀模式",
str_123: "顯示右下捕獲之眼圖示",
str_124: "下載影片",
str_125: "🔄 重置此網站儲存的所有腳本設定",
str_126: "🔄 重置腳本儲存的所有全局設定",
str_127: "右鍵:匯出圖址(7)",
str_128: isM ? "開啟收藏" : "開啟收藏(9)",
str_129: "關閉收藏",
str_130: "編輯收藏",
str_131: "保存",
str_132: "關閉",
str_133: "選單",
str_134: "浮動選單",
str_135: "無限滾動初始化中...",
str_136: "右鍵:增加圖片縮放級別(+)",
str_137: "頁面圖片添加燈箱模式",
str_138: "此網站禁用",
str_139: "自動聚圖至頁面容器",
str_140: "自動進入影子畫廊",
str_141: isM ? "影子畫廊" : "影子畫廊(G)",
str_142: isM ? "離開畫廊" : "離開畫廊 (Esc)",
str_143: "下一話",
str_144: "下一篇",
str_145: "Fancybox5&Viewer幻燈片播放間隔:",
str_146: "Fancybox5滾輪操作:",
str_147: "畫廊 ( 0、1、3 ) 滾輪操作:",
str_148: "Fancybox5幻燈片過場效果:",
str_149: "已中斷下載!!!",
str_150: "JK滾動",
str_151: "JK平滑滾動",
str_152: "一個視口",
str_153: "標題:",
str_154: "全部選取",
str_155: "取消全選",
str_156: "重新載入",
str_157: "開始下載",
str_158: isM ? "篩選下載" : "篩選下載(F)",
str_159: isM ? "自訂函式" : "自訂函式(6)",
str_160: isM ? "插入圖片" : "插入圖片(1)",
str_161: "載入線程:",
str_162: isM ? "預載:" : "圖片預載數:",
str_163: "🖼️ 開啟簡易模式",
str_164: "🖼️ 關閉簡易模式",
str_165: "圖片總數:",
str_166: "篩選數量:",
str_167: "篩選寬度:",
str_168: "篩選高度:",
str_169: "佈景主題:",
str_170: "反向選取",
str_171: "檔案大小",
str_172: "拖動排序",
str_173: "可拖動圖片來改變圖片順序。",
str_174: "匯出為JSON格式",
str_175: "已匯出JSON格式",
str_176: "匯出為MD格式",
str_177: "已匯出Markdown格式",
str_178: "複製為MD格式",
str_179: "複製為Markdown格式",
str_180: "自動匯出URLs.txt",
str_181: "拼接下載",
str_182: "※ 畫廊圖片循環切換",
str_183: "排除格式",
str_184: "排除錯誤",
str_185: "自動排錯",
str_186: "更多選單",
str_187: "壓縮檔裡創建資料夾",
str_188: "手機畫廊",
str_189: "單圖模式",
str_190: "條漫模式",
str_191: "預設開啟簡易模式",
str_192: "自動進入手機畫廊",
str_193: "匯出JSON",
str_194: "複製MD",
str_195: "匯出MD",
str_196: "前往下一話",
str_197: "前往下一篇",
str_198: "畫廊 ( 5 ) 滾輪操作:",
str_199: "移動裝置雙擊前往下一頁",
str_200: "AVIF轉換為JPG",
str_201: "JPG格式轉換品質",
str_202: "Hitomi.la 圖片格式:",
str_203: isM ? "點我提示✨" : "懸停提示✨",
str_204: "⚙️ 腳本UI最外層堆疊順序",
str_205: "請輸入z-index值(7 ~ 2147483647)",
str_206: "圖片尺寸:",
str_207: "預設",
str_208: "圖片代理",
str_209: "不使用",
str_210: "Fancybox5尾返首時自動關閉",
str_211: "Fancybox5尾返首時自動前往下一頁",
str_212: "匯入",
str_213: "Tampermonkey 5.3.2+ GM_xmlhttpRequest無法多線程下載。\n詳見:https://github.com/Tampermonkey/tampermonkey/issues/2215\nViolentmonkey、ScriptCat、Fetch API,沒有此問題。",
str_214: "全局使用Fetch API下載",
str_215: "需搭配擴充套件來使用\nChrome關鍵字:--disable-web-security 或 CORS Unblock 或 CORS Control\nFireFox關鍵字:CORS Unblock 或 CORS Everywhere\n禁用同源策略,注意此操作極不安全,不懂別做,用完即關。\n無法通過Cloudflare防火牆驗證時須先刪除,過了再加上。",
str_216: isM ? "漫畫目錄" : "漫畫目錄 (C)",
str_217: "網站首頁",
galleryMenu: {
horizontal: isM ? "水平模式" : "水平模式 (5,B,R)",
webtoon: isM ? "條漫模式" : "條漫模式 (4,+,-)",
rtl: isM ? "右至左模式" : "右至左模式 (3,B,R)",
small: isM ? "小圖像模式" : "小圖像模式 (2,B,R)",
single: isM ? "單圖像模式" : "單圖像模式 (1)",
default: isM ? "預設模式" : "預設模式 (0,B,R)",
},
FancyboxWheel: {
z: "圖片縮放",
s: "圖片切換"
},
FancyboxTransition: {
crossfade: "淡入淡出",
fade: "淡出",
slide: "滑動",
classic: "經典",
no: "無過場效果"
},
ShadowGalleryWheel: {
d: "畫廊滾動",
t: "圖片切換",
s: "圖列切換"
},
horizontalWheel: {
d: "水平滾動",
d2: "水平滾動自訂JK",
t: "圖片切換"
},
colorThemes: {
light: "淺色",
dark: "深色"
},
tab: {
p: "頁面",
g: "畫廊",
l: "燈箱",
d: "下載",
o: "其他"
}
};
break;
case "zh":
case "zh-CN":
case "zh-SG":
case "zh-MY":
case "zh-Hans-CN":
case "zh-Hans-SG":
case "zh-Hans-MY":
DL = {
xchina_picnum_error: "图片数量不符,请反馈。",
str_01: "获取图片元素中...",
str_02: "获取图片中 ",
str_03: "获取图片逾时",
str_04: "等待关键元素中...",
str_05: "获取数据中...",
str_06: "获取数据中 ",
str_07: "确认登录状态中...",
str_08: "获取预览图中...",
str_09: "获取最后一张图...",
str_10: "是否拷贝链接至剪贴板?",
str_11: "已拷贝链接至剪贴板",
str_12: "只有拷贝链接功能",
str_13: "请输入图片抓取最大次数",
str_14: "获取下一页中...",
str_15: "获取下一页结束",
str_16: "获取元素中...",
str_17: "获取元素中 ",
str_18: "已聚集所有图片",
str_19: "用来定位插入的元素不存在",
str_20: "没有能插入的图片",
str_21: "延迟",
str_22: "毫秒",
str_23: "第",
str_24: "张下载",
str_25: "完成",
str_26: "错误",
str_27: "下载失败了",
str_28: "张",
str_29: "\n是否只保存目前下载成功的图片?\n只要图片不是100%挂掉,可以调低下载线程数或重新加载网页后重新下载试试看,网站如有Cloudflare防火墙,需要自行取得Cookie,使用Set Cloudflare Clearance Cookies填入或更新Cookie。",
str_30: "图片extension错误",
str_31: "压缩进度: ",
str_32: "自动下载倒数",
str_33: "秒",
str_34: {
n: "nextJS前往下一页",
p: "prevJS前往上一页"
},
str_35: "已点击下一页",
str_36: "自动下载完毕",
str_37: "没有下一页元素",
str_38: "返回上一页",
str_39: "已点击上一页",
str_40: "没有上一页元素",
str_41: "已取消",
str_42: "字数小于3已取消",
str_43: "下载失败数据为空...",
str_44: "没有任何图片元素...",
str_45: "网址已拷贝",
str_46: "即将进行滚动...",
str_47: "左键:进行下载打包压缩\n中键:导出网址URLs.txt文档\n右键:拷贝图片网址和标题或手动模式聚集所有图片",
str_48: "下载&压缩中请稍后再操作!",
str_49: "获取图片中请稍后再操作!",
str_50: "自定义网站收藏的网址在新标籤页打开",
str_51: "请输入自定义压缩档文件夹名称",
str_52: "聚图数量",
str_53: "图片绘制中...",
str_54: "403,未登录网站?",
str_55: "下载加载中...",
str_56: "确认图片状态中...",
str_57: "自动翻页加载中...",
str_58: "已到达最后一页",
str_59: "没有任何主体元素",
str_60: "图片缩放",
str_61: "取消缩放",
str_62: "前往第一张图",
str_63: "左键:前往最后一张图\n右键:导出网址URLs.txt文档",
str_64: "即将开始自动下载!!!",
str_65: "已停止自动下载!!!",
str_66: "💬 Greasy Fork 反馈",
str_67: "⚙️ 设置",
str_68: "当前(※全局)网站设置",
str_69: "显示左下图标按钮",
str_70: "最大下载线程数:",
str_71: "下载后压缩打包",
str_72: "压缩档文件扩展名:",
str_73: "自动下载",
str_74: "ESC键:可中断自动下载\n快捷键 [ ctrl + . ]:开始自动下载或取消自动下载",
str_75: "自动下载倒数秒数:",
str_76: "启用当前漫画站点规则",
str_77: "自动进入画廊需点击主图示按钮",
str_78: "Fancybox&Viewer灯箱功能",
str_79: "页面容器图片缩放比例:",
str_80: "页面容器图片并排数量:",
str_81: "comic类固定为2,comic类并排后为右至左的漫读模式,hcomic类也设置为2将套用。",
str_82: isM ? "取消" : "取消 (Esc)",
str_83: "重置设置",
str_84: "保存设置",
str_85: isM ? "脚本设置" : "脚本设置(*)",
str_86: isM ? "切换模式" : "切换模式(5)",
str_87: isM ? "比例缩放" : "比例缩放(-+)",
str_88: isM ? "取消缩放" : "取消缩放(.)",
str_89: "暂停自动翻页",
str_90: "启用自动翻页",
str_91: "初始化设置",
str_92: "原始模式",
str_93: "并排模式",
str_94: "返回开头了",
str_95: "前往下一集",
str_96: "已是最后一集",
str_97: "共",
str_98: "页获取出错,建议反馈",
str_99: "重试第",
str_100: "次",
str_101: "网址.txt已导出",
str_102: "格式转换中...",
str_103: "页面容器默认使用并排模式",
str_104: isM ? "导出图址" : "导出图址(7)",
str_105: isM ? "复制图址" : "复制图址(1)",
str_106: isM ? "标签画廊" : "标签画廊(8)",
str_107: isM ? "一键下载" : "一键下载(3)",
str_108: "※ 讯息提示显示的位置:",
str_109: {
c: "置中",
ul: "左上",
ur: "右上",
ll: "左下",
lr: "右下",
},
str_110: "WEBP转换为JPG",
str_111: "导出",
str_112: "提示",
str_113: "滚动煞车:",
str_114: "E/EX-HENTAI 加载原始图片链接",
str_115: "自动滚动至首张图片",
str_116: "自动滚动所有懒加载的图片元素",
str_117: "显示浮动菜单",
str_118: "图集标题已更新",
str_119: "Fancybox5滚轮图片缩放",
str_120: "标签画廊使用Viewer插件",
str_121: "关闭页面容器图片导览快捷键",
str_122: "此漫画站使用无限滚动阅读模式",
str_123: "显示右下捕获之眼图标",
str_124: "下载视频",
str_125: "🔄 重置此网站存储的所有脚本设置",
str_126: "🔄 重置脚本存储的所有全局设置",
str_127: "右键:导出图址(7)",
str_128: isM ? "打开收藏" : "打开收藏(9)",
str_129: "关闭收藏",
str_130: "编辑收藏",
str_131: "保存",
str_132: "关闭",
str_133: "菜单",
str_134: "浮动菜单",
str_135: "无限滚动初始化中...",
str_136: "右键:增加图片缩放级别(+)",
str_137: "页面图片添加灯箱模式",
str_138: "此网站禁用",
str_139: "自动聚图至页面容器",
str_140: "自動進入影子畫廊",
str_141: isM ? "影子画廊" : "影子画廊(G)",
str_142: isM ? "离开画廊" : "离开画廊 (Esc)",
str_143: "下一话",
str_144: "下一篇",
str_145: "Fancybox5&Viewer幻灯片播放间隔:",
str_146: "Fancybox5滚轮操作:",
str_147: "画廊 ( 0、1、3 ) 滚轮操作:",
str_148: "Fancybox5幻灯片过场效果:",
str_149: "已中断下载!!!",
str_150: "JK滚动",
str_151: "JK平滑滚动",
str_152: "一个视口",
str_153: "标题:",
str_154: "全部选取",
str_155: "取消全选",
str_156: "重新加载",
str_157: "开始下载",
str_158: isM ? "筛选下载" : "筛选下载(F)",
str_159: isM ? "定义函式" : "定义函式(6)",
str_160: isM ? "插入图片" : "插入图片(1)",
str_161: "加载线程:",
str_162: isM ? "预载:" : "图片预载数:",
str_163: "🖼️ 开启简易模式",
str_164: "🖼️ 关闭简易模式",
str_165: "图片总数:",
str_166: "筛选数量:",
str_167: "筛选宽度:",
str_168: "筛选高度:",
str_169: "布景主题:",
str_170: "反向选取",
str_171: "文件大小",
str_172: "拖动排序",
str_173: "可拖动图片来改变图片顺序。",
str_174: "导出为JSON格式",
str_175: "已导出JSON格式",
str_176: "导出为MD格式",
str_177: "已导出Markdown格式",
str_178: "拷贝为MD格式",
str_179: "拷贝为Markdown格式",
str_180: "自动导出URLs.txt",
str_181: "拼接下载",
str_182: "※ 画廊图片循环切换",
str_183: "排除格式",
str_184: "排除错误",
str_185: "自动排错",
str_186: "更多选单",
str_187: "压缩档里创建资料夹",
str_188: "手机画廊",
str_189: "单图模式",
str_190: "条漫模式",
str_191: "默认打开简易模式",
str_192: "自动进入手机画廊",
str_193: "导出JSON",
str_194: "拷贝MD",
str_195: "导出MD",
str_196: "前往下一话",
str_197: "前往下一篇",
str_198: "画廊 ( 5 ) 滚轮操作:",
str_199: "移动设备双击前往下一页",
str_200: "AVIF转换为JPG",
str_201: "JPG格式转换品质",
str_202: "Hitomi.la 图片格式:",
str_203: isM ? "点我提示✨" : "悬停提示✨",
str_204: "⚙️ 脚本UI最外层堆叠顺序",
str_205: "请输入z-index值(7 ~ 2147483647)",
str_206: "图片尺寸:",
str_207: "默认",
str_208: "图片代理",
str_209: "不使用",
str_210: "Fancybox5尾返首时自动关闭",
str_211: "Fancybox5尾返首时自动前往下一页",
str_212: "导入",
str_213: "Tampermonkey 5.3.2+ GM_xmlhttpRequest无法多线程下载。\n详见:https://github.com/Tampermonkey/tampermonkey/issues/2215\nViolentmonkey、ScriptCat、Fetch API,没有此问题。",
str_214: "全局使用Fetch API下载",
str_215: "需搭配扩展来使用\nChrome关键字:--disable-web-security 或 CORS Unblock 或 CORS Control\n详见稀土掘金:https://juejin.cn/post/7280435431328710716\nFireFox 关键字:CORS Unblock 或 CORS Everywhere\n禁用同源策略,注意此操作极不安全,不懂别做,用完即关。\n无法通过Cloudflare防火墙验证时须先删除,过了再加上。",
str_216: isM ? "漫画目录" : "漫画目录 (C)",
str_217: "网站首页",
galleryMenu: {
horizontal: isM ? "水平模式" : "水平模式 (5,B,R)",
webtoon: isM ? "条漫模式" : "条漫模式 (4,+,-)",
rtl: isM ? "右至左模式" : "右至左模式 (3,B,R)",
small: isM ? "小图像模式" : "小图像模式 (2,B,R)",
single: isM ? "单图像模式" : "单图像模式 (1)",
default: isM ? "默认模式" : "默认模式 (0,B,R)",
},
FancyboxWheel: {
z: "图片缩放",
s: "图片切换"
},
FancyboxTransition: {
crossfade: "淡入淡出",
fade: "淡出",
slide: "滑动",
classic: "经典",
no: "无过场效果"
},
ShadowGalleryWheel: {
d: "画廊滚动",
t: "图片切换",
s: "图列切换"
},
horizontalWheel: {
d: "水平滚动",
d2: "水平滚动自訂JK",
t: "图片切换"
},
colorThemes: {
light: "浅色",
dark: "深色"
},
tab: {
p: "页面",
g: "画廊",
l: "灯箱",
d: "下载",
o: "其他"
}
};
break;
default:
DL = {
xchina_picnum_error: "图片数量不符,请反馈。",
str_01: "Get Images...",
str_02: "Get Images ",
str_03: "Get timed out",
str_04: "Wait Element...",
str_05: "Get Data...",
str_06: "Get Data ",
str_07: "Confirm Login Status",
str_08: "Get Preview Thumbnail",
str_09: "Get Element...",
str_10: "Whether To Copy Link To Clipboard?",
str_11: "Copied",
str_12: "Only Link Can Be Copied",
str_13: "Please Enter The Number Of Images",
str_14: "Get Next Page...",
str_15: "Get Next Page End",
str_16: "Get Element...",
str_17: "Get Element ",
str_18: "All Images Gathered",
str_19: "Element Does Not Exist",
str_20: "No Images",
str_21: "Delay",
str_22: "ms",
str_23: "No. ",
str_24: " Download ",
str_25: "Completed",
str_26: "Error",
str_27: "Download Failed",
str_28: "P",
str_29: "\nDo you want to save only the Images that have been successfully downloaded so far?\nAs long as the image is not 100% dead, you can reduce the number of download threads or reload the web page and try downloading again.\nIf website has a Cloudflare firewall, you need to obtain cookies yourself and use Set Cloudflare Clearance Cookies to fill in the cookies.",
str_30: "Image Extension Error",
str_31: "Compression Progress: ",
str_32: "Countdown ",
str_33: " sec",
str_34: {
n: "JS Go To Next Page",
p: "JS Go To Prev Page",
},
str_35: "Next Page Clicked",
str_36: "AutoDownload Completed",
str_37: "No Next Page Element",
str_38: "Return To Previous Page",
str_39: "Previous Page Clicked",
str_40: "No Previous Page Element",
str_41: "Cancelled",
str_42: "Cancelled",
str_43: "Download Failed Data Is Empty",
str_44: "No Picture Element",
str_45: "URLs Copied ",
str_46: "About To Scroll...",
str_47: "Left Click:Download And Compress\nMiddle Click:Export URLs.txt\nRight Click:Copy Image URL And Title Or Aggregate Images",
str_48: "Downloading & Compressing, Please Try Again Later!",
str_49: "Get Pictureing Please Try Again Later!",
str_50: "Favored Website URL Open in New Tab",
str_51: "Please Enter A Custom zip File Folder Name",
str_52: "Number Of Images",
str_53: "Picture Drawing...",
str_54: "403,Not Logged In To Website?",
str_55: "Download Loading...",
str_56: "Check Picture Statusing...",
str_57: "AutoPager Loading...",
str_58: "Reached The Last Page",
str_59: "No Main Element",
str_60: "Image Zoom",
str_61: "Cancel Eoom",
str_62: "Go To First Image",
str_63: "Left Click:Go To Last Image\nLeft Click:Export URLs.txt",
str_64: "Start Auto Download!!!",
str_65: "Stop Auto Download!!!",
str_66: "💬 Greasy Fork Feedback",
str_67: "⚙️ Settings",
str_68: "Current(※Global) Website Options",
str_69: "Show Lower Left Icon Button",
str_70: "Max Download Thread:",
str_71: "Compressed Packaging",
str_72: "Compressed File Extension:",
str_73: "Auto Download",
str_74: "ESC:Interrupt Auto Download\nShortcut key [ ctrl + . ]:Start Auto Download Or Cancel Auto Download",
str_75: "AutoDownload Countdown Sec:",
str_76: "Comic Site Rules Switch",
str_77: "Auto enter Gallery In Icon Button",
str_78: "Fancybox&Viewer Plugin",
str_79: "Image Zoom Ratio:",
str_80: "Number Of Images Side By Side:",
str_81: "Comic Category Fixed To 2",
str_82: isM ? "Cancel" : "Cancel (Esc)",
str_83: "Reset",
str_84: "Save",
str_85: isM ? "Settings" : "Settings(*)",
str_86: isM ? "Toggle" : "ToggleMode(5)",
str_87: isM ? "Zoom" : "ToggleZoom(-+)",
str_88: isM ? "Cancel" : "CancelZoom(.)",
str_89: "Pause Automatic Page Turning",
str_90: "Enable Automatic Page Turning",
str_91: "Initialization Settings",
str_92: "Original Mode",
str_93: "Side-By-Side Mode",
str_94: "Back To The Beginning",
str_95: "Go To Next Episode",
str_96: "It’s The Last Episode",
str_97: "Have",
str_98: "Page Fetch Error Please Feedback",
str_99: "Retry No.",
str_100: "Bout",
str_101: "MediaURLs.txt Exported",
str_102: "Format Converting",
str_103: "Enable Side-By-Side Mode",
str_104: isM ? "Export" : "ExportURLs(7)",
str_105: isM ? "Copy" : "CopyURLs(1)",
str_106: isM ? "TabView" : "NewTabView(8)",
str_107: isM ? "Download" : "FastDownload(3)",
str_108: "※ Where the message appears:",
str_109: {
c: "Center",
ul: "Upper left",
ur: "Upper right",
ll: "Lower left",
lr: "Lower right",
},
str_110: "Convert WEBP to JPG",
str_111: "Export",
str_112: "Prompt Message",
str_113: "Scroll:",
str_114: "E/EX-HENTAI Load Original Image",
str_115: "Auto Scroll To First Image",
str_116: "Auto Scroll All Image Elements",
str_117: "Show Fixed Menu",
str_118: "Album title has been updated",
str_119: "Fancybox5 Wheel Toggle Zoom",
str_120: "New Tab View Uses Viewer Plugin",
str_121: "Turn Off Image Navigation Shortcut Keys",
str_122: "This Website Uses Infinite Scroll Read Mode",
str_123: "Show Capture Eye Icon",
str_124: "Download Videos",
str_125: "🔄 Reset all script settings stored on this site",
str_126: "🔄 Reset all saved global settings",
str_127: "Right Click:Export URLs(7)",
str_128: isM ? "OpenFavor" : "OpenFavor(9)",
str_129: "Close Favor",
str_130: "Edit Favor",
str_131: "Save",
str_132: "Close",
str_133: "Menu",
str_134: "Float Menu",
str_135: "Infinite Scroll Initializing",
str_136: "Right Click:Increase Image Zzoom Level(+)",
str_137: "Add Fancybox To Image",
str_138: "This Website Is Disabled",
str_139: "Page Content Auto Insert Images",
str_140: "Auto enter Shadow Gallery",
str_141: isM ? "ShadowGallery" : "ShadowGallery(G)",
str_142: isM ? "Close" : "Close (Esc)",
str_143: "Next Chapter",
str_144: "Next Post",
str_145: "Fancybox5&Viewer Play Delay:",
str_146: "Fancybox5 Wheel:",
str_147: "Gallery (0、1、3) Wheel:",
str_148: "Slideshow Transition:",
str_149: "Download Interrupted!!!",
str_150: "JK Scroll ",
str_151: "JK Smooth Scroll",
str_152: "Viewport",
str_153: "Title:",
str_154: "Select All",
str_155: "Unselect All",
str_156: "Reload",
str_157: "Download",
str_158: isM ? "FilterDownload" : "FilterDownload(F)",
str_159: isM ? "Function" : "Function(6)",
str_160: isM ? "Insert Images" : "Insert Images(1)",
str_161: "Threads:",
str_162: "Preload:",
str_163: "🖼️ Enable Simple Mode",
str_164: "🖼️ Turn Off Simple Mode",
str_165: "Total Number Of Images:",
str_166: "Number Of Filters:",
str_167: "Filter Width:",
str_168: "Filter Height:",
str_169: "Setting Theme:",
str_170: "Reverse Selection",
str_171: "Show File Size",
str_172: "Drag Sort",
str_173: "Drag the image to change the order of images",
str_174: "Export JSON",
str_175: "Exported JSON",
str_176: "Export Markdown",
str_177: "Exported Markdown",
str_178: "Copy Markdown",
str_179: "Copied to Markdown format",
str_180: "Auto Export URLs.txt",
str_181: "Combine Download",
str_182: "※ Gallery Image Loop Toggle",
str_183: "Exclude Format",
str_184: "Culling",
str_185: "Auto Culling",
str_186: "More Menu",
str_187: "Create a folder in compressed file",
str_188: "Phone Gallery",
str_189: "Single",
str_190: "Webtoon",
str_191: "Simple mode enabled by default",
str_192: "Auto enter Phone Gallery",
str_193: "Export JSON",
str_194: "Copy Markdown",
str_195: "Export Markdown",
str_196: "Go To Next",
str_197: "Go To Next",
str_198: "Gallery (5) Wheel:",
str_199: "Double Click Go To Next Page",
str_200: "Convert AVIF to JPG",
str_201: "Convert Quality",
str_202: "Hitomi.la Image Format:",
str_203: "TIP✨",
str_204: "⚙️ UI z-index",
str_205: "Please enter a z-index value(7 ~ 2147483647)",
str_206: "Image Size:",
str_207: "Default",
str_208: "Image CDN",
str_209: "Not used",
str_210: "Fancybox5 Last Auto Close",
str_211: "Fancybox5 Last Auto Go To Next",
str_212: "Import",
str_213: "Tampermonkey 5.3.2+ GM_xmlhttpRequest cannot multithread\nSee:https://github.com/Tampermonkey/tampermonkey/issues/2215\nViolentmonkey and ScriptCat and Fetch API do not have this problem",
str_214: "Download globally using Fetch API",
str_215: "Need to be used with extensions\nChrome Keywords:--disable-web-security or CORS Unblock or CORS Control\nFireFox Keywords:CORS Unblock or CORS Everywhere\nWarning:Unsafe",
str_216: isM ? "Chapters" : "Chapters (C)",
str_217: "Home Page",
galleryMenu: {
horizontal: isM ? "Horizontal" : "Horizontal (5,B,R)",
webtoon: isM ? "Webtoon" : "Webtoon (4,+,-)",
rtl: isM ? "Right To Left" : "Right To Left (3,B,R)",
small: isM ? "Small Image" : "Small Image (2,B,R)",
single: isM ? "Single Image" : "Single Image (1)",
default: isM ? "Default" : "Default (0,B,R)",
},
FancyboxWheel: {
z: "zoom",
s: "slide"
},
FancyboxTransition: {
crossfade: "Crossfade",
fade: "Fade",
slide: "Slide",
classic: "Classic",
no: "No Animation"
},
ShadowGalleryWheel: {
d: "Gallery Scroll",
t: "Toggle Image",
s: "Toggle Row"
},
horizontalWheel: {
d: "Horizontal Scroll",
d2: "Horizontal Scroll Custom JK",
t: "Toggle Image"
},
colorThemes: {
light: "Light",
dark: "Dark"
},
tab: {
p: "Page",
g: "Gallery",
l: "Lightbox",
d: "Download",
o: "Other"
}
};
break;
}
const FullPictureLoadBlacklist = localStorage.getItem("FullPictureLoadBlacklist") ?? 0;
_GM_registerMenuCommand(DL.str_66, () => _GM_openInTab("https://greasyfork.org/scripts/463305/feedback"));
_GM_registerMenuCommand(FullPictureLoadBlacklist == 0 ? "❌ " + DL.str_138 : "✔️ " + DL.str_138, () => {
FullPictureLoadBlacklist == 0 ? localStorage.setItem("FullPictureLoadBlacklist", 1) : localStorage.setItem("FullPictureLoadBlacklist", 0);
location.reload();
});
if (FullPictureLoadBlacklist == 1) return;
const FullPictureLoadMsgPos = _GM_getValue("FullPictureLoadMsgPos", 0);
let msgTimeId;
const fn = {
url: (() => siteUrl)(),
lo: (() => _unsafeWindow.location.origin)(),
lp: (() => _unsafeWindow.location.pathname)(),
lh: (() => _unsafeWindow.location.hostname)(),
ls: (() => _unsafeWindow.location.search)(),
curl: (p = null) => {
const url = currentURL;
if (isString(p)) {
return url.includes(p);
} else if (isRegExp(p)) {
return url.search(p) > -1;
}
return url;
},
clh: (p = null) => {
const hostname = new URL(currentURL).hostname;
if (isString(p)) {
return hostname.includes(p);
} else if (isRegExp(p)) {
return hostname.search(p) > -1;
}
return hostname;
},
clp: (p = null) => {
const pathname = new URL(currentURL).pathname;
if (isString(p)) {
return pathname.includes(p);
} else if (isRegExp(p)) {
return pathname.search(p) > -1;
}
return pathname;
},
cls: (p = null) => {
const search = new URL(currentURL).search;
if (isString(p)) {
return search.includes(p);
} else if (isRegExp(p)) {
return search.search(p) > -1;
}
return search;
},
durl: (p = null) => {
const url = _unsafeWindow.document.URL;
if (isString(p)) {
return url.includes(p);
} else if (isRegExp(p)) {
return url.search(p) > -1;
}
return url;
},
dlh: (p = null) => {
const hostname = _unsafeWindow.document.location.hostname;
if (isString(p)) {
return hostname.includes(p);
} else if (isRegExp(p)) {
return hostname.search(p) > -1;
}
return hostname;
},
dlp: (p = null) => {
const pathname = _unsafeWindow.document.location.pathname;
if (isString(p)) {
return pathname.includes(p);
} else if (isRegExp(p)) {
return pathname.search(p) > -1;
}
return pathname;
},
dls: (p = null) => {
const search = _unsafeWindow.document.location.search;
if (isString(p)) {
return search.includes(p);
} else if (isRegExp(p)) {
return search.search(p) > -1;
}
return search;
},
getUSP: (p, s = "s") => {
if (s === "u") {
return new URL(fn.cls()).searchParams.get(p);
}
if (s === "s") {
return new URLSearchParams(fn.cls()).get(p);
}
if (s?.startsWith("http")) {
return new URL(s).searchParams.get(p);
}
if (s?.startsWith("?")) {
new URLSearchParams(s).get(p);
}
return "";
},
cookie: (key) => {
let cookie_object = {
...Object.fromEntries(document.cookie.replace(/\s/g, "").split(";").map(e => e.split("=")))
};
if (key in cookie_object) {
return Reflect.get(cookie_object, key);
}
return "";
},
src: (p, dom = document) => {
let ele;
if (isEle(p)) {
ele = p;
} else if (isString(p)) {
ele = fn.ge(p, dom, dom);
if (!isEle(ele)) return "";
} else {
return "";
}
return ("src" in ele) ? ele.src : "";
},
dir: url => {
if (!url?.includes("/")) return "";
if (isURL(url) && url?.startsWith("http")) {
let obj = new URL(url);
url = obj.origin + obj.pathname;
}
let index = url.lastIndexOf("/") + 1;
url = url.slice(0, index);
return url;
},
ex: e => {
if (fn.lh === "simplyhentai.us") return "webp";
const object = {
j: "jpg",
jpg: "jpg",
p: "png",
png: "png",
g: "gif",
gif: "gif",
w: "webp",
webp: "webp",
a: "avif",
avif: "avif",
t: "tif",
tif: "tif",
b: "bmp",
bmp: "bmp"
};
return object[e];
},
isImage: file => {
file = String(file);
if (file.includes("/")) {
file = file.split("/").at(-1);
}
return /\.(bmp|jpe?g|jfif|png|tiff?|gif|svg|ico|webp|heif|heic|raw|cr2|nef|arw|dng|avif)/i.test(file);
},
isVideo: file => {
file = String(file);
if (file.includes("/")) {
file = file.split("/").at(-1);
}
return /\.(mp4|avi|mkv|mov|wmv|flv|webm|mpeg|mpg|3gp|m4v|ts|vob|ogv|rm|rmvb|m2ts|mxf|asf|swf)/i.test(file);
},
isZip: file => {
file = String(file);
if (file.includes("/")) {
file = file.split("/").at(-1);
}
return /\.(rar|zip|7z|cbz)/i.test(file);
},
checkUrl: (obj = {}) => {
if (fn.clp() === "/" && fn.cls() === "" && !("SPA" in tempData) && !("autoPager" in tempData) && !["none", "ad"].some(c => tempData.category == c)) return false;
const {
u: url,
h: hosts,
p: pathname,
s: search,
st: script_text,
e: elements,
ee: exclude_elements,
t: title,
d: device,
i: comicInfiniteScroll,
cookie: cookie_key
} = obj;
const {
box,
imgs: imgSelector,
srcset: srcsetSelector,
customTitle: titleSelector
} = tempData;
let checkU = true;
let checkH = true;
let checkP = true;
let checkS = true;
let checkE = true;
let checkI = true;
let checkT = true;
let checkD = true;
let checkC = true;
if ("i" in obj) {
checkI = comicInfiniteScroll === 0 ? comicInfiniteScrollMode != 1 : comicInfiniteScrollMode == 1;
if (!checkI) return false;
}
if ("d" in obj) {
if (device === "pc") {
checkD = isPC;
} else if (device === "m") {
checkD = isM || isMobileDeviceUA;
}
if (!checkD) return false;
}
if ("h" in obj) {
if (isArray(hosts)) {
checkH = hosts.some(h => {
if (isRegExp(h)) {
return h.test(fn.lh);
} else if (isString(h)) {
return h === fn.lh;
}
return false;
});
} else if (isRegExp(hosts)) {
checkH = hosts.test(fn.lh);
} else if (isString(hosts)) {
checkH = fn.lh.includes(hosts);
}
if (!checkH) return false;
}
if ("u" in obj) {
if (isArray(url)) {
checkU = url.some(u => {
if (isRegExp(u)) {
return u.test(fn.url);
} else if (isString(u)) {
return fn.url.includes(u);
}
return false;
});
} else if (isRegExp(url)) {
checkU = url.test(fn.url);
} else if (isString(url)) {
checkU = fn.url.includes(url);
}
if (!checkU) return false;
}
if ("t" in obj) {
if (isArray(title)) {
checkT = title.some(t => {
if (isString(t)) {
return document.title.includes(t);
} else if (isRegExp(t)) {
return t.test(document.title);
}
return false;
});
} else if (isString(title)) {
checkT = document.title.includes(title);
} else if (isRegExp(title)) {
checkT = title.test(document.title);
}
if (!checkT) return false;
}
if ("st" in obj) {
if (isArray(script_text)) {
checkT = script_text.every(text => !![...document.scripts].find(script => {
if (isString(text)) {
return script.textContent.includes(text);
} else if (isRegExp(text)) {
return script.textContent.search(text) > -1;
}
}));
} else if (isString(script_text) || isRegExp(script_text)) {
checkT = !![...document.scripts].find(script => {
if (isString(script_text)) {
return script.textContent.includes(script_text);
} else if (isRegExp(script_text)) {
return script.textContent.search(script_text) > -1;
}
});
}
if (!checkT) return false;
}
if ("e" in obj) {
if (isArray(elements)) {
checkE = elements.every(selector => !!fn.ge(selector));
} else if (isString(elements)) {
checkE = !!fn.ge(elements);
}
if (!checkE) return false;
}
if ("ee" in obj) {
if (isArray(exclude_elements)) {
checkE = exclude_elements.some(selector => !fn.ge(selector));
} else if (isString(exclude_elements)) {
checkE = !fn.ge(exclude_elements);
}
if (!checkE) return false;
}
if ("p" in obj) {
if (isArray(pathname)) {
checkH = pathname.some(p => {
if (isRegExp(p)) {
return p.test(fn.lp);
} else if (isString(p)) {
return fn.lp.includes(p);
}
return false;
});
} else if (isRegExp(pathname)) {
checkP = pathname.test(fn.lp);
} else if (isString(pathname)) {
checkP = fn.lp.includes(pathname);
}
if (!checkP) return false;
}
if ("s" in obj) {
if (isRegExp(search)) {
checkS = search.test(fn.ls);
} else if (isString(search)) {
checkS = fn.ls.includes(search);
}
if (!checkS) return false;
}
if ("cookie" in obj) {
checkC = document.cookie.includes(cookie_key);
}
if ("box" in tempData && isArray(box) && !("SPA" in tempData)) {
const [selector] = box;
checkE = !!fn.ge(selector);
if (!checkE) {
debug("\n頁面沒有創建容器的定位元素", selector);
}
}
if ("imgs" in tempData && isString(imgSelector) && !("SPA" in tempData)) {
checkI = !!fn.ge(imgSelector);
if (!checkI) {
debug("\n頁面沒有指定的圖片元素", imgSelector);
}
}
if ("srcset" in tempData && isString(srcsetSelector) && !("SPA" in tempData)) {
checkI = !!fn.ge(srcsetSelector);
if (!checkI) {
debug("\n頁面沒有指定的圖片元素", srcsetSelector);
}
}
if ("customTitle" in tempData && (isString(titleSelector) || isArray(titleSelector)) && !("SPA" in tempData)) {
if (isString(titleSelector)) {
checkT = !!fn.ge(titleSelector);
} else if (isArray(titleSelector)) {
checkT = titleSelector.every(selector => !!fn.ge(selector));
}
if (!checkT) {
if (isString(titleSelector)) {
debug("\n頁面沒有指定的標題元素", titleSelector);
} else if (isArray(titleSelector)) {
debug("\n頁面沒有指定的所有標題元素", titleSelector);
}
}
}
return checkU && checkH && checkP && checkS && checkE && checkI && checkT && checkC;
},
checkAutoPagerEle: (data = {}) => {
let check = true;
const {
ele: pageElementSelector,
observer: observerSelector,
next: nextSelector,
re: replaceSelector
} = data;
const selectors = [
pageElementSelector,
observerSelector,
nextSelector,
replaceSelector
].filter(item => isString(item));
if (selectors.length > 0) {
check = selectors.every(selector => !!fn.ge(selector));
if (check) {
debug("\n圖片全載AutoPager\n頁面包含自動翻頁必須的所有元素");
} else {
console.error("\n圖片全載AutoPager\n頁面沒有包含自動翻頁必須的所有元素");
}
}
return check;
},
getModeUrl: (url, mode, i) => {
//【.html ==> .html?page=2】第一頁 ==> 第二頁
//【 ==> ?page=2】第一頁 ==> 第二頁
if (mode === 1) return url.replace(/\?page=\d+$/, "") + "?page=" + i;
//【.html ==> /2.html】 第一頁 ==> 第二頁
if (mode === 2) return url.slice(0, -5) + "/" + i + ".html";
//【.html ==> _1.html】 第一頁 ==> 第二頁
//return siteUrl.replace(/(_\d+)?\.html$/, "") + "_" + (i - 1) + ".html";
if (mode === 3) return url.replace(/\.html$/, "") + "_" + (i - 1) + ".html";
//【/ ==> /2/】 第一頁 ==> 第二頁
if (mode === 4) return url.slice(0, -1) + "/" + i + "/";
//【 ==> /2】 第一頁 ==> 第二頁
if (mode === "4") return url + "/" + i;
//【.html ==> -2.html】 第一頁 ==> 第二頁
if (mode === 5) return url.replace(/\.html$/, "") + "-" + i + ".html";
//【-1.html ==> -2.html】 第一頁 ==> 第二頁
if (mode === "5") return url.replace(/(-\d+)?\.html$/, "") + "-" + i + ".html";
//【?p=1 ==> ?p=2】 第一頁 ==> 第二頁
if (mode === 6) return url.replace(/\?p=\d+$/, "") + "?p=" + i;
//【/1 ==> /2】 第一頁 ==> 第二頁
//【.html ==> .html/2】 第一頁 ==> 第二頁
if (mode === 7) return url.replace(/(\.html).*$/, "$1").replace(/\/\d+$/, "") + "/" + i;
//【 ==> &page=1】 第一頁 ==> 第二頁
if (mode === 8) return url.replace(/&page=\d+$/, "") + "&page=" + (i - 1);
//【 ==> &page=2】 第一頁 ==> 第二頁
if (mode === "8") return url.replace(/&page=\d+$/, "") + "&page=" + i;
//【.html ==> _2.html】 第一頁 ==> 第二頁
if (mode === 9) return url.replace(/(_\d+)?\.html$/, "") + "_" + i + ".html";
//【.html ==> .html/2】 第一頁 ==> 第二頁
if (mode === 10) return url.replace(/\.html(\/\d+)?$/, "") + ".html/" + i;
//【/ ==> /2.html】 第一頁 ==> 第二頁
//【/1.html ==> /2.html】 第一頁 ==> 第二頁
if (mode === 11) return url.replace(/\/(\d+\.html)?$/, "") + "/" + i + ".html";
//【/ ==> /2.htm】 第一頁 ==> 第二頁
//【/1.htm ==> /2.htm】 第一頁 ==> 第二頁
if (mode === 12) return url.replace(/\/(\d+\.htm)?$/, "") + "/" + i + ".htm";
//【-1-* ==> -2-*】 第一頁 ==> 第二頁
if (mode === 13) return url.replace(/-\d+-[^-]+$/, "") + "-" + i;
//【/1/ ==> /2/】 第一頁 ==> 第二頁
if (mode === 14) return url.replace(/\/\d+\/$/, "") + "/" + i + "/";
//【/index.html ==> /index_2.html】 第一頁 ==> 第二頁
if (mode === 15) return url.replace(/\/(index(_\d+)?\.html)?$/, "") + "/index_" + i + ".html";
//【 ==> /2#list】 第一頁 ==> 第二頁
if (mode === 16) return url.replace(/\/(index(_\d+)?\.html)?$/, "") + "/" + i + "#list";
//【.htm ==> _2.htm】 第一頁 ==> 第二頁
if (mode === 17) return url.replace(/#$/, "").replace(/(_\d+)?\.htm$/, "") + "_" + i + ".htm";
//【/ ==> /page/2/】 第一頁 ==> 第二頁
if (mode === 18) return url.replace(/\/(page\/\d+\/)?$/, "") + "/page/" + i + "/";
//【-1 ==> -2】 第一頁 ==> 第二頁
if (mode === 19) return url.replace(/-\d+$/, "") + "-" + i;
//【 ==> -p-2】 第一頁 ==> 第二頁
if (mode === 20) return url.replace(/-p-\d+$/, "") + "-p-" + i;
},
//重新發送請求
retryUrl: async (url, res, func, retryCount = 10) => {
debug(`\n${func}連線錯誤碼:${res.status}\n`, url);
let retryNum = 1;
let obj = {
fn: func,
url: url,
status: res.status
};
debug(`\n${func}連線錯誤碼:${res.status}重試第${retryNum}次\n`, url);
let retry = await new Promise(async resolve => {
for (let check = 1; check <= retryCount; check++) {
let checkRes = await fetch(url);
if (checkRes.status == 304 || checkRes.status == 200) {
let buffer = await checkRes.arrayBuffer();
resolve({
ok: true,
buffer: buffer
});
break;
} else {
debug(`\n${func}連線錯誤碼:${checkRes.status}重試第${retryNum += 1}次\n`, url);
await delay(3000);
}
if (check >= retryCount) {
resolve({
ok: false
});
}
}
});
if (retry.ok) {
return retry.buffer;
} else {
fetchErrorArray.push(obj);
return null;
}
},
fetchErrorMsg: () => {
if (fetchErrorArray.length > 0) {
debug(`\nfetchErrorArray\n`, fetchErrorArray);
setTimeout(() => fn.showMsg(`${DL.str_97}${fetchErrorArray.length}${DL.str_98}`, 10000), 1500);
}
},
//並行請求取得圖片網址,返回圖片網址。
getImg: async (img, maxPage = 1, mode = 1, rText = null, time = 50, url = siteUrl, msg = 1, request = 0) => {
if (fn.ge(".FullPictureLoadImage") && request == 0) return fn.gae(".FullPictureLoadImage:not(.small)");
isFetching = true;
if (!getImgFnProcessRecord.includes("getImg()")) getImgFnProcessRecord += " > fn.getImg()";
if (msg == 1) fn.showMsg(DL.str_01, 0);
let imgsArray = [];
let fetchNum = 0;
const html = _url => fetch(_url).then(async res => {
debug(`\nfn.getImg() URL`, _url);
if (res.status >= 400) {
let resData = await fn.retryUrl(_url, res, "fn.getImg()");
if (resData !== null) return resData;
}
return res.arrayBuffer();
}).then(buffer => {
const decoder = new TextDecoder(document.characterSet || document.charset || document.inputEncoding);
const htmlText = decoder.decode(buffer);
if (msg == 1) fn.showMsg(`${DL.str_02}${fetchNum+=1}/${Number(maxPage)}`, 0);
return htmlText;
}).catch(error => {
console.error(`\nfn.getImg() > fetch()出錯:\n${decodeURIComponent(_url)}`, error);
});
const resArr = [];
resArr.push(html(url));
if (Number(maxPage, 10) > 1) {
for (let i = 2; i <= Number(maxPage); i++) {
resArr.push(html(fn.getModeUrl(url, mode, i)));
await delay(time);
}
}
await Promise.all(resArr).then(htmls => {
isFetching = false;
if (msg == 1) fn.hideMsg();
for (let i = 0; i < htmls.length; i++) {
let dom = fn.doc(htmls[i]);
let imgs = fn.gae(img, dom, dom);
//debug(`\nfn.getImg() DOM${i}`, dom);
for (let p = 0; p < imgs.length; p++) {
let check = fn.checkImgSrc(imgs[p], rText);
check.ok ? imgsArray.push(decodeURIComponent(check.src)) : debug(`\nfn.getImg() imgs[${p}]錯誤`, imgs[p]);
}
}
});
fn.fetchErrorMsg();
return imgsArray;
},
//單線程請求取得圖片網址,完成一個請求會把圖片元素先插入到當前文檔,類翻頁模式,返回圖片網址。
getImgO: async (img, maxPage = 1, mode = 1, rText = null, time = 200, replaceElement = null, url = siteUrl, msg = 1, request = 0) => {
if (fn.ge(".FullPictureLoadImage") && request == 0) return fn.gae(".FullPictureLoadImage:not(.small)");
isFetching = true;
if (!getImgFnProcessRecord.includes("getImgO()")) getImgFnProcessRecord += " > fn.getImgO()";
if (msg == 1) fn.showMsg(DL.str_01, 0);
let imgsArray = [];
let fetchNum = 0;
const html = async (_url, id = 1) => {
await delay(time);
return fetch(_url).then(async res => {
debug(`\nfn.getImgO() URL`, _url);
if (res.status >= 400) {
let resData = await fn.retryUrl(_url, res, "fn.getImgO()");
if (resData !== null) return resData;
}
return res.arrayBuffer();
}).then(buffer => {
const decoder = new TextDecoder(document.characterSet || document.charset || document.inputEncoding);
const htmlText = decoder.decode(buffer);
let dom = fn.doc(htmlText);
fn.gae(img, dom, dom).forEach(ele => {
let check = fn.checkImgSrc(ele);
if (ele.tagName == "IMG" && check.ok) ele.src = check.src;
if (id == 1) {
let targetEle = fn.gae(img).at(-1);
insertAfter(targetEle, ele.cloneNode(true));
}
});
if (isString(replaceElement)) {
fn.gae(".invisible", dom).forEach(ele => ele.classList.remove("invisible"));
let ce = fn.gae(replaceElement);
let re = fn.gae(replaceElement, dom, dom);
if (ce.length === re.length) {
ce.forEach((e, i) => (e.outerHTML = re[i].outerHTML));
}
}
if (msg == 1) fn.showMsg(`${DL.str_02}${fetchNum+=1}/${Number(maxPage)}`, 0);
return htmlText;
}).catch(error => {
console.error(`\nfn.getImgO() > fetch()出錯:\n${decodeURIComponent(_url)}`, error);
});
};
const resArr = [];
resArr.push(await html(url, 0));
if (Number(maxPage) > 1) {
for (let i = 2; i <= Number(maxPage); i++) {
resArr.push(await html(fn.getModeUrl(url, mode, i)));
}
}
await Promise.all(resArr).then(htmls => {
isFetching = false;
fn.hideMsg();
for (let i = 0; i < htmls.length; i++) {
let dom = fn.doc(htmls[i]);
let imgs = fn.gae(img, dom, dom);
//debug(`\nfn.getImgO() DOM${i}`, dom);
for (let p = 0; p < imgs.length; p++) {
let check = fn.checkImgSrc(imgs[p], rText);
check.ok ? imgsArray.push(decodeURIComponent(check.src)) : debug(`\nfn.getImgO() imgs[${p}]錯誤`, imgs[p]);
}
}
});
fn.fetchErrorMsg();
return imgsArray;
},
//使用Iframe框架加載網頁,完成一個加載會把圖片元素先插入到當前文檔,類翻頁模式,返回圖片網址。
getImgIframe: async (img, maxPage = 1, mode = 1, rEle = null, time = 500, showMsg = 1) => {
if (fn.ge(".FullPictureLoadImage")) return fn.gae(".FullPictureLoadImage:not(.small)");
isFetching = true;
if (!getImgFnProcessRecord.includes("getImgIframe()")) getImgFnProcessRecord += " > fn.getImgIframe()";
if (showMsg == 1) fn.showMsg(DL.str_01, 0);
let imgsArray = [];
let fetchNum = 1;
await fn.waitEle(img);
fn.gae(img).forEach(ele => imgsArray.push(ele));
const html = async (url, index = 0) => {
let targetEle = fn.gae(img).at(-1);
let load = document.createElement("p");
load.className = "FullPictureLoadLoading";
load.innerText = "Loading...";
insertAfter(targetEle, load);
await delay(time);
let dom = null;
for (let i = 1; i < 20; i++) {
dom = await fn.iframeSrcDoc(url, img);
if (dom !== null) {
break;
}
}
if (dom) {
debug("iframeDoc" + index, dom);
fn.gae(img, dom, dom).forEach(ele => {
imgsArray.push(ele);
insertAfter(targetEle, ele.cloneNode(true));
});
if (rEle) {
let ce = fn.gae(rEle);
let re = fn.gae(rEle, dom, dom);
if (ce.length === re.length) {
ce.forEach((e, i) => (e.outerHTML = re[i].outerHTML));
}
}
load.remove();
if (showMsg == 1) fn.showMsg(`${DL.str_02}${fetchNum+=1}/${Number(maxPage)}`, 0);
} else {
fetchNum += 1;
load.remove();
let obj = {
fn: "fn.getImgIframe()",
url: url
};
fetchErrorArray.push(obj);
fn.showMsg(DL.str_03, 3000);
return;
}
}
if (Number(maxPage) > 1) {
for (let i = 2; i <= Number(maxPage); i++) {
await html(fn.getModeUrl(siteUrl, mode, i), i);
}
}
debug("\nfn.getImgiframe() 聚集的所有IMG", imgsArray);
isFetching = false;
fn.hideMsg();
fn.fetchErrorMsg();
return imgsArray;
},
//從指定的所有連結取得圖片網址,有並行請求、單線程、翻頁模式,返回圖片網址。
getImgA: async (elementSelector, link, mode = 0, rText = null, showMsg = 1, request = 0) => {
if (fn.ge(".FullPictureLoadImage") && request == 0) return fn.gae(".FullPictureLoadImage:not(.small)");
isFetching = true;
if (!getImgFnProcessRecord.includes("getImgA()")) getImgFnProcessRecord += " > fn.getImgA()";
if (showMsg == 1) fn.showMsg(DL.str_01, 0);
let links, linkEles, linksNum;
if (isFn(link)) {
links = await link();
linksNum = links.length;
} else if (isArray(link)) {
links = link;
linksNum = links.length;
} else if (isString(link)) {
linkEles = fn.gae(link);
links = [...new Set(linkEles.map(a => a.href))];
linksNum = links.length + 1;
} else {
console.error("\nfn.getImgA() link參數錯誤", link);
return;
}
debug("\nfn.getImgA() links", links);
let imgsArray = [];
let fetchNum = 0;
const html = url => fetch(url).then(async res => {
debug(`\nfn.getImgA() URL`, url);
if (res.status >= 400) {
let resData = await fn.retryUrl(url, res, "fn.getImgA()");
if (resData !== null) return resData;
}
return res.arrayBuffer();
}).then(buffer => {
if (showMsg == 1) fn.showMsg(`${DL.str_02}${fetchNum+=1}/${linksNum}`, 0);
const decoder = new TextDecoder(document.characterSet || document.charset || document.inputEncoding);
const htmlText = decoder.decode(buffer);
return htmlText;
}).catch(error => {
console.error(`\nfn.getImgA fetch()出錯:\n${decodeURIComponent(url)}`, error);
});
const resArr = [];
if (isString(link)) resArr.push(html(siteUrl));
for (let i = 0; i < links.length; i++) {
if (mode == 0) {
resArr.push(html(links[i]));
} else if (mode >= 100) {
await delay(mode);
resArr.push(html(links[i]));
} else if (mode == 1) {
let res = await html(links[i]);
resArr.push(res);
if (isString(link)) {
let dom = fn.doc(res);
debug(`\nfn.getImgA()單線程模式 DOM\n${links[i].href}`, dom);
let imgs = fn.gae(elementSelector, dom, dom);
let imgHtml = "";
for (let p = 0; p < imgs.length; p++) {
let imgSrc;
let check = fn.checkImgSrc(imgs[p], rText);
if (check.ok) {
imgSrc = check.src;
//let blob = await GM_XHR_Download(imgSrc);
//let objectURL = await URL.createObjectURL(blob.blob);
//imgSrc = objectURL;
debug("\nfn.getImgA() 單線程模式imgSrc", imgSrc);
} else {
console.error("\nfn.getImgA() 單線程模式出錯", imgs[p]);
continue;
}
imgHtml += `<img src="${imgSrc}" style="width: auto; height: auto; max-width: 100%; max-height: unset; display:block; float: unset; opacity: 1; border: none; border-radius: unset; padding: 0; margin: 0 auto; transition: unset; transform: unset;">`;
}
linkEles[i].outerHTML = imgHtml;
}
} else if (mode == 2) {
let res = await html(links[i]);
await delay(200);
resArr.push(res);
if (i !== 0) {
let dom = fn.doc(res);
let tE = fn.gae(elementSelector).at(-1);
let eles = fn.gae(elementSelector, dom, dom);
eles.forEach(e => insertAfter(tE, e));
}
}
}
await Promise.all(resArr).then(htmls => {
isFetching = false;
fn.hideMsg();
for (let i = 0; i < htmls.length; i++) {
let dom = fn.doc(htmls[i]);
//if (mode != 1) debug(`\nfn.getImgA() DOM${i}`, dom);
let imgs = fn.gae(elementSelector, dom, dom);
for (let p = 0; p < imgs.length; p++) {
let check = fn.checkImgSrc(imgs[p], rText);
check.ok ? imgsArray.push(check.src) : console.error("\nfn.getImgA() PromiseAll出錯", imgs[p]);
}
}
});
fn.fetchErrorMsg();
return imgsArray;
},
//跨域從指定的所有連結取得圖片網址,並行請求有請求間隔參數,返回圖片網址。
getImgCorsA: (imgSelector, aSelector, time = 100) => {
isFetching = true;
fn.showMsg(DL.str_01, 0);
let xhrNum = 0;
let links;
isString(aSelector) ? links = fn.gau(aSelector) : links = aSelector;
let resArr = links.map(async (url, i, arr) => {
await delay(time * i);
return fn.xhrDoc(url).then(dom => {
fn.showMsg(`${DL.str_02}${xhrNum+=1}/${arr.length}`, 0);
return fn.gae(imgSelector, dom, dom);
});
});
return Promise.all(resArr).then(arr => {
isFetching = false;
fn.hideMsg();
return fn.getImgSrcArr(arr.flat());
});
},
//補全網址
complementSrc: (src, rText = null) => {
if (src.startsWith("//")) {
src = location.protocol + src;
}
if (src.startsWith("data:image/svg+xml,<svg") || src.startsWith("data:image/svg+xml;utf8,<svg")) {
src = fn.dataURLtoBlobURL(src);
}
if (/^\/[^\/]+/.test(src)) {
src = location.origin + src;
}
if (!/^(https?:|blob:|data:)/.test(src) && /^\w+/i.test(src)) {
src = location.origin + "/" + src;
}
if (isArray(rText) && rText.length == 2) {
src = src.replace(rText[0], rText[1]);
}
src = src.replace(/\n/g, "").trim();
return src;
},
//確認元素和圖片網址,嘗試取得網址和補全網址。
checkImgSrc: (ele, rText = null) => {
let imgSrc;
let check = fn.checkDataset(ele);
if (isEle(ele) && ["IMG", "DIV", "A", "SPAN", "LI", "FIGURE", "ARTICLE", "P", "VIDEO"].some(n => n === ele.tagName) && check.ok) {
imgSrc = fn.complementSrc(check.src, rText);
} else if (isEle(ele) && ["IMG", "AMP-IMG"].some(n => n === ele.tagName)) {
if (ele.tagName == "IMG") {
imgSrc = ele.src;
}
if (ele.tagName == "AMP-IMG") {
imgSrc = ele.getAttribute("src");
}
imgSrc = fn.complementSrc(imgSrc, rText);
} else if (["A", "LINK"].some(n => n === ele.tagName)) {
imgSrc = ele.href;
if (isArray(rText) && rText.length == 2) {
imgSrc = imgSrc.replace(rText[0], rText[1]);
}
} else if (isString(ele) && /^(https?:|blob:|data:|\/|\w+)/i.test(ele)) {
imgSrc = ele;
imgSrc = fn.complementSrc(imgSrc, rText);
}
if (isURL(imgSrc)) {
if (imgSrc === location.href) {
return {
ok: false
}
}
return {
ok: true,
src: imgSrc
}
} else {
return {
ok: false
}
}
},
//確認元素有沒有把圖片原始網址放在src以外的屬性
checkDataset: ele => {
if (!isEle(ele)) {
return {
ok: false
}
}
if (["IMG", "DIV", "A", "SPAN", "LI", "FIGURE", "P", "ARTICLE", "VIDEO"].some(n => n === ele.tagName)) {
const datasetArr = [
"data-hd",
"data-src",
"data-original",
"data-original-url",
"data-url",
"data-full-url",
"data-imageurl",
"data-img-url",
"data-lazy",
"data-lazy-load-src",
"data-lazy-src",
"data-lazyload",
"data-lazyload-src",
"data-mfp-src",
"data-actualsrc",
"data-bgsrc",
"data-bigsrc",
"data-bgset",
"data-cfsrc",
"data-cover",
"data-defer-src",
"data-echo",
"data-ecp",
"data-full-path",
"data-high-res-src",
"data-ks-lazyload",
"data-ks-lazyload-custom",
"data-lbwps-srcsmall",
"data-loadsrc",
"data-orig",
"data-orig-file",
"data-large-file",
"data-page-image-url",
"data-pin-media",
"data-placeholder",
"data-preview",
"data-src_big",
"data-wpfc-original-src",
"data-thumb",
"bigimg",
"ess-data",
"file",
"imgsrc",
"lazysrc",
"lg-data-src",
"load-src",
"mydatasrc",
"ng-src",
"org_img_url",
"org_src",
"origin-src",
"original",
"real_src",
//"src2",
"z-image-loader-url",
"zoomfile",
"poster"
];
for (let p of datasetArr) {
let imgSrc = ele.getAttribute(p)?.trim();
if (!!imgSrc) {
return {
ok: true,
src: imgSrc
}
}
}
if (ele.tagName !== "IMG") {
let backgroundImage = getComputedStyle(ele).getPropertyValue("background-image");
if (backgroundImage != "none" && backgroundImage?.startsWith("url")) {
let imgSrc = backgroundImage.slice(5, -2).trim();
if (!!imgSrc) {
return {
ok: true,
src: imgSrc
}
}
}
}
}
return {
ok: false
}
},
//確認加了CDN的圖片網址是否有效,無效則刪除CDN返回原始來源的圖片網址
checkImageCDN: srcArr => {
fn.showMsg("fn.xhrHEA(check)...", 0);
let xhrNum = 0;
return srcArr.map(async (src, i, arr) => {
await delay(25 * i);
let res = await fn.xhrHEAD(src);
fn.showMsg(`fn.xhrHEAD(${xhrNum+=1}/${arr.length})`, 0);
let status = res.status;
if (src.includes("wsrv.nl")) {
return status > 399 ? fn.getUSP("url", src) : src; //wsrv.nl_CDN
} else {
return status > 399 ? src.replace(/i\d\.wp\.com\/|\?.+$/g, "") : src; //WordPressCDN
}
});
},
//移除CDN返回原始來源的圖片網址
removeImageCDN: srcArr => {
return srcArr.map(async (src, i, arr) => {
if (src.includes("wsrv.nl")) {
return fn.getUSP("url", src); //wsrv.nl_CDN
} else {
return src.replace(/i\d\.wp\.com\/|\?.+$/g, ""); //WordPressCDN
}
});
},
//從用AList架設的雲端硬碟,提取圖片和影片網址
getAList: () => {
let paths = [...document.querySelectorAll("a.list-item")].map(a => decodeURIComponent(a.getAttribute("href"))).map(href => fn.isImage(href) || fn.isVideo(href) || /\.(zip|rar)$/i.test(href) ? href : null).filter(Boolean);
fn.showMsg(DL.str_05, 0);
let fetchNum = 0;
let password;
if ("browser-password" in localStorage) {
password = localStorage.getItem("browser-password");
} else {
password = "";
}
let resArr = paths.map((path, i, arr) => {
const body = {
path,
password
};
return fetch("/api/fs/get", {
"headers": {
"accept": "application/json, text/plain, */*",
"content-type": "application/json;charset=UTF-8"
},
"body": JSON.stringify(body),
"method": "POST"
}).then(res => res.json()).then(json => {
fn.showMsg(`${DL.str_06}${fetchNum+=1}/${arr.length}`, 0);
return json.code == 200 ? {
name: json.data.name,
//url: decodeURIComponent(json.data.raw_url)
url: json.data.raw_url
} : null;
});
});
return Promise.all(resArr).then(arr => {
console.log("AListDataArray", arr);
return arr.map(obj => {
if (!obj) return null;
if (fn.isVideo(obj.name)) {
videoSrcArray.push(obj.url);
return null;
} else if (fn.isZip(obj.name)) {
fileUrlArray.push(obj.url);
return null;
} else {
return obj.url;
}
}).filter(Boolean);
});
},
//指定元素選擇器或元素陣列,返回提取出的圖片網址陣列。
getImgSrcArr: (selector, dom = document) => {
let imgs;
isString(selector) ? imgs = fn.gae(selector, dom, dom) : imgs = selector;
let srcs = imgs.map(ele => {
let check = fn.checkImgSrc(ele);
return check.ok ? check.src : null;
}).filter(Boolean);
return [...new Set(srcs)];
},
//指定圖片元素選擇器或圖片元素陣列,返回提取出的圖片網址陣列。
getImgSrcset: (selector, dom = document) => {
let imgs;
isString(selector) ? imgs = fn.gae(selector, dom, dom) : imgs = selector;
let srcs = imgs.map(ele => {
let srcset = ele.getAttribute("srcset") || ele.getAttribute("data-srcset") || ele.getAttribute("data-lazy-srcset") || ele.getAttribute("data-bgset") || ele.getAttribute("data-jg-srcset");
if (srcset && String(srcset).includes(",")) {
let splitArr = srcset.split(",").map(src => src.trim()).filter(Boolean);
splitArr = splitArr.sort((a, b) => {
let a_num;
try {
a_num = a.match(/\s([\d\.]+)(w|x)$/)[1];
} catch {
a_num = 1;
}
let b_num;
try {
b_num = a.match(/\s([\d\.]+)(w|x)$/)[1];
} catch {
b_num = 1;
}
return a_num - b_num;
});
let [src] = splitArr.at(-1).trim().split(" ");
if (/^https:\/\/i\d\.wp\.com/.test(src)) {
src = src.replace(/\?.+$/, "?ssl=1");
}
if (!src.includes(".yituyu.")) {
src = src.replace(/-\d+x\d+\./, ".");
}
//if (decodeURIComponent(src).includes("/none")) console.log(ele);
try {
return decodeURIComponent(src);
} catch {
return src;
}
} else if (srcset && isString(srcset)) {
if (fn.isImage(srcset)) {
return srcset;
} else {
return null;
}
} else {
if (ele?.parentElement?.id === "pagetual-preload") return null;
if (isSimpleMode && ele?.tagName === "A") {
let check = fn.checkDataset(ele);
if (check.ok) {
//if (decodeURIComponent(check.src).includes("/none")) console.log(ele);
if (!fn.isImage(check.src)) {
console.log("\n可能不是含圖片網址的A元素\n", ele);
return null;
}
try {
return decodeURIComponent(check.src);
} catch {
return check.src;
}
} else {
return null;
}
}
let check = fn.checkImgSrc(ele);
if (check.ok) {
let src = check.src;
if (/^https:\/\/i\d\.wp\.com/.test(src)) {
src = src.replace(/\?.+$/, "?ssl=1").replace(/-\d+x\d+\./, ".");
} else {
if (!src.includes(".yituyu.")) {
src = src.replace(/-\d+x\d+\./, ".");
}
if (src.includes(".jpg.jpg")) {
src = src.replace(".jpg.jpg", ".jpg");
}
if (src.includes(".png.png")) {
src = src.replace(".png.png", ".png");
}
}
//if (decodeURIComponent(src).includes("/none")) console.log(ele);
try {
return decodeURIComponent(src);
} catch {
return src;
}
} else {
return null;
}
}
}).filter(Boolean);
return srcs;
},
//指定元素選擇器或元素陣列,返回元素背景圖片的圖片網址陣列。
getBackgroundImage: (selector, dom = document) => {
let eles;
isString(selector) ? eles = fn.gae(selector, dom, dom) : eles = selector;
let srcs = eles.map(ele => {
let backgroundImage = getComputedStyle(ele).getPropertyValue("background-image");
if (backgroundImage != "none" && backgroundImage?.startsWith("url")) {
let imgSrc = backgroundImage.slice(5, -2).trim();
return imgSrc;
} else {
return null;
}
}).filter(Boolean);
return [...new Set(srcs)];
},
//從頭一路翻到尾的自動翻頁函式
getNP: async (pageEle, nextLinkEle, lastEle = null, replaceElement = null, time = 0, dataset = null, msg = 1, retry = 10) => {
//翻頁模式聚集所有圖片或是預覽縮圖然後fn.getImgA()
//用在規則init,fn.getNP(picsEle, nextLinkEle, lastEle, replaceElement, time);
if (fn.ge(".FullPictureLoadImage")) return;
if (isString(nextLinkEle) && !fn.ge(nextLinkEle)) return;
isFetching = true;
if (!getImgFnProcessRecord.includes("getNP()")) getImgFnProcessRecord += " > fn.getNP()";
let nextlink = null;
let page = 1;
if (msg == 1) fn.showMsg(DL.str_14, 0);
const getNextLink = async (url = "", dom = document) => {
if (isFn(nextLinkEle)) {
nextlink = await nextLinkEle(dom);
} else if (isString(nextLinkEle)) {
let ele = fn.ge(nextLinkEle, dom, dom);
if (!!ele) {
if (!!ele?.dataset?.url) {
if (!/^http/.test(ele.dataset.url)) return null;
nextlink = ele.dataset.url;
} else if (ele.tagName === "A") {
nextlink = ele.href;
let nh = ele.hostname;
let lh = fn.lh;
if (nh != lh) nextlink = nextlink.replace(nh, lh);
} else {
try {
ele.getAttribute("href") ? nextlink = ele.getAttribute("href") : nextlink = ele.getAttribute("_href");
} catch {
nextlink = null;
}
}
} else {
nextlink = null;
}
} else {
nextlink = null;
}
if (isString(url) && isString(nextlink) && (url === nextlink)) {
if (msg == 1) fn.showMsg(DL.str_15);
nextlink = null;
}
return nextlink;
};
const getNextPageEles = async url => {
if (msg == 1) fn.showMsg(`${DL.str_14} (Page${page += 1})`, 0);
await fetch(url).then(async res => {
if (res.status >= 400) {
let resData = await fn.retryUrl(url, res, "fn.getNP()");
if (resData !== null) return resData;
}
return res.arrayBuffer();
}).then(buffer => {
const decoder = new TextDecoder(document.characterSet || document.charset || document.inputEncoding);
const htmlText = decoder.decode(buffer);
return htmlText;
}).then(async htmlText => {
let dom = fn.doc(htmlText);
let lastPage = null;
if (isString(lastEle)) {
lastPage = fn.ge(lastEle, dom, dom);
} else if (isFn(lastEle)) {
try {
lastPage = await lastEle(dom);
} catch (error) {
debug("fn.getNP() lastEle() 函式錯誤", error);
lastPage = null;
}
}
if (lastPage) {
isFetching = false;
if (msg == 1) fn.showMsg(DL.str_15);
return;
}
if (!fn.ge(pageEle, dom, dom)) {
for (let i = 1; i <= retry; i++) {
dom = await fn.iframeSrcDoc(url, pageEle);
if (dom != null) {
break;
}
}
}
if (!dom) dom = fn.doc(htmlText);
if (isString(dataset)) {
fn.gae(dataset, dom, dom).forEach(e => {
let check = fn.checkImgSrc(e);
if (check.ok) {
if (e.tagName == "IMG") {
e.src = check.src;
} else if (["A", "DIV", "SPAN", "LI", "FIGURE"].some(n => n === e.tagName)) {
e.style.backgroundImage = `url(${check.src})`;
}
}
});
}
//debug(`\nfn.getNP() > getNextPageEles() DOM\n${decodeURIComponent(url)}`, dom);
let eles = fn.gae(pageEle, dom, dom).map(e => e.cloneNode(true));
fragment.append(...eles);
let targetEle = fn.gae(pageEle).at(-1);
insertAfter(targetEle, fragment);
if (replaceElement) {
let currentPageEles = fn.gae(replaceElement);
let nextPageEles = fn.gae(replaceElement, dom, dom);
if (currentPageEles.length === nextPageEles.length) {
currentPageEles.forEach((e, i) => (e.outerHTML = nextPageEles[i].outerHTML));
}
}
nextlink = await getNextLink(url, dom);
if (nextlink) {
await delay(time);
await getNextPageEles(nextlink);
} else {
isFetching = false;
if (msg == 1) fn.showMsg(DL.str_15);
return;
}
});
};
nextlink = await getNextLink();
if (nextlink) {
await delay(time);
await getNextPageEles(nextlink);
} else {
isFetching = false;
if (msg == 1) fn.showMsg(DL.str_15);
return;
}
},
//傳入免費圖片空間的連結陣列,提取圖片網址
getImageHost: async (links = captureLinksArray) => {
let imgsSrcArr = [];
if (links.length > 0) {
if (/\.\w+$/.test(links[0]) && !/\.html$/.test(links[0]) && !/\/fappic\.com\//.test(links[0]) && !/pixhost\.to\/show\//.test(links[0]) && !/^https?:\/\/imagetwist\.com\//.test(links[0])) return links;
fn.showMsg(DL.str_01, 0);
let xhrNum = 0;
let resArr = links.map(async (url, i, arr) => {
await delay(100 * i);
if (/imagebam/.test(url)) {
return fn.imageBamXHR(url).then(dom => {
fn.showMsg(`${DL.str_02}${xhrNum+=1}/${arr.length}`, 0);
let img = fn.ge("img.main-image", dom);
return img ? img.src : null;
});
} else if (/postimg/.test(url)) {
return fn.xhr(url, {
responseType: "document"
}).then(dom => {
fn.showMsg(`${DL.str_02}${xhrNum+=1}/${arr.length}`, 0);
let a = fn.ge("a#download", dom);
return a ? a.href : null;
});
} else {
return fn.xhr(url, {
responseType: "document"
}).then(dom => {
fn.showMsg(`${DL.str_02}${xhrNum+=1}/${arr.length}`, 0);
let img = fn.ge("#imgpreview,#image,.pic.img.img-responsive,#imageid,#img.image-content,.card-body img,.image.img-fluid,img.pic[alt][title]", dom);
return img ? img.src : null;
});
}
})
await Promise.all(resArr).then(arr => (imgsSrcArr = arr.filter(Boolean)));
}
return imgsSrcArr;
},
//無限滾動切換狀態
toggleAutoPager: () => {
let hide = siteData.autoPager?.hide;
if (autoPagerSwitch === true) {
autoPagerSwitch = false;
fn.showMsg(DL.str_89);
fn.gae(".autoPagerTitle").forEach(e => e.classList.add("off"));
if (isString(hide)) {
let eles = fn.gae(hide);
eles.forEach(e => (e.style.display = ""));
}
} else {
autoPagerSwitch = true;
fn.showMsg(DL.str_90);
fn.gae(".autoPagerTitle").forEach(e => e.classList.remove("off"));
if (isString(hide)) {
let eles = fn.gae(hide);
eles.forEach(e => (e.style.display = "none"));
}
}
},
//無限滾動自動翻頁函式
infiniteScroll: async () => {
fn.addLoading();
let hide = siteData.autoPager?.hide;
let url;
try {
url = await fn.getNextLink(doc);
if (!url) {
autoPagerSwitch = false;
fn.showMsg(DL.str_58, 3000);
fn.removeLoading();
if (isString(hide)) {
let eles = fn.gae(hide);
eles.forEach(e => (e.style.display = ""));
}
return;
}
} catch (error) {
console.error("\n取得下一頁連結出錯\n", error);
fn.removeLoading();
if (isString(hide)) {
let eles = fn.gae(hide);
eles.forEach(e => (e.style.display = ""));
}
return;
}
let mode = siteData.autoPager?.mode;
let eleSelector = siteData.autoPager.ele;
let apiJson;
if (isString(mode) && mode == "json") {
let options = {
cache: "no-cache"
};
if (isFn(siteData.autoPager?.fetchOptions)) {
options = siteData.autoPager.fetchOptions();
}
apiJson = await fetch(url, options).then(res => res.json()).then(json => {
if (isFn(siteData.autoPager?.fetchCB)) {
siteData.autoPager.fetchCB(json);
}
return json;
});
} else if (isNumber(mode) && mode == 1) {
doc = await fn.iframeDoc(url, (siteData.autoPager?.waitEle || eleSelector), 30000);
} else {
if (httpFetchError === false) {
doc = await fn.fetchDoc(url, 0);
}
if (httpFetchError === true || !doc) {
doc = await fn.xhrDoc(url);
}
}
//debug(`\nfn.infiniteScroll()\n${url}\n`, doc);
debug(`\nfn.infiniteScroll()\n${url}`);
let stop = siteData.autoPager?.stop;
if (isFn(stop) || isString(eleSelector)) {
let stopCheck;
if (isFn(stop)) {
try {
stopCheck = await stop(doc);
} catch (error) {
console.error("\nsiteData.autoPager.stop() 函式錯誤\n", error);
stopCheck = false;
}
} else if (isString(eleSelector)) {
stopCheck = !fn.ge(eleSelector, doc, doc); //有元素false沒有元素true
}
if (stopCheck) {
autoPagerSwitch = false;
fn.removeLoading();
fn.showMsg(DL.str_58, 3000);
if (isString(hide)) {
let eles = fn.gae(hide);
eles.forEach(e => (e.style.display = ""));
}
return;
}
}
let history = siteData.autoPager?.history;
if (history != 0 && mode != "json") {
try {
await fn.addHistory(doc?.title ?? document.title, url);
} catch (error) {
console.error(error);
}
}
let wait = siteData.autoPager?.wait;
if (isFn(wait)) {
await wait(doc);
}
let script = siteData.autoPager?.script;
if (isString(script)) {
let scripts = fn.gae(script, doc);
for (let i = 0; i < scripts.length; i++) {
if (scripts[i].src !== "") {
let src = scripts[i].src;
await fn.script(src, 1, 1);
} else {
let code = scripts[i].innerHTML;
await fn.script(code, 0, 1);
}
}
}
let lazySrc = siteData.autoPager?.lazySrc;
if (isString(lazySrc)) {
let eles = fn.gae(lazySrc, doc, doc);
for (let i = 0; i < eles.length; i++) {
let check = fn.checkDataset(eles[i]);
if (check.ok) {
if (eles[i].tagName === "IMG") {
eles[i].src = check.src;
} else if (["DIV", "A", "SPAN", "LI", "FIGURE"].some(n => n === eles[i].tagName)) {
eles[i].style.backgroundImage = `url("${check.src}")`;
}
}
}
}
let bF = siteData.autoPager?.bF;
if (isFn(bF)) await bF(doc);
let re = siteData.autoPager?.re;
if (isString(re)) {
let currentPageEles = fn.gae(re);
let nextPageEles = fn.gae(re, doc, doc);
if (currentPageEles.length === nextPageEles.length) {
currentPageEles.forEach((e, i) => (e.outerHTML = nextPageEles[i].outerHTML));
}
}
let newEles, tE;
let pos = siteData.autoPager?.pos;
if (isFn(eleSelector) && pos || isString(eleSelector)) {
if (isString(mode) && mode == "json") {
newEles = await eleSelector(apiJson);
} else if (isFn(eleSelector)) {
newEles = await eleSelector(doc);
} else if (isString(eleSelector)) {
let nextEle = fn.ge(eleSelector, doc, doc);
if (!nextEle) {
fn.removeLoading();
fn.showMsg(DL.str_59, 3000);
return;
}
tE = fn.gae(eleSelector).at(-1);
newEles = fn.gae(eleSelector, doc, doc);
}
if (siteData.autoPager?.showTitle !== 0) {
let add = true;
let titleText = null;
let num = siteData.autoPager?.pageNum;
let title = siteData.autoPager?.title;
if (isString(num)) {
titleText = `Page ${fn.gt(num, 1, doc)}`;
} else if (isFn(num)) {
titleText = `Page ${await num(doc)}`;
} else if (isFn(title)) {
try {
titleText = await title(mode == "json" ? apiJson : doc, frameWindow);
if (isObject(titleText)) {
titleText.ok ? titleText = titleText.text : add = false;
}
} catch (error) {
console.error("\nsiteData.autoPager.title() 函式錯誤\n", error);
}
}
if (add) {
if (mode == "json") {
url = document.URL;
}
fragment.append(fn.titleUrlEle(url, (titleText || doc?.title || document.title)));
}
}
fragment.append(...newEles);
if (isArray(pos) && pos.length == 2 && isString(pos[0]) && isNumber(pos[1])) {
const [selector, p] = pos;
tE = fn.ge(selector);
if (p === 0) { //元素裡面
tE.append(fragment);
} else if (p === 1) { //元素之前
insertBefore(tE, fragment);
} else if (p === 2) { //元素之後
insertAfter(tE, fragment);
}
} else {
insertAfter(tE, fragment);
}
} else if (isFn(eleSelector)) {
await eleSelector(doc);
}
fn.removeLoading();
let aF = siteData.autoPager?.aF;
if (isFn(aF)) await aF(doc);
if (siteData.category === "comic autoPager") {
await fn.lazyload();
let pagerTitles = fn.gae(".autoPagerTitle");
if (pagerTitles.length > 3) {
let parentE = pagerTitles[0].parentNode;
pagerTitles[0].remove();
let nodes = [...parentE.childNodes];
for (let i = 0; i < nodes.length; i++) {
if (nodes[i].className === "autoPagerTitle") {
break;
}
nodes[i].remove();
}
}
}
let observer = siteData.autoPager?.observer;
if (isString(observer)) {
await delay(siteData.autoPager?.sleep ?? 1000);
let ele = fn.gae(observer).at(-1);
fn.nextObserver.observe(ele);
}
if ("preloadNextPage" in siteData.autoPager) {
setTimeout(() => fn.preloadNextPage(mode == "json" ? apiJson : doc), 3000);
}
},
//無限滾動預讀下一頁
preloadNextPage: async (dom = document) => {
let preloadNextPage = siteData.autoPager?.preloadNextPage;
if (isNumber(preloadNextPage) && preloadNextPage === 1 && siteData.category === "comic autoPager") {
let nextSelector = siteData.autoPager.next;
let nextUrl = null;
if (isString(nextSelector)) {
let nextE = fn.ge(nextSelector, dom, dom);
if (!!nextE) {
nextUrl = nextE.href;
}
} else if (isFn(nextSelector)) {
nextUrl = await nextSelector(dom, 0);
}
if (!!nextUrl) {
let _fetch;
if (siteData.autoPager?.mode == 1 && "waitEle" in siteData.autoPager) {
_fetch = fn.iframeDoc(nextUrl, siteData.autoPager.waitEle);
} else if ("cors" in siteData) {
_fetch = fn.xhrDoc(nextUrl);
} else {
_fetch = fn.fetchDoc(nextUrl);
}
_fetch.then(async nextDoc => {
let srcs = await siteData.getSrcs(nextDoc);
let text;
let title = siteData.autoPager?.title;
if (isFn(title)) {
text = await title(nextDoc);
if (isObject(text)) {
text = nextDoc.title;
}
} else {
text = nextDoc.title;
}
fn.picPreload(srcs, text, "next");
});
}
} else if (isFn(preloadNextPage)) {
preloadNextPage(dom);
}
},
//Iframe框架加載網頁返回框架的document
iframeDoc: (url, selector = null, time = 5000, callback = null) => {
return new Promise(async resolve => {
let tid;
const iframe = document.createElement("iframe");
iframe.name = "FullPictureLoad-iframe";
iframe.id = "FullPictureLoadIframe";
iframe.sandbox = "allow-same-origin allow-scripts allow-popups allow-forms";
iframe.style.cssText = "display: block; visibility: visible; float: none; clear: both; width: 100%; height: 0; background: initial; border: 0px; border-radius: 0px; margin: 0px; padding: 0px; z-index: 2147483647;content-visibility: auto;contain-intrinsic-size: auto 300px;";
tid = setTimeout(() => resolve(null), time);
const call = async () => {
clearTimeout(tid);
let dom = iframe.contentDocument || iframe.contentWindow.document;
if (!dom) resolve(fn.doc("none"));
dom.body.scrollTop = 9999999;
dom.documentElement.scrollTop = 9999999;
try {
await delay(siteData.autoPager?.loadTime || 200);
} catch {
await delay(200);
}
if (selector !== null) {
await fn.waitEle(selector, 600, dom);
}
if (isFn(callback)) {
await callback(dom, iframe.contentWindow);
}
let frameCode = siteData.frameCode;
if (!!frameCode) {
fn.script(frameCode, 0, 1, dom);
}
frameWindow = iframe.contentWindow;
resolve(dom);
iframe.remove();
};
iframe.onload = () => call();
iframe.src = url;
document.body.append(iframe);
});
},
//先用Fetch API取得網頁原始碼,再傳入Iframe框架加載網頁返回框架的document
iframeSrcDoc: (url, selector = null, time = 5000, callback = null) => {
return new Promise(async resolve => {
let tid;
let resText = await fetch(url).then(async res => {
debug(`\nfn.iframeSrcDoc() URL`, url);
if (res.status >= 400) {
let resData = await fn.retryUrl(url, res, "fn.iframeSrcDoc()");
if (resData !== null) return resData;
}
return res.arrayBuffer()
}).then(buffer => {
const decoder = new TextDecoder(document.characterSet || document.charset || document.inputEncoding);
const htmlText = decoder.decode(buffer);
return htmlText;
});
const iframe = document.createElement("iframe");
iframe.name = "FullPictureLoad-iframe";
iframe.id = "FullPictureLoadIframe";
iframe.sandbox = "allow-same-origin allow-scripts allow-popups allow-forms";
//iframe.style.display = "none";
iframe.style.cssText = "display: block; visibility: visible; float: none; clear: both; width: 100%; height: 0; background: initial; border: 0px; border-radius: 0px; margin: 0px; padding: 0px; z-index: 2147483647;content-visibility: auto;contain-intrinsic-size: auto 300px;";
tid = setTimeout(() => resolve(null), time);
const call = async () => {
clearTimeout(tid);
let dom = iframe.contentDocument || iframe.contentWindow.document;
if (!dom) resolve(fn.doc("none"));
dom.body.scrollTop = 9999999;
dom.documentElement.scrollTop = 9999999;
try {
await delay(siteData.autoPager?.loadTime || 200);
} catch {
await delay(200);
}
if (selector !== null) {
await fn.waitEle(selector, 600, dom);
}
if (isFn(callback)) {
await callback(dom, iframe.contentWindow);
}
let frameCode = siteData.frameCode;
if (!!frameCode) {
fn.script(frameCode, 0, 1, dom);
}
frameWindow = iframe.contentWindow;
resolve(dom);
iframe.remove();
};
iframe.onload = () => call();
iframe.srcdoc = resText;
document.body.append(iframe);
});
},
//使用Iframe框架加載網頁,直到框架的window出現指定的環境變數,返回框架的window
iframeVar: async (url, key, time = 1000) => {
const iframe = document.createElement("iframe");
iframe.id = "FullPictureLoadIframe";
iframe.style.display = "none";
iframe.sandbox = "allow-same-origin allow-scripts allow-popups allow-forms";
iframe.src = url;
document.body.append(iframe);
await delay(time);
await new Promise(resolve => {
let loop = setInterval(() => {
let check;
if (isString(key)) {
check = (key in iframe.contentWindow);
} else if (isArray(key)) {
check = key.every(k => (k in iframe.contentWindow));
}
if (check) {
clearInterval(loop);
resolve();
}
}, 100);
});
setTimeout(() => iframe.remove(), 1000);
return iframe.contentWindow;
},
// 讓用Iframe框架加載網頁,能像fetch的寫法
iframe: async (url, details = {}) => {
return new Promise(async (resolve, reject) => {
const iframe = document.createElement("iframe");
iframe.id = "FullPictureLoadIframe";
iframe.style.cssText = "display: block; visibility: visible; float: none; clear: both; width: 100%; height: 0; background: initial; border: 0px; border-radius: 0px; margin: 0px; padding: 0px; z-index: 2147483647;content-visibility: auto;contain-intrinsic-size: auto 300px;";
iframe.sandbox = "allow-same-origin allow-scripts allow-popups allow-forms";
const call = async () => {
const {
loadTime,
waitEle,
waitVar,
cb
} = details;
if (!!loadTime && isNumber(loadTime)) {
await delay(loadTime);
} else {
await delay(1000);
}
const dom = iframe.contentDocument || iframe.contentWindow.document;
if (!!waitEle && (isString(waitEle) || isArray(waitEle))) {
const e = await fn.waitEle(waitEle, 600, dom);
//console.log("waitEle", e);
}
if (!!waitVar) {
await new Promise(end => {
let loop = setInterval(() => {
let check;
if (isString(waitVar)) {
check = (waitVar in iframe.contentWindow);
} else if (isArray(waitVar)) {
check = waitVar.every(k => (k in iframe.contentWindow));
}
if (check) {
//console.log("waitVar", waitVar);
clearInterval(loop);
end();
}
}, 100);
});
}
if (!!cb && isFn(cb)) {
await cb(dom, iframe.contentWindow);
}
setTimeout(() => iframe.remove(), 1000);
const object = {
dom: dom,
frame: iframe.contentWindow
};
//console.log("iframe dom", dom);
//console.log("iframe window", iframe.contentWindow);
resolve(object);
};
iframe.onload = () => call();
iframe.error = reject;
iframe.src = url;
document.body.append(iframe);
});
},
//無限滾動函式用來觀察元素觸發自動翻頁
nextObserver: new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting && autoPagerSwitch) {
observer.unobserve(entry.target);
fn.infiniteScroll();
}
});
}),
//無限滾動取得下一頁連結函式
getNextLink: async (dom) => {
let nextSelector = siteData.autoPager.next;
if (isFn(nextSelector)) {
let nextCode = await nextSelector(dom);
if (nextLink === nextCode && siteData?.autoPager?.mode !== "json") return null;
nextLink = nextCode;
} else if (isString(nextSelector)) {
let nextEle = fn.ge(nextSelector, dom, dom);
try {
if (!nextEle || (nextEle && (nextLink === nextEle.href))) return null;
} catch (error) {
console.error("\nfn.getNextLink() ERROR\n", error);
return null;
}
nextLink = nextEle.href;
const nh = nextEle.hostname;
const lh = fn.lh;
if (nh !== lh) nextLink = nextLink.replace(nh, lh);
} else {
return null;
}
if (!nextLink) return null;
return nextLink;
},
//無限滾動創建標題函式
titleUrlEle: (url, title) => {
let div = document.createElement("div");
autoPagerSwitch ? div.className = "autoPagerTitle" : div.className = "autoPagerTitle off";
if (siteData?.autoPager?.mode === "json") {
div.innerText = title;
} else {
let a = document.createElement("a");
a.href = url;
a.innerText = title;
div.append(a);
}
div.addEventListener("click", event => {
if (event.target.tagName === "DIV") {
fn.toggleAutoPager();
}
});
return div;
},
//無限滾動創建載入中圖示函式
addLoading: () => {
if (siteData.autoPager?.loading === "msg") {
fn.showMsg(DL.str_57, 0);
} else {
try {
let img = new Image();
img.className = "autoPagerLoading";
img.src = autoPagerLoading_gif;
let tE;
let pos = siteData.autoPager?.pos;
if (isArray(pos) && pos.length == 2 && isString(pos[0]) && isNumber(pos[1])) {
const [selector, p] = pos;
tE = fn.ge(selector);
if (p === 0) { //元素裡面
tE.append(img);
} else if (p === 1) { //元素之前
insertBefore(tE, img);
} else if (p === 2) { //元素之後
insertAfter(tE, img);
}
} else {
tE = fn.gae(siteData.autoPager.ele).at(-1);
insertAfter(tE, img);
}
} catch {
fn.showMsg(DL.str_57, 0);
}
}
},
//無限滾動移除載入中圖示函式
removeLoading: () => {
if (siteData.autoPager?.loading === "msg") {
fn.hideMsg();
} else {
try {
fn.ge(".autoPagerLoading").remove();
} catch {
fn.hideMsg();
}
}
},
//無限滾動添加瀏覽器歷史紀錄函式
addHistory: (title, url) => {
history.pushState(null, title, url);
document.title = title;
},
//修改A元素以新分頁的方式開啟連結
openInNewTab: selector => fn.gae(selector).forEach(a => a.setAttribute("target", "_blank")),
//傳入連結陣列使用iframe框架加載取得元素插入到當前頁面指定的位置或返回元素
getEleF: async (links, elements, targetEle = null) => {
if (fn.ge(".FullPictureLoadImage")) return;
isFetching = true;
if (!getImgFnProcessRecord.includes("getEleF()")) getImgFnProcessRecord += " > fn.getEleF()";
fn.showMsg(DL.str_16, 0);
if (isString(links)) {
links = fn.gau(links);
}
let resArr = [];
let fetchNum = 0;
for (let url of links) {
let res = await fn.iframeDoc(url, elements).then(dom => {
fn.clearAllTimer();
fn.showMsg(`${DL.str_17}${fetchNum+=1}/${links.length}`, 0);
let eles = fn.gae(elements, dom, dom);
if (targetEle === null) {
return eles;
}
let ele;
fragment.append(...eles);
if (isArray(targetEle)) {
const [selector, p] = targetEle;
ele = fn.ge(selector);
if (p == 0) ele.append(fragment);
else if (p == 1) insertBefore(ele, fragment);
else if (p == 2) insertAfter(ele, fragment);
}
return eles;
});
resArr.push(res);
}
isFetching = false;
fn.hideMsg();
return Promise.all(resArr).then(arr => arr.flat());
},
//傳入連結陣列並行請求取得元素插入到當前頁面指定的位置或返回元素
getEle: async (links, elements, targetEle = null, removeEles = null, time = 100, retry = 40) => {
if (fn.ge(".FullPictureLoadImage")) return;
isFetching = true;
if (!getImgFnProcessRecord.includes("getEle()")) getImgFnProcessRecord += " > fn.getEle()";
let resArr = [];
let xhrNum = 0;
fn.showMsg(DL.str_16, 0);
if (isString(links)) {
links = fn.gau(links);
}
for (let i = 0; i < links.length; i++) {
let res;
if (time === 0) {
res = await fn.fetchDoc(links[i], {}, retry).then(dom => {
debug(`\nfn.getEle() URL`, decodeURIComponent(links[i]));
fn.showMsg(`${DL.str_17}${xhrNum+=1}/${links.length}`, 0);
//debug(`fn.getEle()\n${decodeURIComponent(links[i])}\n`, dom);
return fn.gae(elements, dom, dom);
});
} else {
res = fn.fetchDoc(links[i], {}, retry).then(dom => {
debug(`\nfn.getEle() URL`, decodeURIComponent(links[i]));
fn.showMsg(`${DL.str_17}${xhrNum+=1}/${links.length}`, 0);
//debug(`fn.getEle()\n${decodeURIComponent(links[i])}\n`, dom);
return fn.gae(elements, dom, dom);
});
}
resArr.push(res);
if (time !== 0 && isNumber(time)) await delay(time);
}
return Promise.all(resArr).then(arr => arr.flat()).then(eles => {
isFetching = false;
fn.hideMsg();
if (targetEle === null) {
if (removeEles) fn.remove(removeEles);
return eles;
}
let ele;
fragment.append(...eles);
if (isArray(targetEle)) {
const [selector, p] = targetEle;
ele = fn.ge(selector);
if (p == 0) ele.append(fragment);
else if (p == 1) insertBefore(ele, fragment);
else if (p == 2) insertAfter(ele, fragment);
} else if (isString(targetEle)) {
ele = fn.ge(targetEle);
ele.innerHTML = "";
ele.append(fragment);
}
if (removeEles) fn.remove(removeEles);
fn.fetchErrorMsg();
});
},
//跨域,傳入連結陣列並行請求取得元素插入到指定的位置
getCorsEle: async (links, elements, targetEle = null, removeEles = null, time = 100) => {
if (fn.ge(".FullPictureLoadImage")) return;
isFetching = true;
if (!getImgFnProcessRecord.includes("getCorsEle()")) getImgFnProcessRecord += " > fn.getCorsEle()";
let resArr = [];
let xhrNum = 0;
fn.showMsg(DL.str_16, 0);
if (isString(links)) {
links = fn.gau(links);
}
for (let i = 0; i < links.length; i++) {
let res;
if (time === 0) {
res = await fn.xhrDoc(links[i]).then(dom => {
debug(`\nfn.getEle() URL`, decodeURIComponent(links[i]));
fn.showMsg(`${DL.str_17}${xhrNum+=1}/${links.length}`, 0);
//debug(`fn.getEle()\n${decodeURIComponent(links[i])}\n`, dom);
return fn.gae(elements, dom, dom);
});
} else {
res = fn.xhrDoc(links[i]).then(dom => {
debug(`\nfn.getEle() URL`, decodeURIComponent(links[i]));
fn.showMsg(`${DL.str_17}${xhrNum+=1}/${links.length}`, 0);
//debug(`fn.getEle()\n${decodeURIComponent(links[i])}\n`, dom);
return fn.gae(elements, dom, dom);
});
}
resArr.push(res);
if (time !== 0 && isNumber(time)) await delay(time);
}
return Promise.all(resArr).then(arr => arr.flat()).then(eles => {
isFetching = false;
fn.hideMsg();
if (targetEle === null) {
if (removeEles) fn.remove(removeEles);
return eles;
}
let ele;
fragment.append(...eles);
if (isArray(targetEle)) {
const [selector, p] = targetEle;
ele = fn.ge(selector);
if (p == 0) ele.append(fragment);
else if (p == 1) insertBefore(ele, fragment);
else if (p == 2) insertAfter(ele, fragment);
} else if (isString(targetEle)) {
ele = fn.ge(targetEle);
ele.innerHTML = "";
ele.append(fragment);
}
if (removeEles) fn.remove(removeEles);
fn.fetchErrorMsg();
});
},
//單線程背景讀取圖片IMG元素陣列的圖片網址
singleThreadLoadImgs: async imgArr => {
for (let i = 0; i < imgArr.length; i++) {
if (!isValidPage) return;
if (!imgArr[i].dataset?.src) continue;
let loadSrc = imgArr[i].dataset.src;
let parent = imgArr[i].parentNode;
let temp = new Image();
if ("referrerpolicy" in (siteData ?? {})) {
temp.setAttribute("referrerpolicy", siteData.referrerpolicy);
}
await new Promise(resolve => {
temp.onload = () => {
imgArr[i].src = loadSrc;
resolve();
};
temp.onerror = () => {
if (loadSrc.includes("https://wsrv.nl/")) {
loadSrc = loadSrc.replace("https://wsrv.nl/?url=", ""); //wsrv.nl_CDN
imgArr[i].dataset.src = loadSrc;
if (!!parent && parent?.nodeName === "A" && !!parent?.getAttribute("data-fancybox")) {
parent.href = loadSrc;
parent.dataset.thumb = loadSrc;
}
} else if (loadSrc.includes(".wp.com/") && !document.title.endsWith("4KHD")) {
loadSrc = loadSrc.replace(/i\d\.wp\.com\/|\?.+$/g, ""); //WordPressCDN
imgArr[i].dataset.src = loadSrc;
if (!!parent && parent?.nodeName === "A" && !!parent?.getAttribute("data-fancybox")) {
parent.href = loadSrc;
parent.dataset.thumb = loadSrc;
}
}
resolve();
};
temp.src = loadSrc;
});
}
},
//單線程背景讀取圖片網址陣列的圖片網址
singleThreadLoadSrcs: async srcArr => {
for (let src of srcArr) {
if (!isValidPage) return;
const temp = new Image();
if ("referrerpolicy" in (siteData ?? {})) {
temp.setAttribute("referrerpolicy", siteData.referrerpolicy);
}
await new Promise(resolve => {
temp.onload = resolve;
temp.onerror = resolve;
temp.src = src;
});
}
},
//圖片預讀函式
picPreload: async (srcArr, title = (apiCustomTitle || customTitle || document.title), page = "current") => {
const errorNumArr = new Array(srcArr.length).fill(0);
const loadImg = async (src, index) => {
await new Promise(resolve => {
const temp = new Image();
if ("referrerpolicy" in siteData) {
temp.setAttribute("referrerpolicy", siteData.referrerpolicy);
}
temp.onload = () => {
resolve("OK");
};
temp.onerror = error => {
if (!isValidPage) return;
const errorNum = errorNumArr[index] + 1;
errorNumArr[index] = errorNum;
if (src.includes("https://wsrv.nl/")) {
src = src.replace("https://wsrv.nl/?url=", ""); //wsrv.nl_CDN
} else if (src.includes(".wp.com/") && !document.title.endsWith("4KHD")) {
src = src.replace(/i\d\.wp\.com\/|\?.+$/g, ""); //WordPressCDN
}
if (/e-hentai\.org|exhentai\.org/.test(fn.lh)) {
resolve("OK");
return;
}
if (errorNum >= 10) {
debug(`\n圖片全載Lazyloading預讀重新載入出錯的圖片已達到10次上限:\n${src}`);
resolve("OK");
return;
}
resolve("OK");
setTimeout(() => {
if (/www\.yinghuamh\.net/.test(fn.lh)) {
const {
Gm,
media
} = _unsafeWindow;
debug(`\n圖片全載Lazyloading預讀出錯 樱花漫画 重新載入另一個圖片伺服器的圖片網址:\n${src}\nto\n${src.replace(Gm.getMediaHost(media), media)}`);
loadImg(src.replace(Gm.getMediaHost(media), media), index);
} else {
debug(`\n圖片全載Lazyloading預讀重新載入出錯的圖片:\n${src}\n錯誤次數:${errorNum}`);
loadImg(src, index);
}
}, 2000);
};
temp.src = src;
});
};
page == "next" ? debug(`\n${title}\n圖片全載開始預讀下一頁`, srcArr) : debug(`\n${title}\n圖片全載Lazyloading開始預讀`);
for (let i = 0; i < srcArr.length; i++) {
if (!isValidPage) return;
if (/youtube|\.mp4|\.m3u8$|\.webm$/.test(srcArr[i])) continue;
let load = await loadImg(srcArr[i], i);
}
page == "next" ? debug(`\n${title}\n圖片全載下一頁預讀結束`) : debug(`\n${title}\n圖片全載Lazyloading預讀結束`);
},
//观察者 MutationObserver事件,根據圖片燈箱插件檢視圖片時的索引,滾動到頁面相對應的圖片位置
MutationObserver_aff: () => {
const openEvent = () => {
if (fn.ge("span[data-fancybox-current-index]") !== null) {
slideIndex = Number(fn.gt("span[data-fancybox-current-index]")) - 1;
} else if (fn.ge("span[data-fancybox-index]") !== null) {
slideIndex = Number(fn.gt("span[data-fancybox-index]")) - 1;
} else if (fn.ge("badge.b-black.counter") !== null) {
slideIndex = Number(fn.gt("badge.b-black.counter").match(/\d+/)[0]) - 1;
}
if (isNumber(slideIndex)) {
console.log("open - # " + slideIndex + " slide is open!");
}
};
const ContentContainer = document.body;
const configObserver = {
childList: true,
subtree: true,
attributeFilter: ["class"]
};
//当观察到突变时执行的回调函数
const Callbacks = mutationsList => {
mutationsList.forEach((item, index) => {
//console.log("index: ", index, " - \n", item);
if (item.type === "attributes") {
//console.log(item);
if (
item.target.className === "fancybox-slide fancybox-slide--image fancybox-slide--current fancybox-slide--complete" ||
item.target.className === "fancybox__slide has-image can-zoom_in is-selected" ||
item.target.className === "swiper-slide swiper-slide-active" && ![
"www.elitebabes.com",
"pmatehunter.com",
"www.jperotica.com",
"www.metarthunter.com",
"www.femjoyhunter.com",
"nakedporn.pics",
"www.6tu.com"
].some(h => fn.lh.includes(h))
) {
console.log(" # ", item);
openEvent();
fn.scrollEvent(slideIndex);
}
} else if (item.type === "childList") {
//console.log(item);
if (item.removedNodes.length > 1 && /fancybox|swiper/.test(item.removedNodes[1].className)) {
console.log(" # ", item);
console.log("close - # " + slideIndex + " slide is closed!");
//setTimeout(closeEvent, 1000);
fn.scrollEvent(slideIndex);
}
}
});
};
//创建一个链接到回调函数的观察者实例
const Observer = new MutationObserver(Callbacks);
ContentContainer && Observer.observe(ContentContainer, configObserver);
},
//創建用來添加圖片元素的主容器
createImgBox: (selector, pos = 0, width = null) => {
if (fn.ge("#FullPictureLoadMainImgBox") || !isString(selector) && !isEle(selector)) return;
let div = document.createElement("div");
div.id = "FullPictureLoadMainImgBox";
div.style.display = "block";
div.style.textAlign = "center";
div.style.margin = "0 auto";
if (isNumber(width)) {
div.style.maxWidth = width + "px";
}
let targetEle;
if (isString(selector)) {
targetEle = fn.ge(selector);
} else if (isEle(selector)) {
targetEle = selector;
}
if (pos == 0) targetEle.append(div);
if (pos == 1) insertBefore(targetEle, div);
if (pos == 2) insertAfter(targetEle, div);
return div;
},
//插入圖片函式
insertImg: async (imgsArray, insertTargetEle, mode = 2) => {
if (fn.ge(".FullPictureLoadImage") || isFetching || isDownloading) return;
if ("insertImgBF" in siteData && isFn(siteData.insertImgBF)) {
await siteData.insertImgBF();
}
let srcArr = [];
for (let i = 0; i < imgsArray.length; i++) {
let check = fn.checkImgSrc(imgsArray[i]);
check.ok ? srcArr.push(check.src) : console.error("\nfn.insertImg(imgsArray) 格式錯誤!", imgsArray[i]);
}
srcArr = [...new Set(srcArr)];
let noVideoNum = srcArr.filter(src => !/youtube|\.mp4$|\.webm$/.test(src)).length;
let buttonFn = siteData.button;
let buttonBar;
if (isArray(buttonFn)) {
let [, customWidth, insertBr] = buttonFn;
buttonBar = document.createElement("div");
buttonBar.id = "FullPictureLoadOptionsButtonParentDiv";
buttonBar.style.width = "100%";
//buttonBar.style.height = "42px";
buttonBar.style.display = "inline-block";
buttonBar.style.textAlign = "center";
if (isNumber(insertBr)) {
buttonBar.style.marginTop = insertBr * 20 + "px";
}
let width = "24%";
if (isString(customWidth)) width = customWidth;
const buttonObj = [{
id: "FullPictureLoadOpenFavoritesBtn",
className: "FullPictureLoadPageButtonTop",
text: DL.str_128,
cfn: event => {
cancelDefault(event);
createFavorShadowElement();
}
}, {
id: "FullPictureLoadShadowGalleryBtn",
className: "FullPictureLoadPageButtonTop",
text: isM ? DL.str_141.replace("Shadow", "") : DL.str_141,
cfn: event => {
cancelDefault(event);
createShadowGallery();
}
}, {
id: "FullPictureLoadFastDownloadBtn",
className: "FullPictureLoadPageButtonTop",
text: isM ? DL.str_107 : DL.str_107 + ` | [ ${noVideoNum}P ]`,
cfn: event => {
cancelDefault(event);
fastDownloadSwitch = true;
DownloadFn();
}
}, {
id: "FullPictureLoadNewTabViewBtn",
className: "FullPictureLoadPageButtonTop",
text: DL.str_106,
cfn: event => {
cancelDefault(event);
newTabView();
}
}, {
id: "FullPictureLoadOptionsBtn",
className: "FullPictureLoadPageButtonBottom",
text: DL.str_85,
cfn: event => {
cancelDefault(event);
createPictureLoadOptionsShadowElement();
}
}, {
id: "FullPictureLoadToggleImgModeBtn",
className: "FullPictureLoadPageButtonBottom",
text: DL.str_86,
cfn: event => {
cancelDefault(event);
toggleImgMode();
}
}, {
id: "FullPictureLoadToggleZoomeBtn",
className: "FullPictureLoadPageButtonBottom",
text: DL.str_87,
title: DL.str_136,
cfn: event => {
cancelDefault(event);
fn.clearAllTimer(2);
reduceZoom();
},
mfn: event => {
if (event.button == 2) {
cancelDefault(event);
increaseZoom();
}
}
}, {
id: "FullPictureLoadCancelZoomBtn",
className: "FullPictureLoadPageButtonBottom",
text: DL.str_88,
cfn: event => {
cancelDefault(event);
fn.clearAllTimer(2);
cancelZoom();
}
}];
if (isM) {
buttonObj[1] = {
id: "FullPictureLoadShadowGalleryBtn",
className: "FullPictureLoadPageButtonTop",
text: DL.str_188.replace("Phone ", ""),
cfn: event => {
cancelDefault(event);
createFilterUI(1);
}
}
}
const createButton = obj => {
let button = document.createElement("button");
button.id = obj.id;
button.className = obj.className;
button.style.width = width;
//button.style.height = "24px";
button.innerText = obj.text;
button.oncontextmenu = () => false;
if (!!obj.title) button.title = obj.title;
if (!!obj.cfn) button.addEventListener("click", obj.cfn);
if (!!obj.mfn) button.addEventListener("mousedown", obj.mfn);
buttonBar.append(button);
};
[...buttonObj].forEach(obj => createButton(obj));
fragment.append(buttonBar);
}
let blackList = fancyboxBlackList();
if (options.fancybox == 1 && thumbnailSrcArray.length > 0) {
if (!/(www\.)?24cos\.org|www\.lovecos\.net|luohuaxiu\.com|kemono\.su|coomer\.su/.test(fn.lh) || !/^data/.test(thumbnailSrcArray[0])) {
thumbnailSrcArray = [...new Set(thumbnailSrcArray)];
}
}
debug("\nfn.insertImg()插入圖片最後確認 thumbnailSrcArray", thumbnailSrcArray);
debug("\nfn.insertImg()插入圖片最後確認 srcArr", srcArr);
for (let i = 0; i < srcArr.length; i++) {
let img = new Image();
img.alt = `no.${i + 1}`;
img.dataset.index = i;
img.className = "FullPictureLoadImage";
if ("referrerpolicy" in siteData) {
img.setAttribute("referrerpolicy", siteData.referrerpolicy);
}
img.dataset.errorNum = 0;
//if (/vipr\.im/.test(srcArr[i])) img.referrerPolicy = "no-referrer";
if (options.zoom <= 10 && options.zoom > 0 && (blackList || options.fancybox !== 1)) {
img.style.width = `${options.zoom * 10}%`;
img.style.height = "auto";
}
if (mode == 2 || mode == 3) {
img.src = loading_bak;
img.dataset.src = srcArr[i];
} else {
img.loading = "lazy";
img.decoding = "async";
img.onload = () => {
img.classList.remove("error");
};
img.onerror = error => {
const num = Number(error.target.dataset.errorNum);
if (num < 10) {
error.target.dataset.errorNum = num + 1;
} else {
return;
}
error.target.classList.add("error");
setTimeout(() => {
debug(`\nfn.insertImg()重新載入出錯的圖片:\n${error.target.src}`);
error.target.src = error.target.src;
}, 1000);
};
img.src = srcArr[i];
}
if (options.fancybox == 1 && !blackList) {
let a = document.createElement("a");
a.id = "imgLocationOriginal_" + i;
a.dataset.fancybox = "FullPictureLoadImageOriginal";
thumbnailSrcArray.length > 0 && thumbnailSrcArray.length == noVideoNum ? a.dataset.thumb = thumbnailSrcArray[i] : a.dataset.thumb = srcArr[i];
a.href = "#";
a.dataset.src = srcArr[i];
if (options.zoom <= 10 && options.zoom > 0) {
a.style.width = `${options.zoom * 10}%`;
a.style.height = "auto";
}
a.append(img);
fragment.append(a);
} else {
fragment.append(img);
}
}
if (videoSrcArray.length > 0) {
debug("\nfn.insertImg()插入圖片最後確認 videoSrcArray", videoSrcArray);
if (isPC && siteData.downloadVideo === true && FullPictureLoadCustomDownloadVideo == 1) {
let dbtn = fn.ge("#FullPictureLoadFastDownloadBtn", fragment);
if (dbtn) {
dbtn.innerText = dbtn.innerText.replace("P", `P + ${videoSrcArray.length}V`);
}
}
for (let i = 0; i < videoSrcArray.length; i++) {
let video = document.createElement("video");
video.className = "FullPictureLoadVideo";
video.controls = true;
video.loop = false;
video.autoplay = false;
video.preload = "none";
video.style = "height: 500px;width: 100%;max-width:100%";
let source = document.createElement("source");
source.src = videoSrcArray[i];
source.type = "video/mp4";
video.append(source);
fragment.append(video);
}
}
let end = document.createElement("p");
end.id = "FullPictureLoadEnd";
if ("endColor" in siteData) {
if (isFn(siteData.endColor)) {
end.style.color = siteData.endColor();
} else if (isString(siteData.endColor)) {
end.style.color = siteData.endColor;
}
}
end.innerText = `${DL.str_52}:${noVideoNum}P`;
fragment.append(end);
if (srcArr.length > 0 || (srcArr.length >= 0 && videoSrcArray.length > 0)) {
const [, insertMode] = siteData.insertImg;
if ((insertMode == 2 || insertMode == 3) && siteData.preload != 0) {
fn.picPreload(srcArr);
}
let targetEle;
try {
if (isArray(insertTargetEle)) {
let [selector, pos, removeSelector] = insertTargetEle;
if (("box" in siteData) || selector == "box") {
selector = "#FullPictureLoadMainImgBox";
}
targetEle = fn.ge(selector);
if (pos == 0) {
targetEle.append(fragment);
//targetEle.style.textAlign = "center";
targetEle.style.display = "block";
} else if (pos == 1) {
insertBefore(targetEle, fragment);
//targetEle.parentNode.style.textAlign = "center";
targetEle.parentNode.style.display = "block";
targetEle = targetEle.parentNode;
} else if (pos == 2) {
insertAfter(targetEle, fragment);
//targetEle.parentNode.style.textAlign = "center";
targetEle.parentNode.style.display = "block";
targetEle = targetEle.parentNode;
}
if (isString(removeSelector)) await fn.remove(removeSelector);
if (siteData.msg != 0 && siteData.category != "comic") fn.showMsg(DL.str_18);
} else if (isString(insertTargetEle)) {
let selector = insertTargetEle;
if (("box" in siteData) || selector == "box") {
selector = "#FullPictureLoadMainImgBox";
}
targetEle = fn.ge(selector);
targetEle.innerHTML = "";
targetEle.append(fragment);
//targetEle.style.textAlign = "center";
targetEle.style.display = "block";
if (siteData.msg != 0 && siteData.category != "comic") fn.showMsg(DL.str_18);
}
let insertImgAF = siteData.insertImgAF;
if (isFn(insertImgAF)) insertImgAF(targetEle, buttonBar);
if (isPC && ShowFullPictureLoadFixedMenu == 1) {
fn.waitEle("#insertImgMenu").then(e => isEle(e) ? fn.hideEle(e) : void 0);
}
} catch (error) {
fn.showMsg(DL.str_19, 3000);
console.error("\nfn.insertImg() ele參數錯誤,或用來定位插入的元素不存在。", error);
return;
}
let imgs = fn.gae("img.FullPictureLoadImage:not(.small)");
if (mode == 2 || mode == 3) {
setTimeout(() => {
imgs.forEach(img => fn.imagesObserver.observe(img));
}, 1000);
}
if (siteData.preload != 0) {
let oddNumberImgs = imgs.filter((img, index) => index % 2 == 0);
let evenNumberImgs = imgs.filter((img, index) => index % 2 != 0);
fn.singleThreadLoadImgs(oddNumberImgs);
fn.singleThreadLoadImgs(evenNumberImgs);
}
if (TurnOffImageNavigationShortcutKeys != 1) {
let imgsNum = 0;
document.addEventListener("keydown", event => {
if (isOpenOptionsUI || isOpenGallery || fn.ge(".fancybox-container,#FullPictureLoadFavorSites")) return;
if (event.code === "ArrowUp" || event.key === "ArrowUp") {
if (imgsNum > 0 && viewMode == 0) {
imgsNum -= 1;
imgs[imgsNum].scrollIntoView();
}
} else if (event.code === "ArrowDown" || event.key === "ArrowDown") {
event.preventDefault();
if (imgsNum < imgs.length && viewMode == 0) {
imgsNum += 1;
try {
imgs[imgsNum].scrollIntoView();
} catch {
imgsNum = 0;
imgs[0].scrollIntoView();
fn.showMsg(DL.str_94);
}
}
} else {
imgsNum = 0 - 1;
}
});
}
if (siteData.category === "comic") {
let lastImg = imgs.at(-1);
fn.comicNextObserver.observe(lastImg);
}
if (isPC && ShowFullPictureLoadFixedMenu === 1) {
fn.waitEle("#FullPictureLoadFixedMenu").then(menu => fn.gae(".zoom,.toggleImgMode", menu).forEach(e => (e.style.display = "")));
}
if (options.icon == 1 || siteData.icon == 1) {
fn.waitEle(["#FullPictureLoadGoToFirstImage", "#FullPictureLoadGoToLastImage"]).then(eles => eles.forEach(e => (e.style.display = "unset")));
}
if (options.fancybox == 1 && !("fancybox" in siteData) && ("Fancybox" in _unsafeWindow)) {
_unsafeWindow.Fancybox.bind("[data-fancybox='FullPictureLoadImageOriginal']", FancyboxOptions);
}
if (
!["tupianwu.com", "hentairead.com", "whoreshub.com", "porntrex.com"].some(h => fn.lh.includes(h)) &&
!fn.ge(".umRelevant.umBox") &&
!fn.ge(".videoPlayerWrap") &&
!fn.ge("#xqbj-main") &&
!fn.ge(".PcHeader_rightBox") &&
!fn.ge(".gallery-page #toggle-column")
) {
fn.MutationObserver_aff();
}
if (pageViewMode == 1 || siteData.viewMode == 1) toggleImgMode();
if (goToFirstImage == 1) goToNo1Img();
} else {
fn.showMsg(DL.str_20);
}
},
immediateInsertImg: async (manual = "no") => {
if (captureExclude() || ge(".FullPictureLoadImage")) return;
if ("SPA" in siteData && isFn(siteData.SPA)) {
const validPage = await siteData.SPA();
if (!validPage) return;
}
if (options.autoInsert == 1 && manual === "no" || options.autoInsert == 0 && manual === "yes" || manual === "yes") {
let [insertSelector, insertMode, delayTime] = siteData.insertImg;
await fn.delay(delayTime || 0);
let selector = siteData.srcset || siteData.imgs;
let imgsSrcArray = await getImgs(selector);
await fn.insertImg(imgsSrcArray, insertSelector, insertMode);
}
},
isXPath: xpath => /^\(*(descendant::|\.\/|\/|id\()/.test(xpath),
//返回選擇器的首個元素
ge: (selector, contextNode = null, dom = document) => {
if (isObject(selector)) {
let {
s,
t
} = selector;
let node = fn.gae(s, contextNode, dom).find(e => {
let text = e?.text || e?.innerText;
return text?.includes(t);
});
return isEle(node) ? node : null;
} else if (fn.isXPath(selector)) {
return dom.evaluate(selector, (contextNode ?? document), null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
} else {
return (contextNode ?? document).querySelector(selector);
}
},
//返回A選擇器的首個A元素的href
gu: (selector, contextNode = null, dom = document) => fn.ge(selector, contextNode, dom)?.href,
//返回選擇器的所有元素的陣列
gae: (selector, contextNode = null, dom = document) => {
if (fn.isXPath(selector)) {
let nodes = [];
let results = dom.evaluate(selector, (contextNode ?? document), null, XPathResult.ANY_TYPE, null);
let node = null;
while (node = results.iterateNext()) {
nodes.push(node);
}
return nodes;
} else {
return [...(contextNode ?? document).querySelectorAll(selector)];
}
},
//返回A選擇器的所有A元素的href的陣列並且去除重複
gau: (selector, contextNode = null, dom = document) => [...new Set(fn.gae(selector, contextNode, dom)?.map(a => a?.href))],
//取得網頁喧染後的元素字串
gt: (selector, mode = 1, dom = document) => {
try {
let e;
if (isEle(selector)) {
e = selector;
} else {
e = fn.ge(selector, dom, dom);
}
if (mode == 1) return e?.innerText;
if (mode == 2) return e?.previousElementSibling?.innerText;
if (mode == 3) return e?.previousElementSibling?.previousElementSibling?.innerText;
} catch (error) {
console.error(`\nfn.gt() ERROR\nselector:${selector}\n`, error);
return null;
}
},
getText: (selector, dom = document) => {
let text = "";
if (isString(selector)) {
let ele = fn.ge(selector, dom, dom);
text = ele?.innerText;
if (!!ele && !!text && text?.length > 0) {
return fn.dt({
t: text
});
}
} else if (isArray(selector)) {
for (let s of selector) {
let ele = fn.ge(s, dom, dom);
text = ele?.innerText;
if (!!ele && !!text && text?.length > 0) {
return fn.dt({
t: text
});
}
}
}
return text;
},
//根據關鍵字串或正則搜索符合條件的script,返回script字串
gst: (searchValue, dom = document) => {
try {
let text = [...dom.scripts]?.find(script => {
if (isString(searchValue)) {
return script.textContent.includes(searchValue);
} else if (isRegExp(searchValue)) {
return script.textContent.search(searchValue) > -1;
}
})?.textContent;
return text ? text : "";
} catch {
return null;
}
},
__next_f: (dom = document) => [...dom.scripts]
.filter(script => ["self.__next_f.push", '"'].every(str => script.textContent.includes(str)))
.map(script => {
let code = script.textContent;
let s_index = code.indexOf('"') + 1;
let e_index = code.lastIndexOf('"');
return code.slice(s_index, e_index);
})
.join("")
.replaceAll("\n", "")
.replaceAll("\\", ""),
//刪除指定字串返回字串
dt: (obj = {}, dom = document) => {
let str = dom.title;
if ("s" in obj) {
let selector = obj.s;
str = fn.gt(selector, 1, dom);
} else if ("t" in obj) {
str = obj.t;
}
let dt = obj.d ?? "";
if (isString(dt) && dt !== "" || isRegExp(dt)) {
str = str?.replace(dt, "");
} else if (isArray(dt)) {
dt.forEach(r => (str = str?.replace(r, "")));
}
const _delete = () => {
str = str?.replace(/[\s-]+\([Page\s\d\/]+\)|[\/\s]?[\(\[[(【“]\d+[\w\s\\\/\.\+-/]+[\)\]])】”]|\s?\d+p[\+\s]+\d+v|\s?\d+p\+?\d+v|\s?\d+P|\(\d\)/gi, "")
.replace(/\d+枚(まとめ)?/, "");
};
let j_g_num = ["【", "】"].every(e => str?.includes(e));
if (j_g_num) {
let m = str.match(/【(.+)】/);
if (m) {
let [, text] = m;
if (!Number(text)) {
_delete();
}
}
} else {
_delete();
}
str = str?.replace(/\n/g, " ")
.replace(/ /g, " ")
.replace(/\s\|/g, "")
.replace(/\:/g, ":")
.replace(/\*/g, "*")
.replace(/\?/g, "?")
.replace(/\"/g, "“")
.replace(/\</g, "《")
.replace(/\>/g, "》")
.replace(/\|/g, "|")
.replace(/\//g, "/")
.replace(/\\/g, "\")
.replace(/\s{2,100}/g, " ")
.trim();
return str;
},
//傳入字串和起始關鍵字串(不包含在需要的字串內)和結束的關鍵字串,提取出需要的字串。
stringSlicer: (string, startText, endText) => {
const startIndex = string.indexOf(startText) + startText.length;
const endIndex = string.indexOf(endText, startIndex);
return string.slice(startIndex, endIndex + endText.length);
},
//傳入代碼字串和變數關鍵字串提取變數的字串
textVar: (str, key) => {
let a = str.indexOf(key);
let b = str.indexOf("=", a);
let c = str.indexOf(";", b);
str = str.slice(b + 1, c).replaceAll("'", "").replaceAll('"', "").trim();
return String(str);
},
//傳入代碼字串和變數關鍵字串提取變數的Number數字
numVar: (str, key) => {
let a = str.indexOf(key);
let b = str.indexOf("=", a);
let c = str.indexOf(";", b);
str = str.slice(b + 1, c);
return Number(str);
},
//傳入字串和關鍵字串提取Object字串轉為Object物件
TextToObject: (str, key, mode = 1) => {
let a = str.indexOf(key);
let b = str.indexOf("{", a);
let c = str.indexOf("}", b) + 1;
str = str.slice(b, c);
if (mode == 2) {
return Object.fromEntries(str.slice(1, -1).replaceAll("\n", "").replaceAll("'", "").replaceAll('"', "").split(",").map(e => {
let [k, v] = e.split(":");
return [k.trim(), v.trim()];
}));
} else {
return fn.run(str);
}
},
//傳入字串和關鍵字串提取Array字串轉為Array陣列物件
TextToArray: (str, key) => {
let a = str.indexOf(key);
let b = str.indexOf("[", a);
let c = str.indexOf("]", b) + 1;
str = str.slice(b, c);
return fn.run(str);
},
//簡單解析執行一些壓縮混淆過的代碼
parseCode: str => {
let s = str.indexOf("(");
let e = str.lastIndexOf(")") + 1;
str = str.slice(s, e);
return fn.run(str);
},
//取得元素的屬性值
attr: (selector, attr, dom = document) => {
if (isEle(selector)) {
return selector.getAttribute(attr);
}
return fn.ge(selector, dom, dom).getAttribute(attr);
},
//傳入代碼執行代碼
run: code => new Function('"use strict";return (' + code + ')')(),
gm_run: code => {
_GM_addElement(document.body, "script", {
textContent: code
})?.remove();
},
//將字串解析為document物件
doc: str => new DOMParser().parseFromString(str, "text/html"),
//將字串解析為XML物件
xml: str => new DOMParser().parseFromString(str, "text/xml"),
//將字串解析為DOM Node文檔片段
html: str => {
const template = document.createElement("template");
template.innerHTML = str;
return template.content;
},
//根據參數返回修改後的網頁標題
title: (str, mode = 0, dom = document) => {
let split = dom.title.replace(/漫画|\s-\s(漫本)|\[\d+p(\d+v)?\]/gi, "").split(str);
try {
if (mode == 0) return dom.title.replace(str, "").trim();
if (mode == 1) return split[0].replace(/,$/g, "").replace(/,/g, " ").trim();
if (mode == 2) return (split[0] + str + split[1]).replace(/,$/g, "").replace(/,/g, " ").trim();
if (mode == 3) return (split[1] + str + split[0]).replace(/,$/g, "").replace(/,/g, " ").trim();
} catch (error) {
console.error("\nfn.title() ERROR", error);
return dom.title;
}
},
//創建一個指定長度的陣列
arr: (num, cb = null) => {
if (isFn(cb)) {
return Array.from({
length: Number(num)
}, cb);
} else {
return Array.from({
length: Number(num)
});
}
},
//顯示簡短的訊息
showMsg: async (text, time = 1000) => {
if (getType(msgTimeId) == "Number") {
clearTimeout(msgTimeId);
}
let msgE = fn.ge("#FullPictureLoadMsg");
if (!msgE) {
msgE = document.createElement("div");
msgE.id = "FullPictureLoadMsg";
if (FullPictureLoadMsgPos == 1) {
msgE.style.cssText = "top:10px;left:10px;";
} else if (FullPictureLoadMsgPos == 2) {
msgE.style.cssText = "top:10px;right:10px;";
} else if (FullPictureLoadMsgPos == 3) {
msgE.style.cssText = "bottom:10px;left:72px;";
} else if (FullPictureLoadMsgPos == 4) {
msgE.style.cssText = "bottom:10px;right:10px;";
} else {
msgE.style.cssText = "top:30%;left:50%;margin-left:-180px;";
}
document.body.append(msgE);
}
msgE.innerText = text;
if (!!time && isNumber(time)) {
msgTimeId = setTimeout(() => fn.hideMsg(), time);
}
},
//隱藏訊息
hideMsg: () => {
const msgE = fn.ge("#FullPictureLoadMsg");
msgE?.remove();
},
//圖片元素觀察者,圖片進入可視範圍時把data-src屬性寫入src
imagesObserver: new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
observer.unobserve(entry.target);
let realSrc = entry.target.dataset.src;
let nE = entry.target.nextElementSibling;
let fancyboxE = entry.target.parentNode;
let fancyboxA = null;
let fancyboxNE = null;
if (fancyboxE && fancyboxE?.tagName == "A" && fancyboxE.getAttribute("data-fancybox")) {
fancyboxA = fancyboxE;
fancyboxNE = fancyboxE.nextElementSibling;
}
if (realSrc) {
entry.target.classList.remove("lazyload");
entry.target.onload = () => {
if (!/^(data|blob)/.test(entry.target.src)) {
entry.target.classList.remove("error");
}
};
entry.target.onerror = async (error) => {
if (realSrc.includes("wsrv.nl/")) {
let newSrc = realSrc.replace("https://wsrv.nl/?url=", ""); //wsrv.nl_CDN
entry.target.dataset.src = newSrc;
if (!!fancyboxA) {
fancyboxA.href = newSrc;
fancyboxA.dataset.thumb = newSrc;
}
} else if (realSrc.includes(".wp.com/") && !document.title.endsWith("4KHD")) {
let newSrc = realSrc.replace(/i\d\.wp\.com\/|\?.+$/g, ""); //WordPressCDN
entry.target.dataset.src = newSrc;
if (!!fancyboxA) {
fancyboxA.href = newSrc;
fancyboxA.dataset.thumb = newSrc;
}
}
const errorNum = Number(entry.target.dataset?.errorNum) || 0;
if (errorNum < 20) {
entry.target.dataset.errorNum = errorNum + 1;
} else {
return;
}
if (/www\.yinghuamh\.net/.test(fn.lh)) {
const {
Gm,
media
} = _unsafeWindow;
error.target.dataset.src = error.target.dataset.src.replace(Gm.getMediaHost(media), media);
}
if (/e-hentai\.org|exhentai\.org/.test(fn.lh) && errorNum < 1) {
let url = error.target.dataset.loadfail ?? fn.gae(".gdtm a,.gdtl a")[error.target.dataset.index].href;
let newSrc = await fn.fetchDoc(url).then(async dom => {
let loadfail = fn.ge("#loadfail", dom);
let newUrl = url.replace(/\?nl=.+$/, "") + "?nl=" + loadfail.getAttribute("onclick").split("'")[1];
error.target.dataset.loadfail = newUrl;
return await fn.fetchDoc(newUrl).then(newDoc => {
let src = fn.ge("#img", newDoc).src;
if (fancyboxE && fancyboxE.tagName == "A") fancyboxE.href = src;
return src;
});
});
error.target.dataset.src = newSrc;
}
if (/civitai\.com/.test(fn.lh)) {
if (error.target.dataset.url) {
error.target.dataset.src = error.target.dataset.url;
} else {
error.target.dataset.src = error.target.dataset.src.replace("original=true/", "");
}
}
error.target.src = loading_bak;
error.target.classList.add("error");
setTimeout(() => {
if (/www\.yinghuamh\.net/.test(fn.lh)) {
debug(`\nimagesObserver 樱花漫画圖片出錯 重新載入另一個圖片伺服器的圖片網址:\n${realSrc}\nto\n${error.target.dataset.src}`);
} else if (/e-hentai\.org|exhentai\.org/.test(fn.lh)) {
debug(`\nimagesObserver E紳士圖片出錯 重新載入新的圖片網址:\n${realSrc}\nto\n${error.target.dataset.src}`);
} else {
debug(`\nimagesObserver重新載入出錯圖片:\n${realSrc}\n錯誤次數:${errorNum}`);
}
error.target.src = error.target.dataset.src;
}, 3000);
};
entry.target.src = realSrc;
}
if (!!nE && nE.tagName == "IMG" && !!nE?.dataset?.src) nE.src = nE.dataset.src;
if (fancyboxNE && fancyboxNE.tagName == "A") {
let ele = fancyboxNE.firstElementChild;
if (!!ele && ele.tagName == "IMG" && !!ele?.dataset?.src) ele.src = ele.dataset.src;
}
}
});
}),
imagesViewObserver: new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add("isView");
} else {
entry.target.classList.remove("isView");
}
});
}),
//看漫畫當最後一張圖進入可視範圍時,按住空白鍵前往下一話
comicNextObserver: new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
observer.unobserve(entry.target);
if (!!nextLink) {
const comicSpaceClickNext = () => {
let click = 0;
const callback = event => {
if (event.code === "Space" || event.key === " ") {
click += 1;
if (click >= 5) {
document.removeEventListener("keydown", callback);
fn.showMsg(DL.str_34.n);
location.href = nextLink;
}
}
};
document.addEventListener("keydown", callback);
};
comicSpaceClickNext();
}
}
});
}),
//創建style元素
css: (css, id = null) => {
if (isString(id)) {
if (document.getElementById(id)) return;
}
let style = document.createElement("style");
style.type = "text/css";
if (isString(id)) style.id = id;
style.className = "FullPictureLoadStyle";
style.innerHTML = css;
document.head.append(style);
},
//創建script元素
//fn.script("code"),返回script
//fn.script("code",0,1),script插入到document.body
//fn.script("srcUrl",1,1),script插入到document.body
script: async (code, src = 0, pos = 0, dom = document) => {
let script = dom.createElement("script");
script.className = "FullPictureLoadScript";
if (src == 0) {
script.type = "text/javascript";
script.innerHTML = code;
}
if (src == 0 && pos == 0) {
return script;
} else if (pos == 1) {
if (src == 1) {
await new Promise(resolve => {
script.onload = () => {
resolve();
};
script.src = code;
dom.body.append(script);
});
} else {
dom.body.append(script);
}
}
if (siteData.category === "comic autoPager") {
script.remove();
}
},
//延遲
delay: (time, msg = 1) => {
if (time > 200 && msg == 1) fn.showMsg(`${DL.str_21}${time}${DL.str_22}...`, time);
return new Promise(resolve => setTimeout(resolve, time));
},
//等待函式寫法
wait: (callback, num = 300) => {
if (!isFn(callback)) return;
let isUI = ["imgElements.at(-1)"].some(s => String(callback).includes(s));
if (!isUI) {
debug("fn.wait()函式判斷等待中...", String(callback));
}
let loopNum = 0;
return new Promise(resolve => {
const loopFn = async () => {
let check = await callback(document, _unsafeWindow);
if (!!check) {
if (!isUI) {
debug(`fn.wait()函式判斷等待結束。耗時:${loopNum * 100}ms。`, String(callback));
}
resolve(true);
return;
}
if (loopNum >= num) {
debug("fn.wait()函式判斷達循環上限。", String(callback));
resolve(false);
return;
}
if (!check) {
loopNum += 1;
await delay(100);
return loopFn();
}
};
loopFn();
});
},
//等待元素
waitEle: (selector, max = 200, dom = document, ee = null) => {
let loopNum = 0;
let str = String(selector);
let isUI = ["insertImgMenu", "FullPictureLoad"].some(s => str.includes(s));
if (selector !== "body" && !isUI) {
debug(`fn.waitEle()等待"${String(selector)}"元素中...`);
}
return new Promise(resolve => {
let loop = setInterval(() => {
loopNum += 1;
let check;
let ele;
if (isString(ee)) {
if (fn.ge(ee, dom, dom)) {
clearInterval(loop);
resolve(null);
}
}
if (isString(selector)) {
ele = fn.ge(selector, dom, dom);
check = isEle(ele);
} else if (isArray(selector)) {
check = selector.every(s => isEle(fn.ge(s, dom, dom)));
ele = selector.map(s => fn.gae(s, dom, dom));
ele = [...new Set(ele.flat())];
}
if (check) {
if (selector !== "body" && !isUI) {
debug(`fn.waitEle()等待"${String(selector)}"元素結束。耗時:${loopNum * 100}ms。`);
}
clearInterval(loop);
resolve(ele);
}
if (loopNum >= max) {
clearInterval(loop);
debug(`fn.waitEle()達循環上限,沒有出現"${String(selector)}"元素。`);
resolve(null);
}
}, 100);
});
},
//等待window環境變數
waitVar: (key, max = 200) => {
let loopNum = 0;
debug(`fn.waitVar()等待"${String(key)}"環境變數中...`);
return new Promise(resolve => {
let loop = setInterval(() => {
loopNum += 1;
let check;
if (isString(key)) {
check = (key in _unsafeWindow);
} else if (isArray(key)) {
check = key.every(k => (k in _unsafeWindow));
}
if (check) {
debug(`fn.waitVar()等待"${String(key)}"環境變數結束。耗時:${loopNum * 100}ms。`);
clearInterval(loop);
resolve(true);
}
if (loopNum >= max) {
clearInterval(loop);
debug(`fn.waitVar()等待環境變數達循環上限,沒有出現"${String(key)}"屬性。`);
resolve(false);
}
}, 100);
});
},
//攔截創建IMG元素時的src
HTMLImageElementSrcHook: callback => {
const originalSrcDescriptor = Object.getOwnPropertyDescriptor(HTMLImageElement.prototype, "src");
Object.defineProperty(HTMLImageElement.prototype, "src", {
set: function(value) {
if (isFn(callback)) {
callback(value);
}
originalSrcDescriptor.set.call(this, value);
}
});
},
//確認圖片狀態返回圖片寬高
checkImgStatus: (src, msg = 1) => {
if (isString(msg)) {
fn.showMsg(msg, 0);
} else if (msg === 1) {
fn.showMsg(DL.str_56, 0);
}
return new Promise(resolve => {
const temp = new Image();
if ("referrerpolicy" in siteData) {
temp.setAttribute("referrerpolicy", siteData.referrerpolicy);
}
temp.onload = () => {
if (isString(msg)) fn.hideMsg();
resolve({
ok: true,
src: src,
width: temp.width,
height: temp.height
});
};
temp.onerror = () => {
if (isString(msg)) fn.hideMsg();
resolve({
ok: false,
src: src
});
};
temp.src = src;
});
},
//確認目前下載線程
checkDownloadThread: () => {
let threading;
if (options.threading > 32) {
threading = 32;
} else if (options.threading < 1) {
threading = 1;
} else {
threading = options.threading;
}
return new Promise(resolve => {
let loop = setInterval(() => {
if (currentDownloadThread <= threading) {
clearInterval(loop);
resolve();
}
}, 50);
});
},
//產生隨機字串
generateRandomString: (num, mode = 0) => {
let characters;
if (mode === 0) {
characters = "0123456789";
} else {
characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
}
let string = "";
let charactersLength = characters.length;
for (let i = 0; i < num; i++) {
string += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return string;
},
//取得代碼並創建script注入到當前頁面
getCode: (url, obj = {}) => {
fn.showMsg(DL.str_05, 0);
const {
mode,
cors,
key
} = obj;
if (mode == "dom" && (isString(key) || isRegExp(key))) {
let xhr;
if (cors == true) {
xhr = fn.xhrDoc(url);
} else {
xhr = fn.fetchDoc(url);
}
return xhr.then(dom => {
fn.hideMsg();
let code = fn.gst(key, dom);
_GM_addElement(document.body, "script", {
textContent: code
});
return code;
});
} else {
let xhr;
if (cors == true) {
xhr = fn.xhr(url);
} else {
xhr = fetch(url).then(res => res.text());
}
return xhr.then(text => {
fn.hideMsg();
_GM_addElement(document.body, "script", {
textContent: text
});
return text;
});
}
},
//用Promise封裝GM_xmlhttpRequest
xhr: (url, details = {}) => {
return new Promise((resolve, reject) => {
_GM_xmlhttpRequest({
method: "GET",
url: url,
responseType: "text",
headers: {
"Referer": _unsafeWindow.location.href,
"User-Agent": _unsafeWindow.navigator.userAgent
},
onload: data => {
if (data.status > 400) debug(`\nfn.xhr()連線錯誤碼:${data.status}\n`, url);
resolve(data.response);
},
onerror: error => {
console.error("fn.xhr()ERROR", error);
reject(error)
},
...details
});
});
},
//用Promise封裝GM_xmlhttpRequest
xhrHEAD: (url, details = {}) => {
return new Promise(resolve => {
_GM_xmlhttpRequest({
method: "HEAD",
url: url,
headers: {
"Referer": _unsafeWindow.location.href,
"User-Agent": _unsafeWindow.navigator.userAgent
},
timeout: 20000,
onload: data => {
resolve(data);
},
onerror: error => {
console.log(`fn.xhrHEAD() ERROR\n${url}`, error);
resolve({
status: 403
});
},
ontimeout: error => {
console.log(`fn.xhrHEAD() Timeout\n${url}`, error);
resolve({
status: 524
});
},
...details
});
});
},
checkCors: (url) => new Promise(resolve => {
fetch(url, {
method: "HEAD",
}).then(res => {
resolve(res.ok);
}).catch((error) => {
resolve(false);
});
}),
//用Promise封裝GM_xmlhttpRequest
imageBamXHR: url => {
return new Promise((resolve, reject) => {
_GM_xmlhttpRequest({
method: "GET",
url: url,
responseType: "document",
headers: {
"referrer": url,
"referrerPolicy": "strict-origin-when-cross-origin"
},
onload: data => {
resolve(data.response);
},
onerror: error => {
reject(error);
}
});
});
},
//用Promise封裝GM_xmlhttpRequest,返回經過文字編碼的document物件
xhrDoc: (url, details = {}) => {
if ("xhrOptions" in siteData) {
details = siteData.xhrOptions
}
return new Promise(resolve => {
_GM_xmlhttpRequest({
method: "GET",
url: url,
responseType: "arraybuffer",
headers: {
"Referer": _unsafeWindow.location.href,
"User-Agent": _unsafeWindow.navigator.userAgent
},
onload: data => {
let decoder = new TextDecoder(document.characterSet || document.charset || document.inputEncoding);
let htmlText = decoder.decode(data.response);
let dom = fn.doc(htmlText);
if (data.status >= 400) {
console.error(`\nfn.xhrDoc()連線錯誤碼:${data.status}\n`, url, data, dom);
let obj = {
fn: "fn.xhrDoc()",
url: url,
status: data.status
};
fetchErrorArray.push(obj);
}
resolve(dom);
},
onerror: error => {
console.error(`\nfn.xhrDoc()出錯:\n${decodeURIComponent(url)}`, error);
resolve(null);
},
...details
});
});
},
//用Fetc API,返回經過文字編碼的document物件
fetchDoc: (url, details = {}, retry = 40) => {
if ("xhrOptions" in siteData) {
details = siteData.xhrOptions
}
return new Promise(async resolve => {
fetch(url, {
...details
}).then(async res => {
if (res.status >= 400 && retry > 0) {
let resData = await fn.retryUrl(url, res, "fn.fetchDoc()", retry);
if (resData !== null) return resData;
}
return res.arrayBuffer();
}).then(buffer => {
const decoder = new TextDecoder(document.characterSet || document.charset || document.inputEncoding);
const htmlText = decoder.decode(buffer);
resolve(fn.doc(htmlText));
}).catch(error => {
console.error(`\nfn.fetchDoc()出錯:\n${decodeURIComponent(url)}`, error);
httpFetchError = true;
resolve(null);
});
});
},
getChapters: async (detail = {}) => {
let {
url,
urlIndex,
api,
mode,
node,
wait,
target,
textNode,
urlNode,
sort,
cb
} = detail;
let chapters = [];
let eles = [];
let dom = document;
if ("url" in detail || "api" in detail) {
if ("api" in detail) {
if (isString(api)) {
url = api
} else if (isFn(api)) {
url = await api();
}
} else {
if ("urlIndex" in detail) {
url = fn.gae(url)?.at(urlIndex)?.href;
} else {
if (isFn(url)) {
url = await url();
} else {
url = fn.gu(url);
}
}
}
if (!url) return [];
if (mode == "g") {
dom = await fn.xhrDoc(url);
} else if (mode == "f") {
dom = await fn.iframeDoc(url, target);
} else {
dom = await fn.fetchDoc(url);
}
}
if ("node" in detail) {
dom = fn.ge(node);
}
if ("wait" in detail) {
if (isString(wait)) {
await fn.waitEle(wait);
eles = fn.gae(target, dom, dom);
} else if (isArray(wait)) {
eles = await fn.waitEle(wait);
} else if (isFn(wait)) {
await wait();
eles = fn.gae(target, dom, dom);
}
} else {
eles = fn.gae(target, dom, dom);
}
chapters = eles.map(e => {
let text, url;
text = e.innerText;
if ("textNode" in detail) {
let node = fn.ge(textNode, e, dom);
if (node) {
text = node.innerText;
}
}
text = fn.dt({
t: text
});
if (e.tagName == "OPTION") {
url = e.value;
} else if ("urlNode" in detail) {
url = fn.ge(urlNode, e, dom).href;
} else if (e.tagName == "A") {
url = e.href;
}
if ("cb" in detail) {
return cb(text, url || e, e);
}
return {
text,
url
}
});
if (sort == "r") {
chapters = chapters.reverse();
}
return chapters;
},
//IMHentai網站用的取得圖片網址
getImhentaiSrc: async () => {
await fn.waitVar("g_th");
const server = id => {
if (id > 0 && id <= 274825) return "1";
if (id > 274825 && id <= 403818) return "2";
if (id > 403818 && id <= 527143) return "3";
if (id > 527143 && id <= 632481) return "4";
if (id > 632481 && id <= 816010) return "5";
if (id > 816010 && id <= 970098) return "6";
if (id > 970098 && id <= 1121113) return "7";
if (id > 1121113 && id <= 1259410) return "8";
if (id > 1259410 && id <= 1439024) return "9";
return "10";
};
const galleryId = fn.ge(".gview>#gallery_id,#load_id").value;
const imageDir = fn.ge("#image_dir,#load_dir").value;
const num = fn.ge("#pages,#load_pages").value;
const u_id = Number(fn.ge("#u_id,#load_dir+#gallery_id").value);
return fn.arr(num, (v, i) => `${location.protocol}//m${server(u_id)}.imhentai.xxx/${imageDir}/${galleryId}/${(i + 1)}.${fn.ex(_unsafeWindow.g_th[i + 1][0])}`);
},
manhuaguiJson: (dom = document) => {
let code = fn.gst("x6c", dom);
let data = fn.parseCode(code);
let s = data.indexOf("{");
let e = data.lastIndexOf("}") + 1;
data = data.slice(s, e);
return JSON.parse(data);
},
DM5_getSrcs: (dom, msg = 1) => {
if (msg == 1) fn.showMsg(DL.str_05, 0);
let code = fn.gst("DM5_IMAGE_COUNT", dom);
let imagesNum = fn.numVar(code, "DM5_IMAGE_COUNT");
let chapterURL = fn.textVar(code, "DM5_CURL");
let cid = fn.numVar(code, "DM5_CID");
let mid = fn.numVar(code, "DM5_MID");
let dt = fn.textVar(code, "DM5_VIEWSIGN_DT");
let sing = fn.textVar(code, "DM5_VIEWSIGN");
let keyE = fn.ge("#dm5_key", dom);
let key = keyE.value;
let fetchNum = 0;
let resArr = fn.arr(imagesNum, (v, i) => {
let searchParams = new URLSearchParams({
cid: cid,
page: i + 1,
key: key,
language: 1,
gtk: 6,
_cid: cid,
_mid: mid,
_dt: dt,
_sign: sing
});
let api = `${chapterURL}chapterfun.ashx?${searchParams}`;
return fetch(api).then(res => res.text()).then(text => {
if (msg == 1) fn.showMsg(`${DL.str_06}(${fetchNum+=1}/${imagesNum})`, 0);
return fn.run(text)[0];
});
});
return Promise.all(resArr).then(data => {
if (msg == 1) fn.hideMsg();
return data;
});
},
MXY_getSrcs: (dom, msg = 1) => {
if (msg == 1) fn.showMsg(DL.str_05, 0);
let code = fn.gst("_IMAGE_COUNT", dom);
let imagesNum = fn.numVar(code, "_IMAGE_COUNT");
let chapterURL = fn.textVar(code, "_CURL");
let cid = fn.numVar(code, "_CID");
let mid = fn.numVar(code, "_MID");
let dt = fn.textVar(code, "_VIEWSIGN_DT");
dt = encodeURIComponent(dt);
let sing = fn.textVar(code, "_VIEWSIGN");
let fetchNum = 0;
let resArr = fn.arr(imagesNum, (v, i) => {
let searchParams = new URLSearchParams({
cid: cid,
page: i + 1,
key: "",
_cid: cid,
_mid: mid,
_dt: dt,
_sign: sing
});
let api = `${chapterURL}chapterimage.ashx?${searchParams}`;
return fetch(api).then(res => res.text()).then(text => {
if (msg == 1) fn.showMsg(`${DL.str_06}(${fetchNum+=1}/${imagesNum})`, 0);
return fn.run(text)[0];
});
});
return Promise.all(resArr).then(data => {
if (msg == 1) fn.hideMsg();
return data;
});
},
mqzjw_decrypted_data: (data) => {
const {
CryptoJS,
} = _unsafeWindow;
const key = CryptoJS.enc.Utf8.parse("TRHvYbpGlNFoOdLaXrKRYgvdGwGfjnJj");
const iv = CryptoJS.enc.Utf8.parse("kBKXQIpFYTDOHGLQlRUklPLtNPcBKSve");
const decrypted = CryptoJS.AES.decrypt(data, key, {
iv,
mode: CryptoJS.mode.CBC
});
const pic_list = decrypted.toString(CryptoJS.enc.Utf8);
data = JSON.parse(pic_list);
return data;
},
getMqzjwSrc: async (url = fn.lp, msg = 1) => {
const {
Mcpath,
jQuery: $
} = _unsafeWindow;
const id = url.split("/").at(-1);
let page = 1;
const datas = [];
let loop = true;
let temp = "";
if (msg === 1) fn.showMsg(DL.str_05, 0);
while (loop) {
await $.getJSON("//" + Mcpath.url + Mcpath.web + "index.php/api/data/pic?callback=?", {
cid: id,
page: page
}, (res) => {
if (res.code == 1) {
if (temp != res.data) {
temp = res.data;
} else if (temp == res.data) {
loop = false;
return;
}
let data = fn.mqzjw_decrypted_data(res.data);
if (data.length > 0) {
if (msg === 1) fn.showMsg(`${DL.str_06}${page}/???`, 0);
datas.push(data);
page++;
} else {
loop = false;
}
} else {
loop = false;
}
});
}
return datas.flat().map(e => e.img);
},
//移除元素
remove: async (p, time = 0) => {
if (isString(p)) {
await delay(time);
let selector = p;
fn.gae(selector).forEach(e => {
if (!e?.id?.startsWith("FullPictureLoadIframe")) {
e.remove();
}
});
} else if (isArray(p)) {
let selectors = p;
await delay(time);
selectors.forEach(selector => fn.gae(selector).forEach(e => {
if (!e?.id?.startsWith("FullPictureLoadIframe")) {
e.remove();
}
}));
}
},
hideEle: p => {
let eles;
if (isEle(p)) {
eles = [p];
} else if (isString(p)) {
let selector = p;
eles = fn.gae(selector);
} else if (isArray(p)) {
let selectors = p;
eles = selectors.map(selector => fn.gae(selector));
eles = [...new Set(eles.flat())];
}
eles.forEach(e => e.setAttribute("style", "display: none !important;"));
},
//創建A元素
addUrlHtml: (url, selector, pos = 0, text = "點選進入下一話", css = 0) => {
let _pos;
switch (pos) {
case 0:
_pos = "beforebegin"; //在元素之前。
break;
case 1:
_pos = "afterend"; //在元素之後。
break;
case 2:
_pos = "beforeend"; //在元素裡面,最後一個子元素之後。
break;
case 3:
_pos = "afterbegin"; //在元素裡面,第一個子元素之前。
break;
}
let html = `<div class="addUrl" style="padding: 20px 0; text-align: center;"><a href="${url}"style="font-size: 26px;line-height: 50px;height: 50px;text-align: center;">${text}</a></div>`;
if (isEle(selector)) {
selector.insertAdjacentHTML(_pos, html);
} else if (isString(selector)) {
fn.ge(selector).insertAdjacentHTML(_pos, html);
} else {
return console.error("fn.addUrlHtml() 參數selector錯誤", selector);
}
switch (css) {
case 1:
fn.css(".addUrl>a{text-decoration:none;color:rgb(255 255 255);background-color:rgb(137 5 188);border:solid #bbb;border-radius:0.25rem;font-weight:700;padding:.5rem 2rem}", "addUrlHtml");
break;
case 2:
fn.css(".addUrl>a{text-decoration:none;color:rgb(50 50 50);background-color:rgb(200 200 200);border-radius:0.25rem;padding:.5rem 2rem}", "addUrlHtml");
break;
case 3:
fn.css(".addUrl>a{text-decoration:none;color:#6c757d;background-color:#fff;border:solid #6c757d;border-radius:0.25rem;padding:.5rem 2rem;transition:background-color .2s,color .2s;&:hover{color:#fff;background-color:#6c757d}}", "addUrlHtml");
break;
case 4:
fn.css(".addUrl>a{text-decoration:none;color:#003366;background-color:#fff;border:solid #6c757d;border-radius:0.25rem;padding:.5rem 2rem}", "addUrlHtml");
break;
case 5:
fn.css(".addUrl>a{text-decoration:none;color:rgb(255 255 255);background-color:rgb(77 147 255);border:solid #bbb;border-radius:0.25rem;font-weight:700;padding:.5rem 2rem}", "addUrlHtml");
break;
case 6:
fn.css(".addUrl>a{text-decoration:none;color:rgb(255 255 255);background-color:#b5d540;border:solid #b5d540;border-radius:0.25rem;font-weight:700;padding:.5rem 2rem}", "addUrlHtml");
break;
case 7:
fn.css(".addUrl>a{text-decoration:none;color:rgb(255 255 255);background-color:#65415f;border:solid #65415f;border-radius:0.25rem;font-weight:700;padding:.5rem 2rem}", "addUrlHtml");
break;
case 8:
fn.css(".addUrl>a{text-decoration:none;color:#ddd;background-color:#555;border-radius:0.25rem;padding:.5rem 2rem}", "addUrlHtml");
break;
case 9:
fn.css(".addUrl>a{text-decoration:none;color:#2f98f1;background-color:#2f2f3b;border:solid #c67605;border-radius:0.25rem;padding:.5rem 2rem}", "addUrlHtml");
break;
case 10:
fn.css(".addUrl>a{text-decoration:none;color:rgb(255 255 255);background: var(--success) url('../img/slice.jpg') repeat-x;background-size: contain;border:none;border-radius:0.25rem;padding:.5rem 2rem}", "addUrlHtml");
break;
}
},
dataURLtoBlobURL: dataurl => {
try {
if (dataurl.startsWith("data:image/svg+xml")) {
try {
dataurl = decodeURIComponent(dataurl);
} catch {}
let svg = dataurl.split(",")[1].replaceAll(""", '"').replaceAll('\\"', '"');
//console.log(svg);
return URL.createObjectURL(new Blob([svg], {
type: "image/svg+xml"
}));
}
let arr = dataurl.split(","),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return URL.createObjectURL(new Blob([u8arr], {
type: mime
}));
} catch (error) {
console.error(dataurl);
console.error(error);
return dataurl;
}
},
blobURLtoDataURL: bloburl => fetch(bloburl).then(res => res.blob()).then(blob => fn.blobToDataURL(blob)),
imgSrcToDataURL: (src, type = "image/jpeg", cros = 0) => {
return new Promise((resolve, reject) => {
const img = new Image();
if (cros == 1) {
img.setAttribute("crossOrigin", "");
}
img.onload = () => {
let canvas = document.createElement("canvas");
canvas.height = img.naturalWidth;
canvas.width = img.naturalHeight;
canvas.getContext("2d").drawImage(img, 0, 0);
URL.revokeObjectURL(img.src);
let dataURL = canvas.toDataURL(type);
resolve(dataURL);
};
img.onerror = error => {
reject(error);
}
img.src = src;
});
},
imgSrcToBlobURL: (src, type = "image/jpeg", cros = 0) => {
return new Promise((resolve, reject) => {
const img = new Image();
if (cros == 1) {
img.setAttribute("crossOrigin", "");
}
img.onload = () => {
const canvas = new OffscreenCanvas(img.naturalWidth, img.naturalHeight);
canvas.getContext("2d").drawImage(img, 0, 0);
URL.revokeObjectURL(img.src);
canvas.convertToBlob({
type: type,
quality: 1
}).then(blob => {
let blobURL = URL.createObjectURL(blob);
resolve(blobURL);
});
};
img.onerror = error => {
reject(error);
}
img.src = src;
});
},
imgToBlobURL: (img, type = "image/jpeg", quality = 1) => {
const canvas = new OffscreenCanvas(img.naturalWidth, img.naturalHeight);
canvas.getContext("2d").drawImage(img, 0, 0);
return canvas.convertToBlob({
type: type,
quality: quality
}).then(blob => URL.createObjectURL(blob));
},
imgBlobUrlArr: async (selector, type = "image/jpeg", quality = 0.9) => {
fn.showMsg(DL.str_53, 0);
await delay(200);
let num = 0;
let imgs = await fn.gae(selector).map(async (img, index, arr) => {
let blobUrl = await fn.imgToBlobURL(img, type, quality);
fn.showMsg(`DrawImage ${num += 1}/${arr.length}`, 0);
return blobUrl;
});
fn.hideMsg();
return imgs;
},
blobToDataURL: blob => {
return new Promise(resolve => {
const reader = new FileReader();
reader.onload = () => {
resolve(reader.result);
};
reader.readAsDataURL(blob);
});
},
convertImage: async (blob, type = "image/jpeg", quality = 0.9) => {
const img = new Image();
await new Promise((resolve, reject) => {
img.onload = resolve;
img.onerror = reject;
img.src = URL.createObjectURL(blob);
});
const canvas = new OffscreenCanvas(img.naturalWidth, img.naturalHeight);
canvas.getContext("2d").drawImage(img, 0, 0);
URL.revokeObjectURL(img.src);
return canvas.convertToBlob({
type: type,
quality: quality
});
},
//自動滾動元素
scrollEles: async (ele, time = 100, top = 1) => {
if (isAutoScrolling) return;
isAutoScrolling = true;
let eles = fn.gae(ele);
for (let e of eles) {
if (isEsc) {
isAutoScrolling = false;
_unsafeWindow.scrollTo({
top: 0
});
return;
}
e.scrollIntoView({
behavior: "smooth",
block: "end"
});
await delay(time);
}
if (top === 1) {
_unsafeWindow.scrollTo({
top: 0
});
}
isAutoScrolling = false;
},
//自動滾動元素
aotoScrollEles: async (obj = {}) => {
if (isAutoScrolling) return;
isAutoScrolling = true;
let {
ele: selector,
cb: callback,
time,
top,
end: end_selector,
end_time,
block
} = obj;
let isEnd = false;
if (isString(end_selector)) {
let time_id;
let endE = fn.ge(end_selector);
if (isEle(endE)) {
let observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
time_id = setTimeout(() => {
isEnd = true;
observer.unobserve(endE);
observer = null;
}, end_time || 2000);
} else {
isEnd = false;
if (isNumber(time_id)) {
clearTimeout(time_id);
}
}
});
}, {
threshold: 1,
});
observer.observe(endE);
}
}
let sn = 0;
let timeout = false;
let imgs = fn.gae(selector);
let imgNum = imgs.length;
const autoScrollIntoView = async (arr, num) => {
for (let i = 0; i < arr.length; i++) {
if (isEsc) {
fn.hideMsg();
isAutoScrolling = false;
_unsafeWindow.scrollTo({
top: 0
});
return;
}
fn.showMsg(`AutoScroll ${sn += 1}/${num}`, 0);
await new Promise(resolve => {
let timeId = setTimeout(() => {
timeout = true;
clearInterval(loop);
resolve();
}, time || 5000);
let loop = setInterval(async () => {
if (isEsc) {
clearTimeout(timeId);
clearInterval(loop);
fn.hideMsg();
isAutoScrolling = false;
_unsafeWindow.scrollTo({
top: 0
});
resolve();
return;
}
arr[i].scrollIntoView({
block: (block ?? "start")
});
if (isFn(end_selector)) {
isEnd = end_selector(sn);
}
if (isEnd || await callback(arr[i])) {
clearTimeout(timeId);
clearInterval(loop);
resolve();
}
}, 50);
});
if (timeout) break;
}
fn.hideMsg();
if (timeout) fn.showMsg("Timeout");
let newImgs = fn.gae(selector);
let newImgNum = newImgs.length;
if (imgNum < newImgNum) {
newImgs = newImgs.slice(imgNum);
imgNum = newImgNum;
await autoScrollIntoView(newImgs, newImgNum);
}
};
await autoScrollIntoView(imgs, imgNum);
if (top === 1) {
_unsafeWindow.scrollTo({
top: 0
});
}
if (isString(top)) {
fn.ge(top)?.scrollTo({
top: 0
});
}
isAutoScrolling = false;
},
openInTab: (url, target = "_blank") => {
let a = document.createElement("a");
a.href = url;
a.target = target;
a.style = "display: none;";
document.body.append(a);
a.click();
a.remove();
},
addMutationObserver: (callback, node = document.body, config = MutationObserverConfig) => {
callback();
new MutationObserver(callback).observe(node, config);
},
scrollEvent: slideIndex => {
if (!isNumber(slideIndex)) return;
let modeName = "Samll";
switch (viewMode) {
case 0:
modeName = "Original";
break;
case 1:
modeName = "Samll";
break;
default:
console.error("模式错误");
break;
}
debug(`\nfn.scrollEvent() > imgLocation${modeName}_` + slideIndex);
let elementById = document.getElementById(`imgLocation${modeName}_` + slideIndex);
let [sa, sb, sc] = [
".FullPictureLoadImage",
"#FullPictureLoadImgBox:not([style*=none]) .FullPictureLoadImage.small",
".FullPictureLoadImage:not(.small)"
];
if (!!elementById) {
elementById.scrollIntoView();
} else if (fn.ge(".swiper-slide.swiper-slide-active") && fn.ge(sa)) {
smoothScrollIntoView(fn.gae(sa)[slideIndex]);
} else if (fn.ge(sb)) {
smoothScrollIntoView(fn.gae(sb)[slideIndex]);
} else if (fn.ge(sc)) {
smoothScrollIntoView(fn.gae(sc)[slideIndex]);
} else {
console.error(" # ", "未定位id!");
}
},
//清除定時器
clearAllTimer: (mode = 0) => {
if (mode == 0 || mode == 1) {
let debuggerStr = `
if ((() => {}).constructor === Function) {
Function.prototype.constructor = () => {};
}
`;
_GM_addElement(document.body, "script", {
textContent: debuggerStr
})?.remove();
}
if (mode == 0 || mode == 2) {
let endTidStr = `
let endTid = setTimeout(() => {});
for (let i = 0; i <= endTid; i++) {
clearTimeout(i);
}
`;
_GM_addElement(document.body, "script", {
textContent: endTidStr
})?.remove();
let endTid = setTimeout(() => {});
for (let i = 0; i <= endTid; i++) {
clearTimeout(i);
}
}
if (mode == 0 || mode == 3) {
let endIidStr = `
let endIid = setInterval(() => {});
for (let i = 0; i <= endIid; i++) {
clearInterval(i);
}
`;
_GM_addElement(document.body, "script", {
textContent: endIidStr
})?.remove();
let endIid = setInterval(() => {});
for (let i = 0; i <= endIid; i++) {
clearInterval(i);
}
}
},
//清除定時器
clearSetTimeout: () => {
let endTid = setTimeout(() => {});
for (let i = 0; i <= endTid; i++) {
clearTimeout(i);
}
},
//清除元素事件
clearElementEvent: () => {
return fn.fetchDoc(document.URL).then(dom => {
let newDocumentElement = document.importNode(dom.documentElement, true);
let oldDocumentElement = document.documentElement;
document.replaceChild(newDocumentElement, oldDocumentElement);
debug("網站元素事件已清除");
});
},
//創建IMG元素陣列
createImgArray: (srcs) => {
return srcs.map((src, i) => {
let img = new Image();
img.className = "FullPictureLoadImage lazyload";
img.src = loading_bak;
img.dataset.src = src;
return img;
});
},
//傳入選擇器參數為頁面圖片添加Fancybox5功能
setFancybox: (selector) => {
if (!isOpenFilter) fn.showMsg(DL.str_137);
const loadSrcs = (srcArr) => {
const oddNumberSrcs = srcArr.filter((img, index) => index % 2 == 0);
const evenNumberSrcs = srcArr.filter((img, index) => index % 2 != 0);
fn.singleThreadLoadSrcs(oddNumberSrcs);
fn.singleThreadLoadSrcs(evenNumberSrcs);
};
fn.gae(selector).forEach(e => {
let check = fn.checkImgSrc(e);
if (e.nodeName === "IMG") {
let pE = e.parentNode;
if (pE.nodeName === "A") {
let src = check.ok ? check.src : e.src;
pE.dataset.fancybox = "gallery";
pE.href = src;
pE.dataset.thumb = src;
pE.removeAttribute("title");
} else {
let a = document.createElement("a");
let src = check.ok ? check.src : e.src;
a.href = src;
a.dataset.fancybox = "gallery";
a.dataset.thumb = src;
insertBefore(e, a);
a.append(e);
}
} else if (e.nodeName === "A") {
let img = e.querySelector("img");
let check = fn.checkImgSrc(img);
let src = check.ok ? check.src : img.src;
e.dataset.fancybox = "gallery";
e.dataset.thumb = src;
}
});
let srcs = fn.getImgSrcArr(selector);
loadSrcs(srcs);
if (siteData.fancybox?.v === 3) {
return;
}
let gallery = fn.gae("[data-fancybox]");
let FancyboxOptions;
if (isM) {
FancyboxOptions = {
Hash: false,
idle: false,
showClass: false,
hideClass: false,
Images: {
Panzoom: {
maxScale: 4
},
zoom: false,
},
Slideshow: {
timeout: FancyboxSlideshowTimeoutNum,
},
Carousel: {
transition: FancyboxSlideshowTransition
},
Thumbs: {
showOnStart: false
},
Toolbar: {
display: {
left: ["infobar"],
middle: ["flipX", "flipY"],
right: ["iterateZoom", "slideshow", "thumbs", "close"]
}
},
on: {
done: (fancybox, slide) => {
isOpenFancybox = true;
if (fancybox.isCurrentSlide(slide)) {
smoothScrollIntoView(gallery[slide.index]);
} else {
smoothScrollIntoView(gallery[fancybox.getSlide().index]);
}
if (fancybox.carousel.page == 0 && (fancybox.carousel.prevPage == fancybox.carousel.pages.at(-1).index)) {
if (FancyboxAutoClose == 1) {
fancybox.close();
}
if (FancyboxAutoNext == 1) {
if (!!nextLink) {
fn.showMsg(DL.str_34.n);
setTimeout(() => (location.href = nextLink), 100);
}
}
}
},
close: () => {
setTimeout(() => {
isOpenFancybox = false;
}, 100);
}
}
};
} else {
FancyboxOptions = {
Hash: false,
idle: false,
showClass: false,
hideClass: false,
wheel: FancyboxWheel,
Images: {
Panzoom: {
maxScale: 4
},
zoom: false
},
Slideshow: {
timeout: FancyboxSlideshowTimeoutNum,
},
Carousel: {
transition: FancyboxSlideshowTransition
},
Thumbs: {
showOnStart: false
},
Toolbar: {
display: {
left: ["infobar"],
middle: ["zoomIn", "zoomOut", "iterateZoom", "toggle1to1", "rotateCCW", "rotateCW", "flipX", "flipY", "fitX", "fitY", "reset"],
right: ["slideshow", "fullscreen", "thumbs", "close"]
}
},
on: {
done: (fancybox, slide) => {
isOpenFancybox = true;
if (fancybox.isCurrentSlide(slide)) {
smoothScrollIntoView(gallery[slide.index]);
} else {
smoothScrollIntoView(gallery[fancybox.getSlide().index]);
}
if (fancybox.carousel.page == 0 && (fancybox.carousel.prevPage == fancybox.carousel.pages.at(-1).index)) {
if (FancyboxAutoClose == 1) {
fancybox.close();
}
if (FancyboxAutoNext == 1) {
if (!!nextLink) {
fn.showMsg(DL.str_34.n);
setTimeout(() => (location.href = nextLink), 100);
}
}
}
},
close: () => {
setTimeout(() => {
isOpenFancybox = false;
}, 100);
}
}
};
}
_unsafeWindow.Fancybox.bind("[data-fancybox]", FancyboxOptions);
},
lazyload: async () => {
let check = !!fn.ge("img.FullPictureLoadImage.lazyload");
if (check) {
let lazyload = siteData?.autoPager?.lazyload;
let imgs = fn.gae("img.FullPictureLoadImage.lazyload");
if (lazyload != 0) {
let oddNumberImgs = imgs.filter((img, index) => index % 2 == 0);
let evenNumberImgs = imgs.filter((img, index) => index % 2 != 0);
fn.singleThreadLoadImgs(oddNumberImgs);
fn.singleThreadLoadImgs(evenNumberImgs);
await delay(1000);
imgs.forEach(img => fn.imagesObserver.observe(img));
} else {
await delay(1000);
imgs.forEach((img, i) => {
setTimeout(() => {
img.src = img.dataset.src;
img.classList.remove("lazyload");
fn.imagesObserver.observe(img);
}, i * 200);
});
}
}
},
setStyleSheet: () => {
for (const sheet of document.styleSheets) {
if (sheet.href) {
for (const rule of sheet.rules) {
if (rule.selectorText === "textarea") {
//rule.style.removeProperty("height");
rule.style.setProperty("height", "auto");
return;
}
}
}
}
},
copymangaUI: () => {
let lastScrollTop = 0;
document.addEventListener("scroll", event => {
let st = event.srcElement.scrollingElement.scrollTop;
if (st > lastScrollTop) {
fn.ge("h4.header").setAttribute("style", "top: -30px;");
fn.ge("div.footer").setAttribute("style", "bottom: -41px;");
lastScrollTop = st;
} else if (st < lastScrollTop - 20) {
fn.ge("h4.header").removeAttribute("style");
fn.ge("div.footer").removeAttribute("style");
lastScrollTop = st;
}
});
fn.run("$(document).off()");
},
copymanga_M_UI: (c, h) => {
let s = fn.curl().split("/").slice(-2);
let url = `https://${fn.lh}/h5/details/comic/${s[0]}`;
let html = `
<div class="comicControlBottom van-popup van-popup--bottom hide" style="z-index: 2024;">
<div class="comicControlBottomBottom">
<a href="${c}" style="color: white;">
<span class="comicControlBottomBottomItem">
<span class="comicControlBottomBottomItemIcon iconfont iconRead_btn_nor_Catalog"></span>
<span class="comicControlBottomBottomItemText">目錄</span>
</span>
</a>
<a href="${h}" style="color: white;">
<span class="comicControlBottomBottomItem">
<span class="comicControlBottomBottomItemIcon iconfont iconRead_btn_nor_home"></span>
<span class="comicControlBottomBottomItemText">首頁</span>
</span>
</a>
</div>
</div>
`;
document.querySelector(".comicContentPopup").insertAdjacentHTML("beforeend", html);
document.addEventListener("click", (e) => {
if (e.target.nodeName === "IMG") {
let b = fn.ge(".comicControlBottom");
if (b.classList.contains("hide")) {
b.classList.remove("hide");
} else {
b.classList.add("hide");
}
}
});
},
MyComicUI: () => {
let lastScrollTop = 0;
document.addEventListener("scroll", event => {
let st = event.srcElement.scrollingElement.scrollTop;
if (st > lastScrollTop) {
fn.ge("header[data-flux-header]").style.display = "none";
fn.ge("div:has(>div>div>div>button[x-ref])").style.display = "none";
lastScrollTop = st;
} else if (st < lastScrollTop - 20) {
fn.ge("header[data-flux-header]").style.display = "";
fn.ge("div:has(>div>div>div>button[x-ref])").style.display = "";
lastScrollTop = st;
}
});
},
MangabzUI: () => {
let lastScrollTop = 0;
document.addEventListener("scroll", event => {
let st = event.srcElement.scrollingElement.scrollTop;
if (st > lastScrollTop) {
fn.ge(".top-bar").setAttribute("style", "top: -74px;");
lastScrollTop = st;
} else if (st < lastScrollTop - 20) {
fn.ge(".top-bar").removeAttribute("style");
lastScrollTop = st;
}
});
},
XmanhuaUI: () => {
const clickToggleToolbar = () => {
if (isOpenGallery) return;
let ht = fn.ge(".header.toolbar");
let h = fn.ge(".header");
if (ht) {
h.classList.remove("toolbar");
h.removeAttribute("style");
} else {
h.classList.add("toolbar");
h.setAttribute("style", "top: -64px;")
}
let bt = fn.ge(".reader-bottom.toolbar");
let b = fn.ge(".reader-bottom");
if (bt) {
b.classList.remove("toolbar");
b.removeAttribute("style");
} else {
b.classList.add("toolbar");
b.setAttribute("style", "bottom: -50px;");
}
};
document.addEventListener("click", clickToggleToolbar);
let lastScrollTop = 0;
document.addEventListener("scroll", event => {
let st = event.srcElement.scrollingElement.scrollTop;
if (st > lastScrollTop) {
fn.ge(".header").classList.add("toolbar");
fn.ge(".header").setAttribute("style", "top: -64px;");
fn.ge(".reader-bottom").classList.add("toolbar");
fn.ge(".reader-bottom").setAttribute("style", "bottom: -50px;");
lastScrollTop = st;
} else if (st < lastScrollTop - 20) {
fn.ge(".header").classList.remove("toolbar");
fn.ge(".header").removeAttribute("style");
fn.ge(".reader-bottom").classList.remove("toolbar");
fn.ge(".reader-bottom").removeAttribute("style");
lastScrollTop = st;
}
});
},
cartoonmadUI: () => {
fn.run("document.onkeydown=null");
fn.remove("//td[div[@id='sidebar-follow']] | //td[ins[@class='adsbygoogle']] | //tr[td[script]] | //select");
let ele = fn.ge("//tr[td[@bgcolor='#EAEAEA']]");
if (ele) ele.parentNode.append(ele.cloneNode(true));
let eleM = fn.ge("//tr[td[table[@bgcolor='#CCCCCC']]]");
if (eleM) {
let x = eleM.parentNode.lastElementChild.previousElementSibling;
insertBefore(x, eleM.cloneNode(true));
}
},
copymanga_decrypt_A: async (raw, key) => {
// 解密方法來自https://greasyfork.org/scripts/397848
const encoder = new TextEncoder();
const decoder = new TextDecoder();
const dioKey = encoder.encode(key);
const header = raw.substring(0, 16);
const body = raw.substring(16);
const iv = encoder.encode(header);
const bodyBytes = new Uint8Array(body.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
const cryptoKey = await _unsafeWindow.crypto.subtle.importKey("raw", dioKey, {
name: "AES-CBC"
}, false, ["decrypt"]);
const decryptedBytes = await _unsafeWindow.crypto.subtle.decrypt({
name: "AES-CBC",
iv
}, cryptoKey, bodyBytes);
return JSON.parse(await decoder.decode(decryptedBytes));
},
copymanga_decrypt_B: (raw, key) => {
const CryptoJS = addCryptoJSLibrary();
// 解密方法來自https://greasyfork.org/scripts/421371
const header = raw.substring(0, 16);
const body = raw.substring(16);
const iv = CryptoJS.enc.Utf8.parse(header);
const string = CryptoJS.AES.decrypt(
CryptoJS.enc.Base64.stringify(CryptoJS.enc.Hex.parse(body)),
CryptoJS.enc.Utf8.parse(key), {
iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}
).toString(CryptoJS.enc.Utf8);
return JSON.parse(string);
}
};
const xhrLoadImagesFormat = async (srcs) => {
isXhrHeadRequest = true;
const loaded = [];
let num = 0;
fn.showMsg("fn.xhrHEA(check)...", 0);
return new Promise(resolve => {
const xhrLoadImageFormat = async (src, i) => {
if (await fn.xhrHEAD(src).then(res => res.status) == 200) {
src = src;
} else {
let jpg = src.replace(/\.\w+$/, ".jpg");
let png = src.replace(/\.\w+$/, ".png");
let jpeg = src.replace(/\.\w+$/, ".jpeg");
if (await fn.xhrHEAD(jpg).then(res => res.status) == 200) {
src = jpg;
} else if (await fn.xhrHEAD(png).then(res => res.status) == 200) {
src = png;
} else if (await fn.xhrHEAD(jpeg).then(res => res.status) == 200) {
src = jpeg;
}
}
loaded[i] = src;
num += 1;
fn.showMsg(`fn.xhrHEAD(${num}/${srcs.length})`, 0);
if (num == srcs.length) {
isXhrHeadRequest = false;
resolve(loaded);
}
};
const loadList = srcs.map((src, i) => [xhrLoadImageFormat, null, src, i]);
const queue = new Queue(2);
queue.addList(loadList);
queue.run();
});
};
function simpleLoadImg(img) {
return new Promise((resolve) => {
if (!img) {
resolve();
}
let loadSrc = img.dataset.src;
const temp = new Image();
if ("referrerpolicy" in siteData) {
temp.setAttribute("referrerpolicy", siteData.referrerpolicy);
}
temp.onload = () => {
img.dataset.width = temp.naturalWidth;
img.dataset.height = temp.naturalHeight;
img.classList.add("loaded");
img.src = loadSrc;
resolve();
};
temp.onerror = async () => {
if (loadSrc.includes("https://wsrv.nl/")) {
loadSrc = loadSrc.replace("https://wsrv.nl/?url=", ""); //wsrv.nl_CDN
} else if (loadSrc.includes(".wp.com/") && !document.title.endsWith("4KHD")) {
loadSrc = loadSrc.replace(/i\d\.wp\.com\/|\?.+$/g, ""); //WordPressCDN
}
let check = await fn.delay(3000, 0).then(() => fn.checkImgStatus(loadSrc, 0));
if (check.ok) {
img.dataset.width = check.width;
img.dataset.height = check.height;
img.classList.add("loaded");
img.dataset.src = loadSrc;
img.src = loadSrc;
resolve();
} else {
img.classList.add("loaded");
img.classList.add("error");
img.dataset.src = loadSrc;
img.src = loadSrc;
resolve();
}
};
temp.src = loadSrc;
});
}
//用JS实现多个任务并行执行的队列
//https://juejin.cn/post/6844903961728647181
class Queue {
constructor(workerLen) {
this.workerLen = workerLen ?? 4;
this.list = [];
this.worker = new Array(this.workerLen);
}
* executionFunc(index, func, ...args) {
const _this = this;
yield func.call(...args).then(() => {
_this.worker[index] = undefined;
_this.run();
});
}
addList(list) {
for (const item of list) {
this.list.unshift(item);
}
}
run() {
if (isXhrHeadRequest || isOpenGallery || isOpenFilter) {
const runIndex = [];
for (let i = 0; i < this.workerLen; i++) {
const len = this.list.length;
if (!this.worker[i] && len > 0) {
this.worker[i] = this.executionFunc(i, ...this.list[len - 1]);
runIndex.push(i);
this.list.pop();
}
}
for (const index of runIndex) {
this.worker[index].next();
}
}
}
}
//CSS取得元素返回元素
//const ge = (selector) => document.querySelector(selector);
function ge(selector, node = null) {
return (node || document).querySelector(selector);
}
//延遲
function delay(time = 1000) {
return new Promise(resolve => setTimeout(resolve, time));
}
//等待直至回調函式返回有效物件
function wait(callback) {
return new Promise(ending => {
const loopFn = async () => {
const check = await callback();
if (!!check) {
ending();
return;
} else {
await delay(100);
return loopFn();
}
};
loopFn();
});
}
//CSS取得所有元素返回元素陣列
const gae = (selector, node = null) => [...(node || document).querySelectorAll(selector)];
//Xpath取得元素返回元素
const gx = (xpath) => document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
//Xpath取得所有元素返回元素陣列
const gax = (xpath) => {
let nodes = [];
let results = document.evaluate(xpath, document, null, XPathResult.ANY_TYPE, null);
let node;
while (node = results.iterateNext()) {
nodes.push(node);
}
return nodes;
};
//元素插入在節點之前
const insertBefore = (targetNode, newNode) => {
if ([targetNode, newNode].every(e => isEle(e))) {
targetNode.parentNode.insertBefore(newNode, targetNode);
} else {
console.error("insertBefore參數錯誤\n", targetNode, getType(targetNode), newNode, getType(newNode));
}
};
//元素插入在節點之後
const insertAfter = (targetNode, newNode) => {
if ([targetNode, newNode].every(e => isEle(e))) {
targetNode.parentNode.insertBefore(newNode, targetNode.nextSibling);
} else {
console.error("insertAfter參數錯誤\n", targetNode, getType(targetNode), newNode, getType(newNode));
}
};
//創建Style
const createStyle = css => {
const style = document.createElement("style");
style.type = "text/css";
style.innerHTML = css;
return style;
};
//平滑滾動至元素位置
function smoothScrollIntoView(element) {
element.scrollIntoView(smoothOptions);
}
//立即滾動至元素位置
function instantScrollIntoView(element) {
element.scrollIntoView(instantOptions);
}
//數字字串補0
const getNum = (i, pad = 4) => String(i + 1).padStart(pad, "0");
const getDataMsg = (text, picNum, imgsNum) => {
if (isStopDownload) return;
if (picNum != "none") fn.showMsg(`${DL.str_23}${downloadNum += 1}/${imgsNum}${DL.str_24}${text}`, 0);
};
//取得參照頁
const getReferer = (srcUrl) => {
let referer;
if (isString(siteData.referer) && siteData.referer == "url") {
referer = document.URL;
} else if (/vipr\.im|imagetwist\.com|imgspice\.com/.test(srcUrl) || siteData.referer == "src") {
referer = srcUrl;
} else if (/\.sinaimg\./.test(srcUrl)) {
referer = "https://weibo.com/";
} else if (/imgtaxi\.com/.test(srcUrl)) {
referer = "https://imgtaxi.com/";
} else if (/saint2\.su/.test(srcUrl)) {
referer = "https://saint2.su/";
} else if (/bunkr/.test(srcUrl)) {
referer = "https://bunkr.fi/";
} else if (/mitaku\.net/.test(srcUrl)) {
referer = "https://mitaku.net/";
} else if (isString(siteData.referer) || siteData.referer == "") {
referer = siteData.referer;
} else {
referer = fn.lo + "/";
}
return referer;
};
let v2ph_cookie = _GM_getValue("v2ph_cookie", "");
let myreadingmanga_cookie = _GM_getValue("myreadingmanga_cookie", "");
//取得cookie
const getCookie = () => {
if (fn.lh.includes(".v2ph.")) {
return v2ph_cookie;
} else if (fn.lh.includes("myreadingmanga")) {
return myreadingmanga_cookie;
} else if ("_cf_cookie" in localStorage) {
return localStorage.getItem("_cf_cookie");
}
return "";
};
//Fetch API下載圖片
const Fetch_API_Download = (srcUrl, picNum = "none", imgsNum = "none") => {
currentDownloadThread++;
return new Promise(resolve => {
fetch(srcUrl, {
headers: {
"Accept": "*/*",
//"accept": "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8",
//"cache-control": "no-cache",
//"Upgrade-Insecure-Requests": "1"
},
referrer: getReferer(srcUrl),
referrerPolicy: "strict-origin-when-cross-origin",
/***同域請求攜帶cookie***/
//credentials: "same-origin"
}).then(async res => {
return {
data: res,
blob: await res.blob()
}
}).then(obj => {
currentDownloadThread--;
if (isStopDownload) {
resolve("stop");
return;
}
if (obj.blob.type == "text/html") {
getDataMsg(DL.str_26, picNum, imgsNum);
resolve({
htmlText: obj.blob.text(),
blob: obj.blob,
data: obj.data,
error: "下載錯誤",
picNum: picNum,
src: srcUrl,
finalUrl: obj.data?.url,
get: "Fetch API"
});
} else if (obj.blob.size < 100) {
getDataMsg(DL.str_26, picNum, imgsNum);
resolve({
error: "下載錯誤",
data: obj.data,
picNum: picNum,
src: srcUrl,
get: "Fetch API"
});
} else {
getDataMsg(DL.str_25, picNum, imgsNum);
resolve({
load: "下載成功",
blob: obj.blob,
picNum: picNum,
src: srcUrl,
finalUrl: obj.data?.url,
get: "Fetch API"
});
}
}).catch(error => {
currentDownloadThread--;
getDataMsg(DL.str_26, picNum, imgsNum);
resolve({
error: "下載錯誤",
picNum: picNum,
src: srcUrl,
errorLog: error,
get: "Fetch API"
});
console.error("Fetch_API_Download() Error: ", error);
});
})
};
//GM_xmlhttpRequest下載圖片
const GM_XHR_Download = (srcUrl, picNum = "none", imgsNum = "none") => {
currentDownloadThread++;
return new Promise(resolve => {
_GM_xmlhttpRequest({
method: "GET",
url: srcUrl,
responseType: "blob",
headers: {
"Origin": fn.lo,
"Referer": getReferer(srcUrl),
"User-Agent": navigator.userAgent,
"Accept": "*/*",
//"Upgrade-Insecure-Requests": "1"
},
cookie: getCookie(),
onload: async data => {
currentDownloadThread--;
if (isStopDownload) {
resolve("stop");
return;
}
let blob = data.response;
//debug("GM blob", blob);
//XBrowser Blob的type是""
if (/\/octet-stream/.test(blob.type) && blob.size > 1024 || isM && blob.type == "" && blob.size > 1024) {
resolve({
load: "下載成功",
blob: blob,
picNum: picNum,
src: srcUrl,
finalUrl: data.finalUrl,
get: "GM_xmlhttpRequest"
});
getDataMsg(DL.str_25, picNum, imgsNum);
} else if (/^image|^video|text\/base64\.jpg/.test(blob.type)) {
resolve({
load: "下載成功",
blob: blob,
picNum: picNum,
src: srcUrl,
finalUrl: data.finalUrl,
get: "GM_xmlhttpRequest"
});
getDataMsg(DL.str_25, picNum, imgsNum);
} else {
let htmlText = "none";
if (/text\/html/.test(blob.type)) {
htmlText = blob.text();
}
resolve({
htmlText: htmlText,
blob: blob,
error: "下載錯誤",
picNum: picNum,
src: srcUrl,
finalUrl: data.finalUrl,
data: data,
get: "GM_xmlhttpRequest"
});
getDataMsg(DL.str_26, picNum, imgsNum);
}
},
onerror: error => {
currentDownloadThread--;
resolve({
error: "下載錯誤",
picNum: picNum,
src: srcUrl,
errorLog: error,
get: "GM_xmlhttpRequest"
});
getDataMsg(DL.str_26, picNum, imgsNum);
console.error("GM_XHR_Download() Error: ", error);
}
});
});
};
//下載儲存
const saveData = (blob, fileName) => {
let objURL = URL.createObjectURL(blob);
let a = document.createElement("a");
a.href = objURL;
a.download = fileName;
EClick(a);
//document.body.append(a);
//a.click();
//a.remove();
setTimeout(() => URL.revokeObjectURL(objURL), 4000);
};
const captureExclude = () => (isChangeNum || isOpenOptionsUI || isOpenGallery || isOpenFancybox || isOpenFilter || isFetching || isDownloading);
const checkGeting = () => {
if (isDownloading) {
alert(DL.str_48);
return true;
}
if (isFetching) {
alert(DL.str_49);
return true;
}
return false;
};
//取得圖片主函式
const getImgs = async selector => {
isFetching = true;
let imgs = null;
if (!("SPA" in siteData) && siteData.repeat != 1 && siteData.infiniteCapture != 1 && globalImgArray.length > 0) {
isFetching = false;
imgs = globalImgArray;
return imgs;
} else if (lastValidPageURL === currentURL && siteData.repeat != 1 && siteData.infiniteCapture != 1 && globalImgArray.length > 0) {
isFetching = false;
imgs = globalImgArray;
return imgs;
} else if (ge(".FullPictureLoadImage,.FullPictureLoadVideo") && siteData.repeat != 1) {
imgs = gae(".FullPictureLoadImage:not(.small)");
} else if (isFn(selector)) {
imgs = await selector();
if (isSet(imgs)) {
imgs = [...imgs];
}
if (getImgFnProcessRecord == "" && !getImgFnProcessRecord.includes("專用Fn")) {
getImgFnProcessRecord += " > " + siteData.name + "專用Fn";
}
} else if (isSet(selector)) {
imgs = [...selector];
} else if (!selector || selector === "") {
fn.showMsg(DL.str_41);
return;
} else if (selector.length < 3) {
fn.showMsg(DL.str_42);
return;
} else if ("srcset" in siteData && isString(siteData.srcset)) {
imgs = fn.getImgSrcset(selector);
if (!getImgFnProcessRecord.includes("fn.getImgSrcset(selector)")) {
getImgFnProcessRecord += " > fn.getImgSrcset(selector)";
}
} else if (/^\//.test(selector)) {
imgs = gax(selector);
if (!getImgFnProcessRecord.includes("gax(selector)")) {
getImgFnProcessRecord += " > gax(selector)";
}
} else {
imgs = gae(selector);
if (!getImgFnProcessRecord.includes("gae(selector)")) {
getImgFnProcessRecord += " > gae(selector)";
}
}
if (!isArray(imgs)) {
isFetching = false;
alert("getImgs() Error! ImageList Not Array");
return [];
}
if (isPromise(imgs[0])) {
imgs = await Promise.all(imgs); //取出new Promise的值
}
fn.hideMsg();
if (!isValidPage) return [];
imgs = imgs.flat().filter(Boolean); //去除空、無用
let imgsSrcArr = imgs.map(img => {
let check = fn.checkImgSrc(img);
if (check.ok) {
return check.src;
} else {
console.error("\ngetImgs() imgs 格式錯誤!", img);
return null;
}
}).filter(Boolean);
if (globalImgArray.length === 0 && imgs.length !== 0) {
debug(`\ngetImgs()${getImgFnProcessRecord} 所有圖片網址:`, imgsSrcArr);
debug(`\ngetImgs()${getImgFnProcessRecord} 去重複後的圖片網址:`, [...new Set(imgsSrcArr)]);
}
imgsSrcArr = [...new Set(imgsSrcArr)];
let cdn = Number(_GM_getValue("wp_image_cdn", -1));
if (cdn > -1) {
imgsSrcArr = imgsSrcArr.map(e => {
if (e.includes("?") || e.includes("wp.com/") || e.startsWith("data") || e.startsWith("blob")) {
return e;
} else {
let _old = new URL(e).host;
let _new = `i${cdn}.wp.com/` + _old;
e = e.replace(_old, _new).replace("http:", "https:") + "?ssl=1";
return e;
}
});
}
globalImgArray = imgsSrcArr;
let thums = siteData.thums;
if (isString(thums)) {
thumbnailSrcArray = fn.getImgSrcArr(thums);
}
let videos = siteData.videos;
if (isString(videos)) {
videoSrcArray = fn.gae(videos).map(e => e.src);
} else if (isFn(videos)) {
videoSrcArray = await videos();
}
isFetching = false;
return imgsSrcArr;
};
//自動下載函式
const startAutoDownload = async () => {
let autoDownload = siteData.autoDownload;
if (!autoDownload) return;
let [start, time] = autoDownload;
let next = siteData.next;
let ele;
isFn(next) ? ele = await next() : ele = fn.ge(next);
if (!!ele && start == 1 || !!ele && options.autoDownload == 1) {
isCountdowning = true;
let max = time || options.autoDownloadCountdown;
let countdownNum = Number(max);
fn.showMsg(`${DL.str_32}${max}${DL.str_33}`, 0);
for (let i = 1; i <= Number(max); i++) {
await delay(1000);
if (isStopDownload) return;
fn.showMsg(`${DL.str_32}${countdownNum-=1}${DL.str_33}`, 0);
}
await delay(500);
if (isStopDownload) return;
if (isFn(next) && isString(ele)) {
fn.showMsg(DL.str_34.n);
location.href = ele;
} else if (isEle(ele)) {
fn.showMsg(DL.str_35);
EClick(ele);
}
} else if (!ele && start == 1 || !ele && options.autoDownload == 1) {
fn.showMsg(DL.str_36, 0);
options.autoDownload = 0;
let jsonStr = JSON.stringify(options);
localStorage.setItem("FullPictureLoadOptions", jsonStr);
}
};
const checkURL = (obj) => {
if (isArray(obj)) {
return obj.filter(url => isURL(url));
} else if (isString(obj)) {
if (isURL(obj)) {
return obj;
}
}
return null;
};
const checkDownloadCondition = () => {
if (fn.lh.includes(".v2ph.")) {
const cookie = v2ph_cookie;
if (!!cookie) {
return true;
} else {
alert("微圖坊下載需先填入Cloudflare clearance cookie。");
v2ph_cookie = prompt("Set Cookie", v2ph_cookie || "");
if (!!v2ph_cookie) {
_GM_setValue("v2ph_cookie", v2ph_cookie);
}
return false;
}
}
if (fn.lh.includes("myreadingmanga")) {
const cookie = myreadingmanga_cookie;
if (!!cookie) {
return true;
} else {
alert("MyReadingManga download requires filling in Cloudflare clearance cookie。");
myreadingmanga_cookie = prompt("Set Cookie", myreadingmanga_cookie || "");
if (!!myreadingmanga_cookie) {
_GM_setValue("myreadingmanga_cookie", myreadingmanga_cookie);
}
return false;
}
}
return true;
};
//長圖拼接下載函式
const combineDownloadImages = async (data, fileName) => {
const blobs = data.map(e => e.blob);
const srcs = blobs.map(blob => URL.createObjectURL(blob));
const loadImage = src => new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = reject;
img.src = src;
});
const combineImages = async () => {
const images = await Promise.all(srcs.map(loadImage));
const totalHeight = images.reduce((sum, img) => sum + img.height, 0);
const canvas = new OffscreenCanvas(images[0].width, totalHeight);
const ctx = canvas.getContext("2d");
let currentY = 0;
images.forEach(img => {
ctx.drawImage(img, 0, currentY);
currentY += img.height;
});
return canvas;
};
const canvas = await combineImages();
canvas.convertToBlob({
type: "image/jpeg",
quality: 0.9
}).then(blob => saveData(blob, fileName + ".jpg"));
fn.hideMsg();
promiseBlobArray = [];
downloadNum = 0;
isDownloading = false;
combineDownloadSwitch = false;
srcs.forEach(src => URL.revokeObjectURL(src));
};
const compressed_extension = _GM_getValue("compressed_extension", "zip");
const zipFolderConfig = _GM_getValue("zipFolderConfig", 1);
const convertWebpToJpg = _GM_getValue("convertWebpToJpg", 0);
const convertAvifToJpg = _GM_getValue("convertAvifToJpg", 0);
const jpgConvertQuality = _GM_getValue("jpgConvertQuality", 90);
//圖片影片下載函式
const DownloadFn = async (array = null, text = null) => {
if (checkGeting() || isOpenOptionsUI) return;
const checkDC = checkDownloadCondition();
if (!checkDC) return;
isStopDownload = false;
currentDownloadThread = 0;
downloadNum = 0;
promiseBlobArray = [];
let selector, titleText;
let autoDownload = siteData.autoDownload;
let start;
if (isArray(autoDownload)) {
[start] = autoDownload;
}
let titleReplace = fn.dt({
s: "title"
});
if (fastDownloadSwitch && array === null) {
selector = siteData.srcset || siteData.imgs;
titleText = (customTitle || titleReplace);
} else if (array === null) {
if (!autoDownload || !!autoDownload && start != 1 && options.autoDownload != 1) {
selector = siteData.srcset || siteData.imgs;
titleText = await prompt(DL.str_51, (customTitle || titleReplace));
if (titleText === null) {
fn.showMsg(DL.str_41);
return;
}
} else if (!!autoDownload) {
if (start == 1 || options.autoDownload == 1) {
selector = siteData.srcset || siteData.imgs;
titleText = (customTitle || titleReplace);
} else {
debug("未開啟自動下載");
return;
}
}
}
isDownloading = true;
if (isString(text)) titleText = text;
let imgsSrcArr = isArray(array) ? array : await getImgs(selector);
videoSrcArray = checkURL(videoSrcArray);
if (imgsSrcArr.length > 0 && titleText != null && titleText != "" || videoSrcArray.length > 0) {
fn.showMsg(DL.str_55, 0);
let loopMsg;
const imgsNum = imgsSrcArr.length;
let title = apiCustomTitle ?? titleText;
const zip = new JSZip();
let zipFolder;
let videosNum;
if (videoSrcArray.length > 0 && siteData.downloadVideo && siteData.downloadVideo == true && FullPictureLoadCustomDownloadVideo == 1) {
videosNum = videoSrcArray.length;
if (zipFolderConfig == 1) {
zipFolder = zip.folder(`${title} [${imgsNum}P + ${videosNum}V]`);
}
} else {
if (zipFolderConfig == 1) {
zipFolder = zip.folder(`${title} [${imgsNum}P]`);
}
}
if (imgsSrcArr.length > 0) {
const pad = String(imgsSrcArr.length).length;
for (let [i, src] of imgsSrcArr.entries()) {
let picNum = getNum(i, pad);
let promiseBlob;
await fn.checkDownloadThread();
if (isStopDownload) return (promiseBlobArray = []);
let sameOrigin = false;
try {
if (fn.clh() === new URL(src).hostname) {
sameOrigin = true;
}
} catch (e) {}
(
_GM_getValue("FetchAPIDownload", 0) == 1 ||
sameOrigin && siteData.fetch != 0 ||
src.startsWith("data:") ||
src.startsWith("blob:") ||
siteData.fetch == 1 ||
src.includes(".wp.com/")
) ? promiseBlob = Fetch_API_Download(src, picNum, imgsNum): promiseBlob = GM_XHR_Download(src, picNum, imgsNum);
promiseBlobArray.push(promiseBlob);
}
}
if (videoSrcArray.length > 0 && siteData.downloadVideo === true && FullPictureLoadCustomDownloadVideo == 1 && isPC) {
const pad = String(videosNum).length;
loopMsg = setInterval(() => {
fn.showMsg("Video Downloading...", 0);
}, 2000);
for (let [i, src] of videoSrcArray.entries()) {
let videoNum = getNum(i, pad);
let promiseBlob;
await fn.checkDownloadThread();
if (isStopDownload) {
clearInterval(loopMsg);
promiseBlobArray = [];
return;
}
let sameOrigin = false;
try {
if (fn.clh() === new URL(src).hostname) {
sameOrigin = true;
}
} catch (e) {}
(
_GM_getValue("FetchAPIDownload", 0) == 1 ||
sameOrigin && siteData.fetch != 0 ||
src.startsWith("data:") ||
src.startsWith("blob:") ||
siteData.fetch == 1 ||
src.includes(".wp.com/")
) ? promiseBlob = Fetch_API_Download(src, videoNum, imgsNum + videosNum): promiseBlob = GM_XHR_Download(src, videoNum, imgsNum + videosNum);
promiseBlobArray.push(promiseBlob);
}
}
debug("\nPromiseBlobArray:", promiseBlobArray);
Promise.all(promiseBlobArray).then(async data => {
try {
clearInterval(loopMsg);
} catch {}
if (isStopDownload) {
data = null;
promiseBlobArray = [];
return;
}
debug("\nPromiseAllData:", data);
let blobDataArray = data.filter(item => item.load); //成功下載
let errorDataArray = data.filter(item => item.error); //下載錯誤
debug("\nNewDataArray:", blobDataArray);
debug("\nErrorDataArray:", errorDataArray);
if (errorDataArray.length > 0) {
fn.hideMsg();
options.autoDownload = 0;
let jsonStr = JSON.stringify(options);
localStorage.setItem("FullPictureLoadOptions", jsonStr);
downloadNum = 0;
isDownloading = false;
let yes = await confirm(`${DL.str_27}${errorDataArray.length}${DL.str_28}${DL.str_29}`);
if (!yes) {
promiseBlobArray = [];
blobDataArray = null;
errorDataArray = null;
return;
}
}
if (combineDownloadSwitch && blobDataArray.length > 0) {
return combineDownloadImages(blobDataArray, text);
}
if (blobDataArray.length > 0) {
let total = blobDataArray.length;
for (let [i, data] of blobDataArray.entries()) {
let ex;
let blobData = data.blob;
let type = blobData.type;
try {
if (!fn.isVideo(data.src) && (/octet-stream/.test(type) || isM && type === "")) {
let url = URL.createObjectURL(blobData);
let check = await fn.checkImgStatus(url, 0);
URL.revokeObjectURL(url);
if (check.ok) {
if (/\.webp/i.test(data.src) && convertWebpToJpg != 1) {
blobData = await fn.convertImage(blobData, "image/webp");
ex = "webp";
} else {
blobData = await fn.convertImage(blobData);
ex = "jpg";
}
if (type === "") {
fn.showMsg(`unknown type to ${ex} ${(i+ 1)}/${total}`, 0);
} else {
fn.showMsg(`octet-stream to ${ex} ${(i+ 1)}/${total}`, 0);
}
} else {
console.error("\nDownloadFn() PromiseAll blob資料格式錯誤", data);
fn.showMsg(DL.str_30, 0);
return;
}
} else if (
(/webp/i.test(type) || /\.webp/i.test(data.finalUrl)) && convertWebpToJpg == 1 ||
(/avif/i.test(type) || /\.avif/i.test(data.finalUrl)) && convertAvifToJpg == 1
) {
let quality;
if (jpgConvertQuality == 0) {
quality = 0;
} else if (jpgConvertQuality == 100) {
quality = 1;
} else {
quality = Number("0." + jpgConvertQuality);
}
blobData = await fn.convertImage(blobData, "image/jpeg", quality);
ex = "jpg";
fn.showMsg(`${DL.str_102} to ${ex} ${(i+ 1)}/${total}`, 0);
} else if (/^text\/base64\.jpg/.test(type)) {
ex = "jpg";
} else {
[ex] = type.split("/")[1].match(/\w+/);
if (data.src.endsWith("webm")) {
ex = "webm";
}
}
} catch {
if (/^image/.test(type)) {
ex = "jpg";
} else if (type === "") {
let url = URL.createObjectURL(blobData);
let check = await fn.checkImgStatus(url, 0);
URL.revokeObjectURL(url);
if (check.ok) {
if (/\.webp/i.test(data.src) && convertWebpToJpg != 1) {
ex = "webp";
fn.showMsg(`unknown type to ${ex} ${(i+ 1)}/${total}`, 0);
blobData = await fn.convertImage(blobData, "image/webp");
} else {
ex = "jpg";
fn.showMsg(`unknown type to ${ex} ${(i+ 1)}/${total}`, 0);
blobData = await fn.convertImage(blobData);
}
} else {
console.error("\nDownloadFn() PromiseAll blob資料格式錯誤", data);
fn.showMsg(DL.str_30, 0);
return;
}
} else {
console.error("\nDownloadFn() PromiseAll blob資料格式錯誤", data);
fn.showMsg(DL.str_30, 0);
return;
}
}
let fileName;
["mp4", "webm", "mov"].includes(ex) ? fileName = `${data.picNum}V.${(ex)}` : fileName = `${data.picNum}P.${(siteData.ex || ex)}`;
if (options.zip == 1) {
//console.log(`第${n}/${total}張,檔案名:${fileName},大小:${parseInt(data.blob.size / 1024, 10)} Kb`);
if (zipFolderConfig == 1) {
zipFolder.file(fileName, blobData, {
binary: true
});
} else {
zip.file(fileName, blobData, {
binary: true
});
}
} else {
saveData(blobData, title + "_" + fileName);
await delay(200);
if (i === total - 1) {
fn.hideMsg();
promiseBlobArray = [];
downloadNum = 0;
isDownloading = false;
startAutoDownload();
}
}
}
if (options.zip == 1) {
zip.generateAsync({
type: "blob"
}, (metadata) => {
fn.showMsg(DL.str_31 + metadata.percent.toFixed(2) + " %", 0);
}).then(async data => {
fn.hideMsg();
debug("\nZIP壓縮檔數據:", data);
let fileName;
if (videoSrcArray.length > 0 && siteData.downloadVideo == true && FullPictureLoadCustomDownloadVideo == 1) {
fileName = `${title} [${imgsNum}P + ${videosNum}V].${compressed_extension}`;
} else {
fileName = `${title} [${imgsNum}P].${compressed_extension}`;
}
saveData(data, fileName);
promiseBlobArray = [];
downloadNum = 0;
isDownloading = false;
startAutoDownload();
});
}
} else {
promiseBlobArray = [];
downloadNum = 0;
isDownloading = false;
fn.showMsg(DL.str_43);
return;
}
});
} else {
isDownloading = false;
fn.showMsg(DL.str_41);
return;
}
};
//匯出網址
const exportImgSrcText = async (array = null, text = null) => {
if (checkGeting() || isOpenOptionsUI) return;
let selector = siteData.srcset || siteData.imgs;
let srcArr = isArray(array) ? array : await getImgs(selector);
if (srcArr.length == 0 && videoSrcArray.length == 0 && fileUrlArray.length == 0) return fn.showMsg(DL.str_44);
let picNum = srcArr.length;
let titleText = (text || apiCustomTitle || customTitle || document.title);
let fileName = `${titleText}[${picNum}P]_MediaURLs.txt`;
if (videoSrcArray.length > 0) {
srcArr = srcArr.concat(videoSrcArray);
fileName = `${titleText}[${picNum}P + ${videoSrcArray.length}V]_MediaURLs.txt`;
}
if (fileUrlArray.length > 0) {
srcArr = srcArr.concat(fileUrlArray);
fileName = `${titleText}[${picNum}P`;
if (videoSrcArray.length > 0) {
fileName += ` + ${videoSrcArray.length}V`;
}
fileName += ` + ${fileUrlArray.length} Files]_MediaURLs.txt`;
}
let str = srcArr.join("\n");
let blob = new Blob([str], {
type: "text/plain",
endings: "native"
});
saveData(blob, fileName);
fn.showMsg(`${DL.str_101}`);
};
//複製網址或手動模式的插入圖片
const copyImgSrcText = async () => {
if (checkGeting() || isOpenOptionsUI) return;
let selector = siteData.srcset || siteData.imgs;
let srcArr = await getImgs(selector);
//siteData.insertImg ? debug("手動插入圖片") : debug("複製網址");
if (srcArr.length == 0) return fn.showMsg(DL.str_44);
let imgsNum = srcArr.length;
let videosNum;
if ((!fn.ge(".FullPictureLoadImage") && !!siteData.insertImg) || siteData.repeat == 1 && !!siteData.insertImg) {
const [insertTargetEle, insertMode] = siteData.insertImg;
return fn.insertImg(srcArr, insertTargetEle, insertMode);
}
if (isM) return;
if (videoSrcArray.length > 0) {
videosNum = videoSrcArray.length;
srcArr = srcArr.concat(videoSrcArray);
}
if (fileUrlArray.length > 0) srcArr = srcArr.concat(fileUrlArray);
let title;
if (isString(apiCustomTitle)) {
title = apiCustomTitle;
} else if (isString(customTitle)) {
title = customTitle;
} else {
title = fn.dt({
s: "title"
});
}
if (fileUrlArray.length > 0) {
title = `${title}[${imgsNum}P`;
if (videoSrcArray.length > 0) {
title += ` + ${videoSrcArray.length}V`;
}
title += ` + ${fileUrlArray.length}File]`;
} else if (videoSrcArray.length > 0) {
title = `${title} [${imgsNum}P + ${videosNum}V]`;
} else {
title = `${title} [${imgsNum}P]`;
}
let textArr = [title].concat(srcArr);
let str = textArr.join("\n");
//console.log(str);
copyToClipboard(str);
fn.showMsg(`${DL.str_45}(${textArr.length - 1})`);
};
//複製網址
const copyImgSrcTextB = async (array = null, text = null) => {
if (checkGeting() || isOpenOptionsUI) return;
let selector = siteData.srcset || siteData.imgs;
let srcArr = isArray(array) ? array : await getImgs(selector);
if (srcArr.length == 0 && videoSrcArray.length == 0 && fileUrlArray.length == 0) return fn.showMsg(DL.str_44);
let imgsNum = srcArr.length;
let videosNum;
if (videoSrcArray.length > 0) {
videosNum = videoSrcArray.length;
srcArr = srcArr.concat(videoSrcArray);
}
if (fileUrlArray.length > 0) srcArr = srcArr.concat(fileUrlArray);
let title;
if (isString(text)) {
title = text;
} else if (isString(apiCustomTitle)) {
title = apiCustomTitle;
} else if (isString(customTitle)) {
title = customTitle;
} else {
title = fn.dt({
s: "title"
});
}
if (videoSrcArray.length > 0) {
title = `${title} [${imgsNum}P + ${videosNum}V]`;
} else {
title = `${title} [${imgsNum}P]`;
}
let textArr = [title].concat(srcArr);
let str = textArr.join("\n");
//console.log(str);
copyToClipboard(str);
fn.showMsg(`${DL.str_45}(${textArr.length - 1})`);
};
//匯出為JSON格式
const exportJsonFormat = async (array = null, text = null) => {
if (checkGeting() || isOpenOptionsUI) return;
let selector = siteData.srcset || siteData.imgs;
let srcArr = isArray(array) ? array : await getImgs(selector);
if (srcArr.length == 0 && videoSrcArray.length == 0 && fileUrlArray.length == 0) return fn.showMsg(DL.str_44);
let object = {
url: currentURL,
title: (text || apiCustomTitle || customTitle || document.title),
images: srcArr,
}
if (videoSrcArray.length > 0) {
Reflect.set(object, "videos", videoSrcArray);
};
if (fileUrlArray.length > 0) {
Reflect.set(object, "files", fileUrlArray);
}
let fileName = (text || apiCustomTitle || customTitle || document.title) + ".json";
let blob = new Blob([JSON.stringify(object, null, 4)], {
type: "application/json"
});
saveData(blob, fileName);
fn.showMsg(DL.str_175);
};
//匯出為Markdown格式
const exportMarkdownFormat = async (array = null, text = null) => {
if (checkGeting() || isOpenOptionsUI) return;
let selector = siteData.srcset || siteData.imgs;
let srcArr = isArray(array) ? array : await getImgs(selector);
if (srcArr.length == 0 && videoSrcArray.length == 0 && fileUrlArray.length == 0) return fn.showMsg(DL.str_44);
let title = "## " + (text || apiCustomTitle || customTitle || document.title);
let post = `Post Link:[${currentURL}](${currentURL})`;
let imagesTitle = "## Images";
let images = srcArr.map(async (src, i) => {
if (src.startsWith("blob")) {
src = await fn.blobURLtoDataURL(src);
}
return ``;
});
images = await Promise.all(images);
let textArr = [title, post, imagesTitle].concat(images);
if (videoSrcArray.length > 0) {
let videosTitle = "## Videos";
textArr.push(videosTitle);
let videos = videoSrcArray.map(src => " " + src);
textArr = textArr.concat(videos);
};
if (fileUrlArray.length > 0) {
let filesTitle = "## Files";
textArr.push(filesTitle);
let files = fileUrlArray.map(url => " " + url);
textArr = textArr.concat(files);
}
let str = textArr.join("\n");
let fileName = (text || apiCustomTitle || customTitle || document.title) + ".md";
let blob = new Blob([str], {
type: "text/markdown",
endings: "native"
});
saveData(blob, fileName);
fn.showMsg(DL.str_177);
};
//複製為Markdown格式
const copyMarkdownFormat = async (array = null, text = null) => {
if (checkGeting() || isOpenOptionsUI) return;
let selector = siteData.srcset || siteData.imgs;
let srcArr = isArray(array) ? array : await getImgs(selector);
if (srcArr.length == 0 && videoSrcArray.length == 0 && fileUrlArray.length == 0) return fn.showMsg(DL.str_44);
if (isString(text)) {
text = fn.dt({
t: text
});
}
let title = "## " + (text || apiCustomTitle || customTitle || document.title);
let post = `Post Link:[${currentURL}](${currentURL})`;
let imagesTitle = "## Images";
let images = srcArr.map(async (src, i) => {
if (src.startsWith("blob")) {
src = await fn.blobURLtoDataURL(src);
}
return ``;
});
images = await Promise.all(images);
let textArr = [title, post, imagesTitle].concat(images);
if (videoSrcArray.length > 0) {
let videosTitle = "## Videos";
textArr.push(videosTitle);
let videos = videoSrcArray.map(src => " " + src);
textArr = textArr.concat(videos);
};
let str = textArr.join("\n");
//console.log(str);
copyToClipboard(str);
fn.showMsg(DL.str_179);
};
const copyToClipboard = text => {
if (!!_unsafeWindow.navigator.clipboard && _unsafeWindow.isSecureContext) {
return _unsafeWindow.navigator.clipboard.writeText(text);
} else {
let textArea = document.createElement("textarea");
textArea.value = text;
textArea.style.position = "absolute";
textArea.style.opacity = 0;
textArea.style.left = "-999999px";
textArea.style.top = "-999999px";
document.body.append(textArea);
textArea.focus();
textArea.select();
return new Promise((res, rej) => {
document.execCommand("copy") ? res() : rej();
textArea.remove();
});
}
};
//滾動至首張圖片(動畫效果)
const goToNo1Img = (time = 1000) => {
let ele;
ge("#FullPictureLoadImgBox:not([style*=none])") ? ele = ge(".FullPictureLoadImage.small") : ele = ge(".FullPictureLoadImage");
if (ele) {
if (time != 0) fn.showMsg(DL.str_46);
setTimeout(() => {
ele.scrollIntoView({
behavior: "smooth"
});
}, time);
}
};
//滾動至首尾圖片
const goToImg = img => {
let ele = null;
if (ge("#FullPictureLoadImgBox:not([style*=none])") && img == "first") {
ele = ge(".FullPictureLoadImage.small");
} else if (img == "first") {
ele = ge(".FullPictureLoadImage:not(.small)");
}
if (ge("#FullPictureLoadImgBox:not([style*=none])") && img == "last") {
ele = gae(".FullPictureLoadImage.small").at(-1);
} else if (img == "last") {
ele = gae(".FullPictureLoadImage:not(.small)").at(-1);
}
if (ele) ele.scrollIntoView();
};
//自動滾動元素
const autoScrollEles = () => {
if (isOpenOptionsUI) return;
let scrollEle = siteData.scrollEle;
if (isFn(scrollEle)) {
scrollEle();
} else if (isArray(scrollEle)) {
const [selector, time] = scrollEle;
fn.scrollEles(selector, time);
}
};
//減少圖片縮放級別
const reduceZoom = () => {
if (isFetching || !siteData.insertImg || isOpenOptionsUI) return;
if (options.zoom <= 10 && ge(".FullPictureLoadImage:not(.small)")) {
options.zoom == 0 ? options.zoom = 10 : options.zoom = options.zoom -= 1;
if (options.zoom == 0) cancelZoom();
let jsonStr = JSON.stringify(options);
localStorage.setItem("FullPictureLoadOptions", jsonStr);
if (options.zoom > 0) {
gae(".FullPictureLoadImage:not(.small)").forEach(img => {
if (fancyboxBlackList() || options.fancybox !== 1) {
img.style.width = `${options.zoom * 10}%`;
} else {
let pE = img.parentNode;
if (pE.nodeName === "A") {
pE.style.width = `${options.zoom * 10}%`;
}
}
});
fn.showMsg(`${DL.str_60} ${options.zoom * 10}%`);
}
}
};
//增加圖片縮放級別
const increaseZoom = () => {
if (isFetching || !siteData.insertImg || isOpenOptionsUI) return;
if (options.zoom > 1 && options.zoom <= 10 && ge(".FullPictureLoadImage:not(.small)")) {
options.zoom = options.zoom += 1;
if (options.zoom > 10) cancelZoom();
let jsonStr = JSON.stringify(options);
localStorage.setItem("FullPictureLoadOptions", jsonStr);
if (options.zoom > 0 && options.zoom <= 10) {
gae(".FullPictureLoadImage:not(.small)").forEach(img => {
if (fancyboxBlackList() || options.fancybox !== 1) {
img.style.width = `${options.zoom * 10}%`;
} else {
let pE = img.parentNode;
if (pE.nodeName === "A") {
pE.style.width = `${options.zoom * 10}%`;
}
}
});
fn.showMsg(`${DL.str_60} ${options.zoom * 10}%`);
}
}
};
let viewMode = 0;
//切換圖片檢視模式
const toggleImgMode = async () => {
if (isFetching || !siteData.insertImg || isOpenOptionsUI) return;
let column;
if (gae(".FullPictureLoadImage").length < 1) {
fn.showMsg("沒有圖片或只有影片");
return;
}
if (ge(".FullPictureLoadImage:not(.small):not([style*=none])")) {
if (ge("#FullPictureLoadImgBox")) {
ge("#FullPictureLoadImgBox").style.display = "block";
gae(".FullPictureLoadImage:not(.small),#FullPictureLoadEnd").forEach(e => {
if (e.tagName == "IMG") {
e.setAttribute("style", "display:none!important;");
if (options.zoom > 0) e.style.width = `${options.zoom * 10}%`;
} else {
e.setAttribute("style", "display:none!important;");
}
});
viewMode = 1;
fn.showMsg(DL.str_93);
return;
}
let width;
if (options.column == 2 || siteData.category == "comic") {
width = "48.8%";
column = 2;
} else if (options.column == 3) {
width = "32%";
column = 3;
} else if (options.column == 5) {
width = "19.2%";
column = 5;
} else if (options.column == 6) {
width = "16%";
column = 6;
} else {
column = 4;
isM ? width = "24%" : width = "24.4%";
}
let imgBox = document.createElement("div");
imgBox.id = "FullPictureLoadImgBox";
imgBox.style.width = "100%";
imgBox.style.maxWidth = "1400px";
imgBox.style.backgroundColor = "#F6F6F6";
imgBox.style.textAlign = "center";
imgBox.style.display = "block";
let srcArr = gae(".FullPictureLoadImage:not(.small)").map(e => e.dataset.src ?? e.src);
if (siteData.category == "comic" || (options.column == 2 && siteData.category == "hcomic")) {
imgBox.style.direction = "rtl";
}
let blackList = fancyboxBlackList();
srcArr.forEach((src, i) => {
let a = document.createElement("a");
if (options.fancybox == 1 && !blackList) {
a.id = "imgLocationSamll_" + i;
a.dataset.fancybox = "FullPictureLoadImageSmall";
thumbnailSrcArray.length > 0 && thumbnailSrcArray.length == srcArr.length ? a.dataset.thumb = thumbnailSrcArray[i] : a.dataset.thumb = src;
a.href = "#";
a.dataset.src = src;
}
let img = new Image();
img.alt = `no.${i + 1}`;
img.dataset.index = i;
img.className = "FullPictureLoadImage small";
if ("referrerpolicy" in siteData) {
img.setAttribute("referrerpolicy", siteData.referrerpolicy);
}
img.dataset.errorNum = 0;
if ([2, 3].some(n => siteData.insertImg[1] == n)) {
img.src = loading_bak;
img.dataset.src = src;
} else {
img.decoding = "async";
img.loading = "lazy";
img.onload = () => {
img.classList.remove("error");
};
img.onerror = error => {
const num = Number(error.target.dataset.errorNum);
if (num < 20) {
error.target.dataset.errorNum = num + 1;
} else {
return;
}
error.target.classList.add("error");
setTimeout(() => {
error.target.src = error.target.src;
}, 3000);
};
img.src = src;
}
let item = document.createElement("div");
item.style.width = width;
//item.style.height = "auto";
//item.style.float = "left";
item.style.display = "inline-block";
if (siteData.category == "comic" || (options.column == 2 && siteData.category == "hcomic")) {
item.style.verticalAlign = "middle"
} else {
item.style.verticalAlign = "top"
}
item.style.padding = "0.1%";
item.style.border = "1px solid #a0a0a0";
if (options.fancybox == 1 && !blackList) {
a.append(img);
item.append(a);
imgBox.append(item);
} else {
item.append(img);
imgBox.append(item);
}
});
fragment.append(imgBox);
let tE = ge("#FullPictureLoadEnd");
insertBefore(tE, fragment);
if (ge(".FullPictureLoadVideo")) {
gae(".FullPictureLoadVideo").forEach(e => insertBefore(tE, e));
}
if (options.fancybox == 1 && !("fancybox" in siteData) && ("Fancybox" in _unsafeWindow)) {
_unsafeWindow.Fancybox.bind("[data-fancybox='FullPictureLoadImageSmall']", FancyboxOptions);
}
//tE.parentNode.style.textAlign = "center";
tE.parentNode.style.display = "block";
gae(".FullPictureLoadImage:not(.small),#FullPictureLoadEnd").forEach(e => {
if (e.tagName == "IMG") {
e.setAttribute("style", "display:none!important;");
if (options.zoom > 0) e.style.width = `${options.zoom * 10}%`;
} else {
e.setAttribute("style", "display:none!important;");
}
});
viewMode = 1;
fn.showMsg(DL.str_93);
let smallImgs = gae("img.FullPictureLoadImage.small");
setTimeout(() => {
smallImgs.forEach(img => fn.imagesObserver.observe(img));
}, 1000);
let imgDivs = gae("#FullPictureLoadImgBox>div");
if (siteData.category == "comic") {
let lastImg = imgDivs.at(-1);
fn.comicNextObserver.observe(lastImg);
}
let imgsNum = 0;
if (imgDivs[0].nextSibling && siteData.category == "comic") {
await fn.checkImgStatus(imgDivs[0].nextSibling.querySelector("img").dataset.src, "Wait Loading...");
if (imgDivs[0].offsetHeight < imgDivs[0].nextSibling.offsetHeight) {
imgDivs[0].style.height = (imgDivs[0].nextSibling.offsetHeight) + "px";
let img = imgDivs[0].querySelector("img");
await fn.checkImgStatus(img.dataset.src, "Wait Loading...");
let num = (imgDivs[0].offsetHeight - img.height) / 2;
img.style.marginTop = `${num}px`;
}
await delay(1200);
instantScrollIntoView(imgDivs[0]);
}
if (TurnOffImageNavigationShortcutKeys != 1) {
document.addEventListener("keydown", async event => {
if (isOpenOptionsUI || isOpenGallery || ge(".fancybox-container,#FullPictureLoadFavorSites") || ["F11", "F12"].some(k => event.code === k || event.key === k)) return;
if (event.code === "ArrowUp" || event.key === "ArrowUp") {
event.preventDefault();
if (imgsNum > 0 && viewMode == 1) {
imgsNum -= column;
instantScrollIntoView(imgDivs[imgsNum]);
}
} else if (event.code === "ArrowDown" || event.key === "ArrowDown") {
event.preventDefault();
if (imgsNum < imgDivs.length && imgsNum != imgDivs.length && viewMode == 1) {
imgsNum += column;
try {
if (imgDivs[imgsNum].nextSibling && siteData.category === "comic") {
debug(`\n第${imgsNum + 1}張(左)高:${imgDivs[imgsNum].offsetHeight}\n第${imgsNum + 2}張(右)高:${imgDivs[imgsNum].nextSibling.offsetHeight}`);
await fn.checkImgStatus(imgDivs[imgsNum].nextSibling.querySelector("img").dataset.src, "Wait Loading...");
if (imgDivs[imgsNum].offsetHeight < imgDivs[imgsNum].nextSibling.offsetHeight) {
imgDivs[imgsNum].style.height = (imgDivs[imgsNum].nextSibling.offsetHeight) + "px";
let img = imgDivs[imgsNum].querySelector("img");
await fn.checkImgStatus(img.dataset.src, "Wait Loading...");
let num = (imgDivs[imgsNum].offsetHeight - img.height) / 2;
debug(`\n修改了之後\n第${imgsNum + 1}張(左)高:${imgDivs[imgsNum].offsetHeight}\n第${imgsNum + 2}張(右)高:${imgDivs[imgsNum].nextSibling.offsetHeight}`);
img.style.marginTop = `${num}px`;
}
} else if (siteData.category === "comic") {
imgDivs[imgsNum].src = imgDivs[imgsNum].dataset.src;
await fn.checkImgStatus(imgDivs[imgsNum].dataset.src, "Wait Loading...");
}
instantScrollIntoView(imgDivs[imgsNum]);
await delay(200);
instantScrollIntoView(imgDivs[imgsNum]);
} catch {
if (siteData.category === "comic" && siteData.next && siteData.insertImg) {
if (isString(siteData.next)) {
let next = fn.ge(siteData.next);
if (next) {
fn.showMsg(DL.str_95, 3000);
EClick(next);
} else {
imgsNum = 0 - column;
fn.showMsg(DL.str_96, 3000);
}
} else if (isFn(siteData.next)) {
let next = await siteData.next();
if (next) {
fn.showMsg(DL.str_95, 3000);
location.href = next;
} else {
imgsNum = 0;
fn.showMsg(DL.str_96, 3000);
}
}
} else {
imgsNum = 0;
instantScrollIntoView(imgDivs[0]);
fn.showMsg(DL.str_94);
}
}
}
} else if (event.code === "Delete" && (siteData.category === "comic" || (options.column == 2 && siteData.category === "hcomic"))) {
if (imgDivs[0].style.display === "none") {
imgDivs[0].style.display = "inline-block";
} else {
imgDivs[0].style.display = "none";
}
} else {
imgsNum = 0 - column;
}
});
}
} else if (ge(".FullPictureLoadImage.small")) {
ge("#FullPictureLoadImgBox").style.display = "none";
gae(".FullPictureLoadImage:not(.small),#FullPictureLoadEnd").forEach(e => e.removeAttribute("style"));
if (options.zoom > 0) {
gae(".FullPictureLoadImage:not(.small)").forEach(img => (img.style.width = `${options.zoom * 10}%`));
}
viewMode = 0;
fn.showMsg(DL.str_92);
}
};
const newTabViewLightGallery = localStorage.getItem("newTabViewLightGallery") ?? 0;
const getConfig = () => {
const default_Config = {
ViewMode: 0,
MobileViewMode: "single",
webtoonWidth: isM ? window.innerWidth : 800,
shadowGalleryWheel: 2,
horizontalWheel: 0,
jumpNum: 100,
behavior: "smooth",
threading: 2,
colorThemes: "dark",
showSize: 0,
noSize: 0,
move: 0,
aee: 0
};
let newWindowData = localStorage.getItem("newWindowData");
if (newWindowData == null) {
localStorage.setItem("newWindowData", JSON.stringify(default_Config));
newWindowData = {};
} else if (isString(newWindowData)) {
newWindowData = JSON.parse(newWindowData);
}
const config = Object.assign(default_Config, newWindowData);
return config;
};
const saveConfig = (config = getConfig()) => {
localStorage.setItem("newWindowData", JSON.stringify(config));
};
const setDefault = () => {
const keys = [
"newTabViewLightGallery",
"newWindowData",
"FullPictureLoadComicInfiniteScrollMode",
"FullPictureLoadOptions",
"FullPictureLoadCustomDownloadVideo",
"FullPictureLoadShowEye"
];
for (const key of keys) {
if (!!localStorage.getItem(key)) {
localStorage.removeItem(key);
}
}
_GM_setValue("language", null);
_GM_setValue("FetchAPIDownload", 0);
_GM_setValue("UI_zIndex", 2147483647)
_GM_setValue("FullPictureLoadMsgPos", 0);
_GM_setValue("pageViewMode", 0);
_GM_setValue("goToFirstImage", 1);
_GM_setValue("GalleryInIcon", 0);
_GM_setValue("ShowFullPictureLoadFixedMenu", 1);
_GM_setValue("FavorOpenInNewTab", 0);
_GM_setValue("FullPictureLoadLoopView", 1);
_GM_setValue("convertWebpToJpg", 0);
_GM_setValue("FancyboxSlideshowTimeout", 3);
_GM_setValue("FancyboxWheel", 1);
_GM_setValue("FancyboxSlideshowTransition", "fade");
_GM_setValue("FancyboxAutoClose", 1);
_GM_setValue("FancyboxAutoNext", 1);
_GM_setValue("exclude_ex_config", {});
_GM_setValue("compressed_extension", "zip");
_GM_setValue("zipFolderConfig", 1);
_GM_setValue("doubleTouchNext", 1);
_GM_setValue("convertWebpToJpg", 0);
_GM_setValue("convertAvifToJpg", 0);
_GM_setValue("jpgConvertQuality", 90);
_GM_setValue("icon_top", "auto");
_GM_setValue("icon_bottom", "24px");
_GM_setValue("icon_left", "24px");
_GM_setValue("icon_right", "auto");
_GM_setValue("eye_icon_top", "auto");
_GM_setValue("eye_icon_bottom", "24px");
_GM_setValue("eye_icon_left", "auto");
_GM_setValue("eye_icon_right", "24px");
_GM_setValue("eye_menu_top", "auto");
_GM_setValue("eye_menu_bottom", "22px");
_GM_setValue("eye_menu_left", "auto");
_GM_setValue("eye_menu_right", "64px");
_GM_setValue("image_size", -1);
_GM_setValue("wp_image_cdn", -1);
_GM_setValue("TurnOffImageNavigationShortcutKeys", 0);
};
//新分頁空白頁檢視圖片
const newTabView = async (src_array = null) => {
if (checkGeting() || isDragging || "eye" in siteData && siteData.eye === 0) return;
const config = getConfig();
let imgSrcs;
if (isArray(src_array)) {
imgSrcs = src_array;
} else if ("SPA" in siteData) {
let selector = siteData.capture || siteData.srcset || siteData.imgs;
imgSrcs = await getImgs(selector);
} else if (!("capture" in siteData)) {
globalImgArray.length > 0 ? imgSrcs = globalImgArray : imgSrcs = await getImgs(siteData.srcset || siteData.imgs);
} else {
captureSrcArray.length > 0 ? imgSrcs = captureSrcArray : imgSrcs = await getImgs(siteData.srcset || siteData.imgs);
}
if (!!imgSrcs?.length && imgSrcs.length > 0) {
let newWindow;
let dom;
try {
if ("yujianobj" in _unsafeWindow || isXBrowser) {
newWindow = _unsafeWindow.open(location.origin);
} else {
newWindow = _unsafeWindow.open("about:blank", "_blank");
}
dom = newWindow.document;
} catch {
alert("An error occurred\nUnable to use window.open()");
return;
}
dom.write(`
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=4, user-scalable=yes, shrink-to-fit=no">
<title>${DL.str_106.replace(/\(.\)/, "")}:${apiCustomTitle ?? customTitle ?? document.title}</title>
</head>
<body style="text-align: center;">
<div id="imgBox" tabindex="-1"></div>
</body>
</html>
`);
newWindow.siteData = siteData;
newWindow.fn = fn;
newWindow.isM = isM;
newWindow.isPC = isPC;
newWindow.config = config;
newWindow.lightGallery = newTabViewLightGallery;
newWindow.FancyboxAutoClose = FancyboxAutoClose;
newWindow.totalNumberOfElements = 0;
newWindow.currentReferenceElement = null;
newWindow.imgViewIndex = -1;
newWindow.webtoonWidth = config.webtoonWidth;
newWindow.category = siteData.category;
newWindow.newImgs = imgSrcs;
newWindow.thumbnailSrcArray = isArray(src_array) ? [] : thumbnailSrcArray;
newWindow.DL = DL;
newWindow.menuLanguage = DL.galleryMenu;
newWindow.isOpenFancybox = false;
newWindow.l10n = Fancyboxl10nV5();
newWindow.lightboxSwitch = options.fancybox;
newWindow.smoothOptions = smoothOptions;
newWindow.instantOptions = instantOptions;
newWindow.smoothScrollIntoView = smoothScrollIntoView;
newWindow.instantScrollIntoView = instantScrollIntoView;
newWindow.loopView = _GM_getValue("FullPictureLoadLoopView", 1);
let newWindowStyleCss = `
body {
background-color: #333;
display: block;
margin: 0px;
}
#FixedMenu {
text-align: center;
font-family: ui-monospace, sans-serif, system-ui, -apple-system, Segoe UI, Arial;
font-weight: 500;
font-size: 14px;
color: ${config.colorThemes == "dark" ? "#fff" : "#000"};
width: ${isM ? "102px" : "152px"};
height: auto;
padding: 5px 5px 2px 5px;
position: fixed;
left: ${isM ? "0px" : "-158px"};
bottom: 0px;
border: #ccc 1px solid;
border-radius: 3px;
background-color: ${config.colorThemes == "dark" ? "#222" : "#fff"};
z-index: 2;
opacity: ${isM ? "1" : "0.5"};
&:hover {
left: 0px;
opacity: 1;
}
}
.FixedMenuitem {
width: ${isM ? "90px" : "140px"};
height: 24px;
line-height: 24px;
overflow: hidden;
font-size: 14px;
border: #ccc 1px solid;
background-color: ${config.colorThemes == "dark" ? "#333" : "#f6f6f6"};
padding: 0 5px 0 5px;
margin: 0 2px 3px 0;
cursor: pointer;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.FixedMenuitem.active {
color: #fff;
background: #1790E6;
}
#FixedMenu select {
font-weight: normal;
text-align: center;
color: ${config.colorThemes == "dark" ? "#fff" : "#000"};
background-color: ${config.colorThemes == "dark" ? "#333" : "#f6f6f6"};
border: none;
width: 100%;
height: 100%;
padding: 0 auto;
}
#setting-btn {
width: auto;
height: auto;
position: fixed;
right: ${isM ? "10px" : "30px"};
bottom: 150px;
z-index: ${UI_zIndex - 3};
}
.setting-btn {
width: 48px;
height: 48px;
text-align: center;
user-select:none;
color: ${config.colorThemes == "dark" ? "#fff" : "#000"};
margin: 5px 0;
overflow: hidden;
border: ${config.colorThemes == "dark" ? "rgb(200, 200, 200) 1px solid" : "rgb(51, 51, 51) 1px solid"};
background: ${config.colorThemes == "dark" ? "rgba(37, 36, 44, 0.8)" : "rgba(255, 255, 255, 0.8)"};
border-radius: 12px;
}
.setting-btn .icon {
margin-top: 10px;
width: 28px;
height: 28px;
}
.hide {
display: none !important;
}
img.default {
vertical-align: middle;
width: auto;
height: auto;
object-fit: contain;
border: solid #fff;
background-color: #fff;
}
img.single {
width: auto;
height: auto;
max-width: ${isFirefox ? "calc(100% - 6px)" : "calc(100% - 4px)"};
max-height: 99vh;
display: block;
margin: 0 auto;
border: solid #fff;
}
img.webtoon {
width: 100%;
height: auto;
display: block;
margin: 0 auto;
border: unset !important;
}
img.small {
display: inline-block;
vertical-align: middle;
width: auto;
height: auto;
max-width: 31.8%;
max-height: 33vh;
border: solid #fff;
}
img.horizontal {
vertical-align: middle;
width: auto;
height: 100%;
object-fit: contain;
border: solid #fff;
background-color: #fff;
}
.horizontal_first {
margin-left: 1em !important;
}
.horizontal_last {
margin-right: 1em !important;
}
.no_r_l_border {
border-right: none !important;
border-left: none !important;
}
.viewer-backdrop {
background-color: rgba(0, 0, 0, .94) !important;
}
`;
if (_GM_getValue("FancyboxSlideshowTransition") === "no") {
newWindowStyleCss += `
.fancybox__container .to-next>.fancybox__content,
.fancybox__container .to-prev>.fancybox__content {
display: none !important;
}
`;
}
//添加主要CSS
_GM_addElement(dom.head, "style", {
textContent: newWindowStyleCss
});
//添加FancyboxCSS
_GM_addElement(dom.head, "style", {
textContent: FancyboxV5Css
});
//添加ViewerJsCSS
_GM_addElement(dom.head, "style", {
textContent: ViewerJsCss
});
//引入Fancybox
_GM_addElement(dom.head, "script", {
textContent: JqueryJS + FancyboxV5JS + `
var FancyboxOptions = {};
if (isM) {
FancyboxOptions = {
Hash: false,
idle: false,
showClass: false,
hideClass: false,
Images: {
Panzoom: {
maxScale: 4
},
zoom: false
},
Slideshow: {
timeout: ${FancyboxSlideshowTimeoutNum},
},
Carousel: {
transition: "${FancyboxSlideshowTransition}"
},
Thumbs: {
showOnStart: false
},
Toolbar: {
display: {
left: ["infobar"],
middle: ["flipX", "flipY"],
right: ["iterateZoom", "slideshow", "thumbs", "close"]
}
},
on: {
done: (fancybox, slide) => {
isOpenFancybox = true;
let slideIndex = slide.index;
let imgs = [...document.images];
if (config.ViewMode != 4) {
imgs.forEach(e => (e.style.border = ""));
}
if (fancybox.isCurrentSlide(slide)) {
imgViewIndex = slideIndex;
if (config.ViewMode != 4) {
imgs[slideIndex].style.border = "solid #32a1ce";
}
smoothScrollIntoView(imgs[slideIndex]);
} else {
imgViewIndex = fancybox.getSlide().index;
if (config.ViewMode != 4) {
imgs[slideIndex].style.border = "solid #32a1ce";
}
smoothScrollIntoView(imgs[fancybox.getSlide().index]);
}
if (fancybox.carousel.page == 0 && (fancybox.carousel.prevPage == fancybox.carousel.pages.at(-1).index)) {
if (FancyboxAutoClose == 1) {
fancybox.close();
}
}
},
close: fancybox => {
document.body.classList.remove("hide-scrollbar");
let slideIndex = fancybox.getSlide().index;
imgViewIndex = slideIndex;
let imgs = [...document.images];
if (config.ViewMode != 4) {
imgs.forEach(e => (e.style.border = ""));
imgs[slideIndex].style.border = "solid #32a1ce";
}
smoothScrollIntoView(imgs[slideIndex]);
setTimeout(() => {
isOpenFancybox = false;
}, 200);
}
}
}
} else {
FancyboxOptions = {
Hash: false,
idle: false,
showClass: false,
hideClass: false,
wheel: "${FancyboxWheel}",
Images: {
Panzoom: {
maxScale: 4
},
zoom: false
},
Slideshow: {
timeout: ${FancyboxSlideshowTimeoutNum},
},
Carousel: {
transition: "${FancyboxSlideshowTransition}"
},
Thumbs: {
showOnStart: false
},
Toolbar: {
display: {
left: ["infobar"],
middle: ["zoomIn", "zoomOut", "iterateZoom", "toggle1to1", "rotateCCW", "rotateCW", "flipX", "flipY", "fitX", "fitY", "reset"],
right: ["slideshow", "fullscreen", "thumbs", "close"]
}
},
on: {
done: (fancybox, slide) => {
isOpenFancybox = true;
let slideIndex = slide.index;
let imgs = [...document.images];
imgs.forEach(e => (e.style.border = ""));
if (fancybox.isCurrentSlide(slide)) {
imgViewIndex = slideIndex;
let img = imgs[imgViewIndex];
currentReferenceElement = img;
img.style.border = "solid #32a1ce";
smoothScrollIntoView(img);
} else {
imgViewIndex = fancybox.getSlide().index;
let img = imgs[imgViewIndex];
currentReferenceElement = img;
img.style.border = "solid #32a1ce";
smoothScrollIntoView(img);
}
if (fancybox.carousel.page == 0 && (fancybox.carousel.prevPage == fancybox.carousel.pages.at(-1).index)) {
if (FancyboxAutoClose == 1) {
fancybox.close();
}
}
},
close: fancybox => {
document.body.classList.remove("hide-scrollbar");
let slideIndex = fancybox.getSlide().index;
imgViewIndex = slideIndex;
let imgs = [...document.images];
imgs.forEach(e => (e.style.border = ""));
let img = imgs[imgViewIndex];
currentReferenceElement = img;
img.style.border = "solid #32a1ce";
smoothScrollIntoView(img);
setTimeout(() => {
isOpenFancybox = false;
}, 200);
}
}
}
}
if (l10n !== "EN") {
Fancybox.defaults.l10n = l10n;
}
`
});
//引入ViewerJs
_GM_addElement(dom.head, "script", {
textContent: ViewerJs
});
const newWindowScriptCode = `
const fragment = new DocumentFragment();
let loadQueue = null;
if (lightboxSwitch == 1 && lightGallery == 1) {
var ViewerJsInstance = new Viewer(document.querySelector("#imgBox"), {
navbar: false,
title: false,
initialCoverage: 0.99,
interval: ${FancyboxSlideshowTimeoutNum},
url: "data-src",
viewed: event => {
let slideIndex = event.detail.index;
let imgs = [...document.images];
imgViewIndex = slideIndex;
let img = event.detail.originalImage;
currentReferenceElement = img;
if (config.ViewMode != 4) {
imgs.forEach(e => (e.style.border = ""));
img.style.border = "solid #32a1ce";
}
smoothScrollIntoView(img);
}
});
}
function setFancybox() {
Fancybox.bind("[data-fancybox]", FancyboxOptions);
}
let menuDiv;
function addFixedMenu() {
menuDiv = document.createElement("div");
menuDiv.id = "FixedMenu";
const menuObj = [{
id: "MenuThreadingItem"
}, {
id: "MenuHorizontalItem",
text: menuLanguage.horizontal,
cfn: () => horizontalImageLayout()
}, {
id: "MenuWebtoonItem",
text: menuLanguage.webtoon,
cfn: () => webtoonImageLayout()
}, {
id: "MenuRTLItem",
text: menuLanguage.rtl,
cfn: () => rtlImageLayout()
}, {
id: "MenuSmallItem",
text: menuLanguage.small,
cfn: () => smallImageLayout()
}, {
id: "MenuSinglePageItem",
text: menuLanguage.single,
cfn: () => singleImageLayout()
}, {
id: "MenuDefaultItem",
text: menuLanguage.default,
cfn: () => defaultImageLayout()
}];
const createMenu = obj => {
let item = document.createElement("div");
item.id = obj.id;
item.className = "FixedMenuitem";
item.innerText = obj.text || "";
item.oncontextmenu = () => false;
if (!!obj.cfn) item.addEventListener("click", obj.cfn);
menuDiv.append(item);
};
menuObj.forEach(obj => createMenu(obj));
let threadingSelect = document.createElement("select");
for (let i = 1; i <= 32; i++) {
let option = document.createElement("option");
option.value = i;
option.innerText = DL.str_162 + i;
threadingSelect.append(option);
}
menuDiv.querySelector("#MenuThreadingItem").append(threadingSelect);
fragment.append(menuDiv);
document.body.append(fragment);
threadingSelect.value = config.threading;
threadingSelect.addEventListener("change", () => {
config.threading = Number(threadingSelect.value);
saveConfig();
if (!isM) {
document.querySelector("#imgBox").focus();
}
});
}
addFixedMenu();
let btnDiv;
function addButtons() {
btnDiv = document.createElement("div");
btnDiv.id = "setting-btn";
btnDiv.className = "hide";
const btnObj = [{
id: "addBtn",
svg: '<svg class="icon" fill="currentColor" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><path d="M1024 432v160c0 8.8-7.2 16-16 16H624c-8.8 0-16 7.2-16 16v384c0 8.8-7.2 16-16 16H432c-8.8 0-16-7.2-16-16V624c0-8.8-7.2-16-16-16H16c-8.8 0-16-7.2-16-16V432c0-8.8 7.2-16 16-16h384c8.8 0 16-7.2 16-16V16c0-8.8 7.2-16 16-16h160c8.8 0 16 7.2 16 16v384c0 8.8 7.2 16 16 16h384c8.8 0 16 7.2 16 16z"></path></svg>',
cfn: increaseWidth
}, {
id: "reduceBtn",
svg: '<svg class="icon" fill="currentColor" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><path d="M1024 432v160c0 8.8-7.2 16-16 16H16c-8.8 0-16-7.2-16-16V432c0-8.8 7.2-16 16-16h992c8.8 0 16 7.2 16 16z"></path></svg>',
cfn: reduceWidth
}];
const createDiv = obj => {
let item = document.createElement("div");
item.id = obj.id;
item.className = "setting-btn";
item.innerHTML = obj.svg;
item.oncontextmenu = () => false;
item.addEventListener("click", obj.cfn);
btnDiv.append(item);
};
btnObj.forEach(obj => createDiv(obj));
document.body.append(btnDiv);
}
addButtons();
if (isM) {
document.querySelector("#MenuHorizontalItem").classList.add("hide");
menuDiv.classList.add("hide");
let lastScrollTop = 0;
let scroll = "";
document.addEventListener("scroll", event => {
if (isOpenFancybox || document.querySelector(".viewer-container .viewer-canvas>img")) return;
let st = event.srcElement.scrollingElement.scrollTop;
if (st > lastScrollTop) {
scroll = "down";
menuDiv.classList.add("hide");
if (config.ViewMode == 4) {
btnDiv.classList.add("hide");
}
lastScrollTop = st;
} else if (st < lastScrollTop - 20) {
scroll = "up";
menuDiv.classList.remove("hide");
if (config.ViewMode == 4) {
btnDiv.classList.remove("hide");
}
lastScrollTop = st;
}
});
}
function toggleDirection(box, imgs) {
if (box.style.direction == "rtl") {
document.body.style.direction = "ltr";
box.style.direction = "ltr";
imgs.at(0).classList.remove("horizontal_last");
imgs.at(0).classList.add("horizontal_first");
imgs.at(-1).classList.remove("horizontal_first");
imgs.at(-1).classList.add("horizontal_last");
} else {
document.body.style.direction = "rtl";
box.style.direction = "rtl";
imgs.at(0).classList.remove("horizontal_first");
imgs.at(0).classList.add("horizontal_last");
imgs.at(-1).classList.remove("horizontal_last");
imgs.at(-1).classList.add("horizontal_first");
}
}
function toggle_r_l_border(imgs) {
imgs.forEach(img => {
if (img.classList.contains("no_r_l_border")) {
img.classList.remove("no_r_l_border");
} else {
img.classList.add("no_r_l_border");
}
});
}
document.addEventListener("keydown", event => {
if (isOpenFancybox || document.querySelector(".viewer-container .viewer-canvas>img") || ["F11", "F12"].some(k => event.code === k || event.key === k) || (config.ViewMode == 5 && event.shiftKey)) return;
const imgs = [...document.images];
if (event.code === "Numpad0" || event.code === "Digit0" || event.key === "0") return defaultImageLayout();
if (event.code === "Numpad1" || event.code === "Digit1" || event.key === "1") return singleImageLayout();
if (event.code === "Numpad2" || event.code === "Digit2" || event.key === "2") return smallImageLayout();
if (event.code === "Numpad3" || event.code === "Digit3" || event.key === "3") return rtlImageLayout();
if (event.code === "Numpad4" || event.code === "Digit4" || event.key === "4") return webtoonImageLayout();
if (event.code === "Numpad5" || event.code === "Digit5" || event.key === "5") return horizontalImageLayout();
if ((event.code === "Home" || event.key === "Home") || (event.code === "End" || event.key === "End")) {
event.preventDefault();
if (event.code === "Home" || event.key === "Home") {
imgViewIndex = 0;
} else {
imgViewIndex = imgs.length - 1;
}
const img = imgs[imgViewIndex];
if (config.ViewMode != 4 && ([0, 1, 3].some(m => config.ViewMode == m) && config.shadowGalleryWheel != 2)) {
imgs.forEach(e => (e.style.border = ""));
img.style.border = "solid #32a1ce";
}
currentReferenceElement = img;
return instantScrollIntoView(img);
}
if (config.ViewMode == 4 && (["NumpadAdd", "Equal"].some(k => event.code === k) || ["+", "="].some(k => event.code === k))) {
return increaseWidth();
}
if (config.ViewMode == 4 && (["NumpadSubtract", "Minus"].some(k => event.code === k) || ["-", "_"].some(k => event.key === k))) {
return reduceWidth();
}
if ((event.code === "KeyR" || event.key === "r" || event.key === "R") && [0, 2, 3, 5].some(m => config.ViewMode == m)) {
let box = document.querySelector("#imgBox");
if (config.ViewMode == 5) {
toggleDirection(box, imgs);
if (imgs[imgViewIndex] !== undefined) {
return instantScrollIntoView(imgs[imgViewIndex]);
}
} else {
if (box.style.direction == "rtl") {
return (box.style.direction = "ltr");
} else {
return (box.style.direction = "rtl");
}
}
}
if ((event.code === "KeyB" || event.key === "b" || event.key === "B") && [0, 2, 3, 5].some(m => config.ViewMode == m)) {
toggle_r_l_border(imgs);
if (imgs[imgViewIndex] !== undefined) {
return instantScrollIntoView(imgs[imgViewIndex]);
}
return;
}
if ((["KeyW", "KeyA", "ArrowUp", "ArrowLeft"].some(k => event.code === k) || ["w", "W", "a", "A", "KeyA", "ArrowUp", "ArrowLeft"].some(k => event.key === k)) && imgViewIndex < 0) {
if (config.ViewMode == 4 && (event.code === "ArrowUp" || event.key === "ArrowUp")) return;
if (config.ViewMode == 5 && (event.code === "ArrowLeft" || event.key === "ArrowLeft")) return;
if (loopView != 1) return;
event.preventDefault();
imgViewIndex = imgs.length - 1;
const img = imgs[imgViewIndex];
if (config.ViewMode != 4) {
imgs.forEach(e => (e.style.border = ""));
img.style.border = "solid #32a1ce";
}
currentReferenceElement = img;
return instantScrollIntoView(img);
} else if ((["KeyW", "KeyA", "ArrowUp", "ArrowLeft"].some(k => event.code === k) || ["w", "W", "a", "A", "KeyA", "ArrowUp", "ArrowLeft"].some(k => event.key === k)) && imgViewIndex >= 0) {
if (config.ViewMode == 4 && (event.code === "ArrowUp" || event.key === "ArrowUp")) return;
if (config.ViewMode == 5 && (event.code === "ArrowLeft" || event.key === "ArrowLeft")) return;
event.preventDefault();
imgViewIndex--;
if (imgViewIndex < 0 && loopView != 1) {
imgViewIndex = 0;
return;
}
let img = imgs[imgViewIndex];
if (img === undefined) {
imgViewIndex = imgs.length - 1;
img = imgs[imgViewIndex];
}
if (config.ViewMode != 4) {
imgs.forEach(e => (e.style.border = ""));
if (img !== undefined) {
img.style.border = "solid #32a1ce";
}
}
currentReferenceElement = img;
return instantScrollIntoView(img);
} else if ((["KeyS", "KeyD", "ArrowDown", "ArrowRight"].some(k => event.code === k) || ["s", "S", "d", "D", "ArrowDown", "ArrowRight"].some(k => event.key === k)) && imgViewIndex <= imgs.length - 1) {
if (config.ViewMode == 4 && (event.code === "ArrowDown" || event.key === "ArrowDown")) return;
if (config.ViewMode == 5 && (event.code === "ArrowRight" || event.key === "ArrowRight")) return;
event.preventDefault();
imgViewIndex++;
if (imgViewIndex > imgs.length - 1 && loopView != 1) {
imgViewIndex = imgs.length - 1;
return;
}
let img = imgs[imgViewIndex];
if (imgViewIndex > imgs.length - 1 && category === "comic") {
return window.close();
} else if (imgViewIndex > imgs.length - 1) {
imgViewIndex = 0;
}
if (config.ViewMode != 4) {
imgs.forEach(e => (e.style.border = ""));
if (img !== undefined) {
img.style.border = "solid #32a1ce";
}
}
if (img === undefined) {
imgViewIndex = 0;
img = imgs[imgViewIndex];
}
currentReferenceElement = img;
return instantScrollIntoView(img);
} else if ((event.code === "Delete" || event.key === "Delete")) {
for (const img of imgs) {
if (!img.classList.contains("hide")) {
img.classList.add("hide");
break;
}
}
if (imgs[imgViewIndex] !== undefined && config.ViewMode != 4) {
if (config.shadowGalleryWheel != 2) {
imgs.forEach(e => (e.style.border = ""));
imgs[imgViewIndex].style.border = "solid #32a1ce";
}
instantScrollIntoView(imgs[imgViewIndex]);
}
return;
} else if ((event.code === "Enter" || event.key === "Enter")) {
imgs.forEach(e => e.classList.remove("hide"));
if (imgs[imgViewIndex] !== undefined && config.ViewMode != 4) {
if (config.shadowGalleryWheel != 2) {
imgs.forEach(e => (e.style.border = ""));
imgs[imgViewIndex].style.border = "solid #32a1ce";
}
instantScrollIntoView(imgs[imgViewIndex]);
}
return;
} else if (!["KeyR", "NumpadAdd", "Equal", "NumpadSubtract", "Minus"].some(k => event.code === k) || !["r", "R", "-", "+", "=", "_"].some(k => event.key === k)) {
imgViewIndex = -1;
}
});
document.addEventListener("wheel", (event) => {
if (!isOpenFancybox && !document.querySelector(".viewer-container .viewer-canvas>img") && config.ViewMode == 4 && (event.ctrlKey || event.altKey || event.shiftKey)) {
event.preventDefault();
event.stopPropagation();
if (event.deltaY < 0) {
increaseWidth();
}
if (event.deltaY > 0) {
reduceWidth();
}
}
}, {
passive: false
});
document.addEventListener("wheel", (event) => {
if (event.shiftKey && config.ViewMode == 5) {
const viewImgs = [...document.querySelectorAll("img.isView")];
const middleIndex = Math.floor(viewImgs.length / 2 - 1);
let img;
if (middleIndex > -1) {
img = viewImgs[middleIndex];
} else {
img = viewImgs[0];
}
imgViewIndex = Number(img.dataset.index);
}
if (!isOpenFancybox && !document.querySelector(".viewer-container .viewer-canvas>img") && ([0, 1, 3].some(m => config.ViewMode == m) && [1, 2].some(m => config.shadowGalleryWheel == m) || config.ViewMode == 5) && !event.ctrlKey && !event.altKey && !event.shiftKey && !event.metaKey) {
event.preventDefault();
event.stopPropagation();
if (config.ViewMode == 5 && (config.horizontalWheel == 0 || config.horizontalWheel == 1)) {
if (document.body.style.direction == "rtl") {
return (document.body.scrollLeft -= event.deltaY);
} else {
return (document.body.scrollLeft += event.deltaY);
}
}
const imgs = [...document.images];
if (config.shadowGalleryWheel == 1 || config.ViewMode == 5) {
if (event.deltaY < 0 && imgViewIndex < 0) {
if (loopView != 1) return;
imgViewIndex = imgs.length - 1;
imgs[imgViewIndex].style.border = "solid #32a1ce";
return instantScrollIntoView(imgs[imgViewIndex]);
} else if (event.deltaY < 0 && imgViewIndex >= 0) {
imgViewIndex--;
if (imgViewIndex < 0 && loopView != 1) {
imgViewIndex = 0;
return;
}
if (imgViewIndex < 0) imgViewIndex = imgs.length - 1;
if (config.ViewMode != 4) {
imgs.forEach(e => (e.style.border = ""));
if (imgs[imgViewIndex] !== undefined) {
imgs[imgViewIndex].style.border = "solid #32a1ce";
}
}
return instantScrollIntoView(imgs[imgViewIndex]);
} else if (event.deltaY > 0 && imgViewIndex <= imgs.length - 1) {
imgViewIndex++;
if (imgViewIndex > imgs.length - 1 && loopView != 1) {
imgViewIndex = imgs.length - 1;
return;
}
if (imgs[imgViewIndex] === undefined) {
imgViewIndex = 0;
}
if (config.ViewMode != 4) {
imgs.forEach(e => (e.style.border = ""));
if (imgs[imgViewIndex] !== undefined) {
imgs[imgViewIndex].style.border = "solid #32a1ce";
}
}
return instantScrollIntoView(imgs[imgViewIndex]);
} else {
imgViewIndex = -1;
}
} else if (config.shadowGalleryWheel == 2) {
if (event.deltaY < 0) {
if (Number(currentReferenceElement?.dataset?.index) <= 0) return;
imgs.forEach(e => (e.style.border = ""));
return instantScrollIntoView(getPrevRowElement());
}
if (event.deltaY > 0) {
if (Number(currentReferenceElement?.dataset?.index) >= totalNumberOfElements - 1) return;
imgs.forEach(e => (e.style.border = ""));
return instantScrollIntoView(getNextRowElement());
}
}
}
}, {
passive: false
});
function aspectRatio() {
const verticalScreen = window.innerHeight / window.innerWidth > 1;
const imgs = [...document.images];
imgs.forEach(img => {
if (verticalScreen && img.className === "default") {
img.style.minWidth = "98vw";
img.style.maxWidth = "98vw";
img.style.minHeight = "";
img.style.maxHeight = "";
} else if (img.className === "default") {
img.style.minHeight = "calc(100vh - 4px)";
img.style.maxHeight = "calc(100vh - 4px)";
img.style.minWidth = "";
img.style.maxWidth = "98vw";
}
if (config.ViewMode == 5) {
let num = 6;
if (devicePixelRatio > 1 && !navigator.userAgent.includes("Firefox")) {
num = 3;
}
img.style.height = (document.body.clientHeight - num) + "px";
}
});
if (imgs[imgViewIndex] !== undefined && config.ViewMode != 4 && isPC) {
if (config.shadowGalleryWheel != 2) {
imgs.forEach(e => (e.style.border = ""));
imgs[imgViewIndex].style.border = "solid #32a1ce";
}
setTimeout(() => instantScrollIntoView(imgs[imgViewIndex]), 100);
}
}
if (isM) {
window.addEventListener("deviceorientation", () => {
aspectRatio();
});
} else {
window.addEventListener("resize", () => {
aspectRatio();
});
}
function increaseWidth() {
let imgs = [...document.images];
if (webtoonWidth < 1900 && webtoonWidth < window.innerWidth) {
webtoonWidth = (Number(webtoonWidth) + 50);
config.webtoonWidth = webtoonWidth;
saveConfig();
imgs.forEach(e => (e.style.maxWidth = webtoonWidth + "px"));
} else {
webtoonWidth = isM ? window.innerWidth : 800;
config.webtoonWidth = webtoonWidth;
saveConfig();
imgs.forEach(e => (e.style.maxWidth = webtoonWidth + "px"));
}
}
function reduceWidth() {
let imgs = [...document.images];
if (webtoonWidth > 100) {
webtoonWidth = (Number(webtoonWidth) - 50);
config.webtoonWidth = webtoonWidth;
saveConfig();
imgs.forEach(e => (e.style.maxWidth = webtoonWidth + "px"));
} else {
webtoonWidth = isM ? window.innerWidth : 800;
config.webtoonWidth = webtoonWidth;
saveConfig();
imgs.forEach(e => (e.style.maxWidth = webtoonWidth + "px"));
}
}
function getNextRowElement() {
const eles = [...document.images];
const index = Number(currentReferenceElement.dataset.index);
if (index >= eles.length - 1) {
imgViewIndex = index;
return eles.at(-1);
}
for (let i = index + 1; i < eles.length; i++) {
if (eles[i].offsetTop > currentReferenceElement.offsetTop) {
currentReferenceElement = eles[i];
imgViewIndex = i;
return eles[i];
}
}
imgViewIndex = eles.length - 1;
return eles.at(-1);
}
function getPrevRowElement() {
const eles = [...document.images];
const index = Number(currentReferenceElement.dataset.index);
if (index <= 0) {
imgViewIndex = 0;
return eles.at(0);
}
for (let i = index - 1; i >= 0; i--) {
if (eles[i].offsetTop < currentReferenceElement.offsetTop) {
currentReferenceElement = eles[i];
imgViewIndex = i;
return eles[i];
}
}
imgViewIndex = 0;
return eles.at(0);
}
function simpleLoadImg(img) {
return new Promise((resolve) => {
if (!img) {
resolve();
}
let loadSrc = img.dataset.src;
let temp = new Image();
if ("referrerpolicy" in siteData) {
temp.setAttribute("referrerpolicy", siteData.referrerpolicy);
}
temp.onload = () => {
img.dataset.width = temp.naturalWidth;
img.dataset.height = temp.naturalHeight;
img.classList.add("loaded");
img.src = loadSrc;
temp = null;
resolve();
};
temp.onerror = () => {
if (loadSrc.includes("https://wsrv.nl/")) {
loadSrc = loadSrc.replace("https://wsrv.nl/?url=", "");
} else if (loadSrc.includes(".wp.com/") && !document.title.endsWith("4KHD")) {
loadSrc = loadSrc.replace(/i\\d\\.wp\\.com\\/|\\?.+$/g, "");
}
img.classList.add("error");
img.dataset.src = loadSrc;
img.src = loadSrc;
temp = null;
resolve();
};
temp.src = loadSrc;
});
}
class Queue {
constructor(workerLen) {
this.workerLen = workerLen ?? 4;
this.list = [];
this.worker = new Array(this.workerLen);
}
* executionFunc(index, func, ...args) {
const _this = this;
yield func.call(...args).then(() => {
_this.worker[index] = undefined;
_this.run();
});
}
addList(list) {
for (const item of list) {
this.list.unshift(item);
}
}
run() {
const runIndex = [];
for (let i = 0; i < this.workerLen; i++) {
const len = this.list.length;
if (!this.worker[i] && len > 0) {
this.worker[i] = this.executionFunc(i, ...this.list[len - 1]);
runIndex.push(i);
this.list.pop();
}
}
for (const index of runIndex) {
this.worker[index].next();
}
}
}
function loadImgs(imgs) {
loadQueue = null;
loadQueue = new Queue(Number(config.threading));
loadQueue.addList(imgs.map(img => [simpleLoadImg, null, img]));
loadQueue.run();
}
function createImgElement(mode) {
window.scrollTo({
top: 0
});
const imgBox = document.querySelector("#imgBox");
if (config.ViewMode == 3) {
imgBox.style.direction = "rtl";
} else {
imgBox.style.direction = "";
}
imgViewIndex = -1;
[...document.querySelectorAll(".FixedMenuitem")].forEach(item => item.classList.remove("active"));
imgBox.innerHTML = "";
document.body.style.overflow = "hidden scroll";
document.body.style.direction = "";
const imgElements = newImgs.map((src, i) => {
let img = document.createElement("img");
img.className = mode;
img.dataset.index = i;
img.dataset.fancybox = "gallery";
if ("referrerpolicy" in siteData) {
img.setAttribute("referrerpolicy", siteData.referrerpolicy);
}
img.src = "${loading_bak}";
img.dataset.src = src;
if (thumbnailSrcArray.length > 0) {
img.dataset.thumb = thumbnailSrcArray[i];
} else {
img.dataset.thumb = src;
}
if (config.ViewMode == 4) {
img.style.maxWidth = webtoonWidth + "px";
}
return img;
});
fragment.append(...imgElements);
imgBox.append(fragment);
if (config.ViewMode == 5) {
document.body.style.overflow = "scroll hidden";
imgBox.style.display = "flex";
imgBox.style.height = "100vh";
imgBox.style.width = "fit-content";
imgElements.at(0).classList.add("horizontal_first");
imgElements.at(-1).classList.add("horizontal_last");
} else {
imgBox.style.display = "";
imgBox.style.height = "";
imgBox.style.width = "";
}
if (lightboxSwitch ==1 && lightGallery == 1) {
ViewerJsInstance.update();
} else if (lightboxSwitch == 1){
setFancybox();
}
loadImgs(imgElements);
aspectRatio();
if (isPC && config.ViewMode == 4) {
btnDiv.classList.remove("hide");
} else {
btnDiv.classList.add("hide");
}
currentReferenceElement = imgElements.at(0);
totalNumberOfElements = imgElements.length;
if (config.ViewMode == 5 && ["comic", "hcomic"].some(c => category == c)) {
toggleDirection(imgBox, imgElements);
}
if (["comic"].some(c => category == c)) {
toggle_r_l_border(imgElements);
}
fn.wait(() => imgElements.at(-1)?.offsetHeight > 100).then(() => {
setTimeout(() => {
aspectRatio();
[...document.images].forEach(img => {
fn.imagesObserver.observe(img);
if (config.ViewMode == 5) {
fn.imagesViewObserver.observe(img);
}
if (mode === "horizontal") {
let num = 6;
if (devicePixelRatio > 1 && !navigator.userAgent.includes("Firefox")) {
num = 3;
}
img.style.height = (document.body.clientHeight - num) + "px";
}
});
}, 1000);
});
}
function saveConfig() {
localStorage.setItem("newWindowData", JSON.stringify(config));
}
function defaultImageLayout() {
config.ViewMode = 0;
saveConfig();
createImgElement("default");
document.querySelector("#MenuDefaultItem").classList.add("active");
}
function singleImageLayout() {
config.ViewMode = 1;
saveConfig();
createImgElement("single");
document.querySelector("#MenuSinglePageItem").classList.add("active");
}
function smallImageLayout() {
config.ViewMode = 2;
saveConfig();
createImgElement("small");
document.querySelector("#MenuSmallItem").classList.add("active");
}
function rtlImageLayout() {
config.ViewMode = 3;
saveConfig();
createImgElement("default");
document.querySelector("#MenuRTLItem").classList.add("active");
}
function webtoonImageLayout() {
config.ViewMode = 4;
saveConfig();
createImgElement("webtoon");
document.querySelector("#MenuWebtoonItem").classList.add("active");
}
function horizontalImageLayout() {
config.ViewMode = 5;
saveConfig();
createImgElement("horizontal");
document.querySelector("#MenuHorizontalItem").classList.add("active");
}
if (config.ViewMode == 1) {
singleImageLayout();
} else if (config.ViewMode == 2) {
smallImageLayout();
} else if (config.ViewMode == 3) {
rtlImageLayout();
} else if (config.ViewMode == 4) {
webtoonImageLayout();
} else if (config.ViewMode == 5) {
horizontalImageLayout();
} else {
defaultImageLayout();
}
`;
//注入主要代碼
_GM_addElement(dom.head, "script", {
textContent: newWindowScriptCode
});
} else {
alert("No Image.");
return;
}
};
const hidePageScrollbarY = () => fn.css("html,body{overflow-y:hidden !important}", "overflowYHidden");
let closeGallery;
let isChangeSize = false;
let changeSizeTimeId;
//創建影子畫廊
const createShadowGallery = async (srcs_array = null) => {
if (("fancybox" in siteData) && !("gallery" in siteData && siteData.gallery == 0) || ("gallery" in siteData && siteData.gallery == 1)) {
return createIframeGallery();
}
if (checkGeting() || isOpenGallery || isOpenOptionsUI || !isValidPage) return;
isOpenGallery = true;
if ("SPA" in siteData) {
lastValidPageURL = currentURL;
}
let srcs;
if (isArray(srcs_array)) {
srcs = srcs_array;
} else if ("SPA" in siteData || siteData.repeat == 1 || siteData.infiniteCapture == 1) {
let selector = siteData.capture || siteData.srcset || siteData.imgs;
srcs = await getImgs(selector);
} else if (!("capture" in siteData)) {
globalImgArray.length > 0 ? srcs = globalImgArray : srcs = await getImgs(siteData.srcset || siteData.imgs);
} else {
captureSrcArray.length > 0 ? srcs = captureSrcArray : srcs = await getImgs(siteData.srcset || siteData.imgs);
}
if (srcs.length < 1) {
fn.showMsg(DL.str_44);
return (isOpenGallery = false);
}
fn.hideMsg();
const config = getConfig();
let webtoonWidth = config.webtoonWidth;
let totalNumberOfElements = 0;
let imgViewIndex = -1;
let currentReferenceElement;
let nextButtonIsShown = false;
let isShowAlert = false;
let loopView = _GM_getValue("FullPictureLoadLoopView", 1);
let isOpenChapterList = false;
let chapterListObtained = false;
const mainHtml = `<div id="FullPictureLoadShadowGallery" style="overflow: clip !important;display: initial !important;position: fixed !important;"></div>`;
document.body.insertAdjacentHTML("beforeend", mainHtml);
const FullPictureLoadShadowGallery = ge("#FullPictureLoadShadowGallery");
const shadow = FullPictureLoadShadowGallery.attachShadow({
mode: "closed"
});
const increaseWidth = () => {
if (getType(changeSizeTimeId) == "Number") {
clearTimeout(changeSizeTimeId);
}
isChangeSize = true;
let imgs = gae("img", shadow);
if (webtoonWidth < 1900 && webtoonWidth < _unsafeWindow.innerWidth) {
webtoonWidth = (Number(webtoonWidth) + 50);
config.webtoonWidth = webtoonWidth;
saveConfig(config);
imgs.forEach(e => (e.style.maxWidth = webtoonWidth + "px"));
} else {
webtoonWidth = isM ? _unsafeWindow.innerWidth : 800;
config.webtoonWidth = webtoonWidth;
saveConfig(config);
imgs.forEach(e => (e.style.maxWidth = webtoonWidth + "px"));
}
changeSizeTimeId = setTimeout(() => (isChangeSize = false), 1000);
};
const reduceWidth = () => {
if (getType(changeSizeTimeId) == "Number") {
clearTimeout(changeSizeTimeId);
}
isChangeSize = true;
let imgs = gae("img", shadow);
if (webtoonWidth > 100) {
webtoonWidth = (Number(webtoonWidth) - 50);
config.webtoonWidth = webtoonWidth;
saveConfig(config);
imgs.forEach(e => (e.style.maxWidth = webtoonWidth + "px"));
} else {
webtoonWidth = isM ? _unsafeWindow.innerWidth : 800;
config.webtoonWidth = webtoonWidth;
saveConfig(config);
imgs.forEach(e => (e.style.maxWidth = webtoonWidth + "px"));
}
changeSizeTimeId = setTimeout(() => (isChangeSize = false), 1000);
};
closeGallery = () => {
_unsafeWindow.removeEventListener("resize", aspectRatio);
_unsafeWindow.removeEventListener("keydown", kEvent);
if (!isOpenFilter) fn.remove("#overflowYHidden");
FullPictureLoadShadowGallery?.remove();
isOpenGallery = false;
if (isCaptureMode) {
updateEyeNum(srcs.length);
}
if ("focus" in siteData) {
let selector = siteData.focus;
let ele;
if (isString(selector)) {
if (selector.startsWith("last:")) {
selector = selector.slice(5);
ele = fn.gae(selector).at(-1);
} else {
ele = ge(selector);
}
} else if (isFn(selector)) {
ele = selector();
}
if (!isEle(ele)) return;
setTimeout(() => instantScrollIntoView(ele), 100);
}
if (("closeAF" in siteData) && isFn(siteData.closeAF)) {
siteData.closeAF();
}
};
const toggleWidthEvent = (event) => {
if (!isOpenFancybox && config.ViewMode == 4 && (event.ctrlKey || event.altKey || event.shiftKey)) {
event.preventDefault();
event.stopPropagation();
if (event.deltaY < 0) {
increaseWidth();
}
if (event.deltaY > 0) {
reduceWidth();
}
}
};
FullPictureLoadShadowGallery.addEventListener("wheel", toggleWidthEvent, {
passive: false
});
const getNextRowElement = () => {
const eles = gae("img,#next", shadow);
const index = Number(currentReferenceElement.dataset.index);
if (index >= eles.length - 1) {
imgViewIndex = index;
return eles.at(-1);
}
for (let i = index + 1; i < eles.length; i++) {
if (eles[i].offsetTop > currentReferenceElement.offsetTop) {
currentReferenceElement = eles[i];
imgViewIndex = i;
return eles[i];
}
}
imgViewIndex = eles.length - 1;
return eles.at(-1);
};
const getPrevRowElement = () => {
const eles = gae("img,#next", shadow);
const index = Number(currentReferenceElement.dataset.index);
if (index <= 0) {
imgViewIndex = 0;
return eles.at(0);
}
for (let i = index - 1; i >= 0; i--) {
if (eles[i].offsetTop < currentReferenceElement.offsetTop) {
currentReferenceElement = eles[i];
imgViewIndex = i;
return eles[i];
}
}
imgViewIndex = 0;
return eles.at(0);
};
const toggleImage = (event) => {
if (isOpenChapterList) return;
if (event.shiftKey && config.ViewMode == 5) {
const viewImgs = gae("img.isView", shadow);
const middleIndex = Math.floor(viewImgs.length / 2 - 1);
let img;
if (middleIndex > -1) {
img = viewImgs[middleIndex];
} else {
img = viewImgs[0];
}
imgViewIndex = Number(img.dataset.index);
}
if (!isOpenFancybox && ([0, 1, 3].some(m => config.ViewMode == m) && [1, 2].some(m => config.shadowGalleryWheel == m) || config.ViewMode == 5) && !event.ctrlKey && !event.altKey && !event.shiftKey && !event.metaKey) {
event.preventDefault();
event.stopPropagation();
const imgs = gae("img", shadow);
const next = ge("#next", shadow) || ge("#menuNext", shadow);
const isRTL = mainElement.style.direction == "rtl";
if (config.ViewMode == 5 && (config.horizontalWheel == 0 || config.horizontalWheel == 1)) {
if (isString(nextLink) && (mainElement.scrollWidth - mainElement.offsetWidth) < Math.abs(mainElement.scrollLeft + (isRTL ? -2 : 2)) && event.deltaY > 0) {
if (isShowAlert) {
let num = Number(alertMessage.innerText.match(/\d/));
if (num > 0) {
alertMessage.innerText = DL.str_113 + (num -= 1);
}
if (num <= 0) {
alertMessage.innerText = siteData.category?.includes("comic") ? DL.str_196 : DL.str_197;
return (isGoToNext = true) && setTimeout(() => (location.href = nextLink), 100);
}
}
isShowAlert = true;
alertDiv.classList.remove("hide");
} else if (isString(nextLink)) {
isShowAlert = false;
alertMessage.innerText = DL.str_113 + "3";
alertDiv.classList.add("hide");
}
if (config.horizontalWheel == 0) {
if (isRTL) {
return (mainElement.scrollLeft -= event.deltaY);
} else {
return (mainElement.scrollLeft += event.deltaY);
}
} else if (config.horizontalWheel == 1) {
let num;
if (event.deltaY > 0) {
if (config.jumpNum == 0) {
if (isRTL) {
num = mainElement.scrollLeft - _unsafeWindow.innerWidth;
} else {
num = mainElement.scrollLeft + _unsafeWindow.innerWidth;
}
} else {
if (isRTL) {
num = mainElement.scrollLeft - Number(config.jumpNum);
} else {
num = mainElement.scrollLeft + Number(config.jumpNum);
}
}
} else {
if (config.jumpNum == 0) {
if (isRTL) {
num = mainElement.scrollLeft + _unsafeWindow.innerWidth;
} else {
num = mainElement.scrollLeft - _unsafeWindow.innerWidth;
}
} else {
if (isRTL) {
num = mainElement.scrollLeft + Number(config.jumpNum);
} else {
num = mainElement.scrollLeft - Number(config.jumpNum);
}
}
}
return mainElement.scrollTo({
left: num,
behavior: config.behavior
});
}
}
if (config.shadowGalleryWheel == 1 || config.ViewMode == 5) {
if (isShowAlert && event.deltaY > 0) {
let num = Number(alertMessage.innerText.match(/\d/));
if (num > 0) {
alertMessage.innerText = DL.str_113 + (num -= 1);
}
if (num <= 0) {
alertMessage.innerText = siteData.category?.includes("comic") ? DL.str_196 : DL.str_197;
return (isGoToNext = true) && setTimeout(() => (location.href = nextLink), 100);
}
} else if (event.deltaY > 0 && imgViewIndex >= imgs.length - 1 && config.ViewMode == 5 && isString(nextLink)) {
isShowAlert = true;
alertDiv.classList.remove("hide");
} else if (event.deltaY < 0 && imgViewIndex < 0) {
if (loopView != 1) return;
nextButtonIsShown = false;
if (config.ViewMode == 5) {
isShowAlert = false;
alertMessage.innerText = DL.str_113 + "3";
alertDiv.classList.add("hide");
}
imgViewIndex = imgs.length - 1;
imgs[imgViewIndex].style.border = "solid #32a1ce";
return instantScrollIntoView(imgs[imgViewIndex]);
} else if (event.deltaY < 0 && imgViewIndex >= 0) {
nextButtonIsShown = false;
if (config.ViewMode == 5) {
isShowAlert = false;
alertMessage.innerText = DL.str_113 + "3";
alertDiv.classList.add("hide");
}
imgViewIndex--;
if (imgViewIndex < 0 && loopView != 1) {
imgViewIndex = 0;
return;
}
if (imgViewIndex < 0) imgViewIndex = imgs.length - 1;
if (config.ViewMode != 4) {
imgs.forEach(e => (e.style.border = ""));
if (imgs[imgViewIndex] !== undefined) {
imgs[imgViewIndex].style.border = "solid #32a1ce";
}
}
return instantScrollIntoView(imgs[imgViewIndex]);
} else if (event.deltaY > 0 && nextButtonIsShown) {
next.style.backgroundColor = "gray";
return (isGoToNext = true) && setTimeout(() => (location.href = nextLink), 500);
} else if (event.deltaY > 0 && imgViewIndex <= imgs.length - 1) {
imgViewIndex++;
if (imgViewIndex > imgs.length - 1 && loopView != 1 && !next) {
imgViewIndex = imgs.length - 1;
return;
}
if (imgs[imgViewIndex] === undefined && next && !nextButtonIsShown) {
nextButtonIsShown = true;
next.style.border = "solid #32a1ce";
imgs.forEach(e => (e.style.border = ""));
return instantScrollIntoView(next);
} else if (imgs[imgViewIndex] === undefined) {
imgViewIndex = 0;
}
if (config.ViewMode != 4) {
imgs.forEach(e => (e.style.border = ""));
if (imgs[imgViewIndex] !== undefined) {
imgs[imgViewIndex].style.border = "solid #32a1ce";
}
}
if (imgs[imgViewIndex] !== undefined) {
return instantScrollIntoView(imgs[imgViewIndex]);
}
} else {
imgViewIndex = -1;
}
} else if (config.shadowGalleryWheel == 2) {
if (event.deltaY < 0) {
nextButtonIsShown = false;
if (Number(currentReferenceElement?.dataset?.index) <= 0) return;
imgs.forEach(e => (e.style.border = ""));
return instantScrollIntoView(getPrevRowElement());
}
if (event.deltaY > 0) {
if (Number(currentReferenceElement?.dataset?.index) >= totalNumberOfElements - 1) return;
imgs.forEach(e => (e.style.border = ""));
return instantScrollIntoView(getNextRowElement());
}
}
}
};
FullPictureLoadShadowGallery.addEventListener("wheel", toggleImage, {
passive: false
});
const aspectRatio = () => {
const verticalScreen = _unsafeWindow.innerHeight / _unsafeWindow.innerWidth > 1;
const imgs = gae("img", shadow);
imgs.forEach(img => {
if (verticalScreen && img.className === "default") {
img.style.maxWidth = "96vw";
img.style.maxHeight = "";
img.style.minWidth = "96vw";
img.style.minHeight = "";
} else if (img.className === "default") {
img.style.maxHeight = "calc(100vh - 6px)";
img.style.maxWidth = "100%";
img.style.minHeight = "calc(100vh - 6px)";
img.style.minWidth = "";
}
if (config.ViewMode == 5) {
let num = 6;
if (devicePixelRatio > 1 && !isFirefox) {
num = 3;
}
img.style.height = (mainElement.clientHeight - num) + "px";
}
});
if (imgs[imgViewIndex] !== undefined && config.ViewMode != 4) {
if (config.shadowGalleryWheel != 2) {
imgs.forEach(e => (e.style.border = ""));
imgs[imgViewIndex].style.border = "solid #32a1ce";
}
setTimeout(() => instantScrollIntoView(imgs[imgViewIndex]), 100);
}
};
_unsafeWindow.addEventListener("resize", aspectRatio);
const toggleDirection = (box, imgs) => {
if (box.style.direction == "rtl") {
mainElement.style.direction = "ltr";
box.style.direction = "ltr";
imgs.at(0).classList.remove("horizontal_last");
imgs.at(0).classList.add("horizontal_first");
imgs.at(-1).classList.remove("horizontal_first");
imgs.at(-1).classList.add("horizontal_last");
} else {
mainElement.style.direction = "rtl";
box.style.direction = "rtl";
imgs.at(0).classList.remove("horizontal_first");
imgs.at(0).classList.add("horizontal_last");
imgs.at(-1).classList.remove("horizontal_last");
imgs.at(-1).classList.add("horizontal_first");
}
};
const toggle_r_l_border = (imgs) => {
imgs.forEach(img => {
if (img.classList.contains("no_r_l_border")) {
img.classList.remove("no_r_l_border");
} else {
img.classList.add("no_r_l_border");
}
});
};
const kEvent = (event) => {
if (isOpenFancybox || ["F11", "F12"].some(k => event.code === k || event.key === k) || (config.ViewMode == 5 && event.shiftKey)) return;
const imgs = gae("img", shadow);
const next = ge("#next", shadow);
if (event.code === "Escape" || event.key === "Escape") {
if (isOpenChapterList) {
isOpenChapterList = false;
return list_main.classList.add("hide");
}
return closeGallery();
}
if (event.code === "Numpad0" || event.code === "Digit0" || event.key === "0") return defaultImageLayout();
if (event.code === "Numpad1" || event.code === "Digit1" || event.key === "1") return singleImageLayout();
if (event.code === "Numpad2" || event.code === "Digit2" || event.key === "2") return smallImageLayout();
if (event.code === "Numpad3" || event.code === "Digit3" || event.key === "3") return rtlImageLayout();
if (event.code === "Numpad4" || event.code === "Digit4" || event.key === "4") return webtoonImageLayout();
if (event.code === "Numpad5" || event.code === "Digit5" || event.key === "5") return horizontalImageLayout();
if ((event.code === "Home" || event.key === "Home") || (event.code === "End" || event.key === "End")) {
event.preventDefault();
nextButtonIsShown = false;
if (event.code === "Home" || event.key === "Home") {
imgViewIndex = 0;
} else {
imgViewIndex = imgs.length - 1;
}
const img = imgs[imgViewIndex];
if (config.ViewMode != 4 && ([0, 1, 3].some(m => config.ViewMode == m) && config.shadowGalleryWheel != 2)) {
imgs.forEach(e => (e.style.border = ""));
img.style.border = "solid #32a1ce";
}
currentReferenceElement = img;
return instantScrollIntoView(img);
}
if (event.code === "KeyN" || event.key === "n" || event.key === "N") {
if (isString(nextLink)) {
isShowAlert = true;
alertMessage.innerText = siteData.category?.includes("comic") ? DL.str_196 : DL.str_197;
alertDiv.classList.remove("hide");
if (isEle(next)) {
next.style.backgroundColor = "gray";
}
return (isGoToNext = true) && setTimeout(() => (location.href = nextLink), 100);
}
}
if (event.code === "KeyC" || event.key === "c" || event.key === "C") {
if (chapterListObtained) {
if (isOpenChapterList) {
list_main.classList.add("hide");
isOpenChapterList = false;
} else {
list_main.classList.remove("hide");
isOpenChapterList = true;
const button = ge(".current-chapter", list_main);
list_main.scrollTop = button.offsetTop - (list_main.clientHeight / 2) + button.clientHeight;
}
}
}
if (event.code === "KeyJ" || event.key === "j" || event.key === "J") {
let num;
if (config.ViewMode == 5) {
const isRTL = mainElement.style.direction == "rtl";
if (config.jumpNum == 0) {
if (isRTL) {
num = mainElement.scrollLeft - _unsafeWindow.innerWidth;
} else {
num = mainElement.scrollLeft + _unsafeWindow.innerWidth;
}
} else {
if (isRTL) {
num = mainElement.scrollLeft - Number(config.jumpNum);
} else {
num = mainElement.scrollLeft + Number(config.jumpNum);
}
}
return mainElement.scrollTo({
left: num,
behavior: config.behavior
});
};
if (config.jumpNum == 0) {
if (_unsafeWindow.devicePixelRatio > 1 && [0, 1, 3].some(m => config.ViewMode == m)) {
num = mainElement.scrollTop + imgs[0].offsetHeight;
} else {
num = mainElement.scrollTop + _unsafeWindow.innerHeight;
}
} else {
num = mainElement.scrollTop + Number(config.jumpNum);
}
let lastTop = mainElement.scrollHeight - _unsafeWindow.innerHeight;
if (num >= lastTop) {
num = lastTop;
}
return mainElement.scrollTo({
top: num,
behavior: config.behavior
});
}
if (event.code === "KeyK" || event.key === "k" || event.key === "K") {
let num;
if (config.ViewMode == 5) {
const isRTL = mainElement.style.direction == "rtl";
if (config.jumpNum == 0) {
if (isRTL) {
num = mainElement.scrollLeft + _unsafeWindow.innerWidth;
} else {
num = mainElement.scrollLeft - _unsafeWindow.innerWidth;
}
} else {
if (isRTL) {
num = mainElement.scrollLeft + Number(config.jumpNum);
} else {
num = mainElement.scrollLeft - Number(config.jumpNum);
}
}
return mainElement.scrollTo({
left: num,
behavior: config.behavior
});
};
if (config.jumpNum == 0) {
if (_unsafeWindow.devicePixelRatio > 1 && [0, 1, 3].some(m => config.ViewMode == m)) {
num = mainElement.scrollTop - imgs[0].offsetHeight;
} else {
num = mainElement.scrollTop - _unsafeWindow.innerHeight;
}
} else {
num = mainElement.scrollTop - Number(config.jumpNum);
}
if (num <= 0) {
num = 0;
}
return mainElement.scrollTo({
top: num,
behavior: config.behavior
});
}
if (config.ViewMode == 4 && (["NumpadAdd", "Equal"].some(k => event.code === k) || ["+", "="].some(k => event.code === k))) {
return increaseWidth();
}
if (config.ViewMode == 4 && (["NumpadSubtract", "Minus"].some(k => event.code === k) || ["-", "_"].some(k => event.key === k))) {
return reduceWidth();
}
if ((event.code === "KeyR" || event.key === "r" || event.key === "R") && [0, 2, 3, 5].some(m => config.ViewMode == m)) {
let box = ge("#imgBox", shadow);
if (config.ViewMode == 5) {
toggleDirection(box, imgs);
if (isEle(imgs[imgViewIndex])) {
return instantScrollIntoView(imgs[imgViewIndex]);
}
} else {
if (box.style.direction == "rtl") {
return (box.style.direction = "ltr");
} else {
return (box.style.direction = "rtl");
}
}
}
if ((event.code === "KeyB" || event.key === "b" || event.key === "B") && [0, 2, 3, 5].some(m => config.ViewMode == m)) {
toggle_r_l_border(imgs);
if (isEle(imgs[imgViewIndex])) {
return instantScrollIntoView(imgs[imgViewIndex]);
}
return;
}
if ((["KeyW", "KeyA", "ArrowUp", "ArrowLeft"].some(k => event.code === k) || ["w", "W", "a", "A", "KeyA", "ArrowUp", "ArrowLeft"].some(k => event.key === k)) && imgViewIndex < 0) {
if (config.ViewMode == 4 && (event.code === "ArrowUp" || event.key === "ArrowUp")) return;
if (config.ViewMode == 5 && (event.code === "ArrowLeft" || event.key === "ArrowLeft")) return;
if (loopView != 1) return;
event.preventDefault();
nextButtonIsShown = false;
imgViewIndex = imgs.length - 1;
const img = imgs[imgViewIndex];
if (config.ViewMode != 4) {
imgs.forEach(e => (e.style.border = ""));
img.style.border = "solid #32a1ce";
}
currentReferenceElement = img;
return instantScrollIntoView(img);
} else if ((["KeyW", "KeyA", "ArrowUp", "ArrowLeft"].some(k => event.code === k) || ["w", "W", "a", "A", "KeyA", "ArrowUp", "ArrowLeft"].some(k => event.key === k)) && imgViewIndex >= 0) {
if (config.ViewMode == 4 && (event.code === "ArrowUp" || event.key === "ArrowUp")) return;
if (config.ViewMode == 5 && (event.code === "ArrowLeft" || event.key === "ArrowLeft")) return;
event.preventDefault();
nextButtonIsShown = false;
imgViewIndex--;
if (imgViewIndex < 0 && loopView != 1) {
imgViewIndex = 0;
return;
}
let img = imgs[imgViewIndex];
if (img === undefined) {
imgViewIndex = imgs.length - 1;
img = imgs[imgViewIndex];
}
if (config.ViewMode != 4) {
imgs.forEach(e => (e.style.border = ""));
if (img !== undefined) {
img.style.border = "solid #32a1ce";
}
}
currentReferenceElement = img;
return instantScrollIntoView(img);
} else if ((["KeyS", "KeyD", "ArrowDown", "ArrowRight"].some(k => event.code === k) || ["s", "S", "d", "D", "ArrowDown", "ArrowRight"].some(k => event.key === k)) && nextButtonIsShown) {
if (config.ViewMode == 4 && (event.code === "ArrowDown" || event.key === "ArrowDown")) return;
if (config.ViewMode == 5 && (event.code === "ArrowRight" || event.key === "ArrowRight")) return;
next.style.backgroundColor = "gray";
return (isGoToNext = true) && setTimeout(() => (location.href = nextLink), 500);
} else if ((["KeyS", "KeyD", "ArrowDown", "ArrowRight"].some(k => event.code === k) || ["s", "S", "d", "D", "ArrowDown", "ArrowRight"].some(k => event.key === k)) && imgViewIndex <= imgs.length - 1) {
if (config.ViewMode == 4 && (event.code === "ArrowDown" || event.key === "ArrowDown")) return;
if (config.ViewMode == 5 && (event.code === "ArrowRight" || event.key === "ArrowRight")) return;
event.preventDefault();
imgViewIndex++;
if (imgViewIndex > imgs.length - 1 && loopView != 1 && !next) {
imgViewIndex = imgs.length - 1;
return;
}
let img = imgs[imgViewIndex];
if (config.ViewMode != 4) {
imgs.forEach(e => (e.style.border = ""));
if (img !== undefined) {
img.style.border = "solid #32a1ce";
}
}
if (img === undefined && next && !nextButtonIsShown) {
nextButtonIsShown = true;
next.style.border = "solid #32a1ce";
currentReferenceElement = next;
return instantScrollIntoView(next);
} else if (img === undefined) {
imgViewIndex = 0;
img = imgs[imgViewIndex];
}
currentReferenceElement = img;
return instantScrollIntoView(img);
} else if ((event.code === "Delete" || event.key === "Delete")) {
for (const img of imgs) {
if (!img.classList.contains("hide")) {
img.classList.add("hide");
break;
}
}
if (imgs[imgViewIndex] !== undefined && config.ViewMode != 4) {
if (config.shadowGalleryWheel != 2) {
imgs.forEach(e => (e.style.border = ""));
imgs[imgViewIndex].style.border = "solid #32a1ce";
}
instantScrollIntoView(imgs[imgViewIndex]);
}
return;
} else if ((event.code === "Enter" || event.key === "Enter")) {
imgs.forEach(e => e.classList.remove("hide"));
if (imgs[imgViewIndex] !== undefined && config.ViewMode != 4) {
if (config.shadowGalleryWheel != 2) {
imgs.forEach(e => (e.style.border = ""));
imgs[imgViewIndex].style.border = "solid #32a1ce";
}
instantScrollIntoView(imgs[imgViewIndex]);
}
return;
} else if (!["KeyR", "NumpadAdd", "Equal", "NumpadSubtract", "Minus"].some(k => event.code === k) || !["r", "R", "-", "+", "=", "_"].some(k => event.key === k)) {
imgViewIndex = -1;
}
};
_unsafeWindow.addEventListener("keydown", kEvent);
hidePageScrollbarY();
let placeHeight;
if (isMobileEdge || isMobileYandex) {
placeHeight = "54px";
} else if (isVia || isXBrowser) {
placeHeight = "2px";
} else {
placeHeight = "30px";
}
/**
選單淡入淡出
transform: translate(0);
transition: all .8s ease-in-out;
&:hover {
transform: translate(138px);
transition: all .2s ease-in-out;
}
*/
const style = createStyle(`
#shadowGallery {
z-index: ${UI_zIndex - 3} !important;
}
p#imgBox {
display: block;
min-height: calc(100vh - 70px);
padding: 0;
margin: 0;
}
.place {
height: ${placeHeight};
padding: 0;
margin: 0;
}
#FixedMenu {
text-align: center;
font-family: ui-monospace, sans-serif, system-ui, -apple-system, Segoe UI, Arial;
font-weight: 500;
font-size: 14px;
color: ${config.colorThemes == "dark" ? "#fff" : "#000"};
width: ${isM ? "102px" : "150px"};
height: auto;
padding: 5px 5px 2px 5px;
position: fixed;
left: ${isM ? "0px" : "-156px"};
bottom: 0px;
border: #ccc 1px solid;
border-radius: 3px;
background-color: ${config.colorThemes == "dark" ? "#222" : "#fff"};
z-index: ${UI_zIndex - 3};
opacity: ${isM ? "1" : "0.5"};
&:hover {
left: 0px;
opacity: 1;
}
}
.FixedMenuitem {
width: ${isM ? "90px" : "138px"};
height: 24px;
line-height: 24px;
overflow: hidden;
font-size: 14px;
border: #ccc 1px solid;
background-color: ${config.colorThemes == "dark" ? "#333" : "#f6f6f6"};
padding: 0 5px 0 5px;
margin: 0 2px 3px 0;
cursor: pointer;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#MenuJumpItem {
width: 148px;
padding: 0px;
}
.FixedMenuitem.active {
color: #fff;
background: #1790e6;
}
#setting-btn {
width: auto;
height: auto;
position: fixed;
right: ${isM ? "10px" : "30px"};
bottom: 150px;
z-index: ${UI_zIndex - 3};
}
.setting-btn {
width: 48px;
height: 48px;
text-align: center;
user-select:none;
color: ${config.colorThemes == "dark" ? "#fff" : "#000"};
margin: 5px 0;
overflow: hidden;
border: ${config.colorThemes == "dark" ? "rgb(200, 200, 200) 1px solid" : "rgb(51, 51, 51) 1px solid"};
background: ${config.colorThemes == "dark" ? "rgba(37, 36, 44, 0.8)" : "rgba(255, 255, 255, 0.8)"};
border-radius: 12px;
}
.setting-btn .icon {
margin-top: 10px;
width: 28px;
height: 28px;
}
.hide {
display: none !important;
}
img.default {
vertical-align: middle;
width: auto;
height: auto;
object-fit: contain;
border: solid #fff;
background-color: #fff;
}
img.single {
width: auto;
height: auto;
max-width: calc(100% - 6px);
max-height: calc(100vh - 6px);
display: block;
margin: 0 auto;
border: solid #fff;
}
img.webtoon {
width: 100%;
height: auto;
max-width: 800px;
display: block;
margin: 0 auto;
border: unset;
}
img.small {
display: inline-block;
vertical-align: middle;
width: auto;
height: auto;
max-width: 31.8%;
max-height: 33vh;
border: solid #fff;
}
img.horizontal {
vertical-align: middle;
width: auto;
height: 100%;
object-fit: contain;
border: solid #fff;
background-color: #fff;
}
.horizontal_first {
margin-left: 1em !important;
}
.horizontal_last {
margin-right: 1em !important;
}
.no_r_l_border {
border-right: none !important;
border-left: none !important;
}
#next {
display: block;
text-align: center;
font-family: ui-monospace, sans-serif, system-ui, -apple-system, Segoe UI, Arial;
padding: 10px 0;
margin: ${isM ? "2px" : "6px 1px 6px 7px"};
border: 4px solid #fff;
border-radius: 12px;
color: rgb(0, 0, 0);
background-color: antiquewhite;
font-size: 26px;
line-height: 50px;
height: 50px;
text-decoration: unset;
cursor: pointer;
}
#FixedMenu select {
font-weight: normal;
text-align: center;
color: ${config.colorThemes == "dark" ? "#fff" : "#000"};
background-color: ${config.colorThemes == "dark" ? "#333" : "#f6f6f6"};
border: none;
width: 100%;
height: 100%;
padding: 0 auto;
}
#FixedMenu select option {
text-align: center;
}
#behaviorInput {
vertical-align: middle;
width: 16px;
height: 16px;
margin-top: ${isFirefox ? "2px" : "0px"};
}
#alertBox {
color: #000;
position: fixed;
top: calc(50% - 73px);
left: calc(50% - 125px);
transform: translate(-20%, -50%);
padding: 20px;
background-color: #f9f9f9;
border: 1px solid #ddd;
z-index: ${UI_zIndex - 2};
border-radius: 10px;
font-size: 14px;
text-align: center;
font-family: ui-monospace, sans-serif, system-ui, -apple-system, Segoe UI, Arial;
}
#hint {
font-size: 16px;
font-weight: bold;
}
#alertBox #nextAlert {
float: left;
cursor: pointer;
padding: 5px 22px;
border: 1px solid #ffdb11;
background-color: #ffdb11;
border-radius: 10px 0px 0px 10px;
}
#alertBox #closeAlert {
float: right;
cursor: pointer;
padding: 5px 22px;
border: 1px solid #ebebeb;
background-color: #ebebeb;
border-radius: 0px 10px 10px 0px;
}
#modal-content-list {
background-color: ${config.colorThemes == "dark" ? "#282828" : "#eee"};
position: fixed;
z-index: ${UI_zIndex - 3};
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
padding: 10px;
border: 1px solid #888;
min-width: 350px;
max-width: 600px;
max-height: 90%;
overflow-y: auto;
}
.closeModal {
position: absolute;
color: ${config.colorThemes == "dark" ? "#fff" : "#000"};
font-size: 18px;
font-weight: bold;
cursor: pointer;
}
.chapter-list-container {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 20px;
padding-top: 20px;
}
.chapter-btn {
background-color: ${config.colorThemes == "dark" ? "#3c3c3c" : "#fff"};
color: ${config.colorThemes == "dark" ? "#fff" : "#000"};
border: ${config.colorThemes == "dark" ? "none" : "1px solid #a2a2a2"};
padding: 10px;
cursor: pointer;
border-radius: 5px;
font-size: 13px;
width: calc(33.3333% - 8px);
box-sizing: border-box;
text-align: center;
overflow:hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.chapter-btn:not(.current-chapter):hover {
background-color: #ffa64d;
color: #fff;
}
.current-chapter {
background-color: #1790e6;
color: #fff;
}
#chapters-footer {
margin: 10px 0;
display: flex;
justify-content: flex-end;
}
#footer_close_button {
display: block;
width: 100%;
color: ${config.colorThemes == "dark" ? "#fff" : "#000"};
background-color: ${config.colorThemes == "dark" ? "#454d55" : "#ccc"};
border: none;
border-radius: 5px;
cursor: pointer;
padding: 10px;
box-sizing: content-box;
font-size: 16px;
font-weight: 600;
}
`);
shadow.appendChild(style);
const mainElement = document.createElement("div");
mainElement.id = "shadowGallery";
mainElement.tabIndex = "-1";
Object.assign(mainElement.style, {
left: "0",
right: "0",
top: "0",
bottom: "0",
width: "100vw",
height: "100vh",
margin: "auto",
padding: "0",
position: "fixed",
opacity: "1",
backgroundColor: "#333",
color: "#222",
fontSize: "14px",
overflowY: "scroll",
overflowX: "hidden",
textAlign: "center"
});
shadow.appendChild(mainElement);
let lastScrollTop = 0;
mainElement.addEventListener("scroll", (event) => {
if (mainElement.scrollTop > lastScrollTop) {
if (isM) {
menuDiv.classList.add("hide");
}
if (config.ViewMode == 4) {
ge("#setting-btn", shadow).classList.add("hide");
}
} else if (mainElement.scrollTop < lastScrollTop && !nextButtonIsShown) {
if (isM) {
menuDiv.classList.remove("hide");
}
if (config.ViewMode == 4) {
ge("#setting-btn", shadow).classList.remove("hide");
}
}
lastScrollTop = mainElement.scrollTop;
});
function loadImgs(imgs) {
const loadImgList = imgs.map(img => [simpleLoadImg, null, img]);
const queue = new Queue(Number(config.threading));
queue.addList(loadImgList);
queue.run();
}
async function createGalleryElement(mode) {
mainElement.scrollTo({
top: 0
});
if (!isM) {
mainElement.focus();
}
imgViewIndex = -1;
gae(".FixedMenuitem", shadow).forEach(item => item.classList.remove("active"));
mainElement.style.overflow = "hidden scroll";
mainElement.style.direction = "";
mainElement.innerHTML = "";
menuDiv.style.bottom = "";
const imgElements = srcs.map((src, i) => {
let img = new Image();
img.className = mode;
img.dataset.index = i;
img.dataset.fancybox = "gallery";
if ("referrerpolicy" in siteData) {
img.setAttribute("referrerpolicy", siteData.referrerpolicy);
}
img.src = loading_bak;
img.dataset.src = src;
if (thumbnailSrcArray.length > 0) {
img.dataset.thumb = thumbnailSrcArray[i];
} else {
img.dataset.thumb = src;
}
if (mode === "webtoon") {
img.style.maxWidth = webtoonWidth + "px";
}
return img;
});
if (isM) {
const b = document.createElement("p");
b.className = "place";
fragment.append(b);
}
if (mode === "horizontal") {
imgElements.at(0).classList.add("horizontal_first");
imgElements.at(-1).classList.add("horizontal_last");
}
const p = document.createElement("p");
p.id = "imgBox";
if (config.ViewMode == 3) {
p.style.direction = "rtl";
}
if (isPC && siteData.category.includes("comic") && config.ViewMode != 4 && config.ViewMode != 5) {
if (_unsafeWindow.devicePixelRatio > 1) {
p.style.padding = "2px 8% 0";
} else {
p.style.padding = "0 8%";
}
p.style.margin = "0 auto";
} else if (config.ViewMode == 5) {
p.style.display = "flex";
p.style.height = "100vh";
p.style.width = "fit-content";
mainElement.style.overflow = "scroll hidden";
menuDiv.style.bottom = "20px";
} else if (_unsafeWindow.devicePixelRatio > 1) {
p.style.paddingTop = "1px";
}
p.append(...imgElements);
fragment.append(p);
mainElement.append(fragment);
loadImgs(imgElements);
aspectRatio();
if (isPC && mode === "webtoon") {
btnDiv.classList.remove("hide");
} else {
btnDiv.classList.add("hide");
}
currentReferenceElement = imgElements.at(0);
totalNumberOfElements = imgElements.length;
if (mode === "horizontal" && ["comic", "hcomic"].some(c => siteData.category == c)) {
toggleDirection(p, imgElements);
}
if (["comic"].some(c => siteData.category == c)) {
toggle_r_l_border(imgElements);
}
await fn.wait(() => imgElements.at(-1)?.offsetHeight > 100).then(() => {
setTimeout(() => {
aspectRatio();
gae("img", shadow).forEach(img => {
fn.imagesObserver.observe(img);
if (config.ViewMode == 5) {
fn.imagesViewObserver.observe(img);
}
if (mode === "horizontal") {
let num = 6;
if (devicePixelRatio > 1 && !isFirefox) {
num = 3;
}
img.style.height = (mainElement.clientHeight - num) + "px";
}
});
}, 1000);
});
if (options.fancybox != 1) {
imgElements.forEach(img => {
img.onclick = event => {
cancelDefault(event);
imgViewIndex = Number(img.dataset.index);
currentReferenceElement = event.target;
if (config.ViewMode != 4) {
if (event?.target?.style?.border === "") {
imgElements.forEach(e => (e.style.border = ""));
event.target.style.border = "solid #32a1ce";
} else {
imgElements.forEach(e => (e.style.border = ""));
}
}
}
});
}
if (options.fancybox == 1 && isFn(_unsafeWindow.Fancybox)) {
_unsafeWindow.Fancybox.bind(mainElement, "[data-fancybox]", {
Hash: false,
idle: false,
showClass: false,
hideClass: false,
wheel: FancyboxWheel,
Images: {
Panzoom: {
maxScale: 4
},
zoom: false
},
Slideshow: {
timeout: FancyboxSlideshowTimeoutNum,
},
Carousel: {
transition: FancyboxSlideshowTransition
},
Thumbs: {
showOnStart: false
},
Toolbar: {
display: {
left: ["infobar"],
middle: isM ? ["flipX", "flipY"] : ["zoomIn", "zoomOut", "iterateZoom", "toggle1to1", "rotateCCW", "rotateCW", "flipX", "flipY", "fitX", "fitY", "reset"],
right: ["slideshow", "fullscreen", "thumbs", "close"]
}
},
on: {
done: (fancybox, slide) => {
isOpenFancybox = true;
let slideIndex = slide.index;
let imgs = gae("img", mainElement);
imgs.forEach(e => (e.style.border = ""));
if (fancybox.isCurrentSlide(slide)) {
imgViewIndex = slideIndex;
let img = imgs[slideIndex];
currentReferenceElement = img;
img.style.border = "solid #32a1ce";
instantScrollIntoView(img);
} else {
imgViewIndex = fancybox.getSlide().index;
let img = imgs[imgViewIndex];
currentReferenceElement = img;
img.style.border = "solid #32a1ce";
instantScrollIntoView(img);
}
if (fancybox.carousel.page == 0 && (fancybox.carousel.prevPage == fancybox.carousel.pages.at(-1).index)) {
if (FancyboxAutoClose == 1) {
fancybox.close();
}
if (FancyboxAutoNext == 1) {
if (!!nextLink) {
closeGallery();
fn.showMsg(DL.str_34.n);
setTimeout(() => (location.href = nextLink), 100);
}
}
}
},
close: fancybox => {
document.body.classList.remove("hide-scrollbar");
let slideIndex = fancybox.getSlide().index;
imgViewIndex = slideIndex;
let imgs = gae("img", mainElement);
imgs.forEach(e => (e.style.border = ""));
let img = imgs[imgViewIndex];
currentReferenceElement = img;
img.style.border = "solid #32a1ce";
instantScrollIntoView(img);
setTimeout(() => {
isOpenFancybox = false;
}, 100);
}
}
});
}
if (isString(nextLink) && config.ViewMode != 5) {
totalNumberOfElements = totalNumberOfElements + 1;
const next = document.createElement("div");
next.id = "next";
next.dataset.url = nextLink;
next.dataset.index = imgElements.length;
next.innerText = `${siteData.category?.includes("comic") ? DL.str_143 : DL.str_144}${isM ? "" : "( N )"}`;
mainElement.append(next);
next.addEventListener("click", event => {
cancelDefault(event);
next.style.backgroundColor = "gray";
return (isGoToNext = true) && setTimeout(() => (location.href = nextLink), 200);
});
if (config.shadowGalleryWheel != 1 && [0, 1, 3].some(m => config.ViewMode == m) || [2, 4].some(m => config.ViewMode == m)) {
let isEventAdded = false;
const nextObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
nextButtonIsShown = true;
next.style.border = "solid #32a1ce";
if (isPC) {
alertDiv.classList.remove("hide");
}
if (!isEventAdded) {
isEventAdded = true;
FullPictureLoadShadowGallery.addEventListener("wheel", (event) => {
if (isOpenFancybox || event.ctrlKey || event.altKey || event.shiftKey || event.metaKey) return;
if (event.deltaY < 0) {
next.style.border = "";
nextButtonIsShown = false;
alertMessage.innerText = DL.str_113 + "3";
alertDiv.classList.add("hide");
} else if (event.deltaY > 0 && nextButtonIsShown) {
let num = Number(alertMessage.innerText.match(/\d/));
if (num > 0) {
alertMessage.innerText = DL.str_113 + (num -= 1);
}
if (num <= 0) {
alertMessage.innerText = siteData.category?.includes("comic") ? DL.str_196 : DL.str_197;
next.style.backgroundColor = "gray";
return (isGoToNext = true) && setTimeout(() => (location.href = nextLink), 200);
}
}
}, {
passive: true
});
}
} else {
next.style.border = "";
nextButtonIsShown = false;
alertMessage.innerText = DL.str_113 + "3";
alertDiv.classList.add("hide");
}
});
}, {
threshold: 0.9,
});
setTimeout(() => {
nextObserver.observe(next);
}, 1000);
}
}
if (isM) {
const b = document.createElement("p");
b.className = "place";
mainElement.append(b);
}
}
let menuDiv;
function addFixedMenu() {
menuDiv = document.createElement("div");
menuDiv.id = "FixedMenu";
const menuObj = [{
id: "MenuCancelItem",
text: DL.str_142,
cfn: () => closeGallery()
}, {
id: "MenuSettingsItem",
text: DL.str_85.replace(/\(.\)/, ""),
cfn: () => createPictureLoadOptionsShadowElement()
}, {
id: "MenuFavorItem",
text: DL.str_128.replace(/\(.\)/, ""),
cfn: () => createFavorShadowElement()
}, {
id: "MenuThreadingItem"
}, {
id: "MenuBehaviorItem"
}, {
id: "MenuJumpItem",
}, {
id: "menuHome",
text: DL.str_217,
cfn: () => (location.href = location.origin)
}, {
id: "menuList",
hide: 1,
text: DL.str_216,
cfn: () => {
list_main.classList.remove("hide");
isOpenChapterList = true;
const button = ge(".current-chapter", list_main);
list_main.scrollTop = button.offsetTop - (list_main.clientHeight / 2) + button.clientHeight;
}
}, {
id: "menuNext",
text: `${siteData.category?.includes("comic") ? DL.str_143 : DL.str_144}${isM ? "" : "( N )"}`,
cfn: () => (isGoToNext = true) && setTimeout(() => (location.href = nextLink), 200)
}, {
id: "MenuHorizontalItem",
text: DL.galleryMenu.horizontal,
cfn: () => horizontalImageLayout()
}, {
id: "MenuWebtoonItem",
text: DL.galleryMenu.webtoon,
cfn: () => webtoonImageLayout()
}, {
id: "MenuRTLItem",
text: DL.galleryMenu.rtl,
cfn: () => rtlImageLayout()
}, {
id: "MenuSmallItem",
text: DL.galleryMenu.small,
cfn: () => smallImageLayout()
}, {
id: "MenuSinglePageItem",
text: DL.galleryMenu.single,
cfn: () => singleImageLayout()
}, {
id: "MenuDefaultItem",
text: DL.galleryMenu.default,
cfn: () => defaultImageLayout()
}];
const createMenu = obj => {
if (!isString(nextLink) && obj.id == "menuNext") return;
let item = document.createElement("div");
item.id = obj.id;
item.className = "FixedMenuitem";
if ("hide" in obj) {
item.classList.add("hide");
}
if (!!obj.text) item.innerText = obj.text;
item.oncontextmenu = () => false;
if (!!obj.cfn) item.addEventListener("click", obj.cfn);
menuDiv.append(item);
};
menuObj.forEach(obj => createMenu(obj));
shadow.append(menuDiv);
let threadingSelect = document.createElement("select");
for (let i = 1; i <= 32; i++) {
let option = document.createElement("option");
option.value = i;
option.innerText = DL.str_162 + i;
threadingSelect.append(option);
}
ge("#MenuThreadingItem", menuDiv).append(threadingSelect);
threadingSelect.value = config.threading;
threadingSelect.addEventListener("change", () => {
config.threading = Number(threadingSelect.value);
saveConfig(config);
if (!isM) {
mainElement.focus();
}
});
if (isPC) {
let jumpSelect = document.createElement("select");
for (let i = 0; i <= 100; i++) {
let option = document.createElement("option");
if (i === 0) {
option.value = i;
option.innerText = `${DL.str_150}${DL.str_152}`;
} else {
option.value = i * 50;
option.innerText = `${DL.str_150}${i * 50}px`;
}
jumpSelect.append(option);
}
ge("#MenuJumpItem", menuDiv).append(jumpSelect);
jumpSelect.value = config.jumpNum;
jumpSelect.addEventListener("change", () => {
config.jumpNum = jumpSelect.value;
saveConfig(config);
if (!isM) {
mainElement.focus();
}
});
let behaviorDiv = ge("#MenuBehaviorItem", menuDiv);
let behaviorInput = document.createElement("input");
behaviorInput.id = "behaviorInput";
behaviorInput.type = "checkbox";
behaviorDiv.append(behaviorInput);
let behaviorLabel = document.createElement("label");
behaviorLabel.innerText = DL.str_151;
behaviorDiv.append(behaviorLabel);
behaviorInput.checked = config.behavior == "smooth" ? true : false;
behaviorInput.addEventListener("change", () => {
config.behavior = behaviorInput.checked == true ? "smooth" : "instant";
saveConfig(config);
if (!isM) {
mainElement.focus();
}
});
}
if (isM) {
menuDiv.classList.add("hide");
gae("#MenuBehaviorItem,#MenuJumpItem,#MenuHorizontalItem", menuDiv).forEach(e => e.classList.add("hide"));
}
}
addFixedMenu();
let list_main;
if ("chapters" in siteData) {
// 創建目錄
const get_chapters = siteData.chapters;
const createChapterList = async () => {
let chapterListData = [];
if (isObject(get_chapters)) {
chapterListData = await fn.getChapters(get_chapters);
} else if (isFn(get_chapters)) {
chapterListData = await get_chapters();
}
if (!isArray(chapterListData) || !chapterListData?.length) return;
chapterListObtained = true;
const tempURLs = new Set();
chapterListData = chapterListData.filter(({
url
}) => {
if (tempURLs.has(url) || url == "#") {
return false;
} else {
tempURLs.add(url);
}
return true;
});
ge("#menuList", menuDiv).classList.remove("hide");
list_main = document.createElement("div");
list_main.id = "modal-content-list";
list_main.className = "hide";
const list_close = document.createElement("span");
list_close.id = "closeModal";
list_close.className = "closeModal";
list_close.innerText = `× ${DL.str_132}`;
list_close.addEventListener("click", () => {
list_main.classList.add("hide");
isOpenChapterList = false;
});
list_main.append(list_close);
const list_container = document.createElement("div");
list_container.id = "chapterListContainer";
list_container.className = "chapter-list-container";
list_main.append(list_container);
const pathname = decodeURIComponent(fn.clp());
const search = fn.cls();
let isCurrent = false;
const list = chapterListData.map(({
text,
url
}) => {
const button = document.createElement("button");
button.className = "chapter-btn";
button.innerText = text;
button.dataset.url = url;
if ("checkCurrentChapter" in siteData) {
isCurrent = siteData.checkCurrentChapter(url, text);
}
if (
isCurrent ||
search && url.endsWith(search) ||
!search && decodeURIComponent(url).endsWith(pathname) ||
search.includes("page=") && url.includes(pathname)
) {
button.classList.add("current-chapter");
} else {
button.addEventListener("click", (event) => (location.href = event.target.dataset.url));
}
return button;
});
list_container.append(...list);
const footer = document.createElement("div");
footer.id = "chapters-footer";
const close_button = document.createElement("button");
close_button.id = "footer_close_button";
close_button.innerText = DL.str_132;
close_button.addEventListener("click", () => {
list_main.classList.add("hide");
isOpenChapterList = false;
});
footer.append(close_button);
list_main.append(footer);
shadow.append(list_main);
mainElement.addEventListener("click", () => {
if (isOpenChapterList) {
list_main.classList.add("hide");
isOpenChapterList = false;
}
});
};
createChapterList();
}
let btnDiv;
function addButtons() {
btnDiv = document.createElement("div");
btnDiv.id = "setting-btn";
btnDiv.className = "hide";
const btnObj = [{
id: "addBtn",
svg: '<svg class="icon" fill="currentColor" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><path d="M1024 432v160c0 8.8-7.2 16-16 16H624c-8.8 0-16 7.2-16 16v384c0 8.8-7.2 16-16 16H432c-8.8 0-16-7.2-16-16V624c0-8.8-7.2-16-16-16H16c-8.8 0-16-7.2-16-16V432c0-8.8 7.2-16 16-16h384c8.8 0 16-7.2 16-16V16c0-8.8 7.2-16 16-16h160c8.8 0 16 7.2 16 16v384c0 8.8 7.2 16 16 16h384c8.8 0 16 7.2 16 16z"></path></svg>',
cfn: increaseWidth
}, {
id: "reduceBtn",
svg: '<svg class="icon" fill="currentColor" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><path d="M1024 432v160c0 8.8-7.2 16-16 16H16c-8.8 0-16-7.2-16-16V432c0-8.8 7.2-16 16-16h992c8.8 0 16 7.2 16 16z"></path></svg>',
cfn: reduceWidth
}];
const createDiv = obj => {
let item = document.createElement("div");
item.id = obj.id;
item.className = "setting-btn";
item.innerHTML = obj.svg;
item.oncontextmenu = () => false;
item.addEventListener("click", obj.cfn);
btnDiv.append(item);
};
btnObj.forEach(obj => createDiv(obj));
shadow.append(btnDiv);
}
addButtons();
let alertDiv;
let alertMessage;
let alertHtml = `
<div id="alertBox" class="hide">
<div id="hint">${DL.str_112}</div>
<p id="alertMessage">${DL.str_113}3</p>
<div id="nextAlert">${siteData.category?.includes("comic") ? DL.str_143 : DL.str_144}( N )</div>
<div id="closeAlert">${DL.str_132}</div>
</div>
`;
let alertNode = fn.html(alertHtml);
shadow.append(alertNode);
alertDiv = ge("#alertBox", shadow);
alertMessage = ge("#alertMessage", alertDiv);
ge("#nextAlert", alertDiv).addEventListener("click", event => {
cancelDefault(event);
return (isGoToNext = true) && setTimeout(() => (location.href = nextLink), 100);
});
ge("#closeAlert", alertDiv).addEventListener("click", () => {
isShowAlert = false;
alertMessage.innerText = DL.str_113 + "3";
alertDiv.classList.add("hide");
});
function defaultImageLayout() {
config.ViewMode = 0;
saveConfig(config);
createGalleryElement("default");
ge("#MenuDefaultItem", shadow).classList.add("active");
}
function singleImageLayout() {
config.ViewMode = 1;
saveConfig(config);
createGalleryElement("single");
ge("#MenuSinglePageItem", shadow).classList.add("active");
}
function smallImageLayout() {
config.ViewMode = 2;
saveConfig(config);
createGalleryElement("small");
ge("#MenuSmallItem", shadow).classList.add("active");
}
function rtlImageLayout() {
config.ViewMode = 3;
saveConfig(config);
createGalleryElement("default");
ge("#MenuRTLItem", shadow).classList.add("active");
}
function webtoonImageLayout() {
config.ViewMode = 4;
saveConfig(config);
createGalleryElement("webtoon");
ge("#MenuWebtoonItem", shadow).classList.add("active");
}
function horizontalImageLayout() {
config.ViewMode = 5;
saveConfig(config);
createGalleryElement("horizontal");
ge("#MenuHorizontalItem", shadow).classList.add("active");
}
if (config.ViewMode == 1) {
singleImageLayout();
} else if (config.ViewMode == 2) {
smallImageLayout();
} else if (config.ViewMode == 3) {
rtlImageLayout();
} else if (config.ViewMode == 4) {
webtoonImageLayout();
} else if (config.ViewMode == 5) {
horizontalImageLayout();
} else {
defaultImageLayout();
}
};
//創建框架畫廊
const createIframeGallery = async (srcs_array = null) => {
if (checkGeting() || isOpenGallery || isOpenOptionsUI || !isValidPage) return;
isOpenGallery = true;
if ("SPA" in siteData) {
lastValidPageURL = currentURL;
}
let srcs;
if (isArray(srcs_array)) {
srcs = srcs_array;
} else if ("SPA" in siteData || siteData.repeat == 1 || siteData.infiniteCapture == 1) {
let selector = siteData.capture || siteData.srcset || siteData.imgs;
srcs = await getImgs(selector);
} else if (!("capture" in siteData)) {
globalImgArray.length > 0 ? srcs = globalImgArray : srcs = await getImgs(siteData.srcset || siteData.imgs);
} else {
captureSrcArray.length > 0 ? srcs = captureSrcArray : srcs = await getImgs(siteData.srcset || siteData.imgs);
}
if (srcs.length < 1) {
fn.showMsg(DL.str_44);
return (isOpenGallery = false);
}
fn.hideMsg();
const config = getConfig();
let webtoonWidth = config.webtoonWidth;
let totalNumberOfElements = 0;
let imgViewIndex = -1;
let currentReferenceElement;
let nextButtonIsShown = false;
let isShowAlert = false;
let dNum = 0;
let loopView = _GM_getValue("FullPictureLoadLoopView", 1);
let isOpenChapterList = false;
let chapterListObtained = false;
const iframe = document.createElement("iframe");
iframe.id = "FullPictureLoadIframeGallery";
Object.assign(iframe.style, {
left: "0",
right: "0",
top: "0",
bottom: "0",
width: "100vw",
height: "100vh",
minWidth: "100vw",
minHeight: "100vh",
maxWidth: "100vw",
maxHeight: "100vh",
margin: "auto",
padding: "0",
position: "fixed",
opacity: "1",
backgroundColor: "#333",
color: "#222"
});
document.body.append(iframe);
await new Promise((resolve) => {
iframe.onload = resolve;
iframe.src = "about:blank";
});
const win = iframe.contentWindow;
const dom = iframe.contentDocument;
_GM_addElement(dom.body, "script", {
textContent: FancyboxV5JS
});
_GM_addElement(dom.head, "style", {
textContent: FancyboxV5Css + `
.fancybox__container {
z-index: ${UI_zIndex} !important;
}
`
});
const increaseWidth = () => {
if (getType(changeSizeTimeId) == "Number") {
clearTimeout(changeSizeTimeId);
}
isChangeSize = true;
let imgs = gae("img", mainElement);
if (webtoonWidth < 1900 && webtoonWidth < win.innerWidth) {
webtoonWidth = (Number(webtoonWidth) + 50);
config.webtoonWidth = webtoonWidth;
saveConfig(config);
imgs.forEach(e => (e.style.maxWidth = webtoonWidth + "px"));
} else {
webtoonWidth = isM ? win.innerWidth : 800;
config.webtoonWidth = webtoonWidth;
saveConfig(config);
imgs.forEach(e => (e.style.maxWidth = webtoonWidth + "px"));
}
changeSizeTimeId = setTimeout(() => (isChangeSize = false), 1000);
};
const reduceWidth = () => {
if (getType(changeSizeTimeId) == "Number") {
clearTimeout(changeSizeTimeId);
}
isChangeSize = true;
let imgs = gae("img", mainElement);
if (webtoonWidth > 100) {
webtoonWidth = (Number(webtoonWidth) - 50);
config.webtoonWidth = webtoonWidth;
saveConfig(config);
imgs.forEach(e => (e.style.maxWidth = webtoonWidth + "px"));
} else {
webtoonWidth = isM ? win.innerWidth : 800;
config.webtoonWidth = webtoonWidth;
saveConfig(config);
imgs.forEach(e => (e.style.maxWidth = webtoonWidth + "px"));
}
changeSizeTimeId = setTimeout(() => (isChangeSize = false), 1000);
};
closeGallery = () => {
if (ge("meta[property='og:site_name'][content=禁漫天堂]")) {
_unsafeWindow.removeEventListener("keydown", kEvent);
}
_unsafeWindow.removeEventListener("resize", aspectRatio);
if (!isOpenFilter) fn.remove("#overflowYHidden");
iframe.remove();
isOpenGallery = false;
if (isCaptureMode) {
updateEyeNum(srcs.length);
}
if ("focus" in siteData) {
let selector = siteData.focus;
let ele;
if (isString(selector)) {
if (selector.startsWith("last:")) {
selector = selector.slice(5);
ele = fn.gae(selector).at(-1);
} else {
ele = ge(selector);
}
} else if (isFn(selector)) {
ele = selector();
}
if (!isEle(ele)) return;
setTimeout(() => instantScrollIntoView(ele), 100);
}
if (("closeAF" in siteData) && isFn(siteData.closeAF)) {
siteData.closeAF();
}
};
const toggleWidthEvent = (event) => {
if (!isOpenFancybox && config.ViewMode == 4 && (event.ctrlKey || event.altKey || event.shiftKey)) {
event.preventDefault();
event.stopPropagation();
if (event.deltaY < 0) {
increaseWidth();
}
if (event.deltaY > 0) {
reduceWidth();
}
}
};
dom.addEventListener("wheel", toggleWidthEvent, {
passive: false
});
const getNextRowElement = () => {
const eles = gae("img,#next", mainElement);
const index = Number(currentReferenceElement.dataset.index);
if (index >= eles.length - 1) {
imgViewIndex = index;
return eles.at(-1);
}
for (let i = index + 1; i < eles.length; i++) {
if (eles[i].offsetTop > currentReferenceElement.offsetTop) {
currentReferenceElement = eles[i];
imgViewIndex = i;
return eles[i];
}
}
imgViewIndex = eles.length - 1;
return eles.at(-1);
};
const getPrevRowElement = () => {
const eles = gae("img,#next", mainElement);
const index = Number(currentReferenceElement.dataset.index);
if (index <= 0) {
imgViewIndex = 0;
return eles.at(0);
}
for (let i = index - 1; i >= 0; i--) {
if (eles[i].offsetTop < currentReferenceElement.offsetTop) {
currentReferenceElement = eles[i];
imgViewIndex = i;
return eles[i];
}
}
imgViewIndex = 0;
return eles.at(0);
};
const toggleImage = (event) => {
if (isOpenChapterList) return;
if (event.shiftKey && config.ViewMode == 5) {
const viewImgs = gae("img.isView", mainElement);
const middleIndex = Math.floor(viewImgs.length / 2 - 1);
let img;
if (middleIndex > -1) {
img = viewImgs[middleIndex];
} else {
img = viewImgs[0];
}
imgViewIndex = Number(img.dataset.index);
}
if (!isOpenFancybox && ([0, 1, 3].some(m => config.ViewMode == m) && [1, 2].some(m => config.shadowGalleryWheel == m) || config.ViewMode == 5) && !event.ctrlKey && !event.altKey && !event.shiftKey && !event.metaKey) {
event.preventDefault();
event.stopPropagation();
const imgs = gae("img", mainElement);
const next = ge("#next", mainElement);
const isRTL = mainElement.style.direction == "rtl";
if (config.ViewMode == 5 && (config.horizontalWheel == 0 || config.horizontalWheel == 1)) {
if (isString(nextLink) && (mainElement.scrollWidth - mainElement.offsetWidth) < Math.abs(mainElement.scrollLeft + (isRTL ? -2 : 2)) && event.deltaY > 0) {
if (isShowAlert) {
let num = Number(alertMessage.innerText.match(/\d/));
if (num > 0) {
alertMessage.innerText = DL.str_113 + (num -= 1);
}
if (num <= 0) {
alertMessage.innerText = siteData.category?.includes("comic") ? DL.str_196 : DL.str_197;
return (isGoToNext = true) && setTimeout(() => (location.href = nextLink), 100);
}
}
isShowAlert = true;
alertDiv.classList.remove("hide");
} else if (isString(nextLink)) {
isShowAlert = false;
alertMessage.innerText = DL.str_113 + "3";
alertDiv.classList.add("hide");
}
if (config.horizontalWheel == 0) {
if (isRTL) {
return (mainElement.scrollLeft -= event.deltaY);
} else {
return (mainElement.scrollLeft += event.deltaY);
}
} else if (config.horizontalWheel == 1) {
let num;
if (event.deltaY > 0) {
if (config.jumpNum == 0) {
if (isRTL) {
num = mainElement.scrollLeft - _unsafeWindow.innerWidth;
} else {
num = mainElement.scrollLeft + _unsafeWindow.innerWidth;
}
} else {
if (isRTL) {
num = mainElement.scrollLeft - Number(config.jumpNum);
} else {
num = mainElement.scrollLeft + Number(config.jumpNum);
}
}
} else {
if (config.jumpNum == 0) {
if (isRTL) {
num = mainElement.scrollLeft + _unsafeWindow.innerWidth;
} else {
num = mainElement.scrollLeft - _unsafeWindow.innerWidth;
}
} else {
if (isRTL) {
num = mainElement.scrollLeft + Number(config.jumpNum);
} else {
num = mainElement.scrollLeft - Number(config.jumpNum);
}
}
}
return mainElement.scrollTo({
left: num,
behavior: config.behavior
});
}
}
if (config.shadowGalleryWheel == 1 || config.ViewMode == 5) {
if (isShowAlert && event.deltaY > 0) {
let num = Number(alertMessage.innerText.match(/\d/));
if (num > 0) {
alertMessage.innerText = DL.str_113 + (num -= 1);
}
if (num <= 0) {
alertMessage.innerText = siteData.category?.includes("comic") ? DL.str_196 : DL.str_197;
return (isGoToNext = true) && setTimeout(() => (location.href = nextLink), 100);
}
} else if (event.deltaY > 0 && imgViewIndex >= imgs.length - 1 && config.ViewMode == 5 && isString(nextLink)) {
isShowAlert = true;
alertDiv.classList.remove("hide");
} else if (event.deltaY < 0 && imgViewIndex < 0) {
if (loopView != 1) return;
nextButtonIsShown = false;
if (config.ViewMode == 5) {
isShowAlert = false;
alertMessage.innerText = DL.str_113 + "3";
alertDiv.classList.add("hide");
}
imgViewIndex = imgs.length - 1;
imgs[imgViewIndex].style.border = "solid #32a1ce";
return instantScrollIntoView(imgs[imgViewIndex]);
} else if (event.deltaY < 0 && imgViewIndex >= 0) {
nextButtonIsShown = false;
if (config.ViewMode == 5) {
isShowAlert = false;
alertMessage.innerText = DL.str_113 + "3";
alertDiv.classList.add("hide");
}
imgViewIndex--;
if (imgViewIndex < 0 && loopView != 1) {
imgViewIndex = 0;
return;
}
if (imgViewIndex < 0) imgViewIndex = imgs.length - 1;
if (config.ViewMode != 4) {
imgs.forEach(e => (e.style.border = ""));
if (imgs[imgViewIndex] !== undefined) {
imgs[imgViewIndex].style.border = "solid #32a1ce";
}
}
return instantScrollIntoView(imgs[imgViewIndex]);
} else if (event.deltaY > 0 && nextButtonIsShown) {
next.style.backgroundColor = "gray";
return (isGoToNext = true) && setTimeout(() => (location.href = nextLink), 500);
} else if (event.deltaY > 0 && imgViewIndex <= imgs.length - 1) {
imgViewIndex++;
if (imgViewIndex > imgs.length - 1 && loopView != 1 && !next) {
imgViewIndex = imgs.length - 1;
return;
}
if (imgs[imgViewIndex] === undefined && next && !nextButtonIsShown) {
nextButtonIsShown = true;
next.style.border = "solid #32a1ce";
imgs.forEach(e => (e.style.border = ""));
return instantScrollIntoView(next);
} else if (imgs[imgViewIndex] === undefined) {
imgViewIndex = 0;
}
if (config.ViewMode != 4) {
imgs.forEach(e => (e.style.border = ""));
if (imgs[imgViewIndex] !== undefined) {
imgs[imgViewIndex].style.border = "solid #32a1ce";
}
}
if (imgs[imgViewIndex] !== undefined) {
return instantScrollIntoView(imgs[imgViewIndex]);
}
} else {
imgViewIndex = -1;
}
} else if (config.shadowGalleryWheel == 2) {
if (event.deltaY < 0) {
nextButtonIsShown = false;
if (Number(currentReferenceElement?.dataset?.index) <= 0) return;
imgs.forEach(e => (e.style.border = ""));
return instantScrollIntoView(getPrevRowElement());
}
if (event.deltaY > 0) {
if (Number(currentReferenceElement?.dataset?.index) >= totalNumberOfElements - 1) return;
imgs.forEach(e => (e.style.border = ""));
return instantScrollIntoView(getNextRowElement());
}
}
}
};
dom.addEventListener("wheel", toggleImage, {
passive: false
});
const aspectRatio = () => {
const verticalScreen = win.innerHeight / win.innerWidth > 1;
const imgs = gae("img", mainElement);
imgs.forEach(img => {
if (verticalScreen && img.className === "default") {
img.style.maxWidth = "96vw";
img.style.maxHeight = "";
img.style.minWidth = "96vw";
img.style.minHeight = "";
} else if (img.className === "default") {
img.style.maxHeight = "calc(100vh - 6px)";
img.style.maxWidth = "100%";
img.style.minHeight = "calc(100vh - 6px)";
img.style.minWidth = "";
}
if (config.ViewMode == 5) {
let num = 6;
if (devicePixelRatio > 1 && !isFirefox) {
num = 3;
}
img.style.height = (mainElement.clientHeight - num) + "px";
}
});
if (imgs[imgViewIndex] !== undefined && config.ViewMode != 4) {
if (config.shadowGalleryWheel != 2) {
imgs.forEach(e => (e.style.border = ""));
imgs[imgViewIndex].style.border = "solid #32a1ce";
}
setTimeout(() => instantScrollIntoView(imgs[imgViewIndex]), 100);
}
};
_unsafeWindow.addEventListener("resize", aspectRatio);
const toggleDirection = (box, imgs) => {
if (box.style.direction == "rtl") {
mainElement.style.direction = "ltr";
box.style.direction = "ltr";
imgs.at(0).classList.remove("horizontal_last");
imgs.at(0).classList.add("horizontal_first");
imgs.at(-1).classList.remove("horizontal_first");
imgs.at(-1).classList.add("horizontal_last");
} else {
mainElement.style.direction = "rtl";
box.style.direction = "rtl";
imgs.at(0).classList.remove("horizontal_first");
imgs.at(0).classList.add("horizontal_last");
imgs.at(-1).classList.remove("horizontal_last");
imgs.at(-1).classList.add("horizontal_first");
}
};
const toggle_r_l_border = (imgs) => {
imgs.forEach(img => {
if (img.classList.contains("no_r_l_border")) {
img.classList.remove("no_r_l_border");
} else {
img.classList.add("no_r_l_border");
}
});
};
const kEvent = (event) => {
if (isOpenFancybox || ["F11", "F12"].some(k => event.code === k || event.key === k) || (config.ViewMode == 5 && event.shiftKey)) return;
const imgs = gae("img", mainElement);
const next = ge("#next", mainElement) || ge("#menuNext", menuDiv);
if (event.code === "Escape" || event.key === "Escape") {
if (isOpenChapterList) {
isOpenChapterList = false;
return list_main.classList.add("hide");
}
return closeGallery();
}
if (event.code === "Numpad0" || event.code === "Digit0" || event.key === "0") return defaultImageLayout();
if (event.code === "Numpad1" || event.code === "Digit1" || event.key === "1") return singleImageLayout();
if (event.code === "Numpad2" || event.code === "Digit2" || event.key === "2") return smallImageLayout();
if (event.code === "Numpad3" || event.code === "Digit3" || event.key === "3") return rtlImageLayout();
if (event.code === "Numpad4" || event.code === "Digit4" || event.key === "4") return webtoonImageLayout();
if (event.code === "Numpad5" || event.code === "Digit5" || event.key === "5") return horizontalImageLayout();
if ((event.code === "Home" || event.key === "Home") || (event.code === "End" || event.key === "End")) {
event.preventDefault();
nextButtonIsShown = false;
if (event.code === "Home" || event.key === "Home") {
imgViewIndex = 0;
} else {
imgViewIndex = imgs.length - 1;
}
const img = imgs[imgViewIndex];
if (config.ViewMode != 4 && ([0, 1, 3].some(m => config.ViewMode == m) && config.shadowGalleryWheel != 2)) {
imgs.forEach(e => (e.style.border = ""));
img.style.border = "solid #32a1ce";
}
currentReferenceElement = img;
return instantScrollIntoView(img);
}
if (event.code === "KeyN" || event.key === "n" || event.key === "N") {
if (isString(nextLink)) {
isShowAlert = true;
alertMessage.innerText = siteData.category?.includes("comic") ? DL.str_196 : DL.str_197;
alertDiv.classList.remove("hide");
if (isEle(next)) {
next.style.backgroundColor = "gray";
}
return (isGoToNext = true) && setTimeout(() => (location.href = nextLink), 100);
}
}
if (event.code === "KeyC" || event.key === "c" || event.key === "C") {
if (chapterListObtained) {
if (isOpenChapterList) {
list_main.classList.add("hide");
isOpenChapterList = false;
} else {
list_main.classList.remove("hide");
isOpenChapterList = true;
const button = ge(".current-chapter", list_main);
list_main.scrollTop = button.offsetTop - (list_main.clientHeight / 2) + button.clientHeight;
}
}
}
if (event.code === "KeyJ" || event.key === "j" || event.key === "J") {
let num;
if (config.ViewMode == 5) {
const isRTL = mainElement.style.direction == "rtl";
if (config.jumpNum == 0) {
if (isRTL) {
num = mainElement.scrollLeft - _unsafeWindow.innerWidth;
} else {
num = mainElement.scrollLeft + _unsafeWindow.innerWidth;
}
} else {
if (isRTL) {
num = mainElement.scrollLeft - Number(config.jumpNum);
} else {
num = mainElement.scrollLeft + Number(config.jumpNum);
}
}
return mainElement.scrollTo({
left: num,
behavior: config.behavior
});
};
if (config.jumpNum == 0) {
if (_unsafeWindow.devicePixelRatio > 1 && [0, 1, 3].some(m => config.ViewMode == m)) {
num = mainElement.scrollTop + imgs[0].offsetHeight;
} else {
num = mainElement.scrollTop + win.innerHeight;
}
} else {
num = mainElement.scrollTop + Number(config.jumpNum);
}
let lastTop = mainElement.scrollHeight - win.innerHeight;
if (num >= lastTop) {
num = lastTop;
}
return mainElement.scrollTo({
top: num,
behavior: config.behavior
});
}
if (event.code === "KeyK" || event.key === "k" || event.key === "K") {
let num;
if (config.ViewMode == 5) {
const isRTL = mainElement.style.direction == "rtl";
if (config.jumpNum == 0) {
if (isRTL) {
num = mainElement.scrollLeft + _unsafeWindow.innerWidth;
} else {
num = mainElement.scrollLeft - _unsafeWindow.innerWidth;
}
} else {
if (isRTL) {
num = mainElement.scrollLeft + Number(config.jumpNum);
} else {
num = mainElement.scrollLeft - Number(config.jumpNum);
}
}
return mainElement.scrollTo({
left: num,
behavior: config.behavior
});
};
if (config.jumpNum == 0) {
if (_unsafeWindow.devicePixelRatio > 1 && [0, 1, 3].some(m => config.ViewMode == m)) {
num = mainElement.scrollTop - imgs[0].offsetHeight;
} else {
num = mainElement.scrollTop - win.innerHeight;
}
} else {
num = mainElement.scrollTop - Number(config.jumpNum);
}
if (num <= 0) {
num = 0;
}
return mainElement.scrollTo({
top: num,
behavior: config.behavior
});
}
if (config.ViewMode == 4 && (["NumpadAdd", "Equal"].some(k => event.code === k) || ["+", "="].some(k => event.code === k))) {
return increaseWidth();
}
if (config.ViewMode == 4 && (["NumpadSubtract", "Minus"].some(k => event.code === k) || ["-", "_"].some(k => event.key === k))) {
return reduceWidth();
}
if ((event.code === "KeyR" || event.key === "r" || event.key === "R") && [0, 2, 3, 5].some(m => config.ViewMode == m)) {
let box = ge("#imgBox", mainElement);
if (config.ViewMode == 5) {
toggleDirection(box, imgs);
if (isEle(imgs[imgViewIndex])) {
return instantScrollIntoView(imgs[imgViewIndex]);
}
} else {
if (box.style.direction == "rtl") {
return (box.style.direction = "ltr");
} else {
return (box.style.direction = "rtl");
}
}
}
if ((event.code === "KeyB" || event.key === "b" || event.key === "B") && [0, 2, 3, 5].some(m => config.ViewMode == m)) {
toggle_r_l_border(imgs);
if (isEle(imgs[imgViewIndex])) {
return instantScrollIntoView(imgs[imgViewIndex]);
}
return;
}
if ((["KeyW", "KeyA", "ArrowUp", "ArrowLeft"].some(k => event.code === k) || ["w", "W", "a", "A", "KeyA", "ArrowUp", "ArrowLeft"].some(k => event.key === k)) && imgViewIndex < 0) {
if (config.ViewMode == 4 && (event.code === "ArrowUp" || event.key === "ArrowUp")) return;
if (config.ViewMode == 5 && (event.code === "ArrowLeft" || event.key === "ArrowLeft")) return;
if (loopView != 1) return;
event.preventDefault();
nextButtonIsShown = false;
imgViewIndex = imgs.length - 1;
const img = imgs[imgViewIndex];
if (config.ViewMode != 4) {
imgs.forEach(e => (e.style.border = ""));
img.style.border = "solid #32a1ce";
}
currentReferenceElement = img;
return instantScrollIntoView(img);
} else if ((["KeyW", "KeyA", "ArrowUp", "ArrowLeft"].some(k => event.code === k) || ["w", "W", "a", "A", "KeyA", "ArrowUp", "ArrowLeft"].some(k => event.key === k)) && imgViewIndex >= 0) {
if (config.ViewMode == 4 && (event.code === "ArrowUp" || event.key === "ArrowUp")) return;
if (config.ViewMode == 5 && (event.code === "ArrowLeft" || event.key === "ArrowLeft")) return;
event.preventDefault();
nextButtonIsShown = false;
imgViewIndex--;
if (imgViewIndex < 0 && loopView != 1) {
imgViewIndex = 0;
return;
}
let img = imgs[imgViewIndex];
if (img === undefined) {
imgViewIndex = imgs.length - 1;
img = imgs[imgViewIndex];
}
if (config.ViewMode != 4) {
imgs.forEach(e => (e.style.border = ""));
if (img !== undefined) {
img.style.border = "solid #32a1ce";
}
}
currentReferenceElement = img;
return instantScrollIntoView(img);
} else if ((["KeyS", "KeyD", "ArrowDown", "ArrowRight"].some(k => event.code === k) || ["s", "S", "d", "D", "ArrowDown", "ArrowRight"].some(k => event.key === k)) && nextButtonIsShown) {
if (config.ViewMode == 4 && (event.code === "ArrowDown" || event.key === "ArrowDown")) return;
if (config.ViewMode == 5 && (event.code === "ArrowRight" || event.key === "ArrowRight")) return;
next.style.backgroundColor = "gray";
return (isGoToNext = true) && setTimeout(() => (location.href = nextLink), 500);
} else if ((["KeyS", "KeyD", "ArrowDown", "ArrowRight"].some(k => event.code === k) || ["s", "S", "d", "D", "ArrowDown", "ArrowRight"].some(k => event.key === k)) && imgViewIndex <= imgs.length - 1) {
if (config.ViewMode == 4 && (event.code === "ArrowDown" || event.key === "ArrowDown")) return;
if (config.ViewMode == 5 && (event.code === "ArrowRight" || event.key === "ArrowRight")) return;
event.preventDefault();
imgViewIndex++;
if (imgViewIndex > imgs.length - 1 && loopView != 1 && !next) {
imgViewIndex = imgs.length - 1;
return;
}
let img = imgs[imgViewIndex];
if (config.ViewMode != 4) {
imgs.forEach(e => (e.style.border = ""));
if (img !== undefined) {
img.style.border = "solid #32a1ce";
}
}
if (img === undefined && next && !nextButtonIsShown) {
nextButtonIsShown = true;
next.style.border = "solid #32a1ce";
currentReferenceElement = next;
return instantScrollIntoView(next);
} else if (img === undefined) {
imgViewIndex = 0;
img = imgs[imgViewIndex];
}
currentReferenceElement = img;
return instantScrollIntoView(img);
} else if ((event.code === "Delete" || event.key === "Delete")) {
for (const img of imgs) {
if (!img.classList.contains("hide")) {
img.classList.add("hide");
break;
}
}
if (imgs[imgViewIndex] !== undefined && config.ViewMode != 4) {
if (config.shadowGalleryWheel != 2) {
imgs.forEach(e => (e.style.border = ""));
imgs[imgViewIndex].style.border = "solid #32a1ce";
}
instantScrollIntoView(imgs[imgViewIndex]);
}
return;
} else if ((event.code === "Enter" || event.key === "Enter")) {
imgs.forEach(e => e.classList.remove("hide"));
if (imgs[imgViewIndex] !== undefined && config.ViewMode != 4) {
if (config.shadowGalleryWheel != 2) {
imgs.forEach(e => (e.style.border = ""));
imgs[imgViewIndex].style.border = "solid #32a1ce";
}
instantScrollIntoView(imgs[imgViewIndex]);
}
return;
} else if (!["KeyR", "NumpadAdd", "Equal", "NumpadSubtract", "Minus"].some(k => event.code === k) || !["r", "R", "-", "+", "=", "_"].some(k => event.key === k)) {
imgViewIndex = -1;
}
};
if (ge("meta[property='og:site_name'][content=禁漫天堂]")) {
_unsafeWindow.addEventListener("keydown", kEvent);
} else {
dom.addEventListener("keydown", kEvent);
}
hidePageScrollbarY();
let placeHeight;
if (isMobileEdge || isMobileYandex) {
placeHeight = "54px";
} else if (isVia || isXBrowser) {
placeHeight = "2px";
} else {
placeHeight = "30px";
}
_GM_addElement(dom.head, "style", {
textContent: `
#iframeGallery {
z-index: ${UI_zIndex - 3} !important;
}
p#imgBox {
display: block;
min-height: calc(100vh - 70px);
padding: 0;
margin: 0;
}
.place {
height: ${placeHeight};
padding: 0;
margin: 0;
}
#FixedMenu {
text-align: center;
font-family: ui-monospace, sans-serif, system-ui, -apple-system, Segoe UI, Arial;
font-weight: 500;
font-size: 14px;
color: ${config.colorThemes == "dark" ? "#fff" : "#000"};
width: ${isM ? "102px" : "150px"};
height: auto;
padding: 5px 5px 2px 5px;
position: fixed;
left: ${isM ? "0px" : "-156px"};
bottom: ${isM ? "54px" : "0px"};
border: #ccc 1px solid;
border-radius: 3px;
background-color: ${config.colorThemes == "dark" ? "#222" : "#fff"};
z-index: ${UI_zIndex - 3};
opacity: ${isM ? "1" : "0.5"};
&:hover {
left: 0px;
opacity: 1;
}
}
.FixedMenuitem {
width: ${isM ? "90px" : "138px"};
height: 24px;
line-height: 24px;
overflow: hidden;
font-size: 14px;
border: #ccc 1px solid;
background-color: ${config.colorThemes == "dark" ? "#333" : "#f6f6f6"};
padding: 0 5px 0 5px;
margin: 0 2px 3px 0;
cursor: pointer;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#MenuJumpItem {
width: 148px;
padding: 0px;
}
.FixedMenuitem.active {
color: #fff;
background: #1790e6;
}
#setting-btn {
width: auto;
height: auto;
position: fixed;
right: ${isM ? "10px" : "30px"};
bottom: 150px;
z-index: ${UI_zIndex - 3};
}
.setting-btn {
width: 48px;
height: 48px;
text-align: center;
user-select:none;
color: ${config.colorThemes == "dark" ? "#fff" : "#000"};
margin: 5px 0;
overflow: hidden;
border: ${config.colorThemes == "dark" ? "rgb(200, 200, 200) 1px solid" : "rgb(51, 51, 51) 1px solid"};
background: ${config.colorThemes == "dark" ? "rgba(37, 36, 44, 0.8)" : "rgba(255, 255, 255, 0.8)"};
border-radius: 12px;
}
.setting-btn .icon {
margin-top: 10px;
width: 28px;
height: 28px;
}
.hide {
display: none !important;
}
img.default {
vertical-align: middle;
width: auto;
height: auto;
object-fit: contain;
border: solid #fff;
background-color: #fff;
}
img.single {
width: auto;
height: auto;
max-width: calc(100% - 6px);
max-height: calc(100vh - 6px);
display: block;
margin: 0 auto;
border: solid #fff;
}
img.webtoon {
width: 100%;
height: auto;
max-width: 800px;
display: block;
margin: 0 auto;
border: unset;
}
img.small {
display: inline-block;
vertical-align: middle;
width: auto;
height: auto;
max-width: 31.8%;
max-height: 33vh;
border: solid #fff;
}
img.horizontal {
vertical-align: middle;
width: auto;
height: 100%;
object-fit: contain;
border: solid #fff;
background-color: #fff;
}
.horizontal_first {
margin-left: 1em !important;
}
.horizontal_last {
margin-right: 1em !important;
}
.no_r_l_border {
border-right: none !important;
border-left: none !important;
}
#next {
display: block;
text-align: center;
font-family: ui-monospace, sans-serif, system-ui, -apple-system, Segoe UI, Arial;
padding: 10px 0;
margin: ${isM ? "2px" : "6px 1px 6px 7px"};
border: solid #fff;
border-radius: 12px;
color: rgb(0, 0, 0);
background-color: antiquewhite;
font-size: 26px;
line-height: 50px;
height: 50px;
text-decoration: unset;
cursor: pointer;
}
#FixedMenu select {
font-weight: normal;
text-align: center;
color: ${config.colorThemes == "dark" ? "#fff" : "#000"};
background-color: ${config.colorThemes == "dark" ? "#333" : "#f6f6f6"};
border: none;
width: 100%;
height: 100%;
padding: 0 auto;
}
#FixedMenu select option {
text-align: center;
}
#behaviorInput {
vertical-align: middle;
width: 16px;
height: 16px;
margin-top: ${isFirefox ? "2px" : "0px"};
}
#alertBox {
color: #000;
position: fixed;
top: calc(50% - 73px);
left: calc(50% - 125px);
transform: translate(-20%, -50%);
padding: 20px;
background-color: #f9f9f9;
border: 1px solid #ddd;
z-index: ${UI_zIndex - 2};
border-radius: 10px;
font-size: 14px;
text-align: center;
font-family: ui-monospace, sans-serif, system-ui, -apple-system, Segoe UI, Arial;
}
#hint {
font-size: 16px;
font-weight: bold;
}
#alertBox #nextAlert {
float: left;
cursor: pointer;
padding: 5px 22px;
border: 1px solid #ffdb11;
background-color: #ffdb11;
border-radius: 10px 0px 0px 10px;
}
#alertBox #closeAlert {
float: right;
cursor: pointer;
padding: 5px 22px;
border: 1px solid #ebebeb;
background-color: #ebebeb;
border-radius: 0px 10px 10px 0px;
}
#modal-content-list {
background-color: ${config.colorThemes == "dark" ? "#282828" : "#eee"};
position: fixed;
z-index: ${UI_zIndex - 3};
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
padding: 10px;
border: 1px solid #888;
min-width: 350px;
max-width: 600px;
max-height: 90%;
overflow-y: auto;
}
.closeModal {
position: absolute;
color: ${config.colorThemes == "dark" ? "#fff" : "#000"};
font-size: 18px;
font-weight: bold;
cursor: pointer;
}
.chapter-list-container {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 20px;
padding-top: 20px;
}
.chapter-btn {
background-color: ${config.colorThemes == "dark" ? "#3c3c3c" : "#fff"};
color: ${config.colorThemes == "dark" ? "#fff" : "#000"};
border: ${config.colorThemes == "dark" ? "none" : "1px solid #a2a2a2"};
padding: 10px;
cursor: pointer;
border-radius: 5px;
font-size: 13px;
width: calc(33.3333% - 8px);
box-sizing: border-box;
text-align: center;
overflow:hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.chapter-btn:not(.current-chapter):hover {
background-color: #ffa64d;
color: #fff;
}
.current-chapter {
background-color: #1790e6;
color: #fff;
}
#chapters-footer {
margin: 10px 0;
display: flex;
justify-content: flex-end;
}
#footer_close_button {
display: block;
width: 100%;
color: ${config.colorThemes == "dark" ? "#fff" : "#000"};
background-color: ${config.colorThemes == "dark" ? "#454d55" : "#ccc"};
border: none;
border-radius: 5px;
cursor: pointer;
padding: 10px;
box-sizing: content-box;
font-size: 16px;
font-weight: 600;
}
`
});
if (_GM_getValue("FancyboxSlideshowTransition") === "no") {
_GM_addElement(dom.head, "style", {
textContent: `
.fancybox__container .to-next>.fancybox__content,
.fancybox__container .to-prev>.fancybox__content {
display: none !important
}
`
});
}
const mainElement = dom.createElement("div");
mainElement.id = "iframeGallery";
mainElement.tabIndex = "-1";
Object.assign(mainElement.style, {
left: "0",
right: "0",
top: "0",
bottom: "0",
width: "100vw",
height: "100vh",
margin: "auto",
padding: "0",
position: "fixed",
opacity: "1",
backgroundColor: "#333",
color: "#222",
fontSize: "14px",
overflowY: "scroll",
overflowX: "hidden",
textAlign: "center"
});
dom.body.appendChild(mainElement);
let lastScrollTop = 0;
mainElement.addEventListener("scroll", (event) => {
if (mainElement.scrollTop > lastScrollTop) {
if (isM) {
menuDiv.classList.add("hide");
}
if (config.ViewMode == 4) {
ge("#setting-btn", dom).classList.add("hide");
}
} else if (mainElement.scrollTop < lastScrollTop && !nextButtonIsShown) {
if (isM) {
menuDiv.classList.remove("hide");
}
if (config.ViewMode == 4) {
ge("#setting-btn", dom).classList.remove("hide");
}
}
lastScrollTop = mainElement.scrollTop;
});
function loadImgs(imgs) {
const loadImgList = imgs.map(img => [simpleLoadImg, null, img]);
const queue = new Queue(Number(config.threading));
queue.addList(loadImgList);
queue.run();
}
async function createGalleryElement(mode) {
mainElement.scrollTo({
top: 0
});
if (!isM) {
mainElement.focus();
}
imgViewIndex = -1;
gae(".FixedMenuitem", dom).forEach(item => item.classList.remove("active"));
mainElement.style.overflow = "hidden scroll";
mainElement.style.direction = "";
mainElement.innerHTML = "";
menuDiv.style.bottom = "";
const imgElements = srcs.map((src, i) => {
let img = new Image();
img.className = mode;
img.dataset.index = i;
img.dataset.fancybox = "gallery";
if ("referrerpolicy" in siteData) {
img.setAttribute("referrerpolicy", siteData.referrerpolicy);
}
img.src = loading_bak;
img.dataset.src = src;
if (thumbnailSrcArray.length > 0) {
img.dataset.thumb = thumbnailSrcArray[i];
} else {
img.dataset.thumb = src;
}
if (mode === "webtoon") {
img.style.maxWidth = webtoonWidth + "px";
}
return img;
});
if (isM) {
const b = document.createElement("p");
b.className = "place";
fragment.append(b);
}
if (mode === "horizontal") {
imgElements.at(0).classList.add("horizontal_first");
imgElements.at(-1).classList.add("horizontal_last");
}
const p = document.createElement("p");
p.id = "imgBox";
if (config.ViewMode == 3) {
p.style.direction = "rtl";
}
if (isPC && siteData.category.includes("comic") && config.ViewMode != 4 && config.ViewMode != 5) {
if (_unsafeWindow.devicePixelRatio > 1) {
p.style.padding = "2px 8% 0";
} else {
p.style.padding = "0 8%";
}
p.style.margin = "0 auto";
} else if (config.ViewMode == 5) {
p.style.display = "flex";
p.style.height = "100vh";
p.style.width = "fit-content";
mainElement.style.overflow = "scroll hidden";
menuDiv.style.bottom = "20px";
} else if (_unsafeWindow.devicePixelRatio > 1) {
p.style.paddingTop = "1px";
}
p.append(...imgElements);
fragment.append(p);
mainElement.append(fragment);
loadImgs(imgElements);
aspectRatio();
if (isPC && mode === "webtoon") {
btnDiv.classList.remove("hide");
} else {
btnDiv.classList.add("hide");
}
currentReferenceElement = imgElements.at(0);
totalNumberOfElements = imgElements.length;
if (mode === "horizontal" && ["comic", "hcomic"].some(c => siteData.category == c)) {
toggleDirection(p, imgElements);
}
if (["comic"].some(c => siteData.category == c)) {
toggle_r_l_border(imgElements);
}
await fn.wait(() => imgElements.at(-1)?.offsetHeight > 100).then(() => {
setTimeout(() => {
aspectRatio();
gae("img", mainElement).forEach(img => {
fn.imagesObserver.observe(img);
if (config.ViewMode == 5) {
fn.imagesViewObserver.observe(img);
}
if (mode === "horizontal") {
let num = 6;
if (devicePixelRatio > 1 && !isFirefox) {
num = 3;
}
img.style.height = (mainElement.clientHeight - num) + "px";
}
});
}, 1000);
});
if (options.fancybox != 1) {
imgElements.forEach(img => {
img.onclick = event => {
cancelDefault(event);
imgViewIndex = Number(img.dataset.index);
currentReferenceElement = event.target;
if (config.ViewMode != 4) {
if (event?.target?.style?.border === "") {
imgElements.forEach(e => (e.style.border = ""));
event.target.style.border = "solid #32a1ce";
} else {
imgElements.forEach(e => (e.style.border = ""));
}
}
}
});
}
if (options.fancybox == 1) {
gae("img", mainElement).forEach(img => {
img.addEventListener("click", (event) => {
cancelDefault(event);
const Fancybox = win.Fancybox;
if (Fancyboxl10nV5() != "EN") {
Fancybox.defaults.l10n = Fancyboxl10nV5();
}
const index = Number(event.target.dataset.index);
Fancybox.fromNodes(gae("[data-fancybox]", mainElement), {
Hash: false,
idle: false,
showClass: false,
hideClass: false,
wheel: FancyboxWheel,
startIndex: index,
Images: {
Panzoom: {
maxScale: 4
},
zoom: false
},
Slideshow: {
timeout: FancyboxSlideshowTimeoutNum,
},
Carousel: {
...Fancybox.defaults.Carousel,
transition: FancyboxSlideshowTransition
},
Thumbs: {
showOnStart: false
},
Toolbar: {
display: {
left: ["infobar"],
middle: isM ? ["flipX", "flipY"] : ["zoomIn", "zoomOut", "iterateZoom", "toggle1to1", "rotateCCW", "rotateCW", "flipX", "flipY", "fitX", "fitY", "reset"],
right: ["slideshow", "fullscreen", "thumbs", "close"]
}
},
on: {
done: (fancybox, slide) => {
isOpenFancybox = true;
let slideIndex = slide.index;
let imgs = gae("img", mainElement);
imgs.forEach(e => (e.style.border = ""));
if (fancybox.isCurrentSlide(slide)) {
imgViewIndex = slideIndex;
let img = imgs[imgViewIndex];
currentReferenceElement = img;
img.style.border = "solid #32a1ce";
instantScrollIntoView(img);
} else {
imgViewIndex = fancybox.getSlide().index;
let img = imgs[imgViewIndex];
currentReferenceElement = img;
img.style.border = "solid #32a1ce";
instantScrollIntoView(img);
}
if (fancybox.carousel.page == 0 && (fancybox.carousel.prevPage == fancybox.carousel.pages.at(-1).index)) {
if (FancyboxAutoClose == 1) {
fancybox.close();
}
if (FancyboxAutoNext == 1) {
if (!!nextLink) {
closeGallery();
fn.showMsg(DL.str_34.n);
setTimeout(() => (location.href = nextLink), 100);
}
}
}
},
close: fancybox => {
let slideIndex = fancybox.getSlide().index;
imgViewIndex = slideIndex;
let imgs = gae("img", mainElement);
imgs.forEach(e => (e.style.border = ""));
let img = imgs[imgViewIndex];
currentReferenceElement = img;
img.style.border = "solid #32a1ce";
instantScrollIntoView(img);
setTimeout(() => {
isOpenFancybox = false;
}, 100);
}
}
});
});
});
}
if (isString(nextLink) && config.ViewMode != 5) {
totalNumberOfElements = totalNumberOfElements + 1;
const next = document.createElement("div");
next.id = "next";
next.dataset.url = nextLink;
next.dataset.index = imgElements.length;
next.innerText = `${siteData.category?.includes("comic") ? DL.str_143 : DL.str_144}${isM ? "" : "( N )"}`;
mainElement.append(next);
next.addEventListener("click", event => {
cancelDefault(event);
next.style.backgroundColor = "gray";
return (isGoToNext = true) && setTimeout(() => (location.href = nextLink), 200);
});
if (config.shadowGalleryWheel != 1 && [0, 1, 3].some(m => config.ViewMode == m) || [2, 4].some(m => config.ViewMode == m)) {
let isEventAdded = false;
const nextObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
nextButtonIsShown = true;
next.style.border = "solid #32a1ce";
if (isPC) {
alertDiv.classList.remove("hide");
}
if (!isEventAdded) {
isEventAdded = true;
dom.addEventListener("wheel", (event) => {
if (isOpenFancybox || event.ctrlKey || event.altKey || event.shiftKey || event.metaKey) return;
if (event.deltaY < 0) {
next.style.border = "";
nextButtonIsShown = false;
alertMessage.innerText = DL.str_113 + "3";
alertDiv.classList.add("hide");
} else if (event.deltaY > 0 && nextButtonIsShown) {
let num = Number(alertMessage.innerText.match(/\d/));
if (num > 0) {
alertMessage.innerText = DL.str_113 + (num -= 1);
}
if (num <= 0) {
alertMessage.innerText = siteData.category?.includes("comic") ? DL.str_196 : DL.str_197;
next.style.backgroundColor = "gray";
return (isGoToNext = true) && setTimeout(() => (location.href = nextLink), 200);
}
}
}, {
passive: true
});
}
} else {
next.style.border = "";
nextButtonIsShown = false;
alertMessage.innerText = DL.str_113 + "3";
alertDiv.classList.add("hide");
}
});
}, {
threshold: 0.9,
});
setTimeout(() => {
nextObserver.observe(next);
}, 1000);
}
}
if (isM) {
const b = document.createElement("p");
b.className = "place";
mainElement.append(b);
}
}
let btnDiv;
function addButtons() {
btnDiv = document.createElement("div");
btnDiv.id = "setting-btn";
btnDiv.className = "hide";
const btnObj = [{
id: "addBtn",
svg: '<svg class="icon" fill="currentColor" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><path d="M1024 432v160c0 8.8-7.2 16-16 16H624c-8.8 0-16 7.2-16 16v384c0 8.8-7.2 16-16 16H432c-8.8 0-16-7.2-16-16V624c0-8.8-7.2-16-16-16H16c-8.8 0-16-7.2-16-16V432c0-8.8 7.2-16 16-16h384c8.8 0 16-7.2 16-16V16c0-8.8 7.2-16 16-16h160c8.8 0 16 7.2 16 16v384c0 8.8 7.2 16 16 16h384c8.8 0 16 7.2 16 16z"></path></svg>',
cfn: increaseWidth
}, {
id: "reduceBtn",
svg: '<svg class="icon" fill="currentColor" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><path d="M1024 432v160c0 8.8-7.2 16-16 16H16c-8.8 0-16-7.2-16-16V432c0-8.8 7.2-16 16-16h992c8.8 0 16 7.2 16 16z"></path></svg>',
cfn: reduceWidth
}];
const createDiv = obj => {
let item = document.createElement("div");
item.id = obj.id;
item.className = "setting-btn";
item.innerHTML = obj.svg;
item.oncontextmenu = () => false;
item.addEventListener("click", obj.cfn);
btnDiv.append(item);
};
btnObj.forEach(obj => createDiv(obj));
dom.body.append(btnDiv);
}
addButtons();
let alertDiv;
let alertMessage;
let alertHtml = `
<div id="alertBox" class="hide">
<div id="hint">${DL.str_112}</div>
<p id="alertMessage">${DL.str_113}3</p>
<div id="nextAlert">${siteData.category?.includes("comic") ? DL.str_143 : DL.str_144}( N )</div>
<div id="closeAlert">${DL.str_132}</div>
</div>
`;
let alertNode = fn.html(alertHtml);
dom.body.append(alertNode);
alertDiv = ge("#alertBox", dom);
alertMessage = ge("#alertMessage", alertDiv);
ge("#nextAlert", alertDiv).addEventListener("click", event => {
cancelDefault(event);
return (isGoToNext = true) && setTimeout(() => (location.href = nextLink), 100);
});
ge("#closeAlert", alertDiv).addEventListener("click", () => {
isShowAlert = false;
alertMessage.innerText = DL.str_113 + "3";
alertDiv.classList.add("hide");
});
let menuDiv;
function addFixedMenu() {
menuDiv = document.createElement("div");
menuDiv.id = "FixedMenu";
const menuObj = [{
id: "MenuCancelItem",
text: DL.str_142,
cfn: () => closeGallery()
}, {
id: "MenuSettingsItem",
text: DL.str_85.replace(/\(.\)/, ""),
cfn: () => createPictureLoadOptionsShadowElement()
}, {
id: "MenuFavorItem",
text: DL.str_128.replace(/\(.\)/, ""),
cfn: () => createFavorShadowElement()
}, {
id: "MenuThreadingItem"
}, {
id: "MenuBehaviorItem"
}, {
id: "MenuJumpItem",
}, {
id: "menuHome",
text: DL.str_217,
cfn: () => (location.href = location.origin)
}, {
id: "menuList",
hide: 1,
text: DL.str_216,
cfn: () => {
list_main.classList.remove("hide");
isOpenChapterList = true;
const button = ge(".current-chapter", list_main);
list_main.scrollTop = button.offsetTop - (list_main.clientHeight / 2) + button.clientHeight;
}
}, {
id: "menuNext",
text: `${siteData.category?.includes("comic") ? DL.str_143 : DL.str_144}${isM ? "" : "( N )"}`,
cfn: () => (isGoToNext = true) && setTimeout(() => (location.href = nextLink), 200)
}, {
id: "MenuHorizontalItem",
text: DL.galleryMenu.horizontal,
cfn: () => horizontalImageLayout()
}, {
id: "MenuWebtoonItem",
text: DL.galleryMenu.webtoon,
cfn: () => webtoonImageLayout()
}, {
id: "MenuRTLItem",
text: DL.galleryMenu.rtl,
cfn: () => rtlImageLayout()
}, {
id: "MenuSmallItem",
text: DL.galleryMenu.small,
cfn: () => smallImageLayout()
}, {
id: "MenuSinglePageItem",
text: DL.galleryMenu.single,
cfn: () => singleImageLayout()
}, {
id: "MenuDefaultItem",
text: DL.galleryMenu.default,
cfn: () => defaultImageLayout()
}];
const createMenu = obj => {
if (!isString(nextLink) && obj.id == "menuNext") return;
let item = document.createElement("div");
item.id = obj.id;
item.className = "FixedMenuitem";
if ("hide" in obj) {
item.classList.add("hide");
}
if (!!obj.text) item.innerText = obj.text;
item.oncontextmenu = () => false;
if (!!obj.cfn) item.addEventListener("click", obj.cfn);
menuDiv.append(item);
};
menuObj.forEach(obj => createMenu(obj));
dom.body.append(menuDiv);
let threadingSelect = document.createElement("select");
for (let i = 1; i <= 32; i++) {
let option = document.createElement("option");
option.value = i;
option.innerText = DL.str_162 + i;
threadingSelect.append(option);
}
ge("#MenuThreadingItem", menuDiv).append(threadingSelect);
threadingSelect.value = config.threading;
threadingSelect.addEventListener("change", () => {
config.threading = Number(threadingSelect.value);
saveConfig(config);
if (!isM) {
mainElement.focus();
}
});
if (isPC) {
let jumpSelect = document.createElement("select");
for (let i = 0; i <= 100; i++) {
let option = document.createElement("option");
if (i === 0) {
option.value = i;
option.innerText = `${DL.str_150}${DL.str_152}`;
} else {
option.value = i * 50;
option.innerText = `${DL.str_150}${i * 50}px`;
}
jumpSelect.append(option);
}
ge("#MenuJumpItem", menuDiv).append(jumpSelect);
jumpSelect.value = config.jumpNum;
jumpSelect.addEventListener("change", () => {
config.jumpNum = jumpSelect.value;
saveConfig(config);
if (!isM) {
mainElement.focus();
}
});
let behaviorDiv = ge("#MenuBehaviorItem", menuDiv);
let behaviorInput = document.createElement("input");
behaviorInput.id = "behaviorInput";
behaviorInput.type = "checkbox";
behaviorDiv.append(behaviorInput);
let behaviorLabel = document.createElement("label");
behaviorLabel.innerText = DL.str_151;
behaviorDiv.append(behaviorLabel);
behaviorInput.checked = config.behavior == "smooth" ? true : false;
behaviorInput.addEventListener("change", () => {
config.behavior = behaviorInput.checked == true ? "smooth" : "instant";
saveConfig(config);
if (!isM) {
mainElement.focus();
}
});
}
if (isM) {
menuDiv.classList.add("hide");
gae("#MenuBehaviorItem,#MenuJumpItem,#MenuHorizontalItem", menuDiv).forEach(e => e.classList.add("hide"));
}
}
addFixedMenu();
let list_main;
if ("chapters" in siteData) {
// 創建目錄
const get_chapters = siteData.chapters;
const createChapterList = async () => {
let chapterListData = [];
if (isObject(get_chapters)) {
chapterListData = await fn.getChapters(get_chapters);
} else if (isFn(get_chapters)) {
chapterListData = await get_chapters();
}
if (!isArray(chapterListData) || !chapterListData?.length) return;
chapterListObtained = true;
const tempURLs = new Set();
chapterListData = chapterListData.filter(({
url
}) => {
if (tempURLs.has(url) || url == "#") {
return false;
} else {
tempURLs.add(url);
}
return true;
});
ge("#menuList", menuDiv).classList.remove("hide");
list_main = document.createElement("div");
list_main.id = "modal-content-list";
list_main.className = "hide";
const list_close = document.createElement("span");
list_close.id = "closeModal";
list_close.className = "closeModal";
list_close.innerText = `× ${DL.str_132}`;
list_close.addEventListener("click", () => {
list_main.classList.add("hide");
isOpenChapterList = false;
});
list_main.append(list_close);
const list_container = document.createElement("div");
list_container.id = "chapterListContainer";
list_container.className = "chapter-list-container";
list_main.append(list_container);
const pathname = decodeURIComponent(fn.clp());
const search = fn.cls();
let isCurrent = false;
const list = chapterListData.map(({
text,
url
}) => {
const button = document.createElement("button");
button.className = "chapter-btn";
button.innerText = text;
button.dataset.url = url;
if ("checkCurrentChapter" in siteData) {
isCurrent = siteData.checkCurrentChapter(url, text);
}
if (
isCurrent ||
search && url.endsWith(search) ||
!search && decodeURIComponent(url).endsWith(pathname) ||
search.includes("page=") && url.includes(pathname)
) {
button.classList.add("current-chapter");
} else {
button.addEventListener("click", (event) => (location.href = event.target.dataset.url));
}
return button;
});
list_container.append(...list);
const footer = document.createElement("div");
footer.id = "chapters-footer";
const close_button = document.createElement("button");
close_button.id = "footer_close_button";
close_button.innerText = DL.str_132;
close_button.addEventListener("click", () => {
list_main.classList.add("hide");
isOpenChapterList = false;
});
footer.append(close_button);
list_main.append(footer);
dom.body.append(list_main);
mainElement.addEventListener("click", () => {
if (isOpenChapterList) {
list_main.classList.add("hide");
isOpenChapterList = false;
}
});
};
createChapterList();
}
function defaultImageLayout() {
config.ViewMode = 0;
saveConfig(config);
createGalleryElement("default");
ge("#MenuDefaultItem", dom).classList.add("active");
}
function singleImageLayout() {
config.ViewMode = 1;
saveConfig(config);
createGalleryElement("single");
ge("#MenuSinglePageItem", dom).classList.add("active");
}
function smallImageLayout() {
config.ViewMode = 2;
saveConfig(config);
createGalleryElement("small");
ge("#MenuSmallItem", dom).classList.add("active");
}
function rtlImageLayout() {
config.ViewMode = 3;
saveConfig(config);
createGalleryElement("default");
ge("#MenuRTLItem", dom).classList.add("active");
}
function webtoonImageLayout() {
config.ViewMode = 4;
saveConfig(config);
createGalleryElement("webtoon");
ge("#MenuWebtoonItem", dom).classList.add("active");
}
function horizontalImageLayout() {
config.ViewMode = 5;
saveConfig(config);
createGalleryElement("horizontal");
ge("#MenuHorizontalItem", dom).classList.add("active");
}
if (config.ViewMode == 1) {
singleImageLayout();
} else if (config.ViewMode == 2) {
smallImageLayout();
} else if (config.ViewMode == 3) {
rtlImageLayout();
} else if (config.ViewMode == 4) {
webtoonImageLayout();
} else if (config.ViewMode == 5) {
horizontalImageLayout();
} else {
defaultImageLayout();
}
};
const getFileSize = (src, element = null, label = null) => {
const config = getConfig();
if (config.noSize == 1) return;
return fn.xhrHEAD(src, {
headers: {
referer: getReferer(src)
}
}).then(res => {
//console.log(res);
if (src != res.finalUrl) {
return getFileSize(res.finalUrl, element);
}
const contentLength = res?.responseHeaders?.split("\r\n")?.find(s => s.startsWith("content-length:"));
//console.log(contentLength);
if (contentLength) {
let [num] = contentLength.match(/\d+/);
if (num.length > 6) {
num = (num / 1000000).toFixed(1);
if (isEle(element)) {
element.innerText = element.innerText + " | Size: " + num + " MB";
}
return num + " MB";
} else {
num = Math.floor(num / 1000);
if (isEle(element)) {
element.innerText = element.innerText + " | Size: " + num + " kB";
}
return num + " kB";
}
} else {
const config = getConfig();
if (config.noSize != 1) {
config.noSize = 1;
saveConfig(config);
if (isEle(label)) {
label.classList.add("line-through");
}
}
}
});
};
let GalleryInIcon = _GM_getValue("GalleryInIcon", 0);
let closeFilter;
//創建篩選下載
const createFilterUI = async (enterGallery = 0) => {
if (checkGeting() || isDragging || isOpenFilter || !isValidPage) return;
isOpenFilter = true;
if ("SPA" in siteData) {
lastValidPageURL = currentURL;
}
let full_srcs;
let isViewMobileGallery = false;
let Viewer;
let ViewerJsInstance;
let ViewerJsInstance_G;
if ("SPA" in siteData || siteData.repeat == 1 || siteData.infiniteCapture == 1) {
let selector = siteData.capture || siteData.srcset || siteData.imgs;
full_srcs = await getImgs(selector);
} else if (!("capture" in siteData)) {
globalImgArray.length > 0 ? full_srcs = globalImgArray : full_srcs = await getImgs(siteData.srcset || siteData.imgs);
} else {
captureSrcArray.length > 0 ? full_srcs = captureSrcArray : full_srcs = await getImgs(siteData.srcset || siteData.imgs);
}
if (full_srcs.length < 1) {
fn.showMsg(DL.str_44);
return (isOpenFilter = false);
}
let srcs;
let g_srcs;
const config = getConfig();
const extensions = {
jpg: 0,
png: 0,
gif: 0,
webp: 0,
bmp: 0,
svg: 0,
ico: 0,
avif: 0,
tiff: 0
};
let image_size = Number(_GM_getValue("image_size", -1));
let exclude_ex_config = _GM_getValue("exclude_ex_config", extensions);
exclude_ex_config = Object.assign(extensions, exclude_ex_config);
let threading = Number(config.threading);
let colorThemes = config.colorThemes;
let showSize = config.showSize;
let move = config.move;
let isOpenChapterList = false;
let chapterListObtained = false;
const exclude_ex_fn = () => {
if (Object.values(exclude_ex_config).some(v => v == 1)) {
srcs = full_srcs.filter(src => {
if (exclude_ex_config.jpg == 1) {
if (/\.jpe?g/i.test(src) || src.startsWith("data:image/jpeg")) {
return false;
}
}
if (exclude_ex_config.png == 1) {
if (/\.png/i.test(src) || src.startsWith("data:image/png")) {
return false;
}
}
if (exclude_ex_config.gif == 1) {
if (/\.gif/i.test(src) || src.startsWith("data:image/gif")) {
return false;
}
}
if (exclude_ex_config.webp == 1) {
if (/\.webp/i.test(src) || src.startsWith("data:image/webp")) {
return false;
}
}
if (exclude_ex_config.bmp == 1) {
if (/\.bmp/i.test(src) || src.startsWith("data:image/bmp")) {
return false;
}
}
if (exclude_ex_config.svg == 1) {
if (/\.svg/i.test(src) || src.startsWith("data:image/svg")) {
return false;
}
}
if (exclude_ex_config.ico == 1) {
if (/\.ico/i.test(src) || src.startsWith("data:image/x-icon")) {
return false;
}
}
if (exclude_ex_config.avif == 1) {
if (/\.avif/i.test(src) || src.startsWith("data:image/avif")) {
return false;
}
}
if (exclude_ex_config.tiff == 1) {
if (/\.tiff?/i.test(src) || src.startsWith("data:image/tiff")) {
return false;
}
}
return true;
});
g_srcs = srcs;
} else {
srcs = full_srcs;
g_srcs = srcs;
}
};
exclude_ex_fn();
const update_g_srcs = () => {
g_srcs = gae(".select+.image", main).map(img => img.dataset.src);
};
if (!("Viewer" in _unsafeWindow)) {
_GM_addElement(document.head, "style", {
textContent: ViewerJsCss
});
_GM_addElement(document.head, "script", {
textContent: ViewerJs
});
}
const mainHtml = `<div id="FullPictureLoadFilterDownload" style="overflow: clip !important;display: initial !important;position: fixed !important;"></div>`;
document.body.insertAdjacentHTML("beforeend", mainHtml);
const shadowElement = ge("#FullPictureLoadFilterDownload");
const shadow = shadowElement.attachShadow({
mode: "closed"
});
hidePageScrollbarY();
const style = createStyle(`
#main {
font-size: 14px !important;
line-height: 20px !important;
font-family: ui-monospace, sans-serif, system-ui, -apple-system, Segoe UI, Arial !important;
font-weight: 500 !important;
text-align: left;
color: black;
inset: 0px;
width: 100%;
height: 100%;
margin: 0px;
padding: 0px;
position: fixed;
opacity: 1;
z-index: 2147483641;
background-color: rgb(240, 240, 240);
overflow: hidden auto;
}
#main.dark {
color: white;
background-color: #333;
}
input,select {
color: #000;
background-color: #fff;
border: 1px solid;
}
input.dark,select.dark {
color: #fff;
background-color: #333;
border: 1px solid #575757;
}
.show {
display: block !important;
}
.hide {
display: none !important;
}
.row {
display: block;
margin: ${isM && isFirefox ? "2px" : "5px"};
padding: 0 0 0 5px;
border: #000 1px solid;
border-radius: 5px;
}
.row.dark {
border: rgb(0, 204, 255) 1px solid;
}
#title {
display: block;
margin: 4px auto 0 auto;
}
.buttons {
display: block;
margin: 0 auto 4px auto;
}
label {
user-select: none;
}
#label-title,
button#close {
display: inline-block;
width: 48px;
}
.number {
display: inline-block;
margin-top: 4px;
padding: ${isM && isFirefox ? "0 0 0 2px" : isM ? "0 2px 0 4px" : "0 0 0 4px"};
border-left: #000 1px solid;
}
.number.dark{
border-left: rgb(0, 204, 255) 1px solid;
}
.close {
margin: 0 5px;
}
#inputTitle {
width: calc(100% - 126px);
}
.buttons button {
margin-top: 4px;
}
button.dark {
color: #fff;
border-color: rgb(81 91 105);
border-style: solid;
background-color: rgb(81 91 105);
border-radius: .5rem;
}
button.mode.active {
color: #fff;
border-color: #1790e6;
border-style: solid;
background-color: #1790e6;
border-radius: .5rem;
}
#imgBox {
text-align: center;
/*min-height: calc(100vh - 120px);*/
}
ul#image-list {
display: block;
max-width: 100%;
margin: ${isM ? "0 0 0 -1px" : "0 0 0 -2px"};
padding: 4px 0 0 0;
}
li.image-item {
list-style: none;
position: relative;
display: inline-flex;
width: 200px;
height: 200px;
margin: 0 4px 4px 0;
padding: 0px;
background-color: #fff;
border: #000 1px solid;
border-radius: 2px;
}
li.image-item.dark {
background-color: #333;
border: rgb(0, 204, 255) 1px solid;
}
li img.image {
display: block;
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
margin: 0px auto;
object-fit: contain;
}
li input.check {
position: absolute;
top: 2px;
left: 2px;
}
li.image-item p {
position: absolute;
font-size: 12px;
line-height: 14px;
width: 100%;
height: 14px;
bottom: 0px;
margin: 0px;
padding: 0px;
background-color: rgba(163, 194, 194, 0.8);
}
li.image-item p.dark {
background-color: rgba(82, 82, 122, 0.8);
}
#size,#move,#auto-exclude-error {
width: 17px;
height: 17px;
vertical-align: sub;
margin: 0 4px 0 -4px;
}
li.line-through:has(>#size) {
text-decoration: line-through;
}
#exclude,#more {
position: relative;
}
#excludeList {
display: none;
list-style-type: none;
top: 28px;
left: 8px;
width: 60px;
text-align: center;
border: #ccc 1px solid;
border-radius: 3px;
position: absolute;
z-index: ${UI_zIndex - 4};
background-color: #fff;
margin: 0;
padding: 0;
}
#excludeList.dark {
color: #fff;
background-color: #333;
}
.excludeItem {
list-style: none;
color: black;
border: #ccc 1px solid;
background-color: #f6f6f6;
padding: 2px;
margin: 2px;
}
.excludeItem.dark {
color: #fff;
background-color: #333;
border: #eee 1px solid;
}
.excludeItem.active {
color: #fff;
background: #1790e6;
text-decoration: line-through;
}
#excludeNum {
display: none;
color: white;
font-size: 12px;
line-height: 16px;
text-align: center;
background-color: #1790e6;
position: absolute;
top: -6px;
left: 1px;
width: 16px;
height: 16px;
border-radius: 8px;
margin: 0;
padding: 0;
z-index: ${UI_zIndex - 4};
}
#more-menu {
display: none;
list-style-type: none;
top: 28px;
left: ${isCh ? "-13px" : "-26px"};
width: ${isCh ? "100px" : "150px"};
text-align: center;
border: #ccc 1px solid;
border-radius: 3px;
position: absolute;
z-index: ${UI_zIndex - 4};
background-color: #fff;
margin: 0;
padding: 0;
}
#more-menu.dark {
color: #fff;
background-color: #333;
}
.more-item {
list-style: none;
color: black;
border: #ccc 1px solid;
background-color: #f6f6f6;
padding: 2px;
margin: 4px;
}
.more-item.dark {
color: #fff;
background-color: #333;
border: #eee 1px solid;
}
img.single {
width: auto;
height: auto;
max-width: calc(100% - 6px);
max-height: calc(100vh - 6px);
display: block;
margin: 0 auto;
border: solid #fff;
}
img.webtoon {
width: 100%;
height: auto;
max-width: 800px;
display: block;
margin: 0 auto;
border: unset;
}
#homePage,a#favor,a#close,#list,a#next,a#prev,#scroll_U,#scroll_D,a#settings {
position: fixed;
z-index: ${UI_zIndex - 4};
color: rgba(143, 143, 143);
font-size: 40px;
width: 48px;
height: 48px;
text-align: center;
/*align-content: center;*/
overflow: hidden;
border: #555 1px solid;
background: rgba(255, 255, 255, 0.8);
border-radius: 12px;
opacity: 0.8;
backdrop-filter: saturate(5) blur(100px);
}
#homePage,a#favor,a#close {
left: 20px;
}
#scroll_U,#scroll_D,a#settings {
right: ${isPC ? "30px" : "20px"};
}
a#next {
left: calc(50% + 40px);
transform: rotate(90deg);
}
a#prev {
left: calc(50% - 88px);
transform: rotate(270deg);
}
#list {
left: calc(50% - 24px);
}
#homePage,#scroll_U {
bottom: 160px;
}
a#favor,#scroll_D,#list,a#next,a#prev {
bottom: 100px;
}
#scroll_D {
transform: rotate(180deg);
}
a#close,a#settings {
bottom: 40px;
}
#homePage.dark,a#favor.dark,a#close.dark,#list.dark,a#next.dark,a#prev.dark,#scroll_U.dark,#scroll_D.dark,a#settings.dark {
color: rgba(255, 255, 255, 0.8);
border: rgb(0, 204, 255) 1px solid;
background: rgb(37, 36, 44, 0.8);
opacity: 0.8;
}
svg.icon {
width: 40px;
height: 40px;
margin-top: 4px;
}
div#next {
display: block;
text-align: center;
margin: 5px;
padding: 10px 0;
border: solid #bbb;
border-radius: 6px;
color: rgb(0, 0, 0);
background-color: #7cffcb;
background-image: linear-gradient(315deg, #7cffcb 0%, #74f2ce 74%);
font-size: 26px;
line-height: 40px;
height: 40px;
text-decoration: unset;
cursor: pointer;
}
div#next.dark {
border: solid #7cffcb;
}
#modal-content-list {
background-color: #eee;
position: fixed;
z-index: ${UI_zIndex - 3};
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
padding: 10px;
border: 1px solid #888;
min-width: 350px;
max-width: 600px;
max-height: 76%;
overflow-y: auto;
}
#modal-content-list.dark {
background-color: #282828;
}
.closeModal {
position: absolute;
color: #000;
font-size: 18px;
font-weight: bold;
cursor: pointer;
}
.closeModal.dark {
color: #fff;
}
.chapter-list-container {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 20px;
padding-top: 20px;
}
.chapter-btn {
background-color: #fff;
color: #000;
border: 1px solid #a2a2a2;
padding: 10px;
cursor: pointer;
border-radius: 5px;
font-size: 13px;
width: calc(33.3333% - 8px);
box-sizing: border-box;
text-align: center;
overflow:hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.chapter-btn.dark {
background-color: #3c3c3c;
color: #fff;
border: none;
}
.current-chapter,
.current-chapter.dark{
background-color: #1790e6;
color: #fff;
}
#chapters-footer {
margin: 10px 0;
display: flex;
justify-content: flex-end;
}
#footer_close_button {
display: block;
width: 100%;
color: #000;
background-color: #ccc;
border: none;
border-radius: 5px;
cursor: pointer;
padding: 10px;
box-sizing: content-box;
font-size: 16px;
font-weight: 600;
}
#footer_close_button.dark {
color: #fff;
background-color: #454d55;
}
@media (max-width: 873px) {
li.image-item {
width: 194px;
height: 194px;
}
}
@media (max-width: 820px) {
li.image-item {
width: 194px;
height: 194px;
}
}
@media (max-width: 768px) {
li.image-item {
width: 181px;
height: 181px;
}
}
@media (max-width: 712px) {
li.image-item {
width: 167px;
height: 167px;
}
}
@media (max-width: 414px) {
li.image-item {
width: 192px;
height: 192px;
}
}
@media (max-width: 412px) {
li.image-item {
width: 191px;
height: 191px;
}
}
@media (max-width: 400px) {
li.image-item {
width: 182px;
height: 182px;
}
}
@media (max-width: 393px) {
li.image-item {
width: 182px;
height: 182px;
}
}
@media (max-width: 390px) {
li.image-item {
width: 180px;
height: 180px;
}
}
@media (max-width: 375px) {
li.image-item {
width: 173px;
height: 173px;
}
}
@media (max-width: 360px) {
li.image-item {
width: 165px;
height: 165px;
}
}
@media (max-width: 320px) {
li.image-item {
width: 145px;
height: 145px;
}
}
`);
shadow.append(style);
const main = document.createElement("div");
main.id = "main";
main.tabIndex = "-1";
shadow.append(main);
main.innerHTML = `
<div id="filter_top" class="row">
<div id="title">
<label id="label-title">${DL.str_153}</label>
<input type="text" id="inputTitle">
<button id="close" class="close">${DL.str_132}</button>
</div>
<div class="buttons">
<button class="mobile_toggle_filter_gallery_btn hide">${DL.str_188}</button>
<button id="shadow_gallery">${DL.str_141.replace(/\(.\)/, "")}</button>
<button id="tab_gallery">${DL.str_106.replace(/\(.\)/, "")}</button>
<button id="favor">${DL.str_128.replace(/\(.\)/, "")}</button>
<button id="exclude-error">${DL.str_184}</button>
<button id="select-all">${DL.str_154}</button>
<button id="unselect-all">${DL.str_155}</button>
<button id="reverse-selection">${DL.str_170}</button>
<button id="reload">${DL.str_156}</button>
<button id="download">${DL.str_157}</button>
<label class="number">${DL.str_169}<select id="colorThemes"></select></label>
<label class="number">${DL.str_206}<select id="imageSize"></select></label>
<label id="label-threading" class="number">${DL.str_161}<select id="threading"></select></label>
<label id="exclude" class="number">${DL.str_183} ▼<p id=excludeNum>0</p><ul id="excludeList"></ul></label>
<label class="number">${DL.str_167}<select id="width"></select></label>
<label class="number">${DL.str_168}<select id="height"></select></label>
<label id="filterNumber" class="number">${DL.str_166 + srcs.length}</label>
<label id="total" class="number">${DL.str_165 + srcs.length}</label>
<label id="more" class="number">${DL.str_186} ☰
<ul id="more-menu">
<li id="combineDownload" class="more-item">${DL.str_181}</li>
<li id="copy" class="more-item">${DL.str_105.replace(/\(.\)/, "")}</li>
<li id="export" class="more-item">${DL.str_104.replace(/\(.\)/, "")}</li>
<li id="export_json" class="more-item">${DL.str_193}</li>
<li id="copy_md" class="more-item">${DL.str_194}</li>
<li id="export_md" class="more-item">${DL.str_195}</li>
<li class="more-item"><input id="auto-exclude-error" type="checkbox"></input>${DL.str_185}</li>
<li class="more-item" title="${DL.str_173}"><input id="move" type="checkbox"></input>${DL.str_172}</li>
<li class="more-item"><input id="size" type="checkbox"></input>${DL.str_171}</li>
<li id="settings" class="more-item">${DL.str_85.replace(/\(.\)/, "")}</li>
</ul>
</label>
</div>
</div>
<div id="imgBox" class="row">
<ul id="image-list"></ul>
</div>
<div id="filter_bottom" class="row">
<div class="buttons">
<button id="settings">${DL.str_85.replace(/\(.\)/, "")}</button>
<button class="mobile_toggle_filter_gallery_btn hide">${DL.str_188}</button>
<button id="shadow_gallery">${DL.str_141.replace(/\(.\)/, "")}</button>
<button id="tab_gallery">${DL.str_106.replace(/\(.\)/, "")}</button>
<button id="favor">${DL.str_128.replace(/\(.\)/, "")}</button>
<button id="copy">${DL.str_105.replace(/\(.\)/, "")}</button>
<button id="export">${DL.str_104.replace(/\(.\)/, "")}</button>
<button id="select-all">${DL.str_154}</button>
<button id="unselect-all">${DL.str_155}</button>
<button id="reverse-selection">${DL.str_170}</button>
<button id="exclude-error">${DL.str_184}</button>
<button id="reload">${DL.str_156}</button>
<button id="combineDownload">${DL.str_181}</button>
<button id="download">${DL.str_157}</button>
<button id="close">${DL.str_132}</button>
</div>
</div>
<div id="gallery_top" class="row hide">
<div class="buttons">
<button class="mobile_toggle_filter_gallery_btn">${DL.str_158.replace(/\(.\)/, "")}</button>
<button id="favor">${DL.str_128.replace(/\(.\)/, "")}</button>
<button id="single" class="mode">${DL.str_189}</button>
<button id="webtoon" class="mode">${DL.str_190}</button>
<button id="close">${DL.str_132}</button>
</div>
</div>
<div id="gallery_imgBox" class="hide"></div>
<div id="gallery_bottom" class="row hide">
<div class="buttons">
<button class="mobile_toggle_filter_gallery_btn">${DL.str_158.replace(/\(.\)/, "")}</button>
<button id="favor">${DL.str_128.replace(/\(.\)/, "")}</button>
<button id="single" class="mode">${DL.str_189}</button>
<button id="webtoon" class="mode">${DL.str_190}</button>
<button id="close">${DL.str_132}</button>
</div>
</div>
<a id="homePage" class="hide" href="javascript:void(0);">
<svg class="icon" fill="currentColor" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M946.56 504.96L560.064 118.848l-25.92-25.856a31.488 31.488 0 0 0-44.416 0L77.504 504.96a63.936 63.936 0 0 0-18.816 45.952c0.384 35.2 29.696 63.36 64.896 63.36h42.496v325.632h691.84V614.272h43.392a63.68 63.68 0 0 0 45.312-18.752c12.096-12.16 18.688-28.16 18.688-45.312a63.616 63.616 0 0 0-18.816-45.184z m-378.56 363.072h-112v-204.032h112v204.032z m217.92-325.76v325.76H632V640a40 40 0 0 0-40-40h-160a40 40 0 0 0-40 40v228.032H238.08v-325.76h-96l370.048-369.664 23.04 23.04 346.88 346.624H785.92z"></path>
</svg>
</a>
<a id="favor" class="hide" href="javascript:void(0);">
<svg class="icon" fill="currentColor" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M529.066667 910.933333c-10.666667 0-21.333333-4.266667-29.866667-12.8L172.8 571.733333c-93.866667-93.866667-93.866667-247.466667 0-343.466666 93.866667-93.866667 247.466667-93.866667 343.466667 0l12.8 12.8 12.8-12.8c93.866667-93.866667 247.466667-93.866667 343.466666 0 44.8 44.8 70.4 106.666667 70.4 170.666666s-25.6 125.866667-70.4 170.666667L558.933333 898.133333c-8.533333 8.533333-19.2 12.8-29.866666 12.8z m-183.466667-667.733333c-42.666667 0-81.066667 17.066667-110.933333 46.933333-61.866667 61.866667-61.866667 160 0 221.866667l294.4 294.4L825.6 512c29.866667-29.866667 46.933333-68.266667 46.933333-110.933333s-17.066667-81.066667-46.933333-110.933334c-29.866667-29.866667-68.266667-46.933333-110.933333-46.933333s-81.066667 17.066667-110.933334 46.933333l-42.666666 42.666667c-17.066667 17.066667-42.666667 17.066667-59.733334 0l-42.666666-42.666667c-32-29.866667-72.533333-46.933333-113.066667-46.933333z"></path>
</svg>
</a>
<a id="close" class="hide" href="javascript:void(0);">
<svg class="icon" fill="currentColor" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M842.947 778.117l-266.1-266.104 266.1-266.13c8.675-8.674 13.447-20.208 13.439-32.478-0.009-12.232-4.773-23.715-13.415-32.332-8.655-8.678-20.15-13.45-32.385-13.457-12.286 0-23.808 4.771-32.474 13.434L512.019 447.144 245.882 181.05c-8.663-8.663-20.175-13.434-32.416-13.434-12.24 0-23.752 4.77-32.414 13.432-8.66 8.637-13.43 20.125-13.438 32.357-0.008 12.27 4.764 23.804 13.438 32.477l266.135 266.13L181.05 778.118c-8.664 8.663-13.436 20.173-13.436 32.415 0 12.24 4.773 23.753 13.438 32.418 8.662 8.663 20.173 13.432 32.413 13.432 12.24 0 23.754-4.77 32.416-13.432L512.015 576.85l266.102 266.1c8.663 8.664 20.186 13.433 32.443 13.433 12.265-0.008 23.749-4.771 32.369-13.412 17.887-17.89 17.893-46.98 0.018-64.854z"></path>
</svg>
</a>
<a id="list" class="hide" href="javascript:void(0);">
<svg class="icon" fill="currentColor" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M853.333333 218.666667a37.333333 37.333333 0 0 1 3.072 74.538666L853.333333 293.333333H362.666667a37.333333 37.333333 0 0 1-3.072-74.538666L362.666667 218.666667h490.666666zM853.333333 474.666667a37.333333 37.333333 0 0 1 3.072 74.538666L853.333333 549.333333H362.666667a37.333333 37.333333 0 0 1-3.072-74.538666L362.666667 474.666667h490.666666zM853.333333 730.666667a37.333333 37.333333 0 0 1 3.072 74.538666L853.333333 805.333333H362.666667a37.333333 37.333333 0 0 1-3.072-74.538666L362.666667 730.666667h490.666666z"></path>
<path d="M202.666667 256m-53.333334 0a53.333333 53.333333 0 1 0 106.666667 0 53.333333 53.333333 0 1 0-106.666667 0Z"></path>
<path d="M202.666667 512m-53.333334 0a53.333333 53.333333 0 1 0 106.666667 0 53.333333 53.333333 0 1 0-106.666667 0Z"></path>
<path d="M202.666667 768m-53.333334 0a53.333333 53.333333 0 1 0 106.666667 0 53.333333 53.333333 0 1 0-106.666667 0Z"></path>
</svg>
</a>
<a id="settings" class="hide" href="javascript:void(0);">
<svg class="icon" fill="currentColor" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M992.6 404.1 897.9 404.1C889.2 372.8 876.9 343.1 861.3 315.4L928.2 248.5C940.4 236.3 940.4 216.3 928.2 204L820 95.9C813.9 89.8 805.8 86.7 797.8 86.7 789.8 86.7 781.7 89.8 775.6 95.9L708.7 162.8C681 147.2 651.3 134.9 620 126.2L620 31.4C620 14.1 605.8 0 588.6 0L435.6 0C418.3 0 404.2 14.2 404.2 31.4L404.2 126.1C372.9 134.8 343.2 147.1 315.5 162.7L248.6 95.8C242.5 89.7 234.4 86.6 226.4 86.6 218.4 86.6 210.3 89.7 204.2 95.8L95.9 204C83.7 216.2 83.7 236.2 95.9 248.5L162.8 315.4C147.2 343.1 134.9 372.8 126.2 404.1L31.4 404.1C14.2 404.1 0 418.3 0 435.6L0 588.5C0 605.8 14.2 619.9 31.4 619.9L126.1 619.9C134.8 651.2 147.1 680.9 162.7 708.6L95.8 775.5C83.6 787.7 83.6 807.7 95.8 820L204 928.1C210.1 934.2 218.2 937.3 226.2 937.3 234.2 937.3 242.3 934.2 248.4 928.1L315.3 861.2C343 876.8 372.7 889.1 404 897.8L404 992.5C404 1009.8 418.2 1023.9 435.4 1023.9L588.3 1023.9C605.6 1023.9 619.7 1009.7 619.7 992.5L619.7 897.8C651 889.1 680.7 876.8 708.4 861.2L775.3 928.1C781.4 934.2 789.5 937.3 797.5 937.3 805.5 937.3 813.6 934.2 819.7 928.1L928.1 820C940.3 807.8 940.3 787.8 928.1 775.5L861.2 708.6C876.8 680.9 889.1 651.2 897.8 619.9L992.5 619.9C1009.8 619.9 1023.9 605.7 1023.9 588.5L1023.9 435.6C1024 418.3 1009.9 404.1 992.6 404.1L992.6 404.1ZM960 555.9 897.8 555.9 849.2 555.9 836.1 602.7C828.8 629 818.4 654.1 805.4 677.2L781.5 719.5 815.9 753.9 859.8 797.8 797.7 859.9 753.8 816 719.4 781.6 677.1 805.5C654 818.5 628.9 828.9 602.6 836.2L555.8 849.3 555.8 897.9 555.8 960 468 960 468 897.8 468 849.2 421.2 836.1C394.9 828.8 369.8 818.4 346.7 805.4L304.4 781.5 270 815.9 226.1 859.8 164 797.7 207.9 753.8 242.3 719.4 218.4 677.1C205.4 654 195 628.9 187.7 602.6L174.6 555.8 126 555.8 64 555.8 64 468 126.2 468 174.8 468 187.9 421.2C195.2 394.9 205.6 369.8 218.6 346.7L242.5 304.4 208.1 270 164.2 226.1 226.3 164 270.2 207.9 304.6 242.3 346.9 218.4C370 205.4 395.1 195 421.4 187.7L468.2 174.6 468.2 126 468.2 64 556 64 556 126.2 556 174.8 602.8 187.9C629.1 195.2 654.2 205.6 677.3 218.6L719.6 242.5 754 208.1 797.9 164.2 860 226.3 816.1 270.2 781.7 304.6 805.6 346.9C818.6 370 829 395.1 836.3 421.4L849.4 468.2 898 468.2 960 468.2 960 555.9 960 555.9Z"></path>
<path d="M512 320C406 320 320 406 320 512 320 618 406 704 512 704 618 704 704 618 704 512 704 406 618 320 512 320L512 320ZM512 640C477.8 640 445.7 626.7 421.5 602.5 397.3 578.3 384 546.2 384 512 384 477.8 397.3 445.7 421.5 421.5 445.7 397.3 477.8 384 512 384 546.2 384 578.3 397.3 602.5 421.5 626.7 445.7 640 477.8 640 512 640 546.2 626.7 578.3 602.5 602.5 578.3 626.7 546.2 640 512 640Z"></path>
</svg>
</a>
`;
const UD_Buttons = ["scroll_U", "scroll_D", "next", "prev"].map(id => {
let html = `
<a id="${id}" class="hide" href="javascript:void(0);">
<svg class="icon" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path d="M233.4 105.4c12.5-12.5 32.8-12.5 45.3 0l192 192c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L256 173.3 86.6 342.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l192-192z"></path>
</svg>
</a>
`;
return fn.html(html);
});
main.append(...UD_Buttons);
ge("#homePage", main).addEventListener("click", event => {
cancelDefault(event);
location.href = location.origin;
});
ge("#list", main).addEventListener("click", event => {
cancelDefault(event);
list_main.classList.remove("hide");
isOpenChapterList = true;
const button = ge(".current-chapter", list_main);
list_main.scrollTop = button.offsetTop - (list_main.clientHeight / 2) + button.clientHeight;
});
ge("a#next", main).addEventListener("click", event => {
cancelDefault(event);
return (isGoToNext = true) && (location.href = nextLink);
});
ge("a#prev", main).addEventListener("click", event => {
cancelDefault(event);
if (isString(prevLink)) {
return (isGoToPrev = true) && (location.href = prevLink);
} else if (prevLink == 1) {
return history.back();
}
});
ge("#scroll_U", main).addEventListener("click", event => {
cancelDefault(event);
instantScrollIntoView(ge(isViewMobileGallery ? "#gallery_top" : "#filter_top", main));
});
ge("#scroll_D", main).addEventListener("click", event => {
cancelDefault(event);
instantScrollIntoView(ge(isViewMobileGallery ? "#gallery_bottom" : "#filter_bottom", main));
});
let lastScrollTop = 0;
main.addEventListener("scroll", event => {
let imgBox;
if (isViewMobileGallery) {
imgBox = ge("#gallery_imgBox", main);
} else {
imgBox = ge("#imgBox", main);
}
if (isViewMobileGallery) {
if (main.scrollTop > lastScrollTop) {
gae("#homePage,a#favor,a#close,#list,a#next,a#prev,a#settings", main).forEach(e => e.classList.add("hide"));
} else if (main.scrollTop < lastScrollTop) {
if (chapterListObtained) {
gae("#homePage,a#favor,a#close,#list,a#settings", main).forEach(e => e.classList.remove("hide"));
} else {
gae("#homePage,a#favor,a#close,a#settings", main).forEach(e => e.classList.remove("hide"));
}
if (isString(nextLink)) {
ge("a#next", main).classList.remove("hide");
}
if (isString(prevLink)) {
ge("a#prev", main).classList.remove("hide");
}
}
}
if (main.scrollTop > lastScrollTop) {
gae("#scroll_U,#scroll_D", main).forEach(e => e.classList.add("hide"));
} else if (
isPC && main.scrollTop < lastScrollTop && imgBox.offsetHeight > (innerHeight * 1.5) ||
isM && main.scrollTop < lastScrollTop
) {
gae("#scroll_U,#scroll_D", main).forEach(e => e.classList.remove("hide"));
}
lastScrollTop = main.scrollTop;
});
closeFilter = () => {
if (isCaptureMode) {
updateEyeNum(full_srcs.length);
}
fn.remove("#overflowYHidden");
shadowElement.remove();
isOpenFilter = false;
ViewerJsInstance?.destroy();
ViewerJsInstance_G?.destroy();
};
const ui_selector = "#main,input,select,.row,.number,button:not(.chapter-btn),.image-item,.image-item p,#excludeList,.excludeItem,#more-menu,.more-item,#homePage,a#favor,a#close,#list,a#next,a#prev,#scroll_U,#scroll_D,a#settings,#next,#modal-content-list,.closeModal,.chapter-btn,#footer_close_button";
let inputs = [];
let startInput;
//參考https://syj0905.github.io/drag-drop-demo/
//還原成原生JavaScript寫法
const drag_sort_start = (event) => {
const dragEle = event.target.closest("li");
const list = event.target.closest("ul");
const index = [...list.childNodes].indexOf(dragEle);
event.dataTransfer.setData("text/plain", index);
};
const drop_sort = (event) => {
const oldIndex = event.dataTransfer.getData("text/plain");
const dropEle = event.target.closest("li");
const list = event.target.closest("ul");
const nodes = [...list.childNodes];
const newIndex = nodes.indexOf(dropEle);
const dragEle = nodes.at(oldIndex);
if (newIndex < oldIndex) {
dropEle.before(dragEle);
} else if (newIndex > oldIndex) {
dropEle.after(dragEle);
}
inputs = gae("input", list).map((input, index) => {
input.dataset.index = index;
return input;
});
startInput = null;
};
let moreE = ge("#more", main);
let moreMenu = ge("#more-menu", main);
moreE.addEventListener("click", (event) => {
if (event.target.id == "more") {
cancelDefault(event);
if (moreE.classList.contains("active")) {
moreE.classList.remove("active");
moreMenu.classList.remove("show");
} else {
moreE.classList.add("active");
moreMenu.classList.add("show");
}
}
});
ge("#export_json", main).addEventListener("click", event => {
cancelDefault(event);
const srcs = gae(".select+.image", main).map(img => img.dataset.src);
if (srcs.length == 0) return;
const text = ge("#inputTitle", main).value;
exportJsonFormat(srcs, text);
});
ge("#copy_md", main).addEventListener("click", event => {
cancelDefault(event);
const srcs = gae(".select+.image", main).map(img => img.dataset.src);
if (srcs.length == 0) return;
const text = ge("#inputTitle", main).value;
copyMarkdownFormat(srcs, text);
});
ge("#export_md", main).addEventListener("click", event => {
cancelDefault(event);
const srcs = gae(".select+.image", main).map(img => img.dataset.src);
if (srcs.length == 0) return;
const text = ge("#inputTitle", main).value;
exportMarkdownFormat(srcs, text);
});
if (isM) {
ge("li:has(>#move)", main).classList.add("hide");
gae(".mobile_toggle_filter_gallery_btn", main).forEach(e => e.classList.remove("hide"));
}
let excludeE = ge("#exclude", main);
let excludeList = ge("#excludeList", main);
excludeE.addEventListener("click", (event) => {
cancelDefault(event);
if (excludeE.classList.contains("active")) {
excludeE.classList.remove("active");
excludeE.firstChild.textContent = DL.str_183 + " ▼";
excludeList.classList.remove("show");
} else {
excludeE.classList.add("active");
excludeE.firstChild.textContent = DL.str_183 + " ▲";
excludeList.classList.add("show");
}
});
Object.entries(exclude_ex_config).forEach(([k, v]) => {
const li = document.createElement("li");
li.className = "excludeItem";
li.innerText = k.toUpperCase();
if (v == 1) {
li.classList.add("active");
}
li.addEventListener("click", (event) => {
cancelDefault(event);
if (li.classList.contains("active")) {
li.classList.remove("active");
Reflect.set(exclude_ex_config, k, 0);
} else {
li.classList.add("active");
Reflect.set(exclude_ex_config, k, 1);
}
_GM_setValue("exclude_ex_config", exclude_ex_config);
exclude_ex_fn();
addLis();
if (isM) {
update_g_srcs();
addGalleryImgs();
}
widthSelect.value = 0;
heightSelect.value = 0;
ge("#filterNumber", main).innerText = DL.str_166 + srcs.length;
let excludeActives = gae(".active", excludeE).length;
let p = ge("#excludeNum", main);
if (excludeActives > 0) {
p.classList.add("show");
p.innerText = excludeActives;
} else {
p.classList.remove("show");
}
});
fragment.append(li);
});
excludeList.append(fragment);
let excludeActives = gae(".active", excludeE).length;
if (excludeActives > 0) {
let p = ge("#excludeNum", main);
p.classList.add("show");
p.innerText = excludeActives;
}
let colorSelect = ge("#colorThemes", main);
Object.keys(DL.colorThemes).forEach((k, i) => {
const option = document.createElement("option");
option.value = k;
option.innerText = DL.colorThemes[k];
fragment.append(option);
});
colorSelect.append(fragment);
colorSelect.value = config.colorThemes;
colorSelect.addEventListener("change", () => {
config.colorThemes = colorSelect.value;
saveConfig(config);
colorThemes = config.colorThemes;
if (colorThemes === "dark") {
gae(ui_selector, shadow).forEach(e => e.classList.add("dark"));
} else {
gae(ui_selector, shadow).forEach(e => e.classList.remove("dark"));
}
if (!isM) {
main.focus();
}
});
let imageSizeSelect = ge("#imageSize", main);
for (let i = -1; i <= 400; i++) {
const option = document.createElement("option");
option.value = i;
if (i < 0) {
option.innerText = DL.str_207;
} else {
option.innerText = i + 100;
}
fragment.append(option);
}
imageSizeSelect.append(fragment);
imageSizeSelect.value = image_size;
imageSizeSelect.addEventListener("change", () => {
image_size = Number(imageSizeSelect.value);
_GM_setValue("image_size", image_size);
if (image_size < 0) {
gae("#image-list .image-item", main).forEach(item => {
item.style.width = "";
item.style.height = "";
});
} else {
gae("#image-list .image-item", main).forEach(item => {
item.style.width = image_size + 100 + "px";
item.style.height = image_size + 100 + "px";
});
}
if (!isM) {
main.focus();
}
});
if (colorThemes === "dark") {
gae(ui_selector, shadow).forEach(e => e.classList.add("dark"));
}
let widthNum = 0;
let heightNum = 0;
const updateFilterList = () => {
let num = 0;
gae("#image-list img", main).forEach(img => {
if (!/^(blob|data)/.test(img.src) || img.classList.contains("loaded")) {
const input = img.previousElementSibling;
const parent = img.parentElement;
let cw = img.naturalWidth >= widthNum;
let ch = img.naturalHeight >= heightNum;
if (cw && ch) {
input.checked = true;
input.classList.add("select");
parent.classList.remove("hide");
num += 1;
} else {
input.checked = false;
input.classList.remove("select");
parent.classList.add("hide");
}
}
});
ge("#filterNumber", main).innerText = DL.str_166 + num;
if (!isM) {
main.focus();
}
};
let widthSelect = ge("#width", main);
for (let i = 0; i <= 40; i++) {
let option = document.createElement("option");
option.value = i;
option.innerText = i == 0 ? "All" : i * 100;
fragment.append(option);
}
widthSelect.append(fragment);
widthSelect.addEventListener("change", () => {
widthNum = Number(widthSelect.value) * 100;
updateFilterList();
if (isM) {
update_g_srcs();
addGalleryImgs();
}
});
let heightSelect = ge("#height", main);
for (let i = 0; i <= 40; i++) {
let option = document.createElement("option");
option.value = i;
option.innerText = i == 0 ? "All" : i * 100;
fragment.append(option);
}
heightSelect.append(fragment);
heightSelect.addEventListener("change", () => {
heightNum = Number(heightSelect.value) * 100;
updateFilterList();
if (isM) {
update_g_srcs();
addGalleryImgs();
}
});
let threadingSelect = ge("#threading", main);
for (let i = 1; i <= 32; i++) {
let option = document.createElement("option");
option.value = i;
option.innerText = i;
fragment.append(option);
}
threadingSelect.append(fragment);
threadingSelect.value = config.threading;
threadingSelect.addEventListener("change", () => {
config.threading = Number(threadingSelect.value);
saveConfig(config);
addLis();
if (isM) {
update_g_srcs();
addGalleryImgs();
}
if (!isM) {
main.focus();
}
});
let titleReplace = fn.dt({
s: "title"
});
ge("#inputTitle", main).value = (apiCustomTitle || customTitle || titleReplace);
if (("SPA" in siteData) && ("customTitle" in siteData)) {
ge("#inputTitle", main).value = await getTitle(siteData.customTitle);
}
gae("#close", main).forEach(button => {
button.addEventListener("click", event => {
cancelDefault(event);
if (isCaptureMode) {
updateEyeNum(full_srcs.length);
}
fn.remove("#overflowYHidden");
shadowElement.remove();
isOpenFilter = false;
ViewerJsInstance?.destroy();
ViewerJsInstance_G?.destroy();
});
});
gae("#settings", main).forEach(button => button.addEventListener("click", event => {
cancelDefault(event);
createPictureLoadOptionsShadowElement();
}));
gae(".mobile_toggle_filter_gallery_btn", main).forEach(button => button.addEventListener("click", event => {
cancelDefault(event);
gae("#gallery_imgBox,.row", main).forEach(e => e.classList.toggle("hide"));
isViewMobileGallery ? isViewMobileGallery = false : isViewMobileGallery = true;
if (!isViewMobileGallery) {
gae("#homePage,a#favor,a#close,#list,a#next,a#prev,a#settings", main).forEach(e => e.classList.add("hide"));
}
}));
gae("#" + config.MobileViewMode, main).forEach(e => e.classList.add("active"));
gae("button.mode", main).forEach(button => button.addEventListener("click", event => {
cancelDefault(event);
gae("button.mode", main).forEach(e => e.classList.remove("active"));
gae("#" + button.id, main).forEach(e => e.classList.add("active"));
config.MobileViewMode = button.id;
saveConfig(config);
gae("#gallery_imgBox img", main).forEach(e => (e.className = button.id));
}));
gae("#shadow_gallery", main).forEach(button => button.addEventListener("click", event => {
cancelDefault(event);
const srcs = gae(".select+.image", main).map(img => img.dataset.src);
if (event.ctrlKey || event.altKey || event.shiftKey) {
createIframeGallery(srcs);
} else {
createShadowGallery(srcs);
}
}));
gae("#tab_gallery", main).forEach(button => button.addEventListener("click", event => {
cancelDefault(event);
const srcs = gae(".select+.image", main).map(img => img.dataset.src);
newTabView(srcs);
}));
gae("#favor", main).forEach(button => button.addEventListener("click", event => {
cancelDefault(event);
createFavorShadowElement();
}));
gae("#copy", main).forEach(button => {
button.addEventListener("click", event => {
cancelDefault(event);
const srcs = gae(".select+.image", main).map(img => img.dataset.src);
if (srcs.length == 0) return;
const text = ge("#inputTitle", main).value;
copyImgSrcTextB(srcs, text);
});
});
gae("#export", main).forEach(button => {
button.addEventListener("click", event => {
cancelDefault(event);
const srcs = gae(".select+.image", main).map(img => img.dataset.src);
if (srcs.length == 0) return;
const text = ge("#inputTitle", main).value;
exportImgSrcText(srcs, text);
});
});
gae("#select-all", main).forEach(button => {
button.addEventListener("click", event => {
cancelDefault(event);
gae("input.check", main).forEach(input => {
input.checked = true;
input.classList.add("select");
ge("#filterNumber", main).innerText = DL.str_166 + srcs.length;
});
if (isM) {
update_g_srcs();
addGalleryImgs();
}
});
});
gae("#unselect-all", main).forEach(button => {
button.addEventListener("click", event => {
cancelDefault(event);
gae("input.check", main).forEach(input => {
input.checked = false;
input.classList.remove("select");
ge("#filterNumber", main).innerText = DL.str_166 + "0";
});
if (isM) {
update_g_srcs();
addGalleryImgs();
}
});
});
gae("#reverse-selection", main).forEach(button => {
button.addEventListener("click", event => {
cancelDefault(event);
gae("input.check", main).forEach(input => {
if (input.checked) {
input.checked = false;
input.classList.remove("select");
} else {
input.checked = true;
input.classList.add("select");
}
const selects = gae(".select+.image", main);
ge("#filterNumber", main).innerText = DL.str_166 + selects.length;
});
if (isM) {
update_g_srcs();
addGalleryImgs();
}
});
});
gae("#exclude-error", main).forEach(button => button.addEventListener("click", event => {
cancelDefault(event);
gae("#image-list img.error", main).forEach(img => {
img.previousElementSibling.checked = false;
img.previousElementSibling.classList.remove("select");
img.parentElement.classList.add("hide");
});
const selects = gae(".select+.image", main);
ge("#filterNumber", main).innerText = DL.str_166 + selects.length;
if (isM) {
update_g_srcs();
addGalleryImgs();
}
}));
gae("#reload", main).forEach(button => button.addEventListener("click", event => {
cancelDefault(event);
widthSelect.value = 0;
heightSelect.value = 0;
ge("#filterNumber", main).innerText = DL.str_166 + srcs.length;
addLis();
if (isM) {
update_g_srcs();
addGalleryImgs();
}
}));
gae("#combineDownload", main).forEach(button => button.addEventListener("click", event => {
cancelDefault(event);
const srcs = gae(".select+.image", main).map(img => img.dataset.src);
if (srcs.length == 0) return;
combineDownloadSwitch = true;
const text = ge("#inputTitle", main).value;
DownloadFn(srcs, text);
}));
gae("#download", main).forEach(button => button.addEventListener("click", event => {
cancelDefault(event);
const srcs = gae(".select+.image", main).map(img => img.dataset.src);
if (srcs.length == 0) return;
const text = ge("#inputTitle", main).value;
DownloadFn(srcs, text);
}));
let inputAEE = ge("#auto-exclude-error", main);
inputAEE.checked = config.aee == 0 ? false : true;
inputAEE.addEventListener("change", () => {
config.aee = inputAEE.checked ? 1 : 0;
saveConfig(config);
widthSelect.value = 0;
heightSelect.value = 0;
ge("#filterNumber", main).innerText = DL.str_166 + srcs.length;
addLis();
if (isM) {
update_g_srcs();
addGalleryImgs();
}
if (!isM) {
main.focus();
}
});
let inputSize = ge("#size", main);
if (config.noSize == 1) {
inputSize.parentNode.classList.add("line-through");
}
inputSize.checked = showSize == 1 ? true : false;
inputSize.addEventListener("change", () => {
showSize = inputSize.checked ? 1 : 0;
config.showSize = showSize;
saveConfig(config);
widthSelect.value = 0;
heightSelect.value = 0;
ge("#filterNumber", main).innerText = DL.str_166 + srcs.length;
addLis();
if (isM) {
update_g_srcs();
addGalleryImgs();
}
if (!isM) {
main.focus();
}
});
let inputMove = ge("#move", main);
if (inputMove) {
inputMove.checked = move == 1 ? true : false;
inputMove.addEventListener("change", () => {
move = inputMove.checked ? 1 : 0;
config.move = move;
saveConfig(config);
widthSelect.value = 0;
heightSelect.value = 0;
ge("#filterNumber", main).innerText = DL.str_166 + srcs.length;
addLis();
if (isM) {
update_g_srcs();
addGalleryImgs();
}
if (!isM) {
main.focus();
}
});
}
const imageList = ge("#image-list", main);
const ViewerOptions = {
navbar: false,
title: false,
initialCoverage: 0.99,
interval: FancyboxSlideshowTimeoutNum,
url: "data-src",
ready: () => gae("body>.viewer-container").forEach(e => e.removeAttribute("style")),
viewed: (event) => instantScrollIntoView(event.detail.originalImage)
};
if (options.fancybox == 1 && ("Viewer" in _unsafeWindow)) {
Viewer = _unsafeWindow.Viewer;
ViewerJsInstance = new Viewer(imageList, ViewerOptions);
}
const addLis = () => {
ge("#total", main).innerText = DL.str_165 + srcs.length;
imageList.innerHTML = "";
const loadImgList = [];
inputs = [];
for (const [index, src] of srcs.entries()) {
const input = document.createElement("input");
input.className = "check select";
input.dataset.index = index;
input.setAttribute("type", "checkbox");
input.checked = true;
input.onchange = () => {
if (input.checked == true) {
input.classList.add("select");
} else {
input.classList.remove("select");
}
const selects = gae(".select+.image", main);
ge("#filterNumber", main).innerText = DL.str_166 + selects.length;
if (isM) {
update_g_srcs();
addGalleryImgs();
}
};
input.onclick = event => {
if ((event.ctrlKey || event.altKey || event.shiftKey) && isEle(startInput)) {
let startNum = Number(startInput.dataset.index);
let endNum = Number(event.target.dataset.index);
if (startNum < endNum) {
for (let i = startNum; i <= endNum; i++) {
if (!inputs[i]?.parentElement?.classList.contains("hide")) {
inputs[i].checked = true;
inputs[i].classList.add("select");
}
}
} else if (startNum > endNum) {
for (let i = startNum; i >= endNum; i--) {
if (!inputs[i]?.parentElement?.classList.contains("hide")) {
inputs[i].checked = true;
inputs[i].classList.add("select");
}
}
}
const selects = gae(".select+.image", main);
ge("#filterNumber", main).innerText = DL.str_166 + selects.length;
} else {
startInput = event.target;
}
};
inputs.push(input);
const img = new Image();
img.className = "image";
if ("referrerpolicy" in siteData) {
img.setAttribute("referrerpolicy", siteData.referrerpolicy);
}
img.src = loading_bak;
img.dataset.src = src;
img.onload = () => {
if (img.classList.contains("loaded")) {
if (move == 0 || isM) {
p.innerText = img.naturalWidth + " x " + img.naturalHeight;
} else {
p.innerText = (index + 1) + "P | " + img.naturalWidth + " x " + img.naturalHeight;
}
if (config.noSize != 1 && showSize != 0) {
getFileSize(img.src, p, inputSize.parentNode);
}
}
img.classList.remove("error");
};
img.onerror = (error) => {
if (siteData?.name == "梦想岛") {
if (!("load_jpg" in error.target.dataset)) {
let src = error.target.dataset.src.replace(/\.\w+$/i, ".jpg");
error.target.dataset.load_jpg = 1;
error.target.dataset.src = src;
error.target.src = src;
} else if (!("load_png" in error.target.dataset)) {
let src = error.target.dataset.src.replace(/\.\w+$/i, ".png");
error.target.dataset.load_png = 1;
error.target.dataset.src = src;
error.target.src = src;
} else if (!("load_jpeg" in error.target.dataset)) {
let src = error.target.dataset.src.replace(/\.\w+$/i, ".jpeg");
error.target.dataset.load_jpeg = 1;
error.target.dataset.src = src;
error.target.src = src;
}
}
if (config.aee == 1) {
input.checked = false;
input.classList.remove("select");
li.classList.add("hide");
const selects = gae(".select+.image", main);
ge("#filterNumber", main).innerText = DL.str_166 + selects.length;
if (isM) {
update_g_srcs();
addGalleryImgs();
}
}
if (move == 0 || isM) {
p.innerText = "? x ?";
} else {
p.innerText = (index + 1) + "P | ? x ?";
}
};
loadImgList.push([simpleLoadImg, null, img]);
const p = document.createElement("p");
if (move == 0 || isM) {
p.innerText = "? x ?";
} else {
p.innerText = (index + 1) + "P | ? x ?";
}
const li = document.createElement("li");
li.className = "image-item";
if (image_size > -1) {
li.style.width = image_size + 100 + "px";
li.style.height = image_size + 100 + "px";
}
if (colorThemes === "dark") {
p.classList.add("dark");
li.classList.add("dark");
}
li.append(input);
li.append(img);
li.append(p);
if (move != 0 && isPC) {
li.setAttribute("draggable", true);
li.addEventListener("dragstart", drag_sort_start);
li.addEventListener("drop", drop_sort);
li.addEventListener("dragenter", cancelDefault);
li.addEventListener("dragover", cancelDefault);
}
fragment.append(li);
}
imageList.append(fragment);
const imgBox = ge("#imgBox", main);
if (imgBox.offsetHeight > (innerHeight * 1.5)) {
gae("#scroll_U,#scroll_D", main).forEach(e => e.classList.remove("hide"));
}
if (Viewer && ViewerJsInstance) {
ViewerJsInstance.update();
}
if (!isM) {
main.focus();
}
setTimeout(() => {
const queue = new Queue(Number(config.threading));
queue.addList(loadImgList);
queue.run();
}, 200);
};
addLis();
if (GalleryInIcon == 1 && options.shadowGallery == 1) {
let button = ge("#shadow_gallery", main);
EClick(button);
}
if (isPC) return;
const gallery_imgBox = ge("#gallery_imgBox", main);
if (options.fancybox == 1 && ("Viewer" in _unsafeWindow)) {
ViewerJsInstance_G = new Viewer(gallery_imgBox, ViewerOptions);
}
const addGalleryImgs = () => {
gallery_imgBox.innerHTML = "";
const loadImgList = [];
for (const [index, src] of g_srcs.entries()) {
const img = new Image();
img.className = ge("button.mode.active", main).id;
if ("referrerpolicy" in siteData) {
img.setAttribute("referrerpolicy", siteData.referrerpolicy);
}
img.src = loading_bak;
img.dataset.src = src;
img.onerror = (error) => {
if (siteData?.name == "梦想岛") {
if (!("load_jpg" in error.target.dataset)) {
let src = error.target.dataset.src.replace(/\.\w+$/i, ".jpg");
error.target.dataset.load_jpg = 1;
error.target.dataset.src = src;
error.target.src = src;
} else if (!("load_png" in error.target.dataset)) {
let src = error.target.dataset.src.replace(/\.\w+$/i, ".png");
error.target.dataset.load_png = 1;
error.target.dataset.src = src;
error.target.src = src;
} else if (!("load_jpeg" in error.target.dataset)) {
let src = error.target.dataset.src.replace(/\.\w+$/i, ".jpeg");
error.target.dataset.load_jpeg = 1;
error.target.dataset.src = src;
error.target.src = src;
}
}
};
loadImgList.push([simpleLoadImg, null, img]);
fragment.append(img);
}
if (isString(nextLink)) {
const next = document.createElement("div");
next.id = "next";
next.dataset.url = nextLink;
if (colorThemes === "dark") {
next.classList.add("dark");
}
next.innerText = `${siteData.category?.includes("comic") ? DL.str_143 : DL.str_144}`;
next.addEventListener("click", event => {
cancelDefault(event);
return (isGoToNext = true) && setTimeout(() => (location.href = nextLink), 200);
});
fragment.append(next);
}
gallery_imgBox.append(fragment);
if (Viewer && ViewerJsInstance_G) {
ViewerJsInstance_G.update();
}
const queue = new Queue(Number(config.threading));
queue.addList(loadImgList);
queue.run();
};
addGalleryImgs();
if (enterGallery || options.mobileGallery == 1) {
let button = ge(".mobile_toggle_filter_gallery_btn", main);
EClick(button);
if (gallery_imgBox.offsetHeight > innerHeight) {
gae("#scroll_U,#scroll_D", main).forEach(e => e.classList.remove("hide"));
}
}
let list_main;
if ("chapters" in siteData) {
// 創建目錄
const get_chapters = siteData.chapters;
const createChapterList = async () => {
let chapterListData = [];
if (isObject(get_chapters)) {
chapterListData = await fn.getChapters(get_chapters);
} else if (isFn(get_chapters)) {
chapterListData = await get_chapters();
}
if (!isArray(chapterListData) || !chapterListData?.length) return;
chapterListObtained = true;
const tempURLs = new Set();
chapterListData = chapterListData.filter(({
url
}) => {
if (tempURLs.has(url) || url == "#") {
return false;
} else {
tempURLs.add(url);
}
return true;
});
list_main = document.createElement("div");
list_main.id = "modal-content-list";
list_main.className = config.colorThemes == "dark" ? "hide dark" : "hide";
const list_close = document.createElement("span");
list_close.className = config.colorThemes == "dark" ? "closeModal dark" : "closeModal";
list_close.innerText = `× ${DL.str_132}`;
list_close.addEventListener("click", () => {
list_main.classList.add("hide");
isOpenChapterList = false;
});
list_main.append(list_close);
const list_container = document.createElement("div");
list_container.id = "chapterListContainer";
list_container.className = "chapter-list-container";
list_main.append(list_container);
const pathname = decodeURIComponent(fn.clp());
const search = fn.cls();
let isCurrent = false;
let currentButton;
const list = chapterListData.map(({
text,
url
}) => {
const button = document.createElement("button");
button.className = config.colorThemes == "dark" ? "chapter-btn dark" : "chapter-btn";
button.innerText = text;
button.dataset.url = url;
if ("checkCurrentChapter" in siteData) {
isCurrent = siteData.checkCurrentChapter(url, text);
}
if (
isCurrent ||
search && url.endsWith(search) ||
!search && decodeURIComponent(url).endsWith(pathname) ||
search.includes("page=") && url.includes(pathname)
) {
button.classList.add("current-chapter");
currentButton = button;
} else {
button.addEventListener("click", (event) => (location.href = event.target.dataset.url));
}
return button;
});
list_container.append(...list);
const footer = document.createElement("div");
footer.id = "chapters-footer";
const close_button = document.createElement("button");
close_button.id = "footer_close_button";
close_button.className = config.colorThemes == "dark" ? "dark" : "";
close_button.innerText = DL.str_132;
close_button.addEventListener("click", () => {
list_main.classList.add("hide");
isOpenChapterList = false;
});
footer.append(close_button);
list_main.append(footer);
shadow.append(list_main);
main.addEventListener("click", () => {
if (isOpenChapterList) {
list_main.classList.add("hide");
isOpenChapterList = false;
}
});
let prev_url = currentButton?.previousElementSibling?.dataset?.url;
if (!isString(prevLink) && isString(prev_url) && prev_url != nextLink) {
prevLink = prev_url;
}
};
createChapterList();
}
};
const getXY = (event) => {
let x, y;
if (event.type.includes("mouse")) {
x = event.clientX;
y = event.clientY;
} else {
x = event.changedTouches[0].clientX;
y = event.changedTouches[0].clientY;
}
return {
x: x,
y: y
}
};
//創建新分頁檢視眼睛圖示按鈕和圖片數量元素
let viewImgDown = false;
let isDragging = false;
let isAddViewImgDraggEvent = false;
let startX, startY, startLeft, startTop;
let eventViewImg, eventMenu;
let EyeNumElement;
let eye_icon_top = _GM_getValue("eye_icon_top", "auto");
let eye_icon_bottom = _GM_getValue("eye_icon_bottom", "24px");
let eye_icon_left = _GM_getValue("eye_icon_left", "auto");
let eye_icon_right = _GM_getValue("eye_icon_right", "24px");
let eye_menu_top = _GM_getValue("eye_menu_top", "auto");
let eye_menu_bottom = _GM_getValue("eye_menu_bottom", "22px");
let eye_menu_left = _GM_getValue("eye_menu_left", "auto");
let eye_menu_right = _GM_getValue("eye_menu_right", "64px");
const eyeObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (!entry.isIntersecting) {
entry.target;
entry.target.style.top = "auto";
entry.target.style.bottom = "24px";
entry.target.style.left = "auto";
entry.target.style.right = "24px";
eventMenu.style.top = "auto";
eventMenu.style.bottom = "22px";
eventMenu.style.left = "auto";
eventMenu.style.right = "64px";
}
});
});
const addNewTabViewButton = () => {
if (ge("#FullPictureLoadEye") || FullPictureLoadShowEye == 0) return;
isAddNewTabViewButton = true;
if ("page" in siteData && isFn(siteData.page)) {
if (!siteData.page()) return;
}
let img = new Image();
img.id = "FullPictureLoadEye";
img.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAEV0lEQVRYhb2XTWwTRxTHTShJ4NDegJ4rwbGngkpVxCGQ3loVcaIlEuJU2h5oKyFQtXaigojj3VAQErTlQxQCiRMaoF+HxjhNjD/XxVISbGPHxEAc3MR8xo5xeMybZNezn7HAYaUXWZuZ9/vPmzdv3loaGjbVEltGzGL2cMDV2ELC+81hYX9zmO9sFgVfS1iIN4t83Opv81u9bV2cp/X7fX0HPtz6zSd1C/mTn4XgnIurbxH5bwkwRYDAGoGDLeDQmsincA7OrUSA7nsAWNIS4psIeEwNNoPj+/I4/jaZvwN9VRaO+edw9HAdmXxGD1w5XDH+Ahc8vqIiOOdrXU3g/mrBy/MEH/o2h8/tt7facEZEiI2EYvvpnoeFc4sFl/2QE4QshOMBkAVgwi02XPYXcHw+f/pqy6EnGfta4OjP35b+WvjyLVkAntlK4IfEI9AVvwKe8QD4snHoGbtFzU9+ezJB6E7+DvbIMXP4vC/O2/odFYD7Qf6RNBt8auQCDN2PQiFfAN//D6Fh4AYs7XXDkt/m7I3eftgyEIHg5GOYLc3CzdwtOBPvNI+k3z7a1LS91oLl1Qj+Y+RnGMnGoFgoUjt7OwN1l/tlsNrwf+fHJgBmgVrsQRKODp803sagfZ0Fa7se3Bm/Ck+mn8pwXHmtCZwVEZp6LIsoFGeoL90cEvm9FjwWavjfKZcMRnteeg6bSYgliPNOFtx37sPbX9lg5W4r1J9wKkQ0DkYoHOdJPtzp63oJ3IERCLDw/rRXA8/mi4o9T+SeQG7qEby7cRusXf8xrNnwqUIE5kR2ekbhB60/7VGcHqyOFvInKsF7E39q4LiSwexDxQrf2XMA1m3eTuGSrfyCK4+5dA0GMpMaAejvr7SrnG8h/iZJQj4qhYYVIMHRPCoBGHYWTgWQdxK8prsPBsYndRejEWANtAXZ5MAwsXA03AIMqyQAw41hl+BrPtgK9T91y/BlPX2QeTStgf877tNcUOT2szvV2em+d10hAG0Lk4SSCAw7Gguv6f4HGt2iBu66O6hXnDos2EbpldfOxBXIFwuyACwyhjWAgS+/5ILAxJQMn3k2Az2jf+hXRzyG2MMZ1fYjQ79ANJeQRWCR0YhQwc+N3pXhWBHRh1Fptont71mwHNpCDk0pZu107CKM5OJQKpVokcFzTnOC2fOP3GG68nw+D8OTMTrH9GIS+VHaquG9bHQZqa2VXDTO5FUYzATAOxGFzuQIdBHz3BuiheZirBcO3Tha2c34n7BH0Qnpdb2V3GovdUWT1WPfqWjHsHt9LXD0EW7/TNMP0ms5JPy62HCy+rO6PeFCTWl1OiM+KDWlmp6QbcvnP7uqvXLvD5H2VSxcbsnUD/thUqWesMPhcSxXww0FyDlBuldyV6Re4TsgxSacGm4qQBq86+DON7GBtPrtyYrhopDAc84eNT24bg4YDcaKiT0c1m/81sM9neslhOjcb/puL5ZX9ceoERzfvwApT7t293t0AgAAAABJRU5ErkJggg==";
img.style.top = eye_icon_top;
img.style.bottom = eye_icon_bottom;
img.style.left = eye_icon_left;
img.style.right = eye_icon_right;
img.oncontextmenu = () => false;
img.addEventListener("click", event => {
cancelDefault(event);
newTabView();
});
document.body.append(img);
eventViewImg = img;
let menuDiv = document.createElement("div");
menuDiv.id = "FullPictureLoadFixedMenuB";
menuDiv.style.top = eye_menu_top;
menuDiv.style.bottom = eye_menu_bottom;
menuDiv.style.left = eye_menu_left;
menuDiv.style.right = eye_menu_right;
const menuObj = [{
id: "FullPictureLoadCaptureNum",
text: "0",
cfn: async event => {
cancelDefault(event);
let selector = siteData.capture || siteData.srcset || siteData.imgs;
let srcArr = await getImgs(selector);
if (srcArr.length == 0) return fn.showMsg(DL.str_44);
let titleText = apiCustomTitle ?? customTitle ?? document.title;
let picNum = srcArr.length;
let fileName = `${titleText}[${picNum}P]_MediaURLs.txt`;
if (videoSrcArray.length > 0) {
srcArr = srcArr.concat(videoSrcArray);
fileName = `${titleText}[${picNum}P + ${videoSrcArray.length}V]_MediaURLs.txt`;
}
let str = srcArr.join("\n");
let blob = new Blob([str], {
type: "text/plain",
endings: "native"
});
saveData(blob, fileName);
fn.showMsg(`${DL.str_101}`);
}
}];
const createMenu = obj => {
let item = document.createElement("div");
if (!!obj.id) item.id = obj.id;
item.innerText = obj.text;
item.oncontextmenu = () => false;
if (!!obj.cfn) item.addEventListener("click", obj.cfn);
if (!!obj.mfn) item.addEventListener("mousedown", obj.mfn);
EyeNumElement = item;
menuDiv.append(item);
};
[...menuObj].forEach(obj => createMenu(obj));
document.body.append(menuDiv);
eventMenu = menuDiv;
eyeObserver.observe(img);
const downEvent = (event) => {
const obj = getXY(event);
viewImgDown = true;
startX = obj.x;
startY = obj.y;
startLeft = eventViewImg.offsetLeft;
startTop = eventViewImg.offsetTop;
};
const moveEvent = (event) => {
if (!viewImgDown) return;
cancelDefault(event);
const obj = getXY(event);
isDragging = true;
const dx = obj.x - startX;
const dy = obj.y - startY;
eye_icon_top = "auto";
eye_icon_bottom = (_unsafeWindow.innerHeight - (startTop + dy + (isM ? 16 : 32))) + "px";
eye_icon_left = "auto";
eye_icon_right = (_unsafeWindow.innerWidth - (startLeft + dx + (isM ? 16 : 48))) + "px";
_GM_setValue("eye_icon_top", eye_icon_top);
_GM_setValue("eye_icon_bottom", eye_icon_bottom);
_GM_setValue("eye_icon_left", eye_icon_left);
_GM_setValue("eye_icon_right", eye_icon_right)
eventViewImg.style.top = eye_icon_top;
eventViewImg.style.bottom = eye_icon_bottom;
eventViewImg.style.left = eye_icon_left;
eventViewImg.style.right = eye_icon_right;
eye_menu_top = "auto";
eye_menu_bottom = (_unsafeWindow.innerHeight - (startTop + dy + (isM ? -16 : 0) + (eventMenu.offsetHeight - ((eventMenu.offsetHeight - eventViewImg.offsetHeight) / 2)))) + "px";
eye_menu_left = "auto";
eye_menu_right = (_unsafeWindow.innerWidth - (startLeft + dx + (isM ? -24 : 8))) + "px";
_GM_setValue("eye_menu_top", eye_menu_top);
_GM_setValue("eye_menu_bottom", eye_menu_bottom);
_GM_setValue("eye_menu_left", eye_menu_left);
_GM_setValue("eye_menu_right", eye_menu_right);
eventMenu.style.opacity = "0";
eventMenu.style.top = eye_menu_top;
eventMenu.style.bottom = eye_menu_bottom;
eventMenu.style.left = eye_menu_left;
eventMenu.style.right = eye_menu_right;
};
const upEvent = (event) => {
eventMenu.style.opacity = "1";
viewImgDown = false;
setTimeout(() => {
isDragging = false;
}, 100);
};
if (isM) {
img.addEventListener("touchstart", downEvent, {
passive: false,
capture: true
});
if (!isAddViewImgDraggEvent) {
isAddViewImgDraggEvent = true;
document.addEventListener("touchmove", moveEvent, {
passive: false,
capture: true
});
document.addEventListener("touchend", upEvent);
}
} else {
img.addEventListener("mousedown", downEvent);
if (!isAddViewImgDraggEvent) {
isAddViewImgDraggEvent = true;
document.addEventListener("mousemove", moveEvent);
document.addEventListener("mouseup", upEvent);
}
}
};
const updateEyeNum = (num) => {
if (isEle(EyeNumElement)) {
EyeNumElement.innerText = num;
}
};
//清除圖片縮放級別
const cancelZoom = () => {
if (isFetching || !siteData.insertImg || isOpenOptionsUI) return;
if (ge(".FullPictureLoadImage:not(.small)")) {
options.zoom = 0;
let jsonStr = JSON.stringify(options);
localStorage.setItem("FullPictureLoadOptions", jsonStr);
gae(".FullPictureLoadImage:not(.small)").forEach(img => {
img.style.width = "";
let pE = img.parentNode;
if (pE.nodeName === "A") {
pE.style.width = "";
}
});
fn.showMsg(DL.str_61);
}
};
//創建腳本在頁面左下的功能按鈕
let imgDown = false;
let isAddDraggEvent = false;
let eventImg;
let icon_top = _GM_getValue("icon_top", "auto");
let icon_bottom = _GM_getValue("icon_bottom", "24px");
let icon_left = _GM_getValue("icon_left", "24px");
let icon_right = _GM_getValue("icon_right", "auto");
const iconObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (!entry.isIntersecting) {
entry.target.style.top = "auto";
entry.target.style.bottom = "24px";
entry.target.style.left = "24px";
entry.target.style.right = "auto";
}
});
});
const addFullPictureLoadButton = () => {
if (ge("#FullPictureLoad")) return;
isAddFullPictureLoadButton = true;
if ("page" in siteData && isFn(siteData.page)) {
if (!siteData.page()) return;
}
let img = new Image();
img.id = "FullPictureLoad";
img.className = "FullPictureLoadFixedBtn";
img.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAACFlBMVEVEREAAAABEREBEREBUXnFTXXBTXG5VXXJUXHFUW28grV0grV0hrl4hrV0hq10iql0oomAhrV2BiZiAiJd/h5V+h5Uiq16OlaKNlKGMk5+Mkp+KkZ89p28nq2Hp9+/n9u3t8PHs7/Dg9Ojp7O3d8+bo7O3o6+zn6+3m6uzl6evX8OLV8OHi5ujh5efO7dze4uTe4ePb3+LY3eDX29/W2t7T19u35Mu25Mr01lqw4sbz1Vmv4sXA1NWs4cPw0lnv0lmp4MCk3r3ozVuh3buu0M6vz83kylugysefycadx8OexsOdxsOF0qZ6zp5pyJK1p2S0pmOsoGRWv4SLlKEmuZpBsnc5t3AmuJmQi2ont5kmtpcptJiOiWg0tWwytGorr5Yqr5YsrpUws2kqrJRNmpMusmcsqpIuqJMssWkqsWQqsGUnsGUzoI8lsGGAf2wkr2Ekr2BzfI0irl8hrl5ye4x9fGogrWAhrV03mIwgrF9xeoshq10gql8dp2ccp2cdpmkcnIUanIYcm4QRoIUTnoURn4QdmYM/h4QcmIMSnYMXmoMWmoIbloIclYJDgYIYl4EaloAek4IfkYFqbm0jjoBqbW0ni4ApiX9Hd35kanBjaXBhaG9MbnpOanhOaXhPaHdDbXZHanZGanRLZnZJZ3RSYnVMZXRPY3ROY3VSYXRQYnRTYHRVX3NUX3RSYHNUXnNTXXJTXXFME6frAAAAHnRSTlMAAAUGZ2dqeHh7lrzNzc7O3O/09PT19fn5+fn5/f4hZOrvAAAB1UlEQVR42oWTzYoTQRSFv6q6RqOoqBicTTCKK1cOURBGBV9AXCgu9Vl8FF/ApcshI4qKgrtBByZK0HSGmMxkMrF/qq6LTjptErGX5zu3uu65dY3TYCh9ag2UNPsfjnmpZW4MgBbaIy/6PCnxvL7gEQhJ7AruAqifcZ96EHDX67ngKgCJn/k3B6AC1O9Cj9ri/2mBsZIf9iLi0rMFDhhjbO6NsL9er+CQG3pYMT+XuGVmuH9SzPF7S/UONDfUHl44/6A24wfdpMgsSO6tP52ffxjF6cUT056MBdxf/cVRzP6PiQG8KhZMJedhewik0QT43RsBQUEwLufZx53Td85p7wCwEu+Fs6qAGBsA1aO3XUZbG/EAsAJJlM/MGgOoDltdYNTam3JIOlVmOaj2N/sAjHf9lGdBqwACmmi0FU/TOWxfEY483o/9tcuvJBXU+90PaZHf5NtVFzTL+N7bqD4GS9DRmzl3btJWk2WFIKradqX8LfudU3VKBuKd0vwc+HCjNDJhkJXfB6jq+wZJBSAT5MmKN1/la7sJ+jmsiyQrdkZo9N819FNnXcSZFTt1rGnXhl/G6a26IP/YOXczi5prQmFY3snbkzNSXGyBV+28p+nNF+vn2h97PvHD5SOHkgAAAABJRU5ErkJggg==";
img.style.top = icon_top;
img.style.bottom = icon_bottom;
img.style.left = icon_left;
img.style.right = icon_right;
img.addEventListener("click", event => {
cancelDefault(event);
fastDownloadSwitch = false;
//DownloadFn();
createFilterUI();
});
if (!isSimpleMode) {
img.setAttribute("title", DL.str_47);
img.oncontextmenu = () => false;
img.addEventListener("mousedown", event => {
if (event.button == 1) {
cancelDefault(event);
exportImgSrcText();
}
if (event.button == 2) {
cancelDefault(event);
copyImgSrcText();
}
});
}
document.body.append(img);
eventImg = img;
iconObserver.observe(img);
if ("insertImg" in siteData) {
let img2 = new Image();
img2.id = "FullPictureLoadGoToFirstImage";
img2.className = "FullPictureLoadFixedBtn";
img2.style.display = "none";
img2.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAA7BJREFUWEetl29olVUYwH/n3jvvGpp/WtNlIdoK1MJazBwO0/mlZqFgRCgGfZC7TTbwixqbMnPiHIIwmdd9MYiMhD4o6gqirenGsoF/MLfaahFz3a1Shlv7e9/3yHnnxXvv3vee96574P3wcp4/v/M8z3nOOQK3o67Oj2+0EMlWPKxEkg3Wp0YIQQiTLgQXCWc0UV4+4ca00Ao1HM3G8B0CuROYp5WfFhgGcQ5v+FMCFaFEOs4An1WlM+6vRIq9QIZLx/Fiowh5kvSJaj6uGrezYQ9QX7sEYV4A3pyl43i160jPNvbsG4ifmAlwquZVfDQieV7nfJE/3RJ5MGG7uFh1wT3CFFF24E70RCyAWrnH7NA5V0pH8gooW51r2Tp19wYHO1qROmIFYXryoiPxBEDlfCz9B13YlULd+s0EVq6JcdfQdZvytu/1EHCdp8Y3RmriCUDwWDVSVOgq1s55RMc1hJBHKfmkUulNA1hbzftbomp3Wnk8sEuIUbxGjtqi0wCnjwdBFjut3q3z5CIhzlC6v0Qw3eH+cWoyyTpPAmKYcMazgtM17wCNTk0iUc51Re8iHUWC+pozCAJ2DeL/OHcVCUmDIFjTgmRDPMDB3HzUl4qxq7mR87//MtOU4KpKQTfwUvTsgjl+QrtK8Qr9WeUGsG2gn02Xz9uJ9iiAYWBu9OwbmYtp36YOv9SM/8JTZH1ez5RpxhscsQWYP8fPnzsCZPh8MQph0+THv0MULFlqS9Y60M+6rGx8Hk/M/Nlf71B87Ts7HQtgRgqUZNkruZxYt/Fxp4JJ0+Cj5m/IeXoB1XkFtgCVHa10Dt2ndu0GcuYvtGR+fvAvO5uu0DV03yEFDkWopNVqtix70QrdFz2d9D4cYt+atQkBam//ZEFvXrqMCcPg2sA95zxaReiwDZ203AC4rhxrGyZoRHaGUgoARdpWHA+RQoDHrVh50BxG0RApBAhSeqDU9XEcgUgRwAhpRg67KwaTupAoiD2rX+dk/ibbOtvb3kz93Zv6GhTiECX7jyjBpK9k+Yufo+W9D22dvHXpK9oH/9IAiDYyxwr5oGoyFkD9ubyUfln4Lu+veDnG0de93exouqxz3kdaOE+FPiI4q2u5OqRKVr3G2y8st+x82/cHwc5bGDLRvVj0Ycgtia/lEayUP0xEG2nh7dErd45AZCY1T7MRhKjlmbHjkZzH50h/4M/ucfoQOEeacdhu1dEQeoCItPPzXCVenTj9SNmJ4BLeRS0EAlP6/QiPAMXOipDq4W0VAAAAAElFTkSuQmCC";
img2.setAttribute("title", DL.str_62);
img2.addEventListener("click", event => {
cancelDefault(event);
goToImg("first");
});
document.body.append(img2);
let img3 = new Image();
img3.id = "FullPictureLoadGoToLastImage";
img3.className = "FullPictureLoadFixedBtn";
img3.style.display = "none";
img3.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAA6lJREFUWEfFl21IlWcYx3/3c46vayG1lq5i5FablrQFbon2oiOYzlgfgsY2gvrinCQEwzayklI69SVQPMdDH4KJMkZBoxf6kpkYVjK32FqgtiGbs8xczeF0O5477ucknZfnzaPUDc+n57ru/++67uu6XwROh9+fwNToRiRbECIbWAIsBQQwhGCIILcRfEcgtY3KykknUytn63GibjH/uw4CnwDz7cyf/B8D0YIrcIiyfUNWPuYA39Yk8iBlL1JWAfMcCkebjSPkcZIna9lZM2E0hzGAHrX7NMj8OIWj3a4jta1UVN2N/hEL0ODJwSXOg1xmJu4SgvLst3h/2XLd5OLvv+H75UempDTnFfxBgBJ2f/lTuFEkQCjybitx5dxaVMq2zJURYqd+7eXjtnPWCVMQQS03PBNPAdSaj6S02aU9b/ErXNnykaHQxrPf0HXvT7tVu07KxKbpmngK4Du6HykP2XlXrHqb43mFhmZ7ui7TeOsHuylAyDrKv6pWhiGAUKv1O6n2qjXvUJtbYChS3d3JsZs37AFgHNfU66pFQwBejxcod+I5RwAq9iY+31suqK9Pwj1+H3jx2QIwRiB1kcDrKQYuOBFXNnOXAV2xRNDoaUJQ9lwAJH6Bz3MFyQYzgPXpS0lyubg0OIDaZpxkIHN+Gp+uyCZB0zg/cIdrwybHgaBDLUEvsCIaICttIS1FH7B6wUv6r/5Hf1F1o4PstIWWXdD/90O+LiwmUXPpfgr6i2vtNPzcYxRjnwIYM2q/pvWb2fVGToRTIBjUoylIVydx7Oi8O8i6lzNwa1rEz/FAgFdb/Tz6L+aE/scQQKVueEcFL7gTnJaGrV3emRa+H7kXbacDGC7B5dLt5JtEaqsWZaAOqYxmLw9jM9BnWoTbX3uT5sKSmWoZ2h/u6UJ9MUMvQpM2VFtkff57lGWtmRWE//ZNKq9e0osxZuhtaLERzRbCUjxEU2K7FccL4UD8yVasOLxHfSA/M8v1TCEciIcdRkrVX5fBlH4cp84Wwpl49HGsVH1HapFin1XF2WXCobjBhUSpnqxJ5t/kduDdeCAci4PJlUypNh5LRwt2I/UXj+lQmTicW8DuVWt1m4ZbPezv7jRutfBZLC+l04bqWu7mgh2EMl+QlKx7jU4avjkiA3B0LZ92UZkQwTN2yzGDHWoGD5PpWVVNTCRVI8Ueq+6wgYjzaRY+q96i7gMg1ePU0b0RmIPHaXRooctrEZIP0chCkgH6p0bcz/PHF6yIkDG/FFMAAAAASUVORK5CYII=";
img3.setAttribute("title", DL.str_63);
img3.addEventListener("click", event => {
cancelDefault(event);
goToImg("last");
});
document.body.append(img3);
}
const downEvent = (event) => {
const obj = getXY(event);
imgDown = true;
startX = obj.x;
startY = obj.y;
startLeft = eventImg.offsetLeft;
startTop = eventImg.offsetTop;
};
const moveEvent = (event) => {
if (!imgDown) return;
cancelDefault(event);
const obj = getXY(event);
isDragging = true;
const dx = obj.x - startX;
const dy = obj.y - startY;
icon_top = "auto";
icon_bottom = (_unsafeWindow.innerHeight - (startTop + dy + (isM ? 16 : 32))) + "px";
icon_left = (startLeft + dx - (isM ? 16 : 0)) + "px";
icon_right = "auto";
_GM_setValue("icon_top", icon_top);
_GM_setValue("icon_bottom", icon_bottom);
_GM_setValue("icon_left", icon_left);
_GM_setValue("icon_right", icon_right);
eventImg.style.top = icon_top;
eventImg.style.bottom = icon_bottom;
eventImg.style.left = icon_left;
eventImg.style.right = icon_right;
};
const upEvent = (event) => {
imgDown = false;
setTimeout(() => {
isDragging = false;
}, 100);
};
if (isM) {
img.addEventListener("touchstart", downEvent, {
passive: false,
capture: true
});
if (!isAddDraggEvent) {
isAddDraggEvent = true;
document.addEventListener("touchmove", moveEvent, {
passive: false,
capture: true
});
document.addEventListener("touchend", upEvent);
}
} else {
img.addEventListener("mousedown", downEvent);
if (!isAddDraggEvent) {
isAddDraggEvent = true;
document.addEventListener("mousemove", moveEvent);
document.addEventListener("mouseup", upEvent);
}
}
};
//創建浮動選單
const addFullPictureLoadFixedMenu = () => {
if (ge("#FullPictureLoadFixedMenu")) return;
isAddFullPictureLoadFixedMenu = true;
if ("page" in siteData && isFn(siteData.page)) {
if (!siteData.page()) return;
}
let menuDiv = document.createElement("div");
menuDiv.id = "FullPictureLoadFixedMenu";
menuDiv.style.width = "54px";
const menuObj = [{
text: DL.str_128,
show: 0,
cfn: event => {
cancelDefault(event);
createFavorShadowElement();
}
}, {
no_s: 1,
name: "shadowGallery",
text: DL.str_141,
show: 0,
cfn: event => {
cancelDefault(event);
createShadowGallery();
}
}, {
no_s: 1,
name: "newTabView",
text: DL.str_106,
show: 0,
cfn: event => {
cancelDefault(event);
newTabView();
}
}, {
text: DL.str_158,
show: 0,
cfn: event => {
cancelDefault(event);
createFilterUI();
}
}, {
no_s: 1,
text: DL.str_107,
show: 0,
cfn: event => {
cancelDefault(event);
fastDownloadSwitch = true;
DownloadFn();
}
}, {
no_s: 1,
text: DL.str_174,
show: 0,
cfn: event => {
cancelDefault(event);
exportJsonFormat();
}
}, {
no_s: 1,
text: DL.str_176,
show: 0,
cfn: event => {
cancelDefault(event);
exportMarkdownFormat();
}
}, {
no_s: 1,
text: DL.str_178,
show: 0,
cfn: event => {
cancelDefault(event);
copyMarkdownFormat();
}
}, {
no_s: 1,
text: DL.str_104,
show: 0,
cfn: event => {
cancelDefault(event);
exportImgSrcText();
}
}, {
no_s: 1,
text: DL.str_105,
show: 0,
cfn: event => {
cancelDefault(event);
copyImgSrcTextB();
}
}, {
no_s: 1,
name: "fn",
text: DL.str_159,
show: 0,
cfn: event => {
cancelDefault(event);
siteData.fn();
}
}, {
no_s: 1,
name: "zoom",
text: DL.str_88,
show: 0,
cfn: event => {
cancelDefault(event);
fn.clearSetTimeout();
cancelZoom();
}
}, {
no_s: 1,
name: "zoom",
text: DL.str_87,
show: 0,
cfn: event => {
cancelDefault(event);
fn.clearSetTimeout();
reduceZoom();
},
mfn: event => {
if (event.button == 2) {
cancelDefault(event);
increaseZoom();
}
}
}, {
no_s: 1,
name: "toggleImgMode",
text: DL.str_86,
show: 0,
cfn: event => {
cancelDefault(event);
toggleImgMode();
}
}, {
no_s: 1,
name: "insert",
id: "insertImgMenu",
text: DL.str_160,
show: 0,
cfn: event => {
cancelDefault(event);
fn.immediateInsertImg("yes");
}
}, {
text: DL.str_85,
show: 0,
cfn: event => {
cancelDefault(event);
createPictureLoadOptionsShadowElement();
}
}, {
text: DL.str_133,
show: 1
}];
const createMenu = obj => {
if (
!("insertImg" in siteData) && obj.name === "insert" ||
!("fn" in siteData) && obj.name === "fn" ||
!siteData.insertImg && ["toggleImgMode", "zoom"].some(e => e === obj.name) ||
"newTabView" === obj.name && siteData.eye === 0 ||
isSimpleMode && ("no_s" in obj)
) return;
let item = document.createElement("div");
item.innerText = obj.text;
if (!!obj.id) item.id = obj.id;
if (obj.show === 0) item.classList.add("itemNoShow");
if (["toggleImgMode", "zoom"].some(e => e === obj.name)) {
item.classList.add(obj.name);
item.style.display = "none";
};
item.oncontextmenu = () => false;
if (!!obj.cfn) item.addEventListener("click", obj.cfn);
if (!!obj.mfn) item.addEventListener("mousedown", obj.mfn);
fragment.append(item);
};
[...menuObj].forEach(obj => createMenu(obj));
menuDiv.append(fragment);
document.body.append(menuDiv);
menuDiv.onmouseenter = () => {
isOpenMenu = true;
fn.gae(".itemNoShow", menuDiv).forEach(e => {
e.classList.remove("itemNoShow");
e.classList.add("itemShow");
e.width = "122px";
});
menuDiv.style.width = "134px";
menuDiv.lastChild.width = "122px";
menuDiv.lastChild.innerText = DL.str_134;
}
menuDiv.onmouseleave = () => {
fn.gae(".itemShow", menuDiv).forEach(e => {
e.classList.remove("itemShow");
e.classList.add("itemNoShow");
e.width = "44px";
});
menuDiv.style.width = "54px";
menuDiv.lastChild.width = "44px";
menuDiv.lastChild.innerText = DL.str_133;
setTimeout(() => (isOpenMenu = false), 200);
}
};
//元素模擬點擊
const EClick = obj => {
const event = new MouseEvent("click", {
bubbles: true,
cancelable: true,
view: _unsafeWindow
});
if (isEle(obj)) {
obj.dispatchEvent(event);
} else if (isString(obj)) {
let ele = fn.ge(obj);
if (isEle(ele)) {
ele.dispatchEvent(event);
} else {
if (!("loopClick" in siteData)) {
console.error("EClick點擊元素參數錯誤", obj);
}
}
}
};
//創建返回頂部按鈕
const addReturnTopButton = () => {
if (ge("FullPictureLoadImageReturnTop")) return;
let a = document.createElement("a");
a.href = "javascript:void(0);";
a.setAttribute("onclick", "window.scrollTo({top:0,behavior:'smooth'});");
let img = new Image();
img.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGoAAABqCAYAAABUIcSXAAAAAXNSR0IArs4c6QAAIlVJREFUeAHtnQmQZVV5x7v79TILs7DJwCzEERwWsZIKiYVbxMECqjAIaKoQ1CguxaIhlWBiqSWk0CQqhii4ICgVQTQaBNGACoOogIoUVaAgBJF1BgGZfXqml/fy/328/+W8++5but/rnmZmbtV959yzfuf/P993zj3v3nN7e15AR6VS6U3FPe+882qu07gi/8c+9rFKGt7b21tzncbNNP+EGjqdwpuUPBm/+c1vamR++umn4/p1r3tdoXg//vGPI3zvvfeuIeXQQw+tuTaJM5W8mkYXtnSaAk0M1ZkckwIZELF69eqQd+3ateFu2rSpRv599tmn5voPf/hDDRm77bZbXO++++7h7rfffhWINIkmz6Qhy0whrqZhCDadRzNyBFovxKSkQMTmzZt7t27dGnJv27atV2E9vm4k+6xZsyoirWdoaCgI4nru3LmEVVLyIE6dI9LMNNK2C1EmKK85KTloi4lZv35934IFC3ohZt68eb0jIyO9o6OjcULOnDlzesfGxgrb0t/fX9myZUuAPzAwUOEcHBysbNy4sQJxKruissspcWhcM9K2h5YVNq5Rz+w0vIggzNpLX/rS0ByT88c//rFPvb4PYgRmH6QI4D7IkPYQ1zs+Pk5cuISXy+XCtvT19VUgq1QqVVReuCqjojLKhKvsMuQprgxxiivvueeeZWsbpD3wwAMVzGNey6aTsP5OwW8nfzOClB8N6YOAvfbaq/fZZ58NkqQFfer5kFMiXkT0LV26dOD444//k3333XeZAFw2e/bs/QXuIpExV6DN4ZR/NjIp/bDq3cIp/2YR8eTw8PAjMqWPrlmz5tFrr7324ccee2xU5ZeVrywix1VnWdpZlgxlyVJet25dRXWXRVIZwjSeBWGyBNFslR3udBBW2Auj9i78NCNIIPVh2qw9qq4EOTpK6ul9anxJRPW/5z3vOVga92cyeX8uYg5T+CyL5vJ93cpNAVXerSLuHpnAO6Uxd335y1++T6SMKXwc8nSMQ5rKHE+1TJ2lvD00bMqIAsR0DEpNnMaDPgiCDEybwCj5FHils88++5DDDjvsGI0dK0XcAghISbFf+YmKw2G+tpsjJ4LTMPtFjIar9Tfdc889N1x44YX3qlOMK3F2YhpVxzhmUROa0LAiwlye6++W+3xLu1SiAUtJYpKg2VSfCWL8UXVBjnpvvxpXOvzwwxeccsopx8vMHCuN2t/lIBZ+HYVkTVTsFEj8Omqm4IRJpkfUsa6/8sorr/3Vr361XmnGJdOY6grirGEQpraVmSlO9fjVVaIAFOAgiXsgaxFmTtPgjBwlKUGQJgT9r3nNa/YQQX+zxx57nCjtmesyqm6U5zDKTv1cV49W7XhuMHFquXnCqlH0iEiLy9im8epqEfbfP/3pT5/VODaWEqY845oAlfPm0PdhLiupdtLeVg1su2AAbKRFuh9SG0slxh81vl9mpf/lL3/5vHe/+91/Kw16kxo0m/ycOoIME2K3Kkgmby68bTlz4GUEOhyXU0eQWfUPq9Ndc+mll15+9913b5R5HlNbGMjU18bHNZUfb6RdLrdtARskzBreIL5lsAFLSdIMqS+vRWiQ7PyAzF6/etzrNUE4S9ztTf5qGSFLcp2ZPIRwPXl/SwELEqTg2a/yMy0jzOFU7Wtx8rTGpYvU1lUyf2MaX0dTDbN2aWaJSYxO0C3t6ogogwdJeVOnBpTUwJIa16/ZU5B08sknLz322GP/Qdd/kRBiolIysrBGxLjuAh6aBiUEZOnSsKo/M38kchgup2and1x//fUXXHXVVY9Blq7H1Ok8YxyfClM4aaIMVEqSzFhMGDB18nP/EwSJtIGPfOQjrz/kkEM+qIbuRl4dmYkzaQ4DHJePnyO9Jl3RkaYhXuky05amV7rsMp/G17ikw01Ph8nddO+9937y/PPPXyVrMQphup0Yk4nMTKH83IPFRKNTzSpucdaMYo+EjHwmKZ3VSYNKMgv9mDo1cHDx4sVzPvzhD5+pycIJ1XyhLfhdjmrJ/ElYRo7KyQRJ47PASXgA39lUZnjTMPurbiTA71MZwq/Jxnc+/vGPX/zEE09wcz2CKZR5R8Pqxq1OyHoeAUvdwjVQeZKULabbWpKJ2ZwaNHjkkUe+SBOGf1NPO6iaLyOpWk0dQS5f+SOJr1uI1XE0BFCI6ouyfJ1zawgjOfGyHL/VROOfb7755qeUfwQzqGWpbDqfTuEnS9akiGpGkgQc0Kxo8C1vecuyN7/5zZ9SD1tSBTslacYQFKwkPyamFWGkq6YNVxbksW9/+9sf/Na3vvWoZrUj6rCjzchyPUnVTb1oQdsHgJsk7pE0Jc3ujdAkk/S+973voOOOO+4/RNIiFU5nqCMpJY94HfzY3E24A7XdiNYJQ94G8oRcxPlwOk3X5x988MFHysTf9fOf/3ytxqweYdIj7YqkwquHU5j1aGzrkfZxv+liWrptL8qaJEqEJE8cVHHJJGl8GhJJK97whjf8pxqwm5Kyqt1HXhND/qo/XDfaYcTPhMPySD6bRHlpRvY4wHMXVc0SUSzs7knbJf/fffWrX71fHTfIwuVvFNol7Fg/rNDhVVbDCQ9p0wONaHkkwvUwDedvCZaDmDiYJMydVraXrly58pNqEDO7WPGu5o1eSkVc+1S67LqlENspQZGs1TYhUbSL62qHZP1yNzAACzDByoARWIEZ2IGhm5OU5aBCty2iyGmT55tZpuDM7iRAPwK99rWv3Udj0qfpVaq8RosQJj0hyCQVSjUDA5E/lTttj8RN29cHBozPYAI2YARWYMZCABhCFpi229SWRCGQSWIaTkUae+I+SZUPSPjB/ffff65M3r8qfLHSF5KEQG6sG9mukDMlneVOO5nDJGMNWUyiwARswAisuLcEu8eEYfWWJrCljFZtbEoUBUAShTAuqRfE4qoqjptZ1Fq2efBDH/rQGbp3WJEKm/PXkER5L+QDXFqRpfb1ggnYgBFYsQAAdixQgyWYggMYtyKrKVEGEzX1uKSwWBZi3U62d+CjH/3okeopb1K47TSVZ72LMvINI+yFfuTbxHUV7HAZs9RGJl1vAiOwAjPMoMILx6tmmDQkikphGpJs8rCxVMLanY6Bk046aani/tFCpoJW/TskSQaUNrbSLNKAEViBGdiBocerdk1gQ6IsTGryNEjG/0j0DJ3M8v5e6WIajkDpSf58Q1zmjuTm25higF9t5dwNrMAM7FheA8u8CWyGSyFRVGBtSk2ebG2YPXrGueeee6R6x+EIYuGqQkV9hKW9rZkQL/S4Bm2twQWswAzsMH9gqXbXmEAwp6wiPAqJckK0iQcgeb6BQmV3VU//wPLlyxdoJfx0hdUIQz6TtrOQRJs5UrISsGvwATOwA0OwVLYS2IKxJxZRWMFPHVFUktcmgR7s888sg+L73//+U6W5NX/6maBU4IL6duigtO3GQw3OyAIzsANDsFRc/GeX3gg30qo6oowkDDPfh3GtW/F8XdzcvuIVr9hTj3n9daoxiVDOvssVAikuJhHswBDzB6ZgC8Zg3UyraoiisFSbeO4ObTJJcgf0IMpJkiF7xkH+zKZaGNydlakGGGRaBXZgCJYmC4zB2stLRVpVQ5TBTccmGFd4SQL061m7BYsWLTpe11nFCOYz1TKXtTO6KVnGxi7YgSFYKizMn7Wq2VhVR1R6c6s76yAJxhn83vWudx0nfzzSZWF2RiIm02Z34ipuc8ESTMFW5ZXAOh2r8nVkRFEAKkeCdKZHIagojxerJxyt60hD+vS0IOTfddTPAo1VFRu06mgwBVuFBVmeAZImb/4yoqoF9HCnzFsVCxcu7OVZcAqB+Xe+850Hq+ClpKNSiNl1TAyBtDODJZh6mg7WYA72cJAvGSbjUCGx9K5Brk9Txz69yYBaxnoei4pS1VN0J71CJEEe2pStkqcCVIubdofOg1yNTmTcDoeqzf61jup1HX8gCtOKXnwY02Nnv9R0fVzXZa1axJsjIq3y6KOPxj/BvEFCxjqNstljgNONmR/kH9TD8X8FGAkg26Hd9VUmMtVHJiHtpkuyTJU3GzLAVDgPirx4gyWdVOQrD6Kq4NeZPQpANTWdXKGbtflOlzY632PyFUzlteVxHZK154Ybbpgj+74np3rrHKVxdLj5PDWRU3BBfWDEgd/144Ip2IIxWBeZP6dnIIuD2Z7+eYzXMXmZTDa0T/+fhEatWLHiT5UoanNGMuG3EFHINP2kMrhKmewePacw//777x9y2E033TRXL631v+Md79ggUBwccnMh2WtZzFJ031PFKupL/L1gKzl+DdZgzmuw3FNpdd3vL0eekF4J465Y/0LyGiYmr18sD6hA1HLorW996ykqZD9dQ1zROND9ljUokUbmo9QTe7/0pS8tfOihhwbzcbon7H/wwQcHdd+yTf/d5aOrzckHd/06ZAY6n9QgP+8Ul/X24yr5Y5wSzmVxUBYXEFThiSXGqboxCkaVkBeb+e8fdgc1vz80Bch+Kp3Ow/WmdSLvRRddtFCDbx0LTvfwww8PXHzxxQtJ6zC7RWU6rpuusUrrww+2YAzWYA72RXJmgrMawdSQt8/FckwkJGjpqKOOWqYZSWZOXJHdbjamWVlF9cmslT772c8ufOqppzIT3qiMJ598sh9C9RL18zawmrio7EbldBLueuxSFtiCsbwxoQB7OICLdO0vpthkYJ0J2yhWYysAmT5cXnBemhQ8vSqEYDqS+p8L0O/vf//7gS984QtoSR3wWaKcRzPaEnmkfXXEFtWRy97ty8CSesEYrKuYBwdwASdUSprQKCYSBOhhytjHgbEKVeTQk5/ZTS5p0mM6GldUh+z24CWXXLKAWVIqT+rH/qfX9qun9n3xi19cqElHnaksqsv5OnWLynYYGIM1mIM9e2nABXWam6yh3D8pUWy2oXUnNtvgAUsyLUmFdOG2uWlct/2uKy33jjvuGLr88svnY8vTcPvV3oqee9946qmnblTDC8nSDKv3K1/5yoK77rorM+nOX1Sn4zp1jVm+DjAGazAHe+SDCzhxnXUmAABQQc0+Ys6vv5Bf5IJT15W6oG67ristV89rz/7+978/V2FZA9J4TVYrEKQlmBHCJfsGkTqPQTpNh1/A9H7961+fp+0LevWg5NY0nrp1FJKcppuM32WnLhhLduqMDU6K2s4/jP7Dqo/nyFV5vGMrwvi/ZEi98wT1zIUKB5zsVD7kLASMiE6OIkG/+93vzr3xxhsbkqRlr/Jpp522Qfclo65bJqV80EEHjch8DNFLHZ64vdx3aXzoPfDAA7N81XhwS5J27nV5uNWTHsEYtEVvgfyvahiVRo2pY41L3rL88Zw6U/ToaZ7xaQCLfYXobWgVLMuUxE4onYvZXgl5knTdo1cw5/3kJz+Z06iE+fPnj59++unrly9fzjtJNQcvQp911lnrtFzD1gOFx6pVq+Z885vf5Hn5mvi8LDWRXbwAY7AGc7CXhsVmXOnMr8YkYBepnx6maWKYvoSo7navXEMBJQ8MZlhjyfw777wz260ll61HW+FAxHptu9OQCDQLskRaHZEuT2PfbMY+2u4w3LxMaVwX/FEXGFMPmLt+c+E6gqh0U0ISwqzPhCjn6bpbBAarDZqdLbjvvvvqBnwLsGTJktEzzzxznZa+MBFxpy9TgjmpOYnTyn/ljDPOWPeSl7wkb+KIjgMTqRWOBXmQkK9IRufr1AVj441rsijX3GQaxby90wonk78IAO7MWUl45JFH6qbQrkNjygjmDgJMjOPyruO1Ot2jvZXWs5yUT+Nr7s+4Md6wYUOGjeOKZHXcVLgpJzXCcLPrCmEWv9xhh6VuN4QuKkMrCKXPfe5zrCDUzUhdvzYT2cbEQTPT0CKHt3IhTBOjnre97W0bjzjiiMJ2UQarGMigsbvuZrpI5lb1Or5RXmNszEmfcsF1DVEE5A9lrpm65uMne10ktDSo//Of//xC/WlZB5DreeUrXzkM0AAO8A5v161qV8+JJ564WUs3mxvlYxUDrdZjXHUdpkj2RuW0E94OxjVEyTRkDZfdDL/sZWHPmwxIFrqooRqLBlkxaLbacPTRR28+4YQTAtxO6ndelTes8jb52vLZra5iLNBuLXUmuKgNztfIbVSPMTbm5E+54Dojih0fCcgfmi5uyYd1cl3UQO3gNcR/SczyisqmgdKAjdKA6DSNGlyUt1GYy5CGbm22isHN8mWXXTalqxiNME45CaL0f0fWHu7uYdanXm18KoucAo/qnv2Nb3xjXmqf02pYBnr729/OmLINcA1wmib1O43dNC7vdxqNeSOMeerFMXvMp+PehlUM7TDW8DYhn2ci12BsvHHhwPnNTaZRROhOOBKQUL07QNEM7IlqpiyzC5mom9em6667bu73vve9eG2nqCzuzDVL2/Cyl71spF2C8uWYjHx4ek0aViaYRWrdrZAsZNcffPP4ez/Nm29TGteGPzAFY2QAc5NkLlxGEKW34mJbaalaj8aI2CAXZmU7K5r5rHbibrpo0i233FLT6LR8rTaUAY77nnZISvMW+dspQ9sBxSqG7ssa3jzz9363NQuMwRrMsSBwABfcesAN7enzli9cMIDp7jjbzVjsljUTe5y4To98z7v11lsbLk2x3MONLMs/7QDcrmztlMUqxgc+8IF1WulouIqRX87Kt61deZwOjMEakjQmBgfpZAKOakwfGSGKDFoUDI1Sz39CgsQNohtq1xVNxs3f/bsM9eoxvZqyDsBa1dMq3mWmbqs8xFdXMda/+MUvLlzF0JhSOOlJ62nkd/12wRaM0SgwB3s4yOfPiJK6sxd4bN4uEOOhC2Uq6zHbEdnQ3zpjUoGDJuWyqp3PeMABB7DasE7PEbQ1acjnb/fabWiUnnhW47X9wHqNj3WrGNpKp072RmWl4SIlLtP6wRaMwVoExUMtupEPLuDE+YMo/X8TAQDEDvsM4prpaCJWjp2JZUPvSQt35qIwx7VyuX/RG3gxk6MXvepVrxpmeYfO0qrcVvGt6ia+nTIY2HnUbOXKlZvp5eRBZmRvp440TVF9hIGtCAywwRzs4QAuyG9u+LeqondLe9kaWr3I36qoKBODG0SVtcX0rzUrIh+ZJ632FOBDS/kVPSa9ARNYNbeOauoWNbhphiaRlKWjaXuUpke7dm455phjtjBNh7wmRU4kKsoBW7RJ9YReUD4n91AysXx6IjpVZvo885MqxmcQZDOZpjL7Gb/66qsf1PVGpDBQdgnr5ECDJGhbRXSrzrSydstUup5OSXJddsEUbCVP4AzmmqKzAXsojGd8yJsRZeH5oAg9nJs/mz8NcqNaqLzVaVyReqODWrrO0zJhgwSd5m9QbARTdiflt5PXWKVpwRRsUSWwBnOwh4O8vEGUp+gMXthGTRFDm1T4uM/bbrvtFipxhS4ordhhjdyJpHUZ5JlMPuefiDuZetrJk08DhoSBqfHFlazjYA8HnkiYm0yjGLRkD8M2wqiYLvN4rQvSf/oPaDxZnVaa+icCSLtpp7r8Ijmmqs60XPxgCabGF6zBHOwZn+DCEwnkDKJciP7hDNvIV1402AdJmlDEZuxKM6Y/1W4mE+mdRxVl4xZxrY40b6O07aRplLcb4e3U304aZCEdGNnPNX6wlD+wBWMIA3Ow5z4OLpwHN9MoLjhQOa0MxEtVDG4UQIGcen7hhzKn/M3wXM2RY3I/CNzonFyJ3c/VSD7CO6gtPiUBlioncAVjsMbsgb3NXlpHRhS2MG/+GOM0ZY9xikL1KPAGPXD/QwpIG0GP6VD4VKYdxg8mxsZ40TgwBEuFhSaBMVjnzZ7HJ/JkRHHBkTd/CuJ1kExFr7jiiutU+VYE2HVMDAEwAzswTDEF4yKzl5aeEQXjZtDmjwI4dZ8zpoFuTFPIURG5lh7hHmIXIfCnhe/MfrAwJsYIF+zAECzBFGyNc2r24CLFMyPKoGL+WKXQU7OsO2XTdHqAMlLwqF51+R9V8iyC7DraQwCswAzswBAsPYlQCfHVNzAH+3S259LriCKCO2Jrle+pKJhewKnXFjf84he/+C8YT0/3IBe+s7pgYixSfMAM7Iyj4kKb0klEuhqR4ldDFIWictYq5vM64mtkqKiWUPgMzyg9Qo9T3aqp5N0qLFOrVMC0kp3J3wCDCliBGdglOMaHw8AYrK1NebMHfjVEpYDCrN6viukijKvwsKeaRo6q4BGp7ejXvva1S9U7tiAcZ5p/l//5mTEYgRWYgR0YVjs+LwQExmDdSJvAso4oAE+1CrsJ40o7rtVcPg4S5k/XI1oCeULnJfLvMoECIdWmpPOyVHQJWIEZZg8MwVLXceuTjk1F2qR09UQR6CMdqxQW03R6g5Y7RugZnHpg8jb9lcy9VWiUBVTcTjULzJNUxbACNmBkvMAODJlIgKlnes20ibLqNIpAKs1rlYLjpgyVpSLdoPFk0DYE+MQnPnGFHlZ8SGky85cKTpk78tGgrRVh8juwASOwAjOwA0NucIVJfGOq2dhk3AqJciQuTGtyUVal8eVFxiotx/MFstAoBNDjv5suuOCCT2n6uQahOcmLq2OH1qx8G91+sBAmnwYbhUWHBjOwA0OZwPjiKNi20qbAkp9Gh0Du1VY1sfe5puvs5FKSPe3X40wD6hWDih9SpbP0Z9dsCTNbD0ku0dND58oG705eTsrG1THV7xo1asaUhatNatrzHZFrTuGxVs+tn3v77bc/rvhh4TEsTdqquG3iZ0SrEKP6K2NMZnBcRMaHKxuNTRa+pUaR0NN1Bj1dxkoFPYNBUYKEWou4rQyYejvwkxJqs4UmP/60QYS90I98m9xe2q6nav8dLMBE4aFNYAVmmD21vcbktYNFU6KoHKYpKDWBAn1cvWFMPSfGKkVvk3ebBsitevr1QU1Fz6dXWXjy499RyMq3xe2kzbRdT//+DizABGwYm+SPj1WCHcNIavJaaVPgx0+rQ4XXmEB2FJYK92u1l8/tsGfSECdmUELFqYfvl+jRr3/SMxGLyM9JPbg6okqHtap/psRDCLJI7mzcNUnC4UltNoImPQ5JnDZ3SrNNOIzqWYi4F+WeqV2T57Y3fQLHiQxofrwSWSU92iStfu67hkpXQ5Yevt/r7LPPPkfPcy93Gbj2Q5j9rmumuhCiI8QzOVzgFwa/u/DCCz+tr14/kydJf2GENgkDzB6WqGZcchlRcJOfpqbP+RDG/nS8omJxFCYQgZjV0IsQVnHDehTq6XPOOec8rRj/SPmjDDcSl4b72uXPNNfypbISVpWT1fAfqY3/QltpszUJLEwSGIFVemPrdiZlOajQbUujnFPCZiZQDw7Gdw4Vx7NeNZ/QUzpekB6SgEPSOl5VGXrve997hF4cPk0Cs9lhplX4FQ9hODNGwwyg5Au5fI3LqXZt0aPIl2mrn9uVYJvalY1Jit+WkqT4uGcSZjUfUHaZUUGLn/YeqKsWItMXX7tkgwr1DmaD8SVMoiVofHhRPYntD9g1S22MP8poaUUvq63WR4Xv0KPM+6kRLyKPBMUJNyWsGj6hThQFdeEH8Kg/JYhrh+NqfLlHb0d+5pprrrlXVfLqLH+k8tQvk4caTdJ1kMTkQZjFgnc7kwflqzkmDIYB9XglAeJLbSo10ywmGhJ6UGSxMeOgJhhDuMobkw59RPkIbWtzsuz1Hi4v7yp9COrwGqmn4EL1heqovijd16nL/0l6k+MqadFt6pjZyozaGVNwZnfKPzM+mEwrDF6eLN3ExZdENQPKPkGuWemAGhuEKV8QpiIGNd2fp7c2TtBuK69Xo2e5TLtpPcrPZRxpvMMm45oA8qrMKCINsx9XHW+rdtdcpb8pviPzxRPD2aqM8oZfZj7uKVl10AwvG5PQJB5vkJvd6rjsqLTNn+cRaDODkxkwk+UxC7JW68ttIiK+g6hl/AEJHx8Gs4apDLQsCNSedLtrA9xj9CbHUUoXO5hQh8vP18e1GurgGjefpxEgSpfly6fxNa5M+LC2Ob3xyiuvvEHrcWuVL/7eUeYgBw2qTqDiZpZ7S+EwrmfyYuKQH5Oo1OVnArTpKW5xm5kNTEoWmwFynyXQ45M7mEEtmfSbMDU+0zDFhR/Sli1bNk8vPa9U/lcr/b4uG1FSv0UrCnNcM7cIqDQMv5bI1oiYn+khlJv0tNBGdbDQFml+uKp7RO0bVVuCIKWP+yOF89jXOPdJLLRWFwk60iS3pSOiKMSAQRbXUnN2e47P7OhBQqb/MXapAUGWzEJ8g0oN5RNyrBmyixlfH+XjV9w897/xjW884NU6tIXOX8qk8I5vVk/ez/VEjzwx5JeJ3vT444//8mc6WF1RGp5pYOWF+5/4D87kYOYgSeHxD62yx4SBFYf0ZpZymTjgpnVyPdGjY6JcIYSlZHmSYVOoRrGlZuyjrllffJPCREGOooMw/NVrvq3Ur70glqusQxYvXnywPolwoMCKnZipz3VPxDVgqntEf4//n2ai96lz3fuDH/zgIWk9q9rxEA9ESaYgCL/C/RjCGH/6qS3xV4XCM1OXjkfINJnZXaO2TKqxjQozeEWmMNUu5c++SQUp6rXxkRZcrtOTtAIqtFJLVoNaod9XHyHeTx8hWSTN3Vdmci/18NkCdRaniIxNrkQEK9VbOaUtwzJPz2havUZvUDypP/NWa2V7jZZ0eHMw/mXFhZD0hAzN9IIUwlV+jQaRx1rUbVOnsmuOrhJFySlZXGMKU+3iiy4yfzUmESIEaBCG3+Th51QxcQq4+P4819SjI/s+iEAsbIvKjRtUpVWWit8L5t9q9Qt9eqBqthQXhEGO0sYTrPghhzh1gFj1Jj2P0fHPLCsNRVqkNB2bOspIj8LGpQkm61fjakwhs0ImGurV7PUdn4sTICWZt4w01VWSWQly0C7iOQVYpBHo8WUDhQVBhCtdrHJQn8DMOorSMGsLwPArKc98B1FKG8+BiIQginDI4FS67DFjyRNjDy4PoRBvgnicLtUicOqmqaO89KjbkCmN7MQPODqiCJlCXN5QiL28aaRArGibM17mRsMAJL5NIaBi/2/lZ3ofBMlvMiEqNiUWKbHdN67q8e6RUZ9/lDZWSORGfUpbpl4IUp54HVNpqTsIU6cJMpSmLFMZjxkTbw3ikS5Nwcta36NhFS2JRQO7NWFQmQ2PKSOKGgEIt4gwaQ6N5nvqvLiFhpW1ZUHsoi9A+wRUfKtC2Uvqzd4wX0WGNvnTE+EqjGriB6XhAg1KXfkxgRARrq5DkSAFgnQdWqMxL97+Y/sEXoFBg0grWeOdWlmEaSVIdccxpUS5EgHUkDBMIhoGYc8880xsko+WCTA+gdCLaQRbTRj4cinbTMeW0zKDsfcqLuEmyHXq2t54eVnlxWYbKo+XyKI+dYh4oRwX00aaVHt4TwmCtocGWXi70ft8MV0uwFNXOp3nmkmHVjViHNNsKkjTgB1aphlf7LCv/3ViX3DN5NibPcoRwDXbe1KWD0iQdkZHEdmx2Qbgs0UApPFiM6+7SKvjbUvIoePwxp9MdeSTXOFOh4mz3Hl3uxBlIUwY181IIz4lTr0+5Ebj2Fna16QrOqStsbcQxBDPdUoMYa3IIY0tA/7pPrYrUWljm5GGeWQTXLSNPMwccSEP10e6BythDP6Ow0VbcCEFF63Rf0rxPAjXec0hbHuSQ/0+ahrqwJngmjhrmmVi5mg/LiTiQmTRAREcrLuFp/pjUhy2Pc2aZWjm1jS6WcKZEGfyLEueRIc3ck2G42eKtlieZu7/AwTBjCGMzrSiAAAAAElFTkSuQmCC";
img.className = "FullPictureLoadImageReturnTop";
a.append(img);
document.body.append(a);
};
//列出一般圖片站
const photoData = customData.filter(item => item.category === "photo");
//列出寫真站
const nsfw1Data = customData.filter(item => item.category === "nsfw1");
//列出老司機站
const nsfw2Data = customData.filter(item => item.category === "nsfw2");
//列出漫畫站
const comicData = customData.filter(item => item.category === "comic");
//列出H漫站
const hcomicData = customData.filter(item => item.category === "hcomic");
//列出自動翻頁
const autoPagerData = customData.filter(item => item.category.includes("autoPager"));
//列出去廣告規則
const AD_Data = customData.filter(item => item.category === "ad");
//列出未分類
const noneData = customData.filter(item => item.category === "none");
let topDistance = () => {};
//創建選項元素
const createPictureLoadOptionsShadowElement = () => {
isOpenOptionsUI = true;
const config = getConfig();
const mainHtml = `<div id="FullPictureLoadOptionsShadowElement" style="display: initial !important;position: fixed !important;"></div>`;
document.body.insertAdjacentHTML("beforeend", mainHtml);
const mainElement = ge("#FullPictureLoadOptionsShadowElement");
const shadow = mainElement.attachShadow({
mode: "closed"
});
const style = createStyle(`
#FullPictureLoadOptions {
text-align: center;
width: 374px;
height: auto;
position: fixed;
top: 10%;
left: calc((100% - 376px) / 2);
border: 1px solid #a0a0a0;
border-radius: 3px;
box-shadow: -2px 2px 5px rgb(0 0 0 / 30%);
background-color: #eee;
padding-bottom: 6px;
z-index: ${UI_zIndex - 1};
}
#FullPictureLoadOptions label {
margin: 0px;
padding: 0px;
}
#FullPictureLoadOptions select {
border: 1px solid #a0a0a0;
background-color: transparent;
border-radius: 0px;
min-width: 60px;
height: unset;
-webkit-box-shadow: unset;
box-shadow: unset;
-webkit-appearance: auto;
appearance: auto;
background-image: unset;
display: inline-block;
margin: 0px;
padding: ${isFirefox ? "0 0 0 4px" : "0px"};
}
#FullPictureLoadOptions *:not(.row,.item,#mypopover) {
user-select: none;
font: unset;
font-family: ui-monospace, sans-serif, system-ui, -apple-system, Segoe UI, Arial;
font-weight: 500;
font-size: 14px;
color: #000;
float: none;
line-height: 22px;
margin-bottom: 0px;
padding: 1px 4px;
width: auto;
}
#FullPictureLoadOptions button {
width: auto;
height: 26px;
line-height: 20px;
min-width: 102px;
max-width: 110px;
min-height: unset;
max-height: 26px;
margin: 0 2px 4px 2px;
display: inline-block;
color: #000000;
border: 1px solid #a0a0a0;
background-color: transparent;
border-radius: unset;
}
#FullPictureLoadOptions input {
width: 14px;
margin: 2px 6px 0 6px;
position: unset;
opacity: 1;
pointer-events: auto;
color: #000000;
height: 18px;
border: 1px solid #a0a0a0;
border-radius: unset;
background-color: transparent;
outline: unset;
display: unset;
-webkit-appearance: auto;
}
#FullPictureLoadOptions p {
width: calc(100% - 16px);
text-align: center;
margin-block-start: 0px;
margin-block-end: 0px;
margin-inline-start: 0px;
margin-inline-end: 0px;
}
#FullPictureLoadOptions .tip {
color: #0075ff !important;
cursor: help;
}
#FullPictureLoadOptions #tabs {
padding: 0 0 0 10px;
}
#FullPictureLoadOptions .tab {
cursor: pointer;
background-color: #ccc;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
padding: 4px;
color: #333;
border-bottom: 3px solid transparent;
overflow: hidden;
}
#FullPictureLoadOptions .tab.active {
padding: 4px 8px;
background-color: rgb(255, 255, 255);
color: rgb(51, 51, 51);
font-weight: bold;
border-bottom: 3px solid rgb(255, 111, 97);
}
#FullPictureLoadOptions .tab.active::before {
content: "⭐";
font-size: 1em;
padding-right: 2px;
}
#FullPictureLoadOptions .hide {
display: none !important;
}
#FullPictureLoadOptions .row {
text-align: left;
margin: 5px 0px;
padding: 4px 0 0 4px;
}
#FullPictureLoadOptions .set {
min-height: 170px;
}
#FullPictureLoadOptions .item {
/*width: 354px;*/
margin-bottom: 4px;
display: flex;
}
#FullPictureLoadOptions .ml {
margin-left: 3px;
}
#mypopover {
text-align: left;
font-size: 11px;
background-color: #eee;
border: 1px solid #a0a0a0;
box-shadow: -2px 2px 5px rgb(0 0 0 / 30%);
}
`);
shadow.appendChild(style);
const main = document.createElement("div");
main.id = "FullPictureLoadOptions";
const FullPictureLoadOptionsMainHtmlStr = `
<div style="width: 100%;">
<p id="title">${DL.str_68}</p>
</div>
<div id="tabs" class="row">
<span id="page_tab" class="tab active">${DL.tab.p}</span>
<span id="gallery_tab" class="tab">${DL.tab.g}</span>
<span id="lightbox_tab" class="tab">${DL.tab.l}</span>
<span id="download_tab" class="tab">${DL.tab.d}</span>
<span id="other_tab" class="tab">${DL.tab.o}</span>
</div>
<div id="page" class="row set">
<div id="iconDIV" class="item">
<input id="icon" type="checkbox">
<label>${DL.str_69}</label>
</div>
<div id="ShowEyeDIV" class="item" style="display: none;">
<input id="ShowEye" type="checkbox">
<label>${DL.str_123}</label>
</div>
<div id="ShowFixedMenuDIV" class="item">
<input id="ShowFixedMenu" type="checkbox">
<label>※ ${DL.str_117}</label>
</div>
<div class="item ml">
<label>${DL.str_108}</label>
<select id="MsgPos"></select>
</div>
<div id="AutoInsertImgDIV" class="item">
<input id="AutoInsertImg" type="checkbox">
<label>${DL.str_139}</label>
</div>
<div id="GoToFirstDIV" class="item">
<input id="GoToFirst" type="checkbox">
<label>※ ${DL.str_115}</label>
</div>
<div id="noPageNavDIV" class="item">
<input id="noPageNav" type="checkbox">
<label>※ ${DL.str_121}</label>
</div>
<div id="ZoomDIV" class="item ml">
<label>${DL.str_79}</label>
<select id="Zoom"></select>
</div>
<div id="viewModeDIV" class="item">
<input id="viewMode" type="checkbox">
<label>※ ${DL.str_103}</label>
</div>
<div id="ColumnDIV" class="item ml">
<label>${DL.str_80}</label>
<select id="Column" title="${DL.str_81}"></select>
</div>
</div>
<div id="gallery" class="row set hide">
<div id="ShadowGalleryModeDIV" class="item">
<input id="ShadowGalleryMode" type="checkbox">
<label>${DL.str_140}</label>
</div>
<div id="MobileGalleryModeDIV" class="item">
<input id="MobileGalleryMode" type="checkbox">
<label>${DL.str_192}</label>
</div>
<div id="GalleryInIconDIV" class="item">
<input id="GalleryInIcon" type="checkbox">
<label>※ ${DL.str_77}</label>
</div>
<div id="ShadowGalleryloopViewDIV" class="item">
<input id="loopView" type="checkbox">
<label>${DL.str_182}</label>
</div>
<div id="ShadowGalleryWheelDIV" class="item ml">
<label>${DL.str_147}</label>
<select id="ShadowGalleryWheel"></select>
</div>
<div id="horizontalWheelDIV" class="item ml">
<label>${DL.str_198}</label>
<select id="horizontalWheel"></select>
</div>
</div>
<div id="lightbox" class="row set hide">
<div id="FancyboxDIV" class="item">
<input id="Fancybox" type="checkbox">
<label>${DL.str_78}</label>
</div>
<div id="FancyboxWheelDIV" class="item ml">
<label>※ ${DL.str_146}</label>
<select id="FancyboxWheel"></select>
</div>
<div id="FancyboxSlideshowTimeoutDIV" class="item ml">
<label>※ ${DL.str_145}</label>
<select id="FancyboxSlideshowTimeout"></select>
</div>
<div id="FancyboxTransitionDIV" class="item ml">
<label>※ ${DL.str_148}</label>
<select id="FancyboxTransition"></select>
</div>
<div class="item">
<input id="FancyboxAutoClose" type="checkbox">
<label>※ ${DL.str_210}</label>
</div>
<div class="item">
<input id="FancyboxAutoNext" type="checkbox">
<label>※ ${DL.str_211}</label>
</div>
<div class="item">
<input id="Viewer" type="checkbox">
<label>${DL.str_120}</label>
</div>
</div>
<div id="download" class="row set hide">
<div id="FetchAPIDownloadDIV" class="item" title="${DL.str_215}">
<input id="FetchAPIDownload" type="checkbox">
<label>※ ${DL.str_214}</label>
<span id="FetchAPIDownloadTIP" class="tip">${DL.str_203}</span>
</div>
<div id="AutoDownloadDIV" class="item" title="${DL.str_74}">
<input id="AutoDownload" type="checkbox">
<label>${DL.str_73}</label>
<span id="AutoDownloadTIP" class="tip">${DL.str_203}</span>
</div>
<div id="CountdownDIV" class="item ml">
<label>${DL.str_75}</label>
<select id="Countdown"></select>
</div>
<div class="item ml" title="${DL.str_213}">
<label>${DL.str_70}</label>
<select id="Threading"></select>
<span id="ThreadingTIP" class="tip">${DL.str_203}</span>
</div>
<div class="item">
<input id="Zip" type="checkbox">
<label>${DL.str_71}</label>
</div>
<div class="item">
<input id="zipFolder" type="checkbox">
<label>※ ${DL.str_187}</label>
</div>
<div class="item ml">
<label>※ ${DL.str_72}</label>
<select id="Extension"></select>
</div>
<div class="item">
<input id="ConvertWEBP" type="checkbox">
<label>※ ${DL.str_110}</label>
</div>
<div class="item">
<input id="ConvertAVIF" type="checkbox">
<label>※ ${DL.str_200}</label>
</div>
<div class="item ml">
<label>※ ${DL.str_201}:</label>
<select id="Quality"></select>
</div>
<div id="CustomDownloadVideoDIV" class="item" style="display: none;">
<input id="CustomDownloadVideo" type="checkbox">
<label>${DL.str_124}</label>
</div>
</div>
<div id="other" class="row set hide">
<div class="item ml">
<label>Language:</label>
<select id="language"></select>
</div>
<div class="item">
<input id="FavorNewTab" type="checkbox">
<label>※ ${DL.str_50}</label>
</div>
<div id="autoExportDIV" class="item">
<input id="autoExport" type="checkbox">
<label>${DL.str_180}</label>
</div>
<div id="ComicDIV" class="item" style="display: none;">
<input id="Comic" type="checkbox">
<label>${DL.str_76}</label>
</div>
<div id="DoubleDIV" class="item">
<input id="Double" type="checkbox">
<label>※ ${DL.str_199}</label>
</div>
<div class="item ml">
<label>※ ${DL.str_208}:</label>
<select id="cdn"></select>
</div>
<div id="CopymangaDIV" class="item">
<input id="Copymanga" type="checkbox">
<label>拷貝漫畫移動端SPA模式</label>
</div>
<div id="EHentaiDIV" class="item">
<input id="EHentai" type="checkbox">
<label>${DL.str_114}</label>
</div>
<div id="HitomiDIV" class="item ml">
<label>${DL.str_202}</label>
<select id="Hitomi"></select>
</div>
<div id="YinawDIV" class="item">
<input id="Yinaw" type="checkbox">
<label>壹纳网使用原始新浪图床链接</label>
</div>
</div>
<button id="CancelBtn">${(isOpenGallery || isOpenFilter) ? DL.str_82.replace(" (Esc)", "") : DL.str_82}</button>
<button id="ResetBtn">${DL.str_83}</button>
<button id="SaveBtn">${DL.str_84}</button>
<div id="mypopover" popover></div>
`;
main.innerHTML = FullPictureLoadOptionsMainHtmlStr;
const tab_toggle = (event, id) => {
cancelDefault(event);
gae(".tab", main).forEach(e => e.classList.remove("active"));
gae(".set", main).forEach(e => e.classList.add("hide"));
event.target.classList.add("active");
ge(id, main).classList.remove("hide");
};
ge("#page_tab", main).addEventListener("click", event => tab_toggle(event, "#page"));
ge("#gallery_tab", main).addEventListener("click", event => tab_toggle(event, "#gallery"));
ge("#lightbox_tab", main).addEventListener("click", event => tab_toggle(event, "#lightbox"));
ge("#download_tab", main).addEventListener("click", event => tab_toggle(event, "#download"));
ge("#other_tab", main).addEventListener("click", event => tab_toggle(event, "#other"));
if (isM && ("popover" in HTMLElement.prototype)) {
let popover = ge("#mypopover", main);
gae(".tip", main).forEach(e => {
e.addEventListener("click", event => {
let text = event.target.closest("div").title;
popover.innerText = text;
popover.togglePopover();
});
});
}
const languageSelect = ge("#language", main);
["UI", "zh", "TW", "EN"].forEach(v => {
const option = document.createElement("option");
option.value = v;
if (v == "UI") {
option.innerText = "Browser UI";
} else if (v == "zh") {
option.innerText = "CN";
} else {
option.innerText = v.toUpperCase();
}
fragment.append(option);
});
languageSelect.append(fragment);
let lv;
if (_GM_getValue("language") == "zh") {
lv = "zh";
} else if (_GM_getValue("language") == "TW") {
lv = "TW";
} else if (_GM_getValue("language") == "EN") {
lv = "EN";
} else {
lv = "UI";
}
const MsgPosSelect = ge("#MsgPos", main);
Object.values(DL.str_109).forEach((v, i) => {
const option = document.createElement("option");
option.value = i;
option.innerText = v;
fragment.append(option);
});
MsgPosSelect.append(fragment);
const ZoomSelect = ge("#Zoom", main);
for (let i = 0; i < 11; i++) {
const option = document.createElement("option");
option.value = i;
option.innerText = i === 0 ? "Auto" : i + "0%";
fragment.append(option);
}
ZoomSelect.append(fragment);
const ColumnSelect = ge("#Column", main);
for (let i = 2; i <= 6; i++) {
const option = document.createElement("option");
option.value = i;
option.innerText = i;
ColumnSelect.append(option);
}
const ShadowGalleryWheelSelect = ge("#ShadowGalleryWheel", main);
Object.values(DL.ShadowGalleryWheel).forEach((v, i) => {
const option = document.createElement("option");
option.value = i;
option.innerText = v;
fragment.append(option);
});
ShadowGalleryWheelSelect.append(fragment);
const horizontalWheelSelect = ge("#horizontalWheel", main);
Object.values(DL.horizontalWheel).forEach((v, i) => {
const option = document.createElement("option");
option.value = i;
option.innerText = v;
fragment.append(option);
});
horizontalWheelSelect.append(fragment);
const FancyboxWheelSelect = ge("#FancyboxWheel", main);
Object.values(DL.FancyboxWheel).forEach((v, i) => {
const option = document.createElement("option");
option.value = i;
option.innerText = v;
fragment.append(option);
});
FancyboxWheelSelect.append(fragment);
const FancyboxSlideshowTimeoutSelect = ge("#FancyboxSlideshowTimeout", main);
for (let i = 0; i < 61; i++) {
const option = document.createElement("option");
option.value = i;
option.innerText = i === 0 ? "500 ms" : i + " sec";
fragment.append(option);
}
FancyboxSlideshowTimeoutSelect.append(fragment);
const FancyboxTransitionSelect = ge("#FancyboxTransition", main);
for (const [k, v] of Object.entries(DL.FancyboxTransition)) {
const option = document.createElement("option");
option.value = k;
option.innerText = v;
fragment.append(option);
}
FancyboxTransitionSelect.append(fragment);
const CountdownSelect = ge("#Countdown", main);
for (let i = 1; i <= 60; i++) {
const option = document.createElement("option");
option.value = i;
option.innerText = i;
fragment.append(option);
}
CountdownSelect.append(fragment);
const ThreadingSelect = ge("#Threading", main);
for (let i = 1; i <= 32; i++) {
const option = document.createElement("option");
option.value = i;
option.innerText = i;
fragment.append(option);
}
ThreadingSelect.append(fragment);
const ExtensionSelect = ge("#Extension", main);
["zip", "cbz"].forEach(v => {
const option = document.createElement("option");
option.value = v;
option.innerText = v;
fragment.append(option);
});
ExtensionSelect.append(fragment);
const HitomiSelect = ge("#Hitomi", main);
["webp", "avif"].forEach(v => {
const option = document.createElement("option");
option.value = v;
option.innerText = v;
fragment.append(option);
});
HitomiSelect.append(fragment);
const QualitySelect = ge("#Quality", main);
for (let i = 0; i <= 100; i++) {
const option = document.createElement("option");
option.value = i;
if (i == 0) {
option.innerText = 0;
} else if (i == 100) {
option.innerText = 1;
} else {
option.innerText = Number("0." + i);
}
fragment.append(option);
}
QualitySelect.append(fragment);
const cdnSelect = ge("#cdn", main);
for (let i = -1; i <= 3; i++) {
const option = document.createElement("option");
option.value = i;
if (i < 0) {
option.innerText = DL.str_209;
} else {
option.innerText = `i${i}.wp.com`;
}
fragment.append(option);
}
cdnSelect.append(fragment);
topDistance = () => {
if (main.offsetHeight < _unsafeWindow.innerHeight) {
let num = (_unsafeWindow.innerHeight - main.offsetHeight) / 2;
main.style.top = num + "px";
} else {
main.style.top = "10px";
}
};
ge("#language", main).value = lv;
ge("#FetchAPIDownload", main).checked = _GM_getValue("FetchAPIDownload", 0) == 1 ? true : false;
ge("#icon", main).checked = options.icon == 1 ? true : false;
ge("#AutoInsertImg", main).checked = options.autoInsert == 1 ? true : false;
ge("#GoToFirst", main).checked = _GM_getValue("goToFirstImage", 1) == 1 ? true : false;
ge("#noPageNav", main).checked = _GM_getValue("TurnOffImageNavigationShortcutKeys", 0) == 1 ? true : false;
ge("#ShowFixedMenu", main).checked = _GM_getValue("ShowFullPictureLoadFixedMenu", 1) == 1 ? true : false;
ge("#FavorNewTab", main).checked = _GM_getValue("FavorOpenInNewTab", 0) == 1 ? true : false;
ge("#loopView", main).checked = _GM_getValue("FullPictureLoadLoopView", 1) == 1 ? true : false;
ge("#MsgPos", main).value = _GM_getValue("FullPictureLoadMsgPos", 0);
ge("#Threading", main).value = options.threading;
ge("#Zip", main).checked = options.zip == 1 ? true : false;
ge("#Extension", main).value = _GM_getValue("compressed_extension", "zip");
ge("#Copymanga", main).checked = _GM_getValue("copymangaSPA_Mode", 1) == 1 ? true : false;
ge("#EHentai", main).checked = _GM_getValue("E_HENTAI_LoadOriginalImage", 0) == 1 ? true : false;
ge("#Hitomi", main).value = _GM_getValue("hitomi_img_type", "webp");
ge("#Yinaw", main).checked = _GM_getValue("setYinawSinaOriginalURL", 0) == 1 ? true : false;
ge("#cdn", main).value = _GM_getValue("wp_image_cdn", -1);
ge("#zipFolder", main).checked = zipFolderConfig == 1 ? true : false;
ge("#ConvertWEBP", main).checked = _GM_getValue("convertWebpToJpg", 0) == 1 ? true : false;
ge("#ConvertAVIF", main).checked = _GM_getValue("convertAvifToJpg", 0) == 1 ? true : false;
ge("#Quality", main).value = _GM_getValue("jpgConvertQuality", 90);
ge("#AutoDownload", main).checked = options.autoDownload == 1 ? true : false;
ge("#Countdown", main).value = options.autoDownloadCountdown;
ge("#Comic", main).checked = options.comic == 1 ? true : false;
ge("#Double", main).checked = _GM_getValue("doubleTouchNext", 1) == 1 ? true : false;
if ((isString(siteData.srcset) || isString(siteData.imgs)) && !isArray(siteData.insertImg)) {
ge("#ShowEyeDIV", main).style.display = "flex";
ge("#ShowEye", main).checked = FullPictureLoadShowEye == 1 ? true : false;
}
const hide = (selectors) => selectors.forEach(s => gae(s, main).forEach(e => e.classList.add("hide")));
if ("insertImg" in siteData) {
const [, insertMode] = siteData.insertImg;
if (![1, 2].some(n => n == insertMode)) {
hide(["#AutoInsertImgDIV"]);
}
}
if (!("insertImg" in siteData)) {
hide([
"#AutoInsertImgDIV",
"#GoToFirstDIV",
"#noPageNavDIV",
"#ZoomDIV",
"#viewModeDIV",
"#ColumnDIV"
]);
}
if (isM) {
hide([
"#noPageNavDIV",
"#ShowFixedMenuDIV",
//"#ShadowGalleryModeDIV",
"#ShadowGalleryWheelDIV",
"#horizontalWheelDIV",
"#FancyboxWheelDIV",
"#ShadowGalleryloopViewDIV"
]);
}
if (isPC) {
hide([
"#MobileGalleryModeDIV",
"#GalleryInIconDIV"
]);
}
if (!["www.2025copy.com", "2025copy.com", "copy2000.site", "www.copy20.com", "copy20.com", "www.mangacopy.com", "mangacopy.com"].some(h => fn.lh === h)) {
hide(["#CopymangaDIV"]);
}
if (!["e-hentai.org", "exhentai.org"].some(h => fn.lh == h)) {
hide(["#EHentaiDIV"]);
}
if (fn.lh != "hitomi.la") {
hide(["#HitomiDIV"]);
}
if (fn.lh != "yinaw.com") {
hide(["#YinawDIV"]);
}
if (isSimpleMode) {
hide([
"#MobileGalleryModeDIV",
"#autoExportDIV"
]);
}
if (isSimpleMode || siteData.aeg == 0) {
hide(["#ShadowGalleryModeDIV"]);
}
if (isSimpleMode) {
hide([
"#iconDIV",
"#AutoDownloadDIV",
"#CountdownDIV"
]);
}
ge("#Viewer", main).checked = (localStorage.getItem("newTabViewLightGallery") ?? 0) == 1 ? true : false;
ge("#Fancybox", main).checked = options.fancybox == 1 ? true : false;
ge("#FancyboxSlideshowTimeout", main).value = FancyboxSlideshowTimeout;
ge("#FancyboxWheel", main).value = _GM_getValue("FancyboxWheel", 1);
ge("#FancyboxTransition", main).value = _GM_getValue("FancyboxSlideshowTransition", "fade");
ge("#FancyboxAutoClose", main).checked = _GM_getValue("FancyboxAutoClose", 1) == 1 ? true : false;
ge("#FancyboxAutoNext", main).checked = _GM_getValue("FancyboxAutoNext", 1) == 1 ? true : false;
ge("#Zoom", main).value = options.zoom;
siteData.category == "comic" ? ge("#Column", main).value = 2 : ge("#Column", main).value = options.column;
//ge("#viewMode", main).checked = options.viewMode == 1 ? true : false;
ge("#viewMode", main).checked = _GM_getValue("pageViewMode", 0) == 1 ? true : false;
ge("#ShadowGalleryMode", main).checked = options.shadowGallery == 1 ? true : false;
ge("#MobileGalleryMode", main).checked = options.mobileGallery == 1 ? true : false;
ge("#GalleryInIcon", main).checked = _GM_getValue("GalleryInIcon", 0) == 1 ? true : false;
ge("#autoExport", main).checked = options.autoExport == 1 ? true : false;
ge("#ShadowGalleryWheel", main).value = config.shadowGalleryWheel;
ge("#horizontalWheel", main).value = config.horizontalWheel;
if (comicSwitch) {
ge("#ComicDIV", main).style.display = "flex";
}
let autoDownload = siteData.autoDownload;
if (isM && showOptions || !autoDownload && showOptions) {
hide([
"#AutoDownloadDIV",
"#CountdownDIV"
]);
}
if (isSimpleMode || isPC && showOptions || (isM && showOptions && !("next" in siteData))) {
hide(["#DoubleDIV"]);
}
let downloadVideo = siteData.downloadVideo;
if (!!downloadVideo && downloadVideo === true && isPC) {
ge("#CustomDownloadVideoDIV", main).style.display = "flex";
ge("#CustomDownloadVideo", main).checked = FullPictureLoadCustomDownloadVideo == 1 ? true : false;
}
ge("#CancelBtn", main).addEventListener("click", event => {
cancelDefault(event);
mainElement.remove();
_unsafeWindow.removeEventListener("resize", topDistance);
setTimeout(() => (isOpenOptionsUI = false), 200);
});
ge("#ResetBtn", main).addEventListener("click", event => {
cancelDefault(event);
setDefault();
location.reload();
});
ge("#SaveBtn", main).addEventListener("click", event => {
cancelDefault(event);
_GM_setValue("language", ge("#language", main).value);
_GM_setValue("FetchAPIDownload", ge("#FetchAPIDownload", main).checked == true ? 1 : 0);
options.icon = ge("#icon", main).checked == true ? 1 : 0;
options.autoInsert = ge("#AutoInsertImg", main).checked == true ? 1 : 0;
_GM_setValue("goToFirstImage", ge("#GoToFirst", main).checked == true ? 1 : 0);
_GM_setValue("TurnOffImageNavigationShortcutKeys", ge("#noPageNav", main).checked == true ? 1 : 0);
_GM_setValue("ShowFullPictureLoadFixedMenu", ge("#ShowFixedMenu", main).checked == true ? 1 : 0);
_GM_setValue("FavorOpenInNewTab", ge("#FavorNewTab", main).checked == true ? 1 : 0);
_GM_setValue("FullPictureLoadLoopView", ge("#loopView", main).checked == true ? 1 : 0);
_GM_setValue("FullPictureLoadMsgPos", ge("#MsgPos", main).value);
options.threading = ge("#Threading", main).value;
options.zip = ge("#Zip", main).checked == true ? 1 : 0;
_GM_setValue("compressed_extension", ge("#Extension", main).value);
_GM_setValue("copymangaSPA_Mode", ge("#Copymanga", main).checked == true ? 1 : 0);
_GM_setValue("E_HENTAI_LoadOriginalImage", ge("#EHentai", main).checked == true ? 1 : 0);
_GM_setValue("hitomi_img_type", ge("#Hitomi", main).value);
_GM_setValue("setYinawSinaOriginalURL", ge("#Yinaw", main).checked == true ? 1 : 0);
_GM_setValue("wp_image_cdn", ge("#cdn", main).value);
_GM_setValue("zipFolderConfig", ge("#zipFolder", main).checked == true ? 1 : 0);
_GM_setValue("convertWebpToJpg", ge("#ConvertWEBP", main).checked == true ? 1 : 0);
_GM_setValue("convertAvifToJpg", ge("#ConvertAVIF", main).checked == true ? 1 : 0);
_GM_setValue("jpgConvertQuality", ge("#Quality", main).value);
options.comic = ge("#Comic", main).checked == true ? 1 : 0;
_GM_setValue("doubleTouchNext", ge("#Double", main).checked == true ? 1 : 0);
options.autoDownload = ge("#AutoDownload", main).checked == true ? 1 : 0;
options.autoDownloadCountdown = ge("#Countdown", main).value;
options.fancybox = ge("#Fancybox", main).checked == true ? 1 : 0;
localStorage.setItem("newTabViewLightGallery", ge("#Viewer", main).checked == true ? 1 : 0);
_GM_setValue("FancyboxSlideshowTimeout", ge("#FancyboxSlideshowTimeout", main).value);
_GM_setValue("FancyboxWheel", ge("#FancyboxWheel", main).value);
_GM_setValue("FancyboxSlideshowTransition", ge("#FancyboxTransition", main).value);
_GM_setValue("FancyboxAutoClose", ge("#FancyboxAutoClose", main).checked == true ? 1 : 0);
_GM_setValue("FancyboxAutoNext", ge("#FancyboxAutoNext", main).checked == true ? 1 : 0);
options.zoom = ge("#Zoom", main).value;
options.column = ge("#Column", main).value;
//options.viewMode = ge("#viewMode", main).checked == true ? 1 : 0;
_GM_setValue("pageViewMode", ge("#viewMode", main).checked == true ? 1 : 0);
options.shadowGallery = ge("#ShadowGalleryMode", main).checked == true ? 1 : 0;
options.mobileGallery = ge("#MobileGalleryMode", main).checked == true ? 1 : 0;
_GM_setValue("GalleryInIcon", ge("#GalleryInIcon", main).checked == true ? 1 : 0);
options.autoExport = ge("#autoExport", main).checked == true ? 1 : 0;
config.shadowGalleryWheel = ge("#ShadowGalleryWheel", main).value;
config.horizontalWheel = ge("#horizontalWheel", main).value;
saveConfig(config);
if ((isString(siteData.srcset) || isString(siteData.imgs)) && !isArray(siteData.insertImg)) {
ge("#ShowEye", main).checked == true ? localStorage.setItem("FullPictureLoadShowEye", 1) : localStorage.setItem("FullPictureLoadShowEye", 0);
}
if (!!downloadVideo && downloadVideo === true && isPC) {
ge("#CustomDownloadVideo", main).checked == true ? localStorage.setItem("FullPictureLoadCustomDownloadVideo", 1) : localStorage.setItem("FullPictureLoadCustomDownloadVideo", 0);
}
let jsonStr = JSON.stringify(options);
localStorage.setItem("FullPictureLoadOptions", jsonStr);
location.reload();
});
shadow.appendChild(main);
topDistance();
_unsafeWindow.addEventListener("resize", topDistance);
};
//腳本的CSS樣式
const FullPictureLoadStyle = `
.fancybox-container,
.fancybox__container,
body > .viewer-container {
z-index: ${UI_zIndex} !important;
}
.fancybox-image,
.viewer-canvas > img {
opacity: 1 !important;
}
.viewer-backdrop {
background-color: rgba(0, 0, 0, 0.96) !important;
}
.viewer-container .viewer-footer,
.viewer-container .viewer-footer .viewer-toolbar {
text-align: center !important;
}
.viewer-toolbar>ul>li {
padding: 0 !important;
margin: 0 !important;
border: none !important;
}
#FullPictureLoadOptionsShadowElement {
z-index: ${UI_zIndex - 1} !important;
}
#FullPictureLoadFavorSites {
z-index: ${UI_zIndex - 2} !important;
}
#FullPictureLoadShadowGallery,
#FullPictureLoadIframeGallery {
z-index: ${UI_zIndex - 3} !important;
}
#FullPictureLoadFilterDownload {
z-index: ${UI_zIndex - 5} !important;
}
.FullPictureLoadImageReturnTop {
position: fixed;
right: 10px;
bottom: 80px;
width: 53px !important;
height: 53px !important;
border: unset;
z-index: ${UI_zIndex - 6};
opacity: 0.6;
}
#FullPictureLoad {
display: block !important;
}
#FullPictureLoadGoToLastImage {
bottom: 66px !important;
}
#FullPictureLoadGoToFirstImage {
bottom: 108px !important;
}
.FullPictureLoadFixedBtn {
position: fixed !important;
left: 24px;
width: 32px !important;
height: 32px !important;
border: unset !important;
border-radius: unset !important;
margin: unset !important;
padding: unset !important;
z-index: ${UI_zIndex - 6} !important;
cursor: pointer !important;
pointer-events: auto !important;
background: unset !important;
min-width: unset !important;
min-height: unset !important;
opacity: 0.8 !important;
}
#FullPictureLoadEye {
position: fixed !important;
display: block !important;
width: 32px !important;
height: 32px !important;
margin: 0 !important;
border-radius: unset !important;
z-index: ${UI_zIndex - 6} !important;
opacity: 1 !important;
cursor: pointer !important;
pointer-events: auto !important;
}
#FullPictureLoadFixedMenu {
text-align: center !important;
font-family: ui-monospace, sans-serif, system-ui, -apple-system, Segoe UI, Arial !important;
font-weight: 500 !important;
font-size: 14px !important;
color: #000000 !important;
height: auto !important;
padding: 5px 5px 2px 5px !important;
position: fixed !important;
left: 10px !important;
bottom: 152px !important;
border: #ccc 1px solid !important;
border-radius: 3px !important;
background-color: #fff !important;
box-sizing: unset !important;
opacity: 0.4;
z-index: ${UI_zIndex - 6} !important;
}
#FullPictureLoadFixedMenu > div,
#FullPictureLoadFixedMenuB > div {
height: 24px !important;
line-height: 24px !important;
width: auto !important;
overflow: hidden !important;
font-size: 14px !important;
text-shadow: unset !important;
text-align: center !important;
letter-spacing: unset !important;
border: #ccc 1px solid !important;
background-color: #f6f6f6 !important;
padding: 0 5px 0 5px !important;
margin: 0 2px 3px 0 !important;
cursor: pointer !important;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#FullPictureLoadFixedMenu:hover,
.FullPictureLoadFixedBtn:hover {
opacity: 1 !important;
}
#FullPictureLoadFixedMenu .itemNoShow {
display: none !important;
}
#FullPictureLoadFixedMenuB {
text-align: center !important;
font-family: ui-monospace, sans-serif, system-ui, -apple-system, Segoe UI, Arial !important;
font-weight: 500 !important;
font-size: 14px !important;
color: #000000 !important;
width: 112px !important;
height: auto !important;
min-height: 29px !important;
padding: 5px 5px 2px 5px !important;
position: fixed !important;
border: #ccc 1px solid !important;
border-radius: 3px !important;
background-color: #fff !important;
opacity: 1;
z-index: ${UI_zIndex - 6} !important;
letter-spacing: unset !important;
}
#FullPictureLoadMsg {
font-family: ui-monospace, sans-serif, system-ui, -apple-system, Segoe UI, Arial !important;
font-size: ${language.includes("zh") ? "24px" : "22px"};
font-weight: 500;
text-align: center;
line-height: 50px;
color: #ffffff;
width: 360px;
height: auto;
padding: 0px !important;
background-color: #000;
border: 1px solid #303030;
border-radius: 10px;
position: fixed;
z-index: ${UI_zIndex - 4};
opacity: 0.7;
}
.FullPictureLoadImage:not(.small) {
width: auto;
height: auto;
max-width: 100%;
max-height: unset !important;
display: block !important;
float: unset !important;
opacity: 1 !important;
border: none !important;
border-radius: unset !important;
padding: 0 !important;
margin: 0 auto !important;
transition: unset !important;
transform: unset !important;
}
.FullPictureLoadImage.small {
width: auto;
height: auto;
max-width: 100% !important;
max-height: 100% !important;
min-height: 50x !important;
display: block !important;
float: unset !important;
opacity: 1 !important;
border: none !important;
border-radius: unset !important;
padding: 0 !important;
margin: auto;
transition: unset !important;
transform: unset !important;
}
#FullPictureLoadImgBox {
display: block;
opacity: 1 !important;
border: none !important;
border-radius: unset !important;
padding: 0 !important;
margin: 0 auto 10px !important;
}
#FullPictureLoadImgBox > div {
height: auto;
}
a[data-fancybox="FullPictureLoadImageOriginal"],
a[data-fancybox="FullPictureLoadImageSmall"] {
position: unset !important;
padding: 0 !important;
margin: 0 auto !important;
display: block !important;
color: unset !important;
border: unset !important;
--local-colour1-primary: unset !important;
--local-colour1-secondary: unset !important;
--local-colour2-primary: unset !important;
--local-colour2-secondary: unset !important;
transition-property: unset !important;
transition-duration: unset !important;
}
#FullPictureLoadEnd {
font-size: 20px;
height: 30px;
width: 100%;
line-height: 30px;
text-align: center !important;
margin: 5px auto !important;
}
#FullPictureLoadEnd
~ *:not(
h3,
ul,
p,
.tags,
[id^="Full"],
[class^="Full"],
a[href="javascript:void(0);"],
.post-info,
.post-tags,
.article-tags,
*[class^="fancybox"],
div[tabindex],
.row,
.text-center,
.link-d,
#myrating,
.gallery-a,
.pagination,
div[class^="picnext"],
a.zwf,
.bo_nav
) {
display: none !important;
}
.FullPictureLoadLoading {
font-size: 20px;
text-align: center;
height: 30px;
line-height: 30px;
margin: 5px auto !important;
border: none !important;
}
.autoPagerTitle {
width: auto;
height: 30px;
font-size: 18px;
color: black;
font-family: ui-monospace, sans-serif, system-ui, -apple-system, Segoe UI, Arial !important;
font-weight: 500 !important;
line-height: 29px;
text-align: center;
overflow: hidden;
display: block;
margin: 10px 5px;
border: 1px solid #e0e0e0;
background-color: #f0f0f0;
background: -webkit-gradient(
linear,
0 0,
0 100%,
from(#f9f9f9),
to(#f0f0f0)
);
background: -moz-linear-gradient(top, #f9f9f9, #f0f0f0);
box-shadow: 0 0 5px rgba(0, 0, 0, 0.6);
border-radius: 5px;
}
.autoPagerTitle.off {
color: white;
border: 1px solid #0e0e0e;
background-color: #0f0f0f;
background: -webkit-gradient(
linear,
0 0,
0 100%,
from(#9f9f9f),
to(#0f0f0f)
);
background: -moz-linear-gradient(top, #9f9f9f, #0f0f0f);
box-shadow: 0 0 5px rgba(255, 255, 255, 0.6);
border-radius: 5px;
}
.autoPagerTitle a:-webkit-any-link {
font-family: ui-monospace, sans-serif, system-ui, -apple-system, Segoe UI, Arial !important;
font-weight: 500 !important;
color: black;
}
.autoPagerTitle.off a:-webkit-any-link {
color: white;
}
.autoPagerLoading {
width: auto;
height: auto;
max-width: 60px !important;
max-height: 60px !important;
display: block !important;
opacity: 1 !important;
border: none !important;
border-radius: unset !important;
padding: 0 !important;
margin: 20px auto !important;
}
#FullPictureLoadOptionsButtonParentDiv {
font-family: ui-monospace, sans-serif, system-ui, -apple-system, Segoe UI, Arial !important;
font-size: initial !important;
font-weight: 500 !important;
max-width: 100% !important;
height: 80px !important;
min-height: unset !important;
margin-bottom: 6px !important;
}
.FullPictureLoadPageButtonTop {
height: 28px !important;
line-height: 26px !important;
min-height: unset !important;
padding: 1px !important;
margin: 10px 0 10px 0 !important;
border-radius: unset !important;
appearance: auto;
text-rendering: auto;
color: black !important;
letter-spacing: normal;
word-spacing: normal;
font-family: ui-monospace, sans-serif, system-ui, -apple-system, Segoe UI, Arial !important;
font-size: 14px !important;
font-weight: 500 !important;
text-transform: none;
text-indent: 0px;
text-shadow: none;
display: inline-block !important;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
align-items: flex-start;
box-sizing: border-box;
background: unset !important;
background-color: #f6f6f6 !important;
border: 1px solid #a0a0a0 !important;
cursor: pointer !important;
}
.FullPictureLoadPageButtonBottom {
height: 28px !important;
line-height: 26px !important;
min-height: unset !important;
padding: 1px !important;
margin: 0px !important;
border-radius: unset !important;
appearance: auto;
text-rendering: auto;
color: black !important;
letter-spacing: normal;
word-spacing: normal;
font-family: ui-monospace, sans-serif, system-ui, -apple-system, Segoe UI, Arial !important;
font-size: 14px !important;
font-weight: 500 !important;
text-transform: none;
text-indent: 0px;
text-shadow: none;
display: inline-block !important;
text-align: center;
align-items: flex-start;
box-sizing: border-box;
background: unset !important;
background-color: #f6f6f6 !important;
border: 1px solid #a0a0a0 !important;
cursor: pointer !important;
}
#FullPictureLoadOptions button:hover,
.FullPictureLoadPageButtonTop:hover,
.FullPictureLoadPageButtonBottom:hover {
color: black !important;
}
.viewer-open:not(.fancybox-active) {
overflow: unset !important;
padding-right: 0px !important;
}
.fancybox-infobar *,
.fancybox__infobar,
a[data-fancybox-download],
a[data-fancybox-download]:hover,
a[data-fancybox-download]:link,
a[data-fancybox-download]:visited,
a[data-fancybox-download]:active {
color: white;
}
a[data-fancybox]:hover {
opacity: 1 !important;
}
.viewer-toolbar > ul > li {
line-height: unset !important;
}
`;
const goToFirstImage = _GM_getValue("goToFirstImage", 1);
const TurnOffImageNavigationShortcutKeys = _GM_getValue("TurnOffImageNavigationShortcutKeys", 0);
const ShowFullPictureLoadFixedMenu = _GM_getValue("ShowFullPictureLoadFixedMenu", 1);
const autoScrollAllElement = _GM_getValue("autoScrollAllElement", 0);
const comicInfiniteScrollMode = localStorage.getItem("FullPictureLoadComicInfiniteScrollMode") ?? 0;
const E_HENTAI_LoadOriginalImage = _GM_getValue("E_HENTAI_LoadOriginalImage", 0);
const setYinawSinaOriginalURL = _GM_getValue("setYinawSinaOriginalURL", 0);
const copymangaSPA_Mode = _GM_getValue("copymangaSPA_Mode", 1);
const hitomi_img_type = _GM_getValue("hitomi_img_type", "webp");
//確認選項設置資料
const checkOptionsData = async () => {
const getOptionsData = localStorage.getItem("FullPictureLoadOptions");
if (getOptionsData === null && options.autoDownload !== 1) {
let jsonStr = JSON.stringify(defaultOptions);
localStorage.setItem("FullPictureLoadOptions", jsonStr);
} else if (options.autoDownload !== 1) {
let optionsJson = JSON.parse(getOptionsData);
options = Object.assign(defaultOptions, optionsJson);
//debug("\nFull Picture Load Options Json\n", options);
}
};
//Fancybox5的語系
const Fancyboxl10nV5 = () => {
let l10n;
switch (language) {
case "TW":
case "zh-TW":
case "zh-HK":
case "zh-Hant-TW":
case "zh-Hant-HK":
l10n = {
PANUP: "上移",
PANDOWN: "下移",
PANLEFT: "左移",
PANRIGHT: "右移",
ZOOMIN: "放大",
ZOOMOUT: "縮小",
TOGGLEZOOM: "切換縮放等級",
TOGGLE1TO1: "切換縮放等級",
ITERATEZOOM: "切換縮放等級",
ROTATECCW: "逆時針旋轉",
ROTATECW: "順時針旋轉",
FLIPX: "水平翻轉",
FLIPY: "垂直翻轉",
FITX: "水平適應",
FITY: "垂直適應",
RESET: "重設",
TOGGLEFS: "切換全螢幕",
CLOSE: "關閉",
NEXT: "下一個",
PREV: "上一個",
MODAL: "使用 ESC 鍵關閉",
ERROR: "發生了錯誤,請稍後再試",
IMAGE_ERROR: "找不到圖像",
ELEMENT_NOT_FOUND: "找不到 HTML 元素",
AJAX_NOT_FOUND: "載入 AJAX 時出錯: 未找到",
AJAX_FORBIDDEN: "載入 AJAX 時出錯: 被阻止",
IFRAME_ERROR: "載入頁面出錯",
TOGGLE_ZOOM: "切換縮放等級",
TOGGLE_THUMBS: "切換縮圖",
TOGGLE_SLIDESHOW: "切換幻燈片",
TOGGLE_FULLSCREEN: "切換全螢幕",
DOWNLOAD: "下載"
};
break;
case "zh":
case "zh-CN":
case "zh-Hans-CN":
l10n = {
PANUP: "上移",
PANDOWN: "下移",
PANLEFT: "左移",
PANRIGHT: "右移",
ZOOMIN: "放大",
ZOOMOUT: "缩小",
TOGGLEZOOM: "切换缩放级别",
TOGGLE1TO1: "切换缩放级别",
ITERATEZOOM: "切换缩放级别",
ROTATECCW: "逆时针旋转",
ROTATECW: "顺时针旋转",
FLIPX: "水平翻转",
FLIPY: "垂直翻转",
FITX: "水平适应",
FITY: "垂直适应",
RESET: "重置",
TOGGLEFS: "切换全屏",
CLOSE: "关闭",
NEXT: "下一个",
PREV: "上一个",
MODAL: "使用 ESC 键关闭",
ERROR: "发生了错误,请稍后再试",
IMAGE_ERROR: "找不到图像",
ELEMENT_NOT_FOUND: "找不到 HTML 元素",
AJAX_NOT_FOUND: "载入 AJAX 时出错: 未找到",
AJAX_FORBIDDEN: "载入 AJAX 时出错: 被阻止",
IFRAME_ERROR: "加载页面出错",
TOGGLE_ZOOM: "切换缩放级别",
TOGGLE_THUMBS: "切换缩略图",
TOGGLE_SLIDESHOW: "切换幻灯片",
TOGGLE_FULLSCREEN: "切换全屏",
DOWNLOAD: "下载"
};
break;
default:
l10n = "EN";
}
if (_unsafeWindow?.Fancybox?.defaults?.l10n && l10n != "EN") {
_unsafeWindow.Fancybox.defaults.l10n = l10n;
_unsafeWindow.Fancybox.defaults.animated = false;
//debug("\nFancybox 5.0.xx 預設選項物件 Fancybox.defaults\n", Fancybox.defaults);
}
return l10n;
};
//Fancybox3的語系
const Fancyboxi18nV3 = async () => {
if (siteData.fancybox?.js === false) return;
switch (language) {
case "TW":
case "zh-TW":
case "zh-HK":
case "zh-Hant-TW":
case "zh-Hant-HK":
_unsafeWindow.jQuery.fancybox.defaults.i18n.tw = {
"CLOSE": "關閉",
"NEXT": "下一個",
"PREV": "上一個",
"ERROR": "無法載入請求的內容。 <br/> 請稍後重試。",
"PLAY_START": "開始幻燈片",
"PLAY_STOP": "暫停幻燈片",
"FULL_SCREEN": "全螢幕",
"THUMBS": "縮圖",
"DOWNLOAD": "下載",
"SHARE": "分享",
"ZOOM": "縮放"
};
_unsafeWindow.jQuery.fancybox.defaults.lang = "tw";
break;
case "zh":
case "zh-CN":
case "zh-Hans-CN":
_unsafeWindow.jQuery.fancybox.defaults.i18n.cn = {
"CLOSE": "关闭",
"NEXT": "下一个",
"PREV": "上一个",
"ERROR": "无法加载请求的内容。 <br/> 请稍后重试。",
"PLAY_START": "开始幻灯片",
"PLAY_STOP": "暂停幻灯片",
"FULL_SCREEN": "全面屏",
"THUMBS": "缩略图",
"DOWNLOAD": "下载",
"SHARE": "分享",
"ZOOM": "缩放"
};
_unsafeWindow.jQuery.fancybox.defaults.lang = "cn";
break;
}
};
//更改Fancybox3的預設選項
const FancyboxOptionsV3 = () => {
if (siteData.fancybox?.js === false) return;
_unsafeWindow.jQuery.fancybox.defaults.buttons = ["zoom", "slideShow", "fullScreen", "thumbs", "close"];
_unsafeWindow.jQuery.fancybox.defaults.loop = true;
_unsafeWindow.jQuery.fancybox.defaults.toolbar = true;
//console.log("fancybox 3.5.7 選項物件", _unsafeWindow.jQuery.fancybox.defaults);
};
//頁面容器快捷鍵
const addKeyEvent = async event => {
if (isOpenFilter || isOpenFancybox || isOpenGallery || ge(".fancybox-container,#FullPictureLoadFavorSites")) return;
if (event.ctrlKey && event.altKey && (event.code === "KeyC" || event.key === "c" || event.key === "C")) return;
if (event.ctrlKey && (event.code === "NumpadDecimal" || event.code === "Period" || event.key === ".")) return;
if ((event.code != "Escape" || event.key != "Escape") && isOpenOptionsUI) return;
if (["INPUT", "TEXTAREA"].some(n => n === document.activeElement.tagName)) return;
if (event.ctrlKey && event.altKey && (event.code === "KeyT" || event.key === "t" || event.key === "T")) {
let str = _unsafeWindow.getSelection().toString();
str == "" ? null : customTitle = str;
let newTitle = await prompt("New Title", customTitle);
newTitle == null ? null : customTitle = newTitle;
fn.showMsg(DL.str_118);
debug("圖集新標題", newTitle || customTitle);
}
if (event.ctrlKey || event.altKey || event.shiftKey) return;
if (event.code === "KeyF" || event.key === "f" || event.key === "F") { //F鍵
return createFilterUI();
}
if (!isSimpleMode && (event.code === "KeyG" || event.key === "g" || event.key === "G")) { //G鍵
return createShadowGallery();
}
if (!isSimpleMode && (event.code === "KeyI" || event.key === "i" || event.key === "I")) { //I鍵
return createIframeGallery();
}
if (!isSimpleMode && (event.code === "Numpad0" || event.key === "0")) { //數字鍵0
fastDownloadSwitch = false;
return DownloadFn();
}
if (!isSimpleMode && (event.code === "Numpad1" || event.key === "1")) return copyImgSrcText(); //數字鍵1
if (!isSimpleMode && (event.code === "Numpad2" || event.key === "2")) return goToImg("first"); //數字鍵2
if (!isSimpleMode && (event.code === "Numpad3" || event.key === "3")) { //數字鍵3
fastDownloadSwitch = true;
return DownloadFn();
}
if (!isSimpleMode && (event.code === "Numpad4" || event.key === "4")) return goToImg("last"); //數字鍵4
if (!isSimpleMode && (event.code === "Numpad5" || event.key === "5")) return toggleImgMode(); //數字鍵5
if (!isSimpleMode && (event.code === "Numpad6" || event.key === "6")) { //數字鍵6
if ("fn" in siteData && isFn(siteData.fn)) {
return siteData.fn();
} else {
return autoScrollEles();
}
}
if (!isSimpleMode && (event.code === "Numpad7" || event.key === "7")) return exportImgSrcText(); //數字鍵7
if (!isSimpleMode && (event.code === "Numpad8" || event.key === "8")) return newTabView(); //數字鍵8
if (event.code === "Numpad9" || event.key === "9") return createFavorShadowElement(); //數字鍵9
if (!isSimpleMode && (event.code === "NumpadSubtract" || event.key === "-")) { //數字鍵-
fn.clearSetTimeout();
return reduceZoom();
}
if (!isSimpleMode && (event.code === "NumpadAdd" || event.key === "+")) { //數字鍵+
fn.clearSetTimeout();
return increaseZoom();
}
if (!isSimpleMode && (event.code === "NumpadDecimal" || event.code === "Period" || event.key === ".")) { //數字鍵.
fn.clearSetTimeout();
return cancelZoom();
}
if (event.code === "NumpadMultiply" || event.key === "*") { //數字鍵*
createPictureLoadOptionsShadowElement();
}
if (event.code === "Escape" || event.key === "Escape") { //Esc鍵
if (!isStopDownload && isDownloading) {
isStopDownload = true;
isDownloading = false;
fn.clearAllTimer(2);
fn.showMsg(DL.str_149);
}
if (isCountdowning) {
isCountdowning = false;
isStopDownload = true;
fn.clearAllTimer(2);
fn.showMsg(DL.str_149);
}
isEsc = true;
setTimeout(() => (isEsc = false), 200);
let UI = ge("#FullPictureLoadOptionsShadowElement");
if (UI) {
UI.remove();
_unsafeWindow.removeEventListener("resize", topDistance);
setTimeout(() => (isOpenOptionsUI = false), 200);
}
return;
}
if (event.code === "NumpadDivide" || event.key === "/") { //數字鍵/
fn.showMsg(DL.str_91);
setDefault(); //重置用戶設定恢復為預設選項
setTimeout(() => location.reload(), 1000);
return;
}
};
const toggleUI = async () => {
if (!"SPA" in siteData || !isFn(siteData.SPA) || !!ge(".FullPictureLoadImage") || isOpenMenu || isFetching) return;
isFetching = true;
if (isOpenGallery) {
closeGallery();
}
if (isOpenFilter) {
closeFilter()
}
const validPage = await siteData.SPA();
isFetching = false;
if (!!validPage) {
isValidPage = true;
if (isAddFullPictureLoadButton) addFullPictureLoadButton();
if (isAddFullPictureLoadFixedMenu) addFullPictureLoadFixedMenu();
if (isAddNewTabViewButton) addNewTabViewButton();
if (!isAddKeyEvent) {
document.addEventListener("keydown", addKeyEvent);
isAddKeyEvent = true;
}
} else {
iconObserver.disconnect();
eyeObserver.disconnect();
fn.remove(".FullPictureLoadFixedBtn,#FullPictureLoadEye,#FullPictureLoadFixedMenu,#FullPictureLoadFixedMenuB,div.addUrl");
EyeNumElement = null;
document.removeEventListener("keydown", addKeyEvent);
isAddKeyEvent = false;
isValidPage = false;
globalImgArray = [];
}
await delay(200);
};
const toggleUI_B = async () => {
if (!"SPA" in siteData || !isFn(siteData.SPA) || !!ge(".FullPictureLoadImage") || isOpenMenu || isFetching) return;
isFetching = true;
if (isOpenGallery) {
closeGallery();
}
if (isOpenFilter) {
closeFilter()
}
const validPage = await siteData.SPA();
isFetching = false;
if (!!validPage) {
isValidPage = true;
if (isAddFullPictureLoadButton) addFullPictureLoadButton();
if (isAddFullPictureLoadFixedMenu) addFullPictureLoadFixedMenu();
if (!isAddKeyEvent) {
document.addEventListener("keydown", addKeyEvent);
isAddKeyEvent = true;
}
await setFPLF();
if ("prev" in siteData) {
await getPrevLink(siteData.prev, "\nURL變換 prevLink:");
}
if ("next" in siteData) {
await getNextLink(siteData.next, "\nURL變換 nextLink:");
}
if (isAddNewTabViewButton) {
addNewTabViewButton();
captureSrcB();
}
} else {
iconObserver.disconnect();
eyeObserver.disconnect();
fn.remove(".FullPictureLoadFixedBtn,#FullPictureLoadEye,#FullPictureLoadFixedMenu,#FullPictureLoadFixedMenuB,div.addUrl");
EyeNumElement = null;
document.removeEventListener("keydown", addKeyEvent);
isAddKeyEvent = false;
isValidPage = false;
globalImgArray = [];
}
};
const getNextLink = async (next, text = "\n圖片全載NEXT:") => {
let tempLink = null;
if (isFn(next)) {
tempLink = await next();
} else if (isString(next) || isObject(next)) {
tempLink = fn.ge(next);
}
debug(text, tempLink);
try {
if (tempLink !== null && tempLink !== undefined) {
if (isString(tempLink)) {
nextLink = tempLink;
return tempLink;
}
if (isEle(tempLink) && ["A", "LINK"].some(t => tempLink?.tagName === t)) {
try {
if (/^http/.test(tempLink.href)) {
nextLink = tempLink.href;
if (tempLink?.tagName === "LINK") {
return nextLink;
}
return tempLink;
} else {
nextElement = tempLink;
}
} catch {}
} else if (isEle(tempLink)) {
nextElement = tempLink;
}
}
} catch {}
return tempLink;
};
const getPrevLink = async (prev, text = "\n圖片全載PREV:") => {
prevLink = null;
let tempLink = null;
if (isNumber(prev)) {
return (prevLink = 1);
} else if (isFn(prev)) {
tempLink = await prev();
} else if (isString(prev) || isObject(prev)) {
tempLink = fn.ge(prev);
}
debug(text, tempLink);
try {
if (tempLink !== null && tempLink !== undefined) {
if (isString(tempLink)) {
return (prevLink = tempLink);
}
if (isEle(tempLink) && ["A", "LINK"].some(t => tempLink?.tagName === t)) {
if (tempLink?.href?.startsWith("http")) {
return (prevLink = tempLink.href);
}
}
}
} catch {}
};
const getTitle = async (title, dom = document) => {
let text;
if (isString(title)) {
text = fn.gt(title, 1, dom);
}
if (isArray(title)) {
let titles = title;
let texts = titles.map(t => fn.gt(t, 1, dom)?.trim());
let [a_text, b_text] = texts;
if (b_text?.toLowerCase()?.includes(a_text?.toLowerCase())) {
text = b_text;
} else {
text = texts.join(" - ").replace("《", "").replace("》", "");
}
} else if (isFn(title)) {
text = await title();
}
return text;
};
let showOptions = false;
let comicSwitch = false;
//遍歷腳本站點JSON數據
for (const [i, data] of customData.entries()) {
tempData = data;
let check = false;
try {
if ("url" in data) {
const url = data.url;
if (isObject(url)) {
check = fn.checkUrl(url);
} else if (isFn(url)) {
check = await url();
}
}
if ("reg" in data) {
const reg = data.reg;
if (isRegExp(reg)) {
check = reg.test(siteUrl);
} else if (isArray(reg)) {
check = reg.some(r => r.test(siteUrl));
} else if (isFn(reg)) {
check = await reg();
}
}
if (check) {
const category = data.category;
if (category == "comic" && data.enable == 0) {
showOptions = true;
comicSwitch = true;
}
const delayTime = data.delay;
if (isNumber(delayTime)) await delay(delayTime);
checkOptionsData();
if (data.enable == 0) {
//checkOptionsData();
if (options.comic == 1 && category === "comic") {
showOptions = true;
options.enable = 1;
debug("\n漫畫類預設關閉的此站規則已開啟");
} else {
//showOptions = true;
debug("\n此規則禁用", data);
continue;
}
}
//if (data.enable != 0) checkOptionsData();
const include = data.include;
if (isString(include)) {
if (!fn.ge(include)) {
debug("\n頁面沒有包含必須的元素", data);
continue;
}
} else if (isArray(include)) {
const checkEles = include.every(e => !!fn.ge(e));
if (!checkEles) {
debug("\n頁面沒有包含必須的所有元素", data);
continue;
}
}
const exclude = data.exclude;
if (isString(exclude)) {
if (!!fn.ge(exclude)) {
debug("\n頁面包含必須排除的元素", data);
continue;
}
} else if (isArray(exclude)) {
const checkEles = exclude.some(s => !!fn.ge(s));
if (checkEles) {
debug("\n頁面包含陣列選擇器中必須排除的元素", data);
continue;
}
}
if ("autoPager" in data && isObject(data.autoPager) && category !== "comic autoPager") {
if (!fn.checkAutoPagerEle(data.autoPager)) {
siteData = {};
_this = {};
continue;
}
}
siteData = data;
_this = data;
if (!data.category.includes("autoPager") && !["none", "ad"].some(c => c === data.category)) {
showOptions = true;
}
const loadingBakBlobURL = fn.dataURLtoBlobURL(loading_bak);
const checkBlobURL = await fn.checkImgStatus(loadingBakBlobURL, 0);
if (checkBlobURL.ok) {
loading_bak = loadingBakBlobURL;
autoPagerLoading_gif = fn.dataURLtoBlobURL(autoPagerLoading_gif);
}
break;
}
} catch (error) {
console.error("圖片全載規則出錯", error);
debug("圖片全載規則出錯", data);
debug("出錯之前的規則", customData[i - 1]);
return;
}
}
_GM_registerMenuCommand(DL.str_204, () => {
let num = prompt(DL.str_205, UI_zIndex);
if (Number(num) && Number(num) > 6 && Number(num) < 2147483648) {
_GM_setValue("UI_zIndex", num);
location.reload();
}
});
if (showOptions) {
_GM_registerMenuCommand(DL.str_67, () => createPictureLoadOptionsShadowElement());
if (!ge("#FullPictureLoadMainStyle") && !["none", "ad"].some(c => c === siteData.category)) {
fn.css(FullPictureLoadStyle, "FullPictureLoadMainStyle");
}
}
let doubleTouchNext = _GM_getValue("doubleTouchNext", 1);
let isObserveURL = false;
let isAddFancybox = false;
let isOutputLog = false;
let isAddNextEvent = false;
let isAddPrevEvent = false;
let isAddOpenInNewTab = false;
let isAddLoadMore = false;
let isAddLoopClick = false;
let isClearLoop = false;
let isAddLoop = false;
// SPA初始化變數
const InitializeVariables = () => {
globalImgArray = [];
thumbnailSrcArray = [];
videoSrcArray = [];
fileUrlArray = [];
siteJson = {};
customTitle = null;
apiCustomTitle = null;
nextLink = null;
nextElement = null;
tempNextLink = null;
isGetAll = false;
};
const historyEvent = () => {
setTimeout(() => {
if (currentURL !== document.URL.replace(new URL(document.URL).hash, "")) {
currentURL = document.URL;
InitializeVariables();
toggleUI_B();
}
}, 200);
};
const historyObserver = () => {
_unsafeWindow.addEventListener("popstate", historyEvent);
};
const headObserver = async () => {
const config = {
attributes: false,
childList: true,
characterData: true,
subtree: true
};
const callback = (mutations, observer) => {
if (isGoToNext || isGoToPrev) return;
mutations.forEach(mutation => {
if (mutation.type === "childList" && mutation?.target?.tagName === "TITLE") {
if (currentURL !== document.URL.replace(new URL(document.URL).hash, "")) {
observer.disconnect();
setTimeout(() => observer.observe(document.head, config), 200);
currentURL = document.URL;
InitializeVariables();
toggleUI_B();
}
}
});
};
const observer = new MutationObserver(callback);
observer.observe(document.head, config);
historyObserver();
};
const navEvent = event => {
if (isGoToNext || isGoToPrev) return;
const url = event.destination.url.replace(new URL(event.destination.url).hash, "");
const c_host = new URL(currentURL).host;
const e_host = new URL(url).host;
if (event.downloadRequest !== null || c_host !== e_host || url.startsWith("blob") || url.startsWith("data")) return;
if (currentURL !== url) {
currentURL = url;
InitializeVariables();
toggleUI_B();
}
};
const navObserver = () => {
//Firefox、Safari尚未支持Navigation API
_unsafeWindow.navigation.addEventListener("navigate", navEvent);
historyObserver();
};
const gmUrlEvent = event => {
if (isGoToNext || isGoToPrev) return;
const url = event.url.replace(new URL(event.url).hash, "");
if (currentURL !== url) {
currentURL = url;
InitializeVariables();
toggleUI_B();
}
};
const gmUrlObserver = () => {
window.addEventListener("urlchange", gmUrlEvent);
historyObserver();
};
const loopObserver = () => {
setInterval(() => {
if (isGoToNext || isGoToPrev) return;
const url = document.URL.replace(new URL(document.URL).hash, "");
if (currentURL !== url) {
currentURL = url;
InitializeVariables();
toggleUI_B();
}
}, 500);
};
const setCss = () => {
if (("category" in siteData) && !["none", "ad"].some(c => c === siteData.category)) {
fn.css(FullPictureLoadStyle, "FullPictureLoadMainStyle");
}
if (("category" in siteData) && options.fancybox == 1 && !isObject(siteData.autoPager) && !["none", "ad"].some(c => c === siteData.category) && siteData.fancybox?.v == 3 && siteData.fancybox?.insertLibrarys == 1) {
fn.css(FancyboxV3Css, "FancyboxV3Css");
} else if (("category" in siteData) && options.fancybox == 1 && !isObject(siteData.autoPager) && !["none", "ad"].some(c => c === siteData.category) && !fancyboxBlackList()) {
fn.css(FancyboxV5Css, "FancyboxV5Css");
}
if ("css" in siteData && isString(siteData.css)) {
fn.css(siteData.css, "FullPictureLoadCustomSiteStyle");
}
if ("mcss" in siteData && isString(siteData.mcss) && isM) {
fn.css(siteData.mcss, "FullPictureLoadCustomMobileSiteStyle");
}
if ("hide" in siteData && (isString(siteData.hide) || isArray(siteData.hide))) {
let text = siteData.hide;
if (isArray(text)) {
text = text.join(",");
}
text += "{display:none!important;}";
fn.css(text, "FullPictureLoadCustomHide");
}
if (_GM_getValue("FancyboxSlideshowTransition") === "no") {
fn.css(".fancybox__container .to-next>.fancybox__content,.fancybox__container .to-prev>.fancybox__content{display:none!important}", "NoFancyboxSlideshowTransition");
}
};
const setFPLF = async () => {
try {
if ("clearEvent" in siteData) {
await fn.clearElementEvent();
}
if ("clearLoop" in siteData) {
if ("SPA" in siteData) {
if (!isClearLoop) {
isClearLoop = true;
fn.clearAllTimer(3);
}
} else {
fn.clearAllTimer(3);
}
}
if ("loop" in siteData) {
if (!isAddLoop) {
isAddLoop = true;
setInterval(() => siteData.loop(), 500);
}
}
setCss();
if (("loopClick" in siteData) && !isAddLoopClick) {
isAddLoopClick = true;
let obj = siteData.loopClick;
if (isObject(obj)) {
let {
s,
t
} = obj;
let time_id = setInterval(() => EClick(s), 200);
if (Number(t)) {
setTimeout(() => clearInterval(time_id), Number(t));
}
}
}
if ("init" in siteData) {
const init_code = siteData.init;
if (isString(init_code)) {
await new Function("siteData", "fn", '"use strict";' + init_code)(siteData, fn);
} else if (isFn(init_code)) {
await init_code();
}
}
setCss();
if (("category" in siteData) && options.fancybox == 1 && siteData.category !== "none" && !isObject(siteData.autoPager) && siteData.fancybox?.v == 3 && siteData.fancybox?.insertLibrarys == 1 && !isAddFancybox) {
isAddFancybox = true;
addLibrarysV3();
Fancyboxi18nV3();
FancyboxOptionsV3();
} else if (("category" in siteData) && options.fancybox == 1 && !siteData.category?.includes("autoPager") && !["none", "ad"].some(c => c === siteData.category) && !fancyboxBlackList() && !isAddFancybox) {
isAddFancybox = true;
addLibrarysV5();
Fancyboxl10nV5();
}
if ("box" in siteData && isArray(siteData.box)) {
const para = siteData.box;
fn.createImgBox(...para);
}
if (!isOutputLog) {
isOutputLog = true;
if (("imgs" in siteData) || ("srcset" in siteData)) {
debug("\nCSS/Xpath/JS選擇器:" + (siteData.srcset || siteData.imgs));
}
if ("threading" in siteData && isNumber(siteData.threading)) {
options.threading = siteData.threading;
debug("\n下載線程數:" + options.threading);
}
}
if ("customTitle" in siteData) {
customTitle = await getTitle(siteData.customTitle);
if (isString(customTitle)) {
customTitle = fn.dt({
t: customTitle
});
}
debug(`\n自定義標題:${customTitle}`);
}
if ("observeURL" in siteData && siteData.observeURL === "body" && !isObserveURL) {
isObserveURL = true;
const observeURL_CB = async (mutationList, observer) => {
if (mutationList) {
const mutationList_removedNodes = [...mutationList].filter(item => item.type === "childList" && item?.removedNodes?.length > 0);
if (mutationList_removedNodes.length > 0) {
for (const mutation of mutationList_removedNodes) {
const removedNodes = mutation.removedNodes;
for (const node of removedNodes) {
if (node?.id == "FullPictureLoadOptionsShadowElement" || node?.id == "FullPictureLoadShadowGallery" || node?.id == "FullPictureLoadIframeGallery") {
return;
}
}
}
}
}
if (observer) {
observer.disconnect();
setTimeout(async () => {
const body = await fn.waitEle("body");
observer.observe(body, MutationObserverConfig);
if (!isOpenGallery && currentURL !== document.URL.replace(new URL(document.URL).hash, "")) {
await toggleUI();
}
if ("customTitle" in siteData && !("capture" in siteData)) {
const newCustomTitle = await getTitle(siteData.customTitle);
if (customTitle !== newCustomTitle && newCustomTitle !== null && newCustomTitle !== undefined && newCustomTitle !== "") {
customTitle = newCustomTitle;
debug(`\n自定義標題:${newCustomTitle}`);
}
}
}, 200);
}
if (mutationList) {
try {
const mutationList_addedNodes = [...mutationList].filter(item => item.type === "childList" && item?.addedNodes?.length > 0);
if (mutationList_addedNodes.length === 0) {
return;
}
const strings = ["FullPictureLoad", "FullPictureLoadOptionsShadowElement", "FullPictureLoadShadowGallery", "FullPictureLoadIframeGallery", "pagetual", "comicRead", "Autopage", "pv-"];
for (const mutation of mutationList_addedNodes) {
const attributes = [mutation?.target?.id, mutation?.target?.className, mutation?.target?.name].filter(Boolean);
const checkM = attributes.some(attr => strings.some(str => attr?.startsWith(str)));
if (checkM) {
return;
}
const addedNodes = mutation.addedNodes;
for (const node of addedNodes) {
const attributes = [node?.id, node?.className, node?.name].filter(Boolean);
const checkN = attributes.some(attr => strings.some(str => attr?.startsWith(str)));
if (checkN) {
return;
}
}
}
//console.log(mutationList_addedNodes);
} catch {}
}
if (isFetching || isDownloading) return;
if (currentURL !== document.URL.replace(new URL(document.URL).hash, "")) {
currentURL = document.URL;
InitializeVariables();
await toggleUI();
const newCustomTitle = await getTitle(siteData.customTitle);
if ("capture" in siteData && !newCustomTitle) {
await captureSrcB(1);
const newCustomTitle = await getTitle(siteData.customTitle);
if (customTitle !== newCustomTitle && newCustomTitle !== null && newCustomTitle !== undefined && newCustomTitle !== "") {
customTitle = newCustomTitle;
}
}
if (customTitle !== newCustomTitle && newCustomTitle !== null && newCustomTitle !== undefined && newCustomTitle !== "") {
customTitle = newCustomTitle;
debug(`\n自定義標題:${newCustomTitle}`);
if ("capture" in siteData) {
captureSrcB();
}
}
if ("prev" in siteData) {
await getPrevLink(siteData.prev, "\nURL變換 prevLink:");
}
if ("next" in siteData) {
await getNextLink(siteData.next, "\nURL變換 nextLink:");
}
if ("insertImg" in siteData) {
let [, insertMode, ] = siteData.insertImg;
if (insertMode === 1 || insertMode === 2) {
if (options.autoInsert == 1) {
await fn.immediateInsertImg();
}
}
}
if (GalleryInIcon == 0 && options.shadowGallery == 1 && siteData.aeg != 0) {
fn.hideMsg();
await createShadowGallery();
}
if (GalleryInIcon == 0 && isM && options.mobileGallery == 1 && siteData.aeg != 0) {
fn.hideMsg();
createFilterUI();
}
}
};
const MutationObserveURL = new MutationObserver(observeURL_CB);
MutationObserveURL.observe(document.body, MutationObserverConfig);
}
if ("observeURL" in siteData && siteData.observeURL === "head" && !isObserveURL) {
isObserveURL = true;
headObserver();
}
if ("observeURL" in siteData && siteData.observeURL === "nav" && !isObserveURL) {
isObserveURL = true;
if ("navigation" in _unsafeWindow) {
navObserver();
} else {
loopObserver();
}
}
if ("observeURL" in siteData && siteData.observeURL === "gm" && !isObserveURL) {
isObserveURL = true;
gmUrlObserver();
}
if ("observeURL" in siteData && siteData.observeURL === "loop" && !isObserveURL) {
isObserveURL = true;
loopObserver();
}
if ("next" in siteData && !isAddNextEvent) {
isAddNextEvent = true;
const next = siteData.next;
const nextE = await getNextLink(next);
const callback = (event) => {
if (event.type === "dblclick") {
if (event?.target?.closest(".fancybox-container,.fancybox__container,.viewer-container,#FullPictureLoadOptionsShadowElement") || isChangeSize) return;
}
if ("observeURL" in siteData && isString(nextLink)) {
fn.showMsg(DL.str_34.n, 0);
return (location.href = nextLink);
}
if (isFn(next)) {
fn.showMsg(DL.str_34.n, 0);
if (isString(nextE)) {
location.href = nextE;
} else if (isEle(nextE)) {
EClick(nextE);
} else {
fn.showMsg(DL.str_37);
}
} else if (isString(next)) {
if (isEle(nextE)) {
EClick(nextE);
fn.showMsg(DL.str_35);
} else if (isString(nextE)) {
fn.showMsg(DL.str_34.n, 0);
location.href = nextE;
} else {
fn.showMsg(DL.str_37);
}
}
};
if (isM && ("next" in siteData) && doubleTouchNext == 1) {
document.addEventListener("dblclick", (event) => callback(event));
}
document.addEventListener("keydown", event => {
if (isOpenOptionsUI || isOpenGallery || isOpenFancybox || isOpenFilter || isDownloading || !isValidPage || ["INPUT", "TEXTAREA"].some(n => n === document.activeElement.tagName) || ge(".fancybox-container,#FullPictureLoadFavorSites")) return;
if (event.code === "ArrowRight" || event.key === "ArrowRight") callback(event);
});
}
if ("prev" in siteData && !isAddPrevEvent) {
isAddPrevEvent = true;
let prev = siteData.prev;
await getPrevLink(prev);
document.addEventListener("keydown", async event => {
if (isOpenOptionsUI || isOpenGallery || isOpenFancybox || isOpenFilter || isDownloading || !isValidPage || ["INPUT", "TEXTAREA"].some(n => n === document.activeElement.tagName) || ge(".fancybox-container,#FullPictureLoadFavorSites")) return;
if (event.code === "ArrowLeft" || event.key === "ArrowLeft") {
event.preventDefault();
if (prev === 1) {
fn.showMsg(DL.str_38);
history.back();
return;
} else if (isString(prev)) {
let ele = fn.ge(prev);
if (ele) {
EClick(ele);
fn.showMsg(DL.str_39);
} else {
fn.showMsg(DL.str_40);
}
} else if (isFn(prev)) {
prev = await prev();
if (isString(prev)) {
fn.showMsg(DL.str_34.p);
location.href = prev;
} else if (isEle(prev)) {
EClick(prev);
fn.showMsg(DL.str_39);
} else {
fn.showMsg(DL.str_40);
}
}
}
});
}
if ("autoClick" in siteData) {
const autoClick = siteData.autoClick;
if (isArray(autoClick)) {
let [selector, delay] = autoClick;
setTimeout(() => {
let ele = fn.ge(selector);
if (ele) {
EClick(ele);
debug(`\n圖片全載autoClick("${selector}")`, ele);
}
}, delay ?? 1000);
} else if (isString(autoClick)) {
let ele = fn.ge(autoClick);
if (!!ele) {
EClick(ele);
debug(`\n圖片全載autoClick("${autoClick}")`, ele);
}
}
}
if ("observerClick" in siteData) {
const observerClick = siteData.observerClick;
let selectors;
if (isString(observerClick)) {
selectors = [observerClick];
} else {
selectors = observerClick;
}
fn.wait(() => selectors.some(selector => !!fn.ge(selector)), 30).then(() => {
selectors.forEach((selector, i) => {
setTimeout(() => {
let ele = fn.ge(selector);
if (ele) {
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
observer.unobserve(entry.target);
EClick(entry.target);
debug(`\n圖片全載observerClick("${selector}")\n`, entry.target);
setTimeout(async () => {
if (await fn.waitEle(selector, 30)) {
observer.observe(fn.ge(selector));
}
}, 1000);
}
});
});
observer.observe(ele);
}
}, (i + 1) * 200);
});
});
}
if ("loadMore" in siteData && isString(siteData.loadMore) && !isAddLoadMore) {
isAddLoadMore = true;
const selector = siteData.loadMore;
const callback = () => {
if (_unsafeWindow.innerHeight + _unsafeWindow.pageYOffset >= document.body.offsetHeight - 200) {
document.removeEventListener("scroll", callback);
const ele = fn.ge(selector);
if (!!ele) {
EClick(ele);
debug(`圖片全載loadMore("${selector}")`);
}
setTimeout(async () => {
if (await fn.waitEle(selector, 30)) {
document.addEventListener("scroll", callback);
}
}, 1000);
}
};
document.addEventListener("scroll", callback);
}
if ("autoPager" in siteData && isObject(siteData.autoPager)) {
const observer = siteData.autoPager?.observer;
if (isString(observer)) {
let ele = fn.gae(observer).at(-1);
if (ele) fn.nextObserver.observe(ele);
} else {
const callback = async () => {
if (_unsafeWindow.innerHeight + _unsafeWindow.pageYOffset >= document.body.offsetHeight - (siteData.autoPager?.bottom ?? screen.height)) {
if (!autoPagerSwitch) return;
document.removeEventListener("scroll", callback);
await fn.infiniteScroll();
await delay(siteData.autoPager?.sleep || 1000);
document.addEventListener("scroll", callback);
}
};
document.addEventListener("scroll", callback);
}
document.addEventListener("dblclick", () => fn.toggleAutoPager());
let hide = siteData.autoPager?.hide;
if (isString(hide)) {
let eles = fn.gae(hide);
eles.forEach(e => (e.style.display = "none"));
}
if ("preloadNextPage" in siteData.autoPager) {
setTimeout(() => fn.preloadNextPage(), 3000);
}
}
if ("insertImg" in siteData) {
const insertImg = siteData.insertImg;
const autoDownload = siteData.autoDownload;
if (isArray(insertImg)) {
let autoStart;
if (isArray(autoDownload)) {
[autoStart] = autoDownload;
autoStart = (autoStart == 1 || options.autoDownload == 1);
}
const [, insertMode] = insertImg;
if (insertMode == 1 && !autoStart || insertMode == 2 && !autoStart) {
if (options.autoInsert == 1) {
if (GalleryInIcon == 0 && options.shadowGallery == 1 && siteData.aeg != 0 || GalleryInIcon == 0 && options.mobileGallery == 1 && siteData.aeg != 0) {
await fn.immediateInsertImg();
} else {
fn.immediateInsertImg();
}
}
}
}
}
if ("autoDownload" in siteData) {
const autoDownload = siteData.autoDownload;
if (isArray(autoDownload)) {
const [autoStart] = autoDownload;
if (autoStart == 1 || options.autoDownload == 1) {
DownloadFn();
}
}
}
if (GalleryInIcon == 0 && options.shadowGallery == 1 && siteData.aeg != 0 && options.autoDownload != 1 && ("imgs" in siteData) && !siteData.category.includes("autoPager") && !["none", "ad"].some(c => c === siteData.category) && !(("capture" in siteData) && ("SPA" in siteData))) {
fn.hideMsg();
if ("SPA" in siteData && isFn(siteData.SPA)) {
if (!!await siteData.SPA()) {
createShadowGallery();
}
} else {
createShadowGallery();
}
}
if (GalleryInIcon == 0 && isM && options.mobileGallery == 1 && siteData.aeg != 0 && options.autoDownload != 1 && ("imgs" in siteData) && !siteData.category.includes("autoPager") && !["none", "ad"].some(c => c === siteData.category)) {
fn.hideMsg();
if ("SPA" in siteData && isFn(siteData.SPA)) {
if (!!await siteData.SPA()) {
createFilterUI();
}
} else {
createFilterUI();
}
}
if (options.autoExport == 1 && options.autoDownload != 1) {
exportImgSrcText();
}
if ("openInNewTab" in siteData && isString(siteData.openInNewTab) && !isAddOpenInNewTab) {
isAddOpenInNewTab = true;
const openInNewTab = siteData.openInNewTab;
fn.openInNewTab(openInNewTab);
fn.addMutationObserver(() => fn.openInNewTab(openInNewTab));
}
if ("topButton" in siteData && isBoolean(siteData.topButton) && siteData.topButton === true) {
addReturnTopButton();
}
if ("setFancybox" in siteData) {
setTimeout(() => {
const setFancybox = siteData.setFancybox;
if (isBoolean(setFancybox) && options.fancybox == 1 && (isString(siteData.srcset) || isString(siteData.imgs))) {
fn.setFancybox(siteData.srcset || siteData.imgs);
} else if (isString(setFancybox) && options.fancybox == 1) {
fn.setFancybox(setFancybox);
}
}, 1200);
}
if ("preloadNext" in siteData) {
//漫畫類預讀下一話圖片
setTimeout(async () => {
const {
page,
preloadNext,
frame,
imgs,
customTitle: title
} = siteData;
try {
if ("page" in siteData) {
if (!page()) return;
}
if (!!nextLink && !!preloadNext && !isDownloading) {
let cors_ok = await fn.checkCors(nextLink);
//debug("\ncors_ok", cors_ok);
let _fetch;
if ("frame" in siteData) {
_fetch = fn.iframeDoc(nextLink, frame);
} else if (!cors_ok || ("cors" in siteData)) {
_fetch = fn.xhrDoc(nextLink);
} else {
_fetch = fn.fetchDoc(nextLink);
}
_fetch.then(async nextDoc => {
//debug("\nnextDoc", nextDoc);
if (isBoolean(preloadNext) && preloadNext === true && isFn(imgs) && isFn(title)) {
fn.picPreload(await imgs(nextDoc), await title(nextDoc), "next");
} else if (isBoolean(preloadNext) && preloadNext === true && isString(imgs) && isFn(title)) {
let arr = fn.getImgSrcArr(imgs, nextDoc);
fn.picPreload(arr, await title(nextDoc), "next");
} else if (isBoolean(preloadNext) && preloadNext === true && isString(imgs) && isArray(title)) {
let arr = fn.getImgSrcArr(imgs, nextDoc);
fn.picPreload(arr, await getTitle(title, nextDoc), "next");
}
if (isFn(preloadNext)) {
preloadNext(nextDoc, siteData);
}
});
}
} catch (error) {
console.error("圖片全載preloadNext()出錯", error);
}
}, 3000);
}
} catch (error) {
console.error("圖片全載規則出錯", error);
debug("圖片全載規則出錯", siteData);
return;
}
};
await setFPLF();
if (("reg" in siteData) || ("url" in siteData)) {
debug("\n列出此站資料", siteData);
debug(`\n列出規則總數(${customData.length})`);
debug("\n列出PHOTO規則", photoData);
debug("\n列出NSFW規則", nsfw1Data);
debug("\n列出NSFW+規則", nsfw2Data);
debug("\n列出COMIC規則", comicData);
debug("\n列出HCOMIC規則", hcomicData);
debug("\n列出自動翻頁規則", autoPagerData);
debug("\n列出去廣告規則", AD_Data);
debug("\n列出未分類規則", noneData);
}
if (isArray(siteData.scrollEle) || isFn(siteData.scrollEle)) {
_GM_registerMenuCommand(autoScrollAllElement == 0 ? "❌ " + DL.str_116 : "✔️ " + DL.str_116, () => {
autoScrollAllElement == 0 ? _GM_setValue("autoScrollAllElement", 1) : _GM_setValue("autoScrollAllElement", 0);
location.reload();
});
}
if (siteData.category === "comic" && siteData.infiniteScroll || siteData.category === "comic autoPager") {
_GM_registerMenuCommand(comicInfiniteScrollMode == 0 ? "❌ " + DL.str_122 : "✔️ " + DL.str_122, () => {
comicInfiniteScrollMode == 0 ? localStorage.setItem("FullPictureLoadComicInfiniteScrollMode", 1) : localStorage.setItem("FullPictureLoadComicInfiniteScrollMode", 0);
location.reload();
});
}
let autoDownload = siteData.autoDownload;
if (!!autoDownload) {
//自動下載快捷鍵
document.addEventListener("keydown", event => {
if (isOpenOptionsUI || isOpenGallery || isOpenFancybox || isOpenFilter || ge(".fancybox-container,#FullPictureLoadFavorSites")) return;
if (event.ctrlKey && (event.code === "NumpadDecimal" || event.code === "Period" || event.key === ".")) {
if (options.autoDownload == 0) {
fn.showMsg(DL.str_64, 0);
options.autoDownload = 1;
let jsonStr = JSON.stringify(options);
localStorage.setItem("FullPictureLoadOptions", jsonStr);
setTimeout(() => location.reload(), 2000);
} else {
isStopDownload = true;
fn.clearAllTimer(2);
options.autoDownload = 0;
let jsonStr = JSON.stringify(options);
localStorage.setItem("FullPictureLoadOptions", jsonStr);
fn.clearSetTimeout();
fn.showMsg(DL.str_65, 0);
location.reload();
}
}
});
}
//移動端手動模式頁面聚圖
if (isM && "insertImg" in siteData) {
let timeId;
const touchstartCB = event => {
//console.log(event);
if (isFetching || isDownloading || isOpenFilter || isOpenFancybox || isOpenGallery || ge(".fancybox-container,#FullPictureLoadFavorSites")) return;
const check = (e) => {
if (["SPAN", "DIV", "A"].some(t => t === e.target.tagName) && getComputedStyle(e.target).getPropertyValue("background-image") != "none") {
return true;
}
if (["A", "FIGURE", "SPAN"].some(t => t === e.target.tagName)) {
return !!e.target.querySelector("img,canvas");
}
if (e.target.tagName === "A" && e.target?.previousElementSibling?.nodeName === "IMG") {
return true;
}
if (["IMG", "CANVAS"].some(t => t === e.target.tagName) && !["Full"].some(id => e.target?.id?.startsWith(id)) && !["fancybox", "viewer-move"].some(className => e.target?.className?.startsWith(className))) {
return true;
}
return false;
};
if (check(event)) {
timeId = setTimeout(() => {
copyImgSrcText();
}, 500);
}
};
const clearCB = () => {
if (isFetching || isDownloading) return;
clearTimeout(timeId);
};
document.addEventListener("touchstart", touchstartCB);
document.addEventListener("touchmove", clearCB);
document.addEventListener("touchend", clearCB);
}
//debug("\n最終options物件\n", options);
//捕獲圖片網址
async function captureSrc(mutationList) {
if (isChangeNum || isOpenOptionsUI || isOpenGallery || isOpenFancybox || isOpenFilter || isDownloading || isFetching || FullPictureLoadShowEye == 0) return;
if (mutationList) {
for (const mutation of mutationList) {
if (mutation.type === "childList" && mutation?.target?.id === "FullPictureLoadCaptureNum") {
return;
}
}
//console.log(mutationList);
}
let imgSrcs = await getImgs(siteData.capture || siteData.srcset || siteData.imgs);
let imagePreloadArray = [];
imgSrcs.forEach(src => {
if (!captureSrcArray.includes(src)) {
captureSrcArray.push(src);
imagePreloadArray.push(src);
}
});
if (isEle(EyeNumElement) && captureTotal != captureSrcArray.length) {
isChangeNum = true;
captureTotal = captureSrcArray.length;
updateEyeNum(captureTotal);
await delay(100);
isChangeNum = false;
if (GalleryInIcon == 0 && options.shadowGallery == 1 && siteData.aeg != 0) {
setTimeout(() => createShadowGallery(), 200);
}
}
}
async function captureSrcB(invalidPage = 0) {
if (isChangeNum || isOpenOptionsUI || isOpenGallery || isOpenFancybox || isOpenFilter || isDownloading || isFetching || FullPictureLoadShowEye == 0) return;
if (invalidPage === 1 && EyeNumElement?.innerText != 0) {
isChangeNum = true;
updateEyeNum(0);
await delay(100);
isChangeNum = false;
return;
}
if (!["m2ph.xyz", "bdsmlr.com"].some(h => fn.lh.includes(h))) {
await delay(900);
}
let captureSrcArray = await getImgs(siteData.capture || siteData.srcset || siteData.imgs);
let num = captureSrcArray.length;
if (isEle(EyeNumElement)) {
isChangeNum = true;
updateEyeNum(num);
await delay(100);
isChangeNum = false;
lastValidPageURL = currentURL;
if (GalleryInIcon == 0 && options.shadowGallery == 1 && siteData.aeg != 0) {
setTimeout(() => createShadowGallery(), 200);
}
}
}
//動態捕獲圖片網址
if ((isString(siteData.srcset) || isString(siteData.imgs)) && !isArray(siteData.insertImg) || isFn(siteData.capture)) {
if (FullPictureLoadShowEye == 1 && siteData.eye != 0) {
await delay(1000);
isCaptureMode = true;
addNewTabViewButton();
captureSrc();
}
}
const defaultFavor = `main-background-color,#454d55
text-color,#fff
background-color,#333
小黃書,https://xchina.site/
紳士会所,https://www.hentaiclub.net/
图宅网,https://www.tuzac.com/
丝袜客,https://siwake.cc/
萌图社,http://www.446m.com/
美图社,https://928r.com/
六色美图,https://www.06se.com/
秀色女神,https://www.xsnvshen.co/
4KHD,https://www.4khd.com/
Xiunice.com,https://xiunice.com/
AVJB,https://avjb.com/albums/
Xasiat,https://www.xasiat.com/albums/
EVERIA.CLUB,https://everia.club/
HotGirl World,https://hotgirl.world/
Cup2D,https://cup2d.com/
AHottie,https://ahottie.net/
HotAsiaGirl,https://hotgirl.asia/photos/
紳士漫畫,https://www.wnacg.com/albums-index-cate-3.html
肉感美ガール,https://bi-girl.net/
エロ画像まとめ,https://geinou-nude.com/`;
let FavorOpenInNewTab = _GM_getValue("FavorOpenInNewTab", 0);
const createFavorShadowElement = () => {
const mainHtml = `<div id="FullPictureLoadFavorSites" style="overflow: clip !important;display: initial !important;position: fixed !important;"></div>`;
document.body.insertAdjacentHTML("beforeend", mainHtml);
const FavorSitesShadowElement = ge("#FullPictureLoadFavorSites");
const shadow = FavorSitesShadowElement.attachShadow({
mode: "closed"
});
hidePageScrollbarY();
const style = createStyle(`
#FavorSitesMain {
z-index: ${UI_zIndex - 2} !important;
}
#FavorUl {
width: 100%;
background-color: transparent;
list-style-type: none;
display: grid;
list-style: none;
margin: 10px 0px 0px 0px;
padding: 0px;
border: 0;
font: inherit;
vertical-align: baseline;
}
.favor-item {
float: left;
width: unset;
height: unset;
min-height: unset;
max-height: 44px;
margin: 0px 10px 10px 0px;
position: unset;
line-height: 24px !important;
padding: 3px;
font: unset;
font-family: ui-monospace, sans-serif, system-ui, -apple-system, Segoe UI, Arial;
font-weight: 500;
font-size: 16px;
text-align: center;
border-radius: 8px;
white-space: nowrap;
list-style: none;
cursor: pointer;
}
.favor-item a {
display: block;
text-align: center;
text-decoration: unset;
font-family: ui-monospace, sans-serif, system-ui, -apple-system, Segoe UI, Arial;
font-weight: 500;
font-size: 16px;
background-color: unset;
border-color: unset;
margin: 0;
}
#editFavorTextarea {
display: block;
height: 30em;
resize: both;
overflow: auto;
background-color: unset;
color: #000000;
border-color: #000000;
margin: 0px auto;
padding: 5px;
max-width: unset;
max-height: unset;
}
#editFavorDiv {
text-align: center;
background-color: #fafafa;
margin: 0;
padding-top: 6px;
}
.editFavorButton {
min-width: 70px;
line-height: 25px;
margin: 5px;
float: none;
padding: 0;
color: #000000;
border: 1px solid #a0a0a0;
background-color: transparent;
}
`);
shadow.append(style);
const FavorSitesElement = document.createElement("div");
FavorSitesElement.id = "FavorSitesMain";
Object.assign(FavorSitesElement.style, {
left: "0",
right: "0",
top: "0",
bottom: "0",
width: "99%",
height: "98%",
margin: "auto",
padding: "10px",
position: "fixed",
opacity: "1",
backgroundColor: "#fafafa",
fontSize: "14px",
overflowY: "auto",
overflowX: "hidden"
});
shadow.append(FavorSitesElement);
const reSize_cb = () => {
const verticalScreen = _unsafeWindow.innerHeight / _unsafeWindow.innerWidth > 1;
let ul = ge("#FavorUl", shadow);
if (ul) {
ul.style.gridTemplateColumns = `${fn.arr(Math.floor(_unsafeWindow.innerWidth / 180), () => "1fr").join(" ")}`;
if (isM) {
if (verticalScreen) {
ul.style.width = "calc(100% - 5px)";
} else {
ul.style.width = "calc(100% - 2px)";
}
}
}
let edit = ge("#editFavorDiv", shadow);
if (edit && isM) {
if (verticalScreen) {
edit.style.width = "calc(100% - 18px)";
} else {
edit.style.width = "calc(100% - 14px)";
}
} else if (edit) {
if (verticalScreen) {
edit.style.width = "calc(100% - 2px)";
} else {
edit.style.width = "calc(100% - 6px)";
}
}
};
const createFavorTextarea = () => {
FavorSitesElement.style.backgroundColor = "#fafafa";
let favorData = _GM_getValue("favorData", defaultFavor);
let editFavorDiv = document.createElement("div");
editFavorDiv.id = "editFavorDiv";
if (isM) {
const verticalScreen = _unsafeWindow.innerHeight / _unsafeWindow.innerWidth > 1;
if (verticalScreen) {
editFavorDiv.style.width = "calc(100% - 18px)";
} else {
editFavorDiv.style.width = "calc(100% - 14px)";
}
} else {
editFavorDiv.style.width = "calc(100% - 6px)";
}
editFavorDiv.style.height = "calc(100% - 20px)";
let textarea = document.createElement("textarea");
textarea.id = "editFavorTextarea";
textarea.style.width = "calc(100% - 20px)";
textarea.style.height = "calc(100% - 30px)";
editFavorDiv.append(textarea);
FavorSitesElement.appendChild(editFavorDiv);
[{
text: DL.str_111,
id: "editFavorExportBtn",
cfn: event => {
cancelDefault(event);
const blob = new Blob([textarea.value], {
type: "text/plain"
});
saveData(blob, "FullPictureLoadFavoriteSites.txt");
}
}, {
text: DL.str_212,
id: "editFavorImportBtn",
cfn: event => {
cancelDefault(event);
const input = document.createElement("input");
input.style.display = "none";
input.type = "file";
input.accept = ".txt";
input.acceptCharset = "utf-8";
FavorSitesElement.appendChild(input);
input.initialValue = input.value;
input.onchange = readFile;
input.click();
function readFile() {
if (input.value !== input.initialValue) {
const [file] = input.files;
if (!file) {
return;
}
const reader = new FileReader();
reader.onloadend = event => {
input.remove();
textarea.value = event.target.result;
};
reader.readAsText(file, "utf-8");
}
}
}
}, {
text: DL.str_131,
id: "editFavorSaveBtn",
cfn: event => {
cancelDefault(event);
_GM_setValue("favorData", textarea.value);
editFavorDiv.remove();
createFavor();
}
}, {
text: DL.str_132,
id: "editFavorCloseBtn",
cfn: event => {
cancelDefault(event);
editFavorDiv.remove();
createFavor();
}
}].forEach(obj => {
let button = document.createElement("button");
button.id = obj.id;
button.className = "editFavorButton";
button.innerText = obj.text;
button.addEventListener("click", obj.cfn);
editFavorDiv.append(button);
});
textarea.value = favorData.replace(/(\n)(\s+)/g, "$1");
};
const createFavor = () => {
let favorData = _GM_getValue("favorData", defaultFavor);
FavorSitesElement.style.backgroundColor = "#454d55";
let FavorUl = document.createElement("ul");
FavorUl.id = "FavorUl";
FavorUl.style.gridTemplateColumns = `${fn.arr(Math.floor(_unsafeWindow.innerWidth / 180), () => "1fr").join(" ")}`;
if (isM) {
const verticalScreen = _unsafeWindow.innerHeight / _unsafeWindow.innerWidth > 1;
if (verticalScreen) {
FavorUl.style.width = "calc(100% - 5px)";
} else {
FavorUl.style.width = "calc(100% - 2px)";
}
}
FavorSitesElement.appendChild(FavorUl);
let favorDataArray = favorData.split("\n").filter(Boolean);
let textColor = "#fff";
let backgroundColor = "#000";
for (let favor of favorDataArray) {
try {
let [name, value] = favor.split(",");
name = name.trim();
value = value.trim();
if (name === "main-background-color") {
FavorSitesElement.style.backgroundColor = value;
} else if (name === "text-color") {
textColor = value;
} else if (name === "background-color") {
backgroundColor = value;
} else {
let li = document.createElement("li");
li.className = "favor-item";
li.style.backgroundColor = backgroundColor;
li.style.color = textColor;
let a = document.createElement("a");
a.innerText = name;
a.href = value;
if (FavorOpenInNewTab == 1) {
a.setAttribute("target", "_blank");
}
a.style.color = textColor;
li.append(a);
fragment.append(li);
}
} catch (error) {
console.error(error);
}
}
[{
text: DL.str_130,
cfn: event => {
cancelDefault(event);
createFavorTextarea();
FavorUl.remove();
}
}, {
text: DL.str_129,
cfn: event => {
cancelDefault(event);
if (!isOpenFilter && !isOpenGallery) fn.remove("#overflowYHidden");
FavorSitesShadowElement.remove();
_unsafeWindow.removeEventListener("resize", reSize_cb);
}
}].forEach(obj => {
let li = document.createElement("li");
li.className = "favor-item";
li.style.backgroundColor = backgroundColor;
li.style.color = textColor;
li.innerText = obj.text;
li.addEventListener("click", obj.cfn);
fragment.append(li);
});
FavorUl.append(fragment);
};
createFavor();
_unsafeWindow.addEventListener("resize", reSize_cb);
};
_GM_registerMenuCommand(DL.str_125, () => {
const keys = [
"newTabViewLightGallery",
"newWindowData",
"FullPictureLoadComicInfiniteScrollMode",
"FullPictureLoadOptions",
"FullPictureLoadCustomDownloadVideo",
"FullPictureLoadShowEye",
"FullPictureLoadBlacklist"
];
for (const key of keys) {
if (key in localStorage) {
localStorage.removeItem(key);
}
}
location.reload();
});
_GM_registerMenuCommand(DL.str_126, () => {
const GM_keys = _GM_listValues();
if (GM_keys.length > 0) {
GM_keys.forEach(key => _GM_deleteValue(key));
}
location.reload();
});
//簡易模式規則
if (!("category" in siteData)) {
isSimpleMode = true;
const setFullPictureLoadSimpleMode = localStorage.getItem("setFullPictureLoadSimpleMode") ?? 0;
_GM_registerMenuCommand(setFullPictureLoadSimpleMode == 0 ? "❌ " + DL.str_191 : "✔️ " + DL.str_191, () => {
setFullPictureLoadSimpleMode == 0 ? localStorage.setItem("setFullPictureLoadSimpleMode", 1) : localStorage.setItem("setFullPictureLoadSimpleMode", 0);
location.reload();
});
let menu_command_id_1;
let menu_command_id_2;
let menu_command_id_3;
const setMode = () => {
menu_command_id_1 = _GM_registerMenuCommand(DL.str_67, createPictureLoadOptionsShadowElement);
checkOptionsData();
siteData = {
imgs: () => {
let eles = gae("a,p,div,span,li,figure,article,picture>source,img:not(.FullPictureLoadFixedBtn)");
let shadowRootEles = eles.map(ele => {
if (("shadowRoot" in ele) && ele?.shadowRoot?.nodeName == "#document-fragment") {
return gae("a,p,div,span,li,figure,article,picture>source,img", ele.shadowRoot);
}
return null;
}).filter(Boolean).flat();
if (shadowRootEles.length) {
eles = [...eles, ...shadowRootEles];
}
return fn.getImgSrcset(eles).map(src => {
if (src.includes(".sinaimg.")) {
return src.replace(/\/orj\d+\/|\/mw\d+\//, "/large/");
} else {
return src;
}
});
},
repeat: 1,
SPA: true,
category: "photo"
};
addFullPictureLoadButton();
if (isPC) {
addFullPictureLoadFixedMenu();
document.addEventListener("keydown", addKeyEvent);
}
if (!ge("#FullPictureLoadMainStyle")) {
fn.css(FullPictureLoadStyle, "FullPictureLoadMainStyle");
}
if (!("Fancybox" in _unsafeWindow)) {
addLibrarysV5();
Fancyboxl10nV5();
}
_GM_unregisterMenuCommand(menu_command_id_2);
registerB();
};
const removeMode = () => {
_GM_unregisterMenuCommand(menu_command_id_1);
siteData = {};
fn.remove(".FullPictureLoadFixedBtn,#FullPictureLoadFixedMenu");
if (isPC) {
document.removeEventListener("keydown", addKeyEvent);
}
_GM_unregisterMenuCommand(menu_command_id_3);
registerA();
};
const registerA = () => {
menu_command_id_2 = _GM_registerMenuCommand(DL.str_163, setMode);
};
const registerB = () => {
menu_command_id_3 = _GM_registerMenuCommand(DL.str_164, removeMode);
};
registerA();
if (setFullPictureLoadSimpleMode == 1) {
setTimeout(() => setMode(), 500);
}
}
if (!isSimpleMode && !siteData.category?.includes("autoPager") && !["none", "ad"].some(c => c === siteData.category)) {
if (siteData.key != 0) {
if (isPC) {
if (ShowFullPictureLoadFixedMenu === 1) addFullPictureLoadFixedMenu();
}
if (!isAddKeyEvent) {
document.addEventListener("keydown", addKeyEvent);
isAddKeyEvent = true;
}
}
if (siteData.icon == 0) {
//return;
} else if (options.icon == 1 || siteData.icon == 1) {
addFullPictureLoadButton();
}
setTimeout(() => {
if (!isOpenGallery && !isOpenFilter) {
toggleUI();
}
}, 500);
}
if (fn.lh.includes(".v2ph.")) {
_GM_registerMenuCommand("🍪 Set V2PH CF Cookie", () => {
v2ph_cookie = prompt("Set Cookie", v2ph_cookie || "");
if (!!v2ph_cookie) {
_GM_setValue("v2ph_cookie", v2ph_cookie);
}
});
} else if (fn.lh.includes("myreadingmanga")) {
_GM_registerMenuCommand("🍪 Set MyReadingManga CF Cookie", () => {
myreadingmanga_cookie = prompt("Set Cookie", myreadingmanga_cookie || "");
if (!!myreadingmanga_cookie) {
_GM_setValue("myreadingmanga_cookie", myreadingmanga_cookie);
}
});
} else {
_GM_registerMenuCommand(("_cf_cookie" in localStorage) ? "🍪 Update Cloudflare Clearance Cookies" : "🍪 Set Cloudflare Clearance Cookies", () => {
let cookie = prompt("Set Cookie", localStorage.getItem("_cf_cookie") || "");
if (!!cookie) {
localStorage.setItem("_cf_cookie", cookie);
}
});
}
})(axios, JSZip);