// ==UserScript== // @name 圖片全載Next // @name:en Full Picture Load // @name:zh-CN 图片全载Next // @name:zh-TW 圖片全載Next // @version 2025.4.11.16 // @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://cdn.jsdelivr.net/gh/skofkyo/AutoPager@e95dd3100f3fbc57116b379e43a7277019381200/CustomPictureDownload/js/JSZip.js // @resource ajaxHookerJS https://cdn.jsdelivr.net/gh/skofkyo/AutoPager@6e02d72caad898a610022408b696ab5e11adaab6/CustomPictureDownload/js/ajaxHooker.js // @resource JqueryJS https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js // @resource FancyboxV5JS https://cdn.jsdelivr.net/npm/@fancyapps/ui@5.0.36/dist/fancybox/fancybox.umd.js // @resource FancyboxV5Css https://cdn.jsdelivr.net/npm/@fancyapps/ui@5.0.36/dist/fancybox/fancybox.css // @resource FancyboxV3JS https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js // @resource FancyboxV3Css https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css // @resource ViewerJs https://cdn.jsdelivr.net/npm/viewerjs@1.11.6/dist/viewer.min.js // @resource ViewerJsCss https://cdn.jsdelivr.net/npm/viewerjs@1.11.6/dist/viewer.min.css // ==/UserScript== (async (JSZip) => { "use strict"; //await wait(() => !!document.body && document.readyState !== "loading"); //await wait(() => !!document.body && document?.body?.childNodes?.length > 0); 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; const 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 isGotAll = 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 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 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/133.0.0.0 Safari/537.36 Edg/133.0.0.0"; const Mobile_UA = "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Mobile Safari/537.36 EdgA/133.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: "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.curl("/gallery/"), SPA: () => _this.page() ? fn.waitEle(["div[class^='UniversalPopup-navigationLayer'],#primary-project-content", "h1[class^='Project-title']", ".grid__item-image[srcset],.ImageElement-image-SRv"]) : false, observeURL: "head", 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],.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: [ ["#FullPictureLoadMainImgBox", 0, ".justified-gallery"], 2 ], customTitle: ".container h1", fancybox: { v: 3, css: false }, category: "photo" }, { name: "小黃書/8色人體攝影", url: { h: [ /xchina\./, /^(tw\.)?8se\.me$/ ], p: /^\/(photo|amateur)\/id-\w+\.html$/, e: ".tab-content div:has(>.fa-picture-o)" }, init: () => { fn.run("$(document).off('keydown')"); fn.remove("//div[@id='tab_1']/div[contains(text(),'推')] | //div[@class='rules']/ul/li[contains(text(),'推')]"); }, imgs: async () => { const isMp4 = fn.ge("video[src$='mp4']"); if (!!isMp4) { const { videos, domain } = _unsafeWindow; videoSrcArray = videos.map(e => domain + e.url); } const [, album_id] = /id-([^.]+)/.exec(fn.lp); let [numP] = fn.gt(".tab-content div:has(>.fa-picture-o)").match(/\d+/); numP = Number(numP); const thumb = fn.ge("a[href*='/photoShow'] img.cr_only"); const srcArrFn = (total, photoUrl = "https://img.xchina.store/photos/", mode = 1) => { let suffix = ".jpg"; if (mode === 2) { suffix = "_600x0.webp"; } return fn.arr(total, (v, i) => photoUrl + album_id + "/" + String(i + 1).padStart(4, "0") + suffix); }; if (!!thumb) { const thumb_src = thumb.src; const OOOI = thumb_src.includes("/0001_600x0.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(".photos>a", ".pager a[current=true]+a:not(.next)", null, ".pager", 1500); } thumbnailSrcArray = fn.getImgSrcArr("a[href*='/photoShow'] img.cr_only"); 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: [ ["//div[div[@class='photos']]/*[last()]", 2, ".pager,.photos"], 2 ], customTitle: () => { try { let text = ""; let texts = []; [ "div:has(>.fa-video-camera) a", "div:has(>.fa-video-camera) .joiner+a", "div:has(>.fa-calendar)", "div:has(>.fa-file-o)", ".models div,.actorsOrModels", "div:has(>.fa-address-card-o)" ].forEach((s, i, a) => { let t = document.querySelector(s)?.innerText; texts.push(t); if (a.length - 1 == i && !!texts[4]) { if (t.includes(texts[4])) { text = text.replace(texts[4], ""); } } if (!!t && t?.length > 0) { text += " " + t; } if (i == 0 && !!t) { text += " -"; } }); if (location.pathname.includes("/amateur/")) { text = document.querySelector(".fa-angle-double-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("div:has(>.fa-tags)+div:has(>.fa-tags)")?.innerText; if (!!t && t?.length > 0) { text = text.replace(/其他中国工作室|其他中國工作室/, t); } } if (text.includes("Graphis")) { let t = document.querySelector("div:has(>.fa-tags)+div:has(>.fa-tags)")?.innerText; if (!!t && t?.length > 0) { text = text.replace("Graphis", "Graphis " + t); } } return text; } catch { return document.title; } }, css: "body{overflow:unset!important}", hide: ".push-slider,.article:has(.recommendation_widget),.article:has(>div>.media),div:has(>.links),a[clickmode=ad],a:has(>div>div>img),.photos>div.item,.jquery-modal.blocker.current,.push-top,.push-bottom,.slider-ad,.article.ad,.pager>.tips,.photoMask,.banner_ad,.banner-sexgps,div[class*='backdrop-show']", topButton: true, downloadVideo: true, category: "nsfw2" }, { name: "小黃書/8色人體攝影 AD", url: { h: [ /xchina\./, /^(tw\.)?8se\.me$/ ] }, init: () => fn.addMutationObserver(() => fn.remove("[class*='exoclick']")), css: "body{overflow:unset!important}", hide: ".push-slider,.article:has(.recommendation_widget),.article:has(>div>.media),div:has(>.links),a[clickmode=ad],a:has(>div>div>img),.photos>div.item,.jquery-modal.blocker.current,.push-top,.push-bottom,.slider-ad,.article.ad,.pager>.tips,.photoMask,.banner_ad,.banner-sexgps,div[class*='backdrop-show']", category: "ad" }, { name: "紳士会所", url: { h: ["www.hentaiclub.net"], 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", fetch: 1, 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: [ ["#FullPictureLoadMainImgBox", 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: /^\/plus\/view-\d+-\d+\.html$/, e: ".main img" }, box: [".main", 1], imgs: () => { let [max] = fn.gt(".paging>li>a,.tags>li>a,.pre_next>li>a").match(/\d+/); return fn.getImg(".main img", max, "5"); }, button: [4], insertImg: [ ["#FullPictureLoadMainImgBox", 0, ".view_img .main"], 2 ], insertImgAF: (parent) => { let text = fn.ge(".view_img .text"); if (text) { insertBefore(parent, text); } }, autoDownload: [0], next: "//li[contains(text(),'上一篇')]/a", prev: "//li[contains(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: (parent) => { let text = fn.ge(".a_img .text"); if (text) { insertBefore(parent, text); } }, autoDownload: [0], next: ".pre_next li:last-child a", prev: ".pre_next li:first-child a", customTitle: ".title>h1", css: ".a_img .main img{max-width:100%!important}", 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.newxiuren.cc", "m.newxiuren.cc", "www.newxiuren.cn", "m.newxiuren.cn", "www.xiuren.mobi", "m.xiuren.mobi", "www.xiuren.online", "m.xiuren.online", "www.xiuren.cloud", "m.xiuren.cloud", "www.xiuren.xin", "m.xiuren.xin", "www.xiuren.red", "m.xiuren.red", "www.xiuren888.com", "m.xiuren888.com", ], url: { h: "xiuren", e: ["img[alt=图片][title=图片]+span", "img[src*='cover.jpg']", "#content img"], p: "piclist", s: "id=" }, imgs: () => { let max = Number(fn.gt("img[alt=图片][title=图片]+span")); let src = fn.src("#content img:not(#cover)"); let dir = fn.dir(src); let id = dir.split("/").at(-2); let srcs = [dir + "cover.jpg"]; for (let i = 1; i <= max; i++) { src = dir + id + String(i).padStart(2, "0") + ".jpg"; srcs.push(src); } return srcs; }, capture: () => _this.imgs(), customTitle: ".Ptitle,.piclist_box", category: "nsfw1" }, { name: "梦想岛", host: ["www.mmxxdd.com"], link: "https://www.mmxxdd.com/website.html", url: { e: ".logo img[alt=梦想岛]", p: "/gallery/" }, 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"); 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: ["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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: ["m2.imn2.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']", category: "nsfw1" }, { name: "漂亮美女网", link: "http://www.plmn5.com/", url: { h: ["www.plmn5.cc", "plmn.cc"], p: ".html", e: ".page>a" }, imgs: () => fn.getImg(".newstext 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: ".news-title-h1", hide: ".newstext br,img[src*='zz2.gif']", 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: { t: "美人图", 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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 0, ".blog-details-text>p:has(>img)"], 2 ], customTitle: "h2.blog-details-headline", category: "nsfw1" }, { 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: "乳乐资源网", url: { h: ["rulel.com"], p: /^\/\d+\.html$/, e: "//i[@class='czs-folder-l']/following-sibling::a[1][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: "乳乐资源网 自動翻頁", url: { h: ["rulel.com"], 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资源站 自動翻頁", url: { h: ["8ezy.com"], e: [".post-list-item", ".post-nav[data-max]"] }, 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("loaded"); }); }, pageNum: () => currentPageNum }, openInNewTab: ".post-list-item a:not([target=_blank])", category: "autoPager" }, { name: "夜社资源", url: { h: ["yeshezy.com"], p: "/play/" }, 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']" }, 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: "牛牛美图", 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: "XGirl/MissBby.com/Xerocos", host: ["xgirl.one", "missbby.com", "xerocos.com"], reg: [ /^https?:\/\/(xgirl\.one|missbby\.com)\/[^\/]+$/, /^https?:\/\/xerocos\.com\/view\// ], 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: "XGirl/MissBby.com 分類自動翻頁", reg: /^https?:\/\/(xgirl\.one|missbby\.com)\//, autoPager: { mode: 1, waitEle: "//div[@class='flex py-4 justify-center md:justify-between mt-4']/preceding-sibling::div[1][@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[1][@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: "Xerocos 分類自動翻頁", reg: /^https?:\/\/xerocos\.com\//, autoPager: { mode: 1, waitEle: "//div[@class='flex py-4 justify-center md:justify-between mt-4']/preceding-sibling::div[1][@class='grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4']//img|//div[@class='flex py-4 justify-center md:justify-between mt-4']/preceding-sibling::div[@class='grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 pb-6']//img", ele: "//div[@class='flex py-4 justify-center md:justify-between mt-4']/preceding-sibling::div[1][@class='grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4']|//div[@class='flex py-4 justify-center md:justify-between mt-4']/preceding-sibling::div[@class='grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 pb-6']", 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], aF: () => fn.gae(".blur-2xl").forEach(e => e.classList.remove("blur-2xl")), bottom: screen.height * 2 }, openInNewTab: ".grid a:not([target=_blank])", category: "autoPager" }, { 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: "私图网", url: { h: "taotu.uk", p: ".html" }, imgs: ".post_container>article img", button: [4], insertImg: [".post_container>article", 2], customTitle: ".post_container_title h1", fancybox: { v: 3, css: false }, category: "nsfw1" }, { name: "私图网", link: "https://taotu.uk/zh_cn/", url: { h: "taotu.uk", e: ".post_images" }, init: () => { const replaceSrc = () => { fn.gae(".post_images img[src*='timthumb.php?src=']").forEach(e => { let src = fn.getUSP("src", e.src); src = src.replace("https://", "https://i0.wp.com/") + "?w=200"; e.src = src; }); }; replaceSrc(); fn.addMutationObserver(replaceSrc); }, category: "none" }, { 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: "美图网", url: { h: ["www.meitu8.cc", "meitu8.cc"], p: ".html", e: "#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: "美图社/花瓣美女", url: { h: [ /^(www\.)?928r\.com$/, /^(www\.)?060k\.com$/, ], p: /^\/post\/\d+\.html$/i }, 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: () => { if (fn.ge("//a[text()='显示全文']")) { let url = fn.gu("//a[text()='显示全文']"); return fn.getImgA("#lightgallery img", [url]); } else { return fn.gae("#lightgallery img"); } }, 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", url: { h: [ /^(www\.)?zhaotaotu\.cc$/, /^(www\.)?kantaotu\.cc$/ ], 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: [ ["#FullPictureLoadMainImgBox", 0, ".photo-show>a"], 2 ], customTitle: ".photo-show blockquote", category: "nsfw2" }, { name: "微密猫", host: [ "www.", "weme[245679].com", "wemimao1.vip", "wemao.xyz", "weiminew.com", "maobao.xyz", "mvxzsp.com", "stxlmt.com", "amstt.com", "xiuren-wang.com", "xiurentaotu.com", "xiuren-tu.com", "xiurenmote.com", "xiurenxiezhen.com", "hywsg.com", "jvidmtpj.com", "panssphw.com", "pansspzp.com", "www.xiuren-wang.com" ], 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)", 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", ee: [ ".read-point-box", "//div[@class='single-content']/p[not(.//img)] | //div[@class='single-content']/fieldset" ] }, imgs: () => fn.ge(".page-links") ? fn.getImg(".single-content img", (fn.gt(".page-links>a:last-child", 2) || 1), 7) : fn.gae(".single-content img"), button: [4], insertImg: [".single-content", 2], customTitle: "h1.entry-title", fancybox: { v: 3, css: false }, category: "nsfw1" }, { name: "柠檬皮", url: { h: "www.emonl.com", p: ".html", e: "//div[@class='single-content']/p[not(.//img)] | //div[@class='single-content']/fieldset", ee: [".read-point-box", ".page-links"] }, imgs: ".single-content img", setFancybox: true, button: [4], insertImg: [".single-content", 0], customTitle: "h1.entry-title", fancybox: { v: 3, css: false }, category: "nsfw1" }, { name: "51sex", url: { h: ["51sex.vip"], p: "/pic/" }, init: () => fn.addUrlHtml(_this.next(), ".headling_main", 1, "下一篇"), imgs: () => { let max = Number(fn.gt(".headling_swiper_num_small")?.match(/\d+/)) || 1; let links = fn.arr(max, (v, i) => siteUrl + "/" + (i + 1)); return fn.getImgA("#bigimg", links); }, button: [4, "24%"], insertImg: [".headling_main", 2], next: () => { let [num] = siteUrl.match(/\d+$/); return siteUrl.replace(/\d+$/, "") + (Number(num) - 1); }, customTitle: ".headling_word_main_box_title", css: ".headling_main{height:auto}", category: "nsfw1" }, { name: "51sex分類自動翻頁", reg: /^https?:\/\/51sex\.vip\/category\/\d+/i, init: () => fn.lp.split("/").length == 3 ? (currentPageNum = 1) : (currentPageNum = Number(fn.lp.split("/").at(-1))), autoPager: { ele: ".headling_main_a", observer: ".headling_main_a", next: () => siteUrl.match(/https?:\/\/51sex\.vip\/category\/\d+/)[0] + "/" + (currentPageNum += 1), stop: (dom) => { let currentEleURLs = fn.gau(".headling_main_a"); if (currentEleURLs.length < 24) { return true; } else { if (currentEleURLs.length > 24) currentEleURLs = currentEleURLs.slice(-24); let nextEleURLs = fn.gau(".headling_main_a", dom); for (let url of currentEleURLs) { if (nextEleURLs.includes(url)) return true; } } return false; }, pageNum: () => currentPageNum }, openInNewTab: "a.headling_main_a:not([target=_blank])", category: "autoPager" }, { name: "美图乐", host: ["www.meitule.net", "www.meitule.com", "www.meitulu.cc"], url: { h: /meitule\.|meitule\.|meitulu\./, 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: "聚美星空", url: { h: "www.uecoy.com", p: ".html", e: ".single-content" }, imgs: async () => { let pages = fn.ge(".page-links"); if (pages) { let max = fn.gt(".page-links a:has(i.be-arrowright)", 2); return fn.getImg(".single-content p>img", max, 7); } else { return fn.gae(".single-content p>img"); } }, button: [4], insertImg: [".single-content", 2], autoDownload: [0], next: "a[rel=prev]", prev: "a[rel=next]", customTitle: ".entry-title", hide: ".page-links", fancybox: { v: 3, css: false }, category: "nsfw1" }, { name: "Elysium", url: { h: "www.elysium.pro", p: "/albums/", e: "a[data-thumbnail]:not([data-video])" }, box: ["div[data-lg-thumb=data-thumbnail]", 2], imgs: async () => { let pages = fn.ge("li.page-item.active+li>a:not([aria-label=Next])"); if (pages) { let links = fn.gau(".pagination>.page-item:not(.disabled)>a:not([aria-label=Next])"); await fn.getEle(links, "div[data-lg-thumb=data-thumbnail]>div", "div[data-lg-thumb=data-thumbnail]", "nav:has(>.pagination)"); } thumbnailSrcArray = fn.gae("a[data-thumbnail]:not([data-video])").map(e => e.dataset.thumbnail); return fn.gae("a[data-thumbnail]:not([data-video])"); }, button: [4], insertImg: [ ["#FullPictureLoadMainImgBox", 0], 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: "MM5MM5美女图片", url: { h: "www.mm5mm5.com", st: "picinfo" }, imgs: () => _unsafeWindow.picinfo[0].split(","), button: [4], insertImg: ["#content", 2], customTitle: ".article>h2", css: ".article .content img{max-width:100%!important}", category: "nsfw1" }, { name: "MM5MM5美女图片M", url: { h: "m.mm5mm5.com", p: "/mm/" }, imgs: () => { let [, max] = fn.gt(".contentpage>span>i").match(/\/(\d+)/); let links = fn.arr(max, (v, i) => i == 0 ? siteUrl : siteUrl + "/" + (i + 1)); return fn.getImgA("div>a>img", links, 2); }, button: [4], insertImg: ["//div[a[img]]", 2], customTitle: ".content>h1", hide: "union[id],.pag-ts,.contentpage", category: "nsfw1" }, { 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: () => { let all = fn.ge("//a[text()='多图显示']"); if (all) { return fn.getImgA(".picsbox img", [all]).then(srcs => srcs.filter(e => !e.includes("/logo/") && !e.includes("onerror"))); } let max = fn.gt("#allnum"); let links = fn.arr(max, (v, i) => i == 0 ? siteUrl : siteUrl.replace(".html", "") + "_" + (i + 1) + ".html"); return fn.getImgA(".picsbox img", links, 2).then(srcs => srcs.filter(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 => !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.twoimg.com/people", url: { h: "www.twoimg.com", 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", 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: () => fn.getImgA("#contpic,#mobile_c_img>img", ".swiper-slide:not(:first-child) a"), thums: ".swiper-slide>a>img", button: [4], insertImg: ["#showimg", 1], endColor: "white", autoDownload: [0], next: "a.next[href$=html]", prev: "a.pver[href$=html]", customTitle: "h2.title,.titlew>h2", hide: ".showcontw #showimg{height:auto!important}[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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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", 1], 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.mntuce.top"], url: { h: "www.mntuce.com", p: ".html" }, init: () => { _unsafeWindow.onload = null; _unsafeWindow.onresize = null; if ("showWarning" in _unsafeWindow) { _unsafeWindow.showWarning = null; } if ("detectDevTools" in _unsafeWindow) { _unsafeWindow.detectDevTools = null; } fn.clearAllTimer(); }, imgs: () => fn.getImgA(".article-content img:not(#ad-image,[alt=close])", ".post-nav-links a"), button: [4], insertImg: [".article-content", 2], customTitle: ".article-title", mcss: ".container,.article{padding:0px}", hide: "#ads,body>*[style^='display: block;'],#lbaeb", category: "nsfw1" }, { name: "美女图册", url: { h: "www.mntuce.com" }, init: () => { _unsafeWindow.onload = null; _unsafeWindow.onresize = null; if ("showWarning" in _unsafeWindow) { _unsafeWindow.showWarning = null; } if ("detectDevTools" in _unsafeWindow) { _unsafeWindow.detectDevTools = null; } fn.clearAllTimer(); }, category: "ad" }, { 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: "www.costhisfox.com", reg: [ /^https?:\/\/www\.costhisfox\.com\/\d+\/$/i, /^https?:\/\/www\.costhisfox\.com\/\d+\.html$/, /^https?:\/\/www\.costhisfox\.com\/\w+\/\d+\.html$/ ], include: "//ul[@class='breadcrumb']//a[text()='cos福利美图']|//ul[@class='breadcrumb']//a[text()='写真系列']", imgs: ".wp-posts-content img[data-src]", button: [4], insertImg: [".wp-posts-content", 2], 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: "RedBust", url: { h: ["redbust.com"], }, srcset: ".entry-inner img", thums: ".entry-inner img", button: [4], insertImg: [".entry-inner", 2], autoDownload: [0], next: ".previous>a", prev: ".next>a", customTitle: "h1.post-title", category: "nsfw2" }, { 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/IMG.Kiwi/JPG5/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://img.kiwi/36_chambers/albums", "https://jpg5.su/xelszy/albums", "https://jpg5.su/rainbowsmile/albums", "https://nfhost.me/insta_girls/albums" ], url: { h: [/putmega\.com$/, "ibb.co", "img.kiwi", "jpg5.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("/").at(-1); } 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: "E次元", url: { h: "www.evacg.org", p: "/archives/", ee: ".poi-alert__msg" }, imgs: "a[data-featherlight] img,.wp-caption img", button: [4], insertImg: [ [".inn-singular__post__body__content", 0, "a[data-featherlight],.wp-caption"], 2 ], customTitle: ".inn-singular__post__title", category: "nsfw1" }, { name: "E次元", url: { h: "www.evacg.org", p: "/archives/", ee: ".poi-alert__msg" }, box: [".inn-singular__post__body__content", 2], imgs: ".inn-singular__post__body__content img", button: [4], insertImg: [ ["#FullPictureLoadMainImgBox", 0, ".inn-singular__post__body__content"], 2 ], customTitle: ".inn-singular__post__title", category: "nsfw1" }, { 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: "推次元", host: ["www.a2cy.com", "a2cy.com"], url: { h: "a2cy.com", p: ".html" }, imgs: ".imgBox img,.w.maxImg.tc:not(.box-shadow) img", 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: "Cosplay VN", url: { h: "cosplayvn.club", e: ".mace-gallery-teaser[data-g1-gallery]" }, imgs: () => { let data = JSON.parse(fn.attr(".mace-gallery-teaser", "data-g1-gallery")).filter(e => e?.type === "image"); thumbnailSrcArray = data.map(e => e.thumbnail); return data.map(e => e.full); }, capture: () => _this.imgs(), customTitle: ".entry-title", category: "nsfw2" }, { name: "咿呀美图", url: { h: "www.1ymt.com", d: "pc" }, page: () => fn.clp("/work/"), SPA: () => _this.page(), observeURL: "nav", imgs: () => _this.page() ? fn.getEle([fn.clp()], ".photo-thumbs li:not(.next)") : [], capture: () => _this.imgs(), category: "nsfw1" }, { 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: ["#FullPictureLoadMainImgBox", 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: "蠢沫沫", 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: "女神社", 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; 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); 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']]]", 2], category: "nsfw2" }, { name: "Chottie", //很多都需要VIP,不然只會重複抓到第一頁的圖片 url: { h: ["chottie.com", "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; 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); let code, imgs; try { code = fn.gst("imgList", dom); imgs = fn.TextToArray(code, "imgList"); } catch { code = fn.gst("snapshotList", dom); imgs = fn.TextToArray(code, "snapshotList"); } 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']]]", 2], 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", e: ".wp-block-image img" }, imgs: () => fn.getImgA(".wp-block-image img", ".page-links>a", 300), button: [4], insertImg: [ [".post-item-metadata", 1, ".wp-block-image"], 2 ], autoDownload: [0], next: ".nav-previous>a", prev: ".nav-next>a", customTitle: ".entry-title", hide: "#af-preloader,#page>a,#page>div:not(#content):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", fetch: 1, 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: "J M G T的AList", url: { h: "alist.qiuyeshudian.com" }, SPA: true, observeURL: "body", imgs: () => fn.getAList(), customTitle: () => fn.dt({ d: [ " | AList", /(\d+Photos)\s|\(\d+Photos\)\s|\d+Photos\s|\d+\spics|\(选登\)|(选登\d+P)/ ] }), 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, fetch: 1, 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: ["#FullPictureLoadMainImgBox", 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(),'图片数量')]"], p: ".html" }, init: () => fn.clearAllTimer(), imgs: () => fn.getImgO("#showimg img", fn.gt("//p[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: "九天美图", host: ["meitu9.com", "jiutianmeitu.com"], url: { e: [".logo-pc", ".logo-moible"], p: "/meitu/" }, init: () => { let ps = fn.gae("#image_div>p"); if (ps.length > 0) { ps.forEach(p => { let a = fn.ge("img", p); if (!a) { tempEles.push(p); } }); } }, imgs: "#image_div img", button: [4], insertImg: ["//p[img]", 2], insertImgAF: (_, bar) => bar.before(...tempEles), customTitle: ".item_title>h1", hide: ".img-box,#installContainer", 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: () => { let { PID, post_url } = _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); return 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]); }, 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); } let ps = fn.gae("#image_div>p"); if (ps.length > 0) { ps.forEach(p => { let a = fn.ge("a", p); if (!a) { tempEles.push(p); } }); } }, imgs: () => { fn.showMsg(DL.str_05, 0); 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=${_unsafeWindow.chenxing.PID}`, "method": "POST", }).then(dom => [...dom.images]); }, button: [4], insertImg: ["#content", 2], insertImgAF: (_, bar) => { bar.before(...tempEles); fn.run("$(document).off()"); }, customTitle: () => fn.dt({ d: [ / – 小姐姐| - 妹妹图集/, /(\d+月\d+打赏群(自购)?资源)/ ] }), css: ".content_left>p{margin:0}", hide: ".affs", category: "nsfw1" }, { name: "14MM图片网/图片吧", host: ["www.luoli.xin", "www.tp8.org"], url: { t: ["14MM图片网", "图片吧"], 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(" – 14MM图片网"), 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: "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: "Coser Lab", url: { h: ["coserlab.io"], p: "/archives/", ee: ".card-body .error-empty,.post-hide-content" }, imgs: () => { thumbnailSrcArray = fn.getImgSrcArr("a.glightbox img"); 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", init: () => _this.page() ? _this.data() : void 0, imgs: () => _this.page() ? fn.gae("div[aria-roledescription='carousel'] img", doc) : [], capture: () => _this.imgs(), 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: "", category: "nsfw1" }, { name: "爱推图", url: { h: "www.aituitu.com", p: ".html", e: ".reading-open" }, imgs: ".single-content img", customTitle: () => fn.dt({ s: ".entry-title", d: "写真" }), category: "nsfw1" }, { 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: "依依美女图片网", url: { h: "www.eemm.cc", p: "/a/" }, imgs: () => fn.getImgA("#post_content img", ".pagelist a"), button: [4], insertImg: ["#post_content", 2], autoDownload: [0], next: ".post-previous a", prev: ".post-next a", customTitle: ".article_container>h1", css: ".article_container{padding:10px 0px!important}#post_content{padding:0px!important}", mcss: ".container{max-width:100% !important;margin:0 !important}", hide: ".code-block,.reply-read", 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 () => { 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) { 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: "魅狸图片网/美女私房照/看妹图", url: { h: [ /rosi8\.com$/, /sfjpg\.(com|net)$/, /sfmm\.cc$/, /kanmeitu\.net$/, /kanmeitu1\.cc$/ ], 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, 200, ".page .pagelist", siteUrl, 0); }, 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: "秀图湾", host: ["www.okxx.de", "okxx.de", "www.xiusz.de", "xiusz.de", "www.xiusz.com", "xiusz.com", "www.aiyes.de", "aiyes.de"], url: { t: "xiusz.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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: "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: [ ["#FullPictureLoadMainImgBox", 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: ["#FullPictureLoadMainImgBox", 2], customTitle: ".mvic-desc h3", category: "nsfw2" }, { name: "HotGirl World", url: { h: ["www.hotgirl2024.com"], P: "/g/" }, 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\/(\?page=\d+)?$/, /^https?:\/\/www\.hotgirl2024\.com\/(category|agency|tag)\/\d+\.html\/(\?page=\d+)?$/, /^https?:\/\/www\.hotgirl2024\.com\/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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: "Chinese Beauties", host: ["sxchinesegirlz02.online"], url: { e: "//p[@class='gridlane-site-title']/a[text()='Chinese Beauties']", p: /^\/[^\/]+\/$/ }, imgs: () => fn.getImgA(".wp-block-image img", ".page-links>a"), button: [4], insertImg: [".entry-content", 2], autoDownload: [0], next: ".nav-previous>a", prev: ".nav-next>a", customTitle: "h1.entry-title", category: "nsfw2" }, { 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: [ ["#FullPictureLoadMainImgBox", 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}", fetch: 1, 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); } } }); apiCustomTitle = fn.dt({ s: "main h2" }); thumbnailSrcArray = thumbs; videoSrcArray = videos; return images; }, fetch: 1, 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/Leaks4fap", url: { h: ["fapodrop.com", "fapsan.com", "leaks4fap.com"], e: ".one-pack img[src*=thumbnail]" }, imgs: async () => { let max = fn.gt("h1.h3").match(/\d+/g).at(-1); let pages = Math.ceil(Number(max) / 24); let links = fn.arr(pages, (v, i) => i == 0 ? fn.lp : fn.lp + "/page/" + (i + 1)); thumbnailSrcArray = await fn.getImgA(".one-pack img[src*=thumbnail]", links); 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: "fapello.ru", url: { h: ["www.fapello.ru", "fapello.ru", "onlyfans.name"], p: "/galleries/" }, box: [".grid:has(figure)", 1], imgs: () => { let pages = fn.ge("nav[role=navigation] p"); if (pages) { let max = Math.ceil(Number(fn.gt(pages).match(/\d+/g).at(-1)) / 50); return fn.getImg(".grid:has(figure) img", max); } else { return fn.gae(".grid:has(figure) img"); } }, button: [4], insertImg: [ ["#FullPictureLoadMainImgBox", 0, ".grid:has(figure)"], 3 ], customTitle: ".content h1", 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: [ ["#FullPictureLoadMainImgBox", 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: "Fapello", url: { h: ["fapello.cc"] }, page: () => fn.clp("/album/"), SPA: () => _this.page() ? fn.waitEle([".album-gallery a:not(.has-video)", ".content-main h1"]) : false, observeURL: "head", imgs: () => _this.page() ? fn.waitEle([".album-gallery a:not(.has-video)"]).then(eles => { videoSrcArray = fn.gae(".album-gallery a.has-video").map(e => e.dataset.src); return eles; }) : [], capture: () => _this.imgs(), customTitle: () => _this.page() ? fn.waitEle(".content-main h1").then(e => e.textContent) : null, 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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: "吃瓜大队", host: ["cgdd.net"], url: { t: "吃瓜大队", p: ".html" }, imgs: ".article-content img", videos: ".article-content video>source", customTitle: ".article-title>a", setFancybox: ".article-content img", downloadVideo: true, hide: ".m-navbar~*:not([id^=Full],[class^='fancybox'],.viewer-container)", category: "nsfw2" }, { name: "套圖TAOTU.ORG", url: { h: "taotu.org" }, imgs: "a[data-fancybox=gallery]", thums: "a[data-fancybox=gallery] img", button: [4], insertImg: [ ["#wrapper-footer", 2], 2 ], autoDownload: [0], next: ".next a", prev: ".prev a", customTitle: ".suit_title>h1", hide: "#right-bottom,#ad,.ad", 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: "美图海", 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.xyz", 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: "尤物丧志/色图/亚色图库/福利姬美图/秀人图/UGIRLS/極品妹子圖/爽图吧/涩图社/美乳小姐姐写真/三上悠亚写真图片/AHottie/高清妹子图", url: { h: [ /^youwu\./, /^setu\./, /^yase\./, /^fuligirl\./, /^xiuren(tu)?\./, /^ugirls\./, /jipin\./, "stuba.netlify.app", "setushe.pics", "meizi.pics", "meiru.neocities.org", "meitu.neocities.org", "sanshang.neocities.org", /ahottie/ ], 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]", category: "nsfw2" }, { name: "色图替換圖片服務器", url: { h: "setu", e: "img[src*='teleimgs.pages.dev']" }, init: () => { const replaceSrc = () => { [...document.querySelectorAll("img[src*='teleimgs.pages.dev']")].forEach(e => { let src = e.src; src = src.replace("teleimgs.pages.dev", "imgfiles.pages.dev"); e.src = src; }); }; replaceSrc(); fn.addMutationObserver(replaceSrc); }, category: "none" }, { name: "胴体的秘密/AsianSexyBody/福利图库/BestGirlSexy/COSER美女图", host: ["dongti.netlify.app", "asiansexybody.netlify.app", "fulituku.neocities.org", "bestgirlsexy4.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: "酱图图", host: ["www.jtttututu.top"], reg: /^https?:\/\/www\.jtttututu\.top\/\?\d+\.html$/, imgs: ".entry-content img", button: [4], insertImg: [".entry-content", 2], customTitle: "h1.entry-title", 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: "秀人图吧", 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: "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: "Pixnoy", url: { h: "www.pixnoy.com", p: "/profile/", e: ".ub_profile" }, imgs: async () => { fn.showMsg(DL.str_05, 0); let pagesNum = Math.ceil(Number(fn.gt(".item_posts .num")) / 12); let username = fn.ge("input[name=username]").value; let userid = fn.ge("input[name=userid]").value; let next; let maxid; let hl = fn.ge("input[name=hl]").value; let srcs = []; let loop = true; let page = 2; const getData = async () => { let params = new URLSearchParams({ username, userid, next, maxid, hl }).toString(); try { let res = await fetch("/api/posts?" + params); let json = await res.json(); fn.showMsg(`${DL.str_06}${page}/${pagesNum}`, 0); json.posts.items.forEach(e => { if (e.type === "img_multi") { srcs = srcs.concat(e.children_items.map(i => i.pic)); } else if (e.type === "igtv") { videoSrcArray.push(e.video); } }); if (!json?.posts?.has_next) { loop = false; return; } next = json.posts.next; maxid = json.posts.maxid; page++; await fn.delay(2000, 0); } catch { await fn.delay(10000); } }; await fn.fetchDoc(fn.lp).then(async dom => { let links = fn.gae("a.cover_link", dom); let f_srcs = []; let f_videos = []; let more = fn.ge("a.more_btn"); if (more) { next = more.dataset.next; maxid = more.dataset.maxid; while (loop) { await getData(); } } let eles = await fn.getEle(links, "div.pic,div.video_img", null, null, 0); eles.forEach(e => { let fe = e.firstElementChild; if (e.classList.contains("video_img")) { f_videos.push(fe.href); } else { f_srcs.push(fe.href); } }); videoSrcArray = f_videos.concat(videoSrcArray); srcs = f_srcs.concat(srcs); }); return srcs; }, customTitle: ".ub_profile .fullname", downloadVideo: true, hide: ".as-bar", category: "nsfw2" }, { name: "Imginn", url: { h: "imginn.com", e: ".userinfo" }, imgs: async () => { fn.showMsg(DL.str_05, 0); let pagesNum = Math.ceil(Number(fn.gt(".userinfo .num")) / 12); let userinfo = fn.ge(".userinfo"); let id = userinfo.dataset.id; let cursor; let username = userinfo.dataset.name; let verified = "1"; let srcs = []; let loop = true; let page = 2; const getData = async () => { let params = new URLSearchParams({ id, cursor, username, verified }).toString(); try { let res = await fetch("/api/posts?" + params); let json = await res.json(); fn.showMsg(`${DL.str_06}${page}/${pagesNum}`, 0); json.items.forEach(e => { if (e.isVideo) { videoSrcArray.push(e.src); } else { srcs = srcs.concat(e.srcs); } }); if (!json?.hasNext) { loop = false; return; } cursor = json.cursor; page++; await fn.delay(2000, 0); } catch { await fn.delay(10000); } }; await fn.fetchDoc(fn.lp).then(async dom => { let links = fn.gae(".items .img a", dom); let f_srcs = []; let f_videos = []; let more = fn.ge(".load-more"); if (more) { cursor = more.dataset.cursor; while (loop) { await getData(); } } let eles = await fn.getEle(links, ".swiper-slide,.proxy-video", null, null, 0); eles.forEach(e => { if (e.classList.contains("proxy-video")) { f_videos.push(e.dataset.proxy); } else { f_srcs.push(e.dataset.src); } }); videoSrcArray = f_videos.concat(videoSrcArray); srcs = f_srcs.concat(srcs); }); return srcs; }, customTitle: ".userinfo .name h1", downloadVideo: true, category: "nsfw2" }, { name: "TW Pornstars", url: () => fn.checkUrl({ 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" ] }) && fn.lp.split("/").length === 2, 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: "h1.user-page", 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: "COSPLAYASIAN/COSPLAYTHOTS/COSPLAYRULE34/WAIFUBITCHES/COSPLAY BOOBS/COSPLAYLEAKS/VIPTHOTS/HENTAI BITCHES/LEAKSFANS/CHARMINGASS/LEAKS PIE/CHERRY LEAKS/SWEETLEAKS/OCOSPLAY/WEB CHARMING/COSPLAY KITTYS/TITSPIE/COSPLAY SOSEDKI", url: { h: [ "cosplayasian.com", "cosplaythots.com", "cosplayrule34.com", "waifubitches.com", "cosplayboobs.com", "cosplayleaks.com", "vipthots.com", "hentaibitches.com", "leaksfan.com", "charmingass.com", "leakspie.com", "cherryleaks.com", "sweetleaks.com", "ocosplay.com", "webcharming.com", "cosplaykittys.com", "titspie.com", "cosplaysosedki.com", "teamzookeepers.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: [ ["#FullPictureLoadMainImgBox", 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: "Thotslife.com", url: { h: ["thotslife.com"], }, srcset: ".entry-content img", videos: "video>source", customTitle: ".entry-title", downloadVideo: true, setFancybox: ".entry-content img", referer: "https://thotslife.com/", category: "nsfw2" }, { name: "Nude Cosplay Albums", url: { h: "nudecosplaygirls.com", p: /^\/[^\/]+\/$/ }, imgs: ".entry-content img.msacwl-img,#post img,.gallery-item img,figure.wp-block-image img", 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: "VoyeurFlash.com", host: ["voyeurflash.com"], reg: /^https?:\/\/voyeurflash\.com\/[^\/]+\/$/, imgs: () => { let [eos, ets] = [".gallery_thumb,.wp-block-image>a>img:not([srcset])", ".wp-block-image>img[srcset]"]; let eo = fn.ge(eos); let et = fn.ge(ets); if (!!eo) { return fn.gae(eos); } else if (!!et) { return fn.getImgSrcset(ets); } else { return []; } }, 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: ["#FullPictureLoadMainImgBox", 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: ".gallery_grid>a", thums: ".gallery_grid>a>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: ".albumgrid-main a[data-fancybox]", thums: ".albumgrid-main a[data-fancybox] img", button: [4], insertImg: ["#FullPictureLoadMainImgBox", 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: ["#FullPictureLoadMainImgBox", 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: ["#FullPictureLoadMainImgBox", 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: ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: ["#FullPictureLoadMainImgBox", 2], customTitle: "h1.text-3xl", category: "nsfw1" }, { 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: "nsfw1" }, { name: "COSFAN", url: { h: "www.cosfan.cc", }, page: () => fn.clp("/cosplay/"), SPA: () => _this.page(), observeURL: "gm", init: () => _this.page() ? fn.waitEle([".cursor-zoom-in img", "#baidu-tongji"]) : fn.waitEle("#baidu-tongji"), imgs: async () => { fn.showMsg(DL.str_05, 0); try { let dom = await fn.fetchDoc(fn.clp()); return [...dom.scripts].filter(script => script.textContent.includes(",https")).map(script => { let code = script.textContent.replaceAll("\n", "").replaceAll("\\", ""); let s = code.indexOf('"') + 1; let e = code.lastIndexOf('"'); return code.slice(s, e); }).join("").split(",").filter(text => text.startsWith("https")); } catch (error) { debug("代碼解析沒有提取出圖片網址"); console.error(error); await fn.waitEle(".cursor-zoom-in img"); await fn.wait(() => { let button = fn.ge("//button[text()='加载更多' or text()='More']"); if (!!button) { EClick(button); } return !button; }); return fn.gae(".cursor-zoom-in img"); } }, insertImgBF: () => fn.createImgBox("div.flex.flex-col.items-center", 2), button: [4], insertImg: ["#FullPictureLoadMainImgBox", 2], insertImgAF: () => fn.hideEle("div.flex.flex-col.items-center"), customTitle: "main main h1", category: "nsfw1" }, { 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: ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: "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").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: "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: "ViPinay", url: { h: "vipinay.com", st: "mwl_data" }, imgs: () => fn.waitEle([".entry-content p>img,.entry-content p>picture>img,.entry-content img[class*='wp-image']"]).then(eles => fn.getImgSrcset(eles)), capture: () => _this.imgs(), customTitle: "h1.entry-title", fetch: 1, 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"], p: /^\/[^\/]+\/$/, e: "figure.gallery-item,.entry-content>div>a[href*='blogger'],.entry-content img[src*='/wp-content/uploads/']" }, imgs: () => { if (fn.ge(".gallery-item img")) { return fn.gae(".gallery-item img"); } 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: [ ["#FullPictureLoadMainImgBox", 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: "X Cosplay", host: ["xcosplay.top"], reg: /^https?:\/\/xcosplay\.top\/[^\/]+\/$/, box: ["p:has(>.g1-img-wrap)", 2], imgs: () => fn.gae(".g1-img-wrap>img").map(e => e.src.replace(/-\d+x\d+\.jpg$/, ".jpg")), button: [4], insertImg: [ ["#FullPictureLoadMainImgBox", 0, "p:has(>.g1-img-wrap)"], 2 ], autoDownload: [0], next: "a[rel=prev]", prev: "a[rel=next]", customTitle: "h1.entry-title", category: "nsfw1" }, { 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", host: ["asiaontop.com", "asiaon.top"], reg: /^https?:\/\/(asiaontop\.com|asiaon\.top)\/[^\/]+\/$/, include: ".modula-items", init: () => fn.addMutationObserver(() => fn.remove("#mdpDeblocker-css")), imgs: "a[data-image-id]", button: [4], insertImg: [ [".modula-items", 2, ".modula-items"], 2 ], autoDownload: [0], next: "a#prepost", prev: "a#nextpost", customTitle: () => fn.gt(".single_post_title_main").replace(":", " -"), category: "nsfw2" }, { name: "AsiaOnTop", reg: /^https?:\/\/(asiaontop\.com|asiaon\.top)\//, init: () => fn.addMutationObserver(() => fn.remove("#mdpDeblocker-css")), css: "[data-aos^=fade][data-aos^=fade]{opacity:1!important;transition-property:unset!important}[data-aos=fade-up]{transform:unset!important}", hide: ".mdpDeblocker-wrapper,.mdpDeblocker-blackout.active", category: "ad" }, { 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: "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(), //button: [4], //insertImg: [".s-post-content", 2], 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: "Hình ảnh gái", url: { h: ["hinhanhgai.com"] }, page: () => ["/image/", "/article/"].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.curl("/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("/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; } return null; }, prev: 1, customTitle: () => { if (fn.clp("/image/")) { return fn.dt({ t: siteJson.name }); } 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: "nsfw1" }, { name: "Maulon", host: "1sex.maulon.vip", url: { t: "Maulon", p: ".html" }, imgs: ".entry-content .separator>a", thums: ".entry-content .separator>a>img", 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/'])", autoDownload: [0], next: "a[rel=prev]", prev: "a[rel=next]", customTitle: ".entry-title,.card_title", hide: "#cboxOverlay,#cboxWrapper", category: "nsfw1" }, { name: "Du lịch Mường Lò", url: { h: "diendandatdai.com" }, init: () => setTimeout(() => _unsafeWindow.jQuery(document).off(), 1000), imgs: ".gallery a:has(img)", thums: ".gallery img", customTitle: "h1.entry-title", 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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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]", button: [4], insertImg: [".content-inner", 2], autoDownload: [0], next: "a.post.prev-post", prev: "a.post.next-post", customTitle: "h1.jeg_post_title", 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: [ ["#FullPictureLoadMainImgBox", 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: "a.e-gallery-item", button: [4], insertImg: ["//div[div[a[contains(@class,'e-gallery-item')]]][@class='elementor-widget-container']", 2], autoDownload: [0], next: "a[rel=prev]", prev: "a[rel=next]", customTitle: "h1.elementor-heading-title", category: "nsfw1" }, { name: "Buon Dua", url: { h: ["buondua.com", "buondua.us"], e: ".article-fulltext img[alt]" }, init: () => { fn.remove("//div[text()='Sponsored ads']"); fn.remove(".search-form~*"); }, imgs: () => fn.getImg(".article-fulltext img[alt]", fn.gt(".pagination-list>span:last-child>a").match(/\d+/)[0]), button: [4], insertImg: [".article-fulltext", 2], customTitle: ".article-header>h1", referrerpolicy: "strict-origin", category: "nsfw2" }, { name: "MISS BABY", url: { h: ["missbaby.top"], e: ".article-fulltext img[alt]" }, init: () => { fn.remove("//div[text()='Sponsored ads']"); fn.remove(".search-form~*"); }, imgs: () => fn.getImg(".article-fulltext img[alt]", fn.gt(".pagination-list>span:last-child>a").match(/\d+/)[0]).then(srcs => srcs.map(src => { if (src.includes(".misskon.") || src.includes(".mrcong.")) { let url = src.replace(/\w+\.\w+\.\w+\//, ""); let obj = new URL(url); return obj.origin + obj.pathname; } return src; })), button: [4], insertImg: [".article-fulltext", 2], customTitle: ".article-header>h1", 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", "hinhsexviet.com", "hinhkhieudam.com", "gaidepvietnam.com"], e: [".entry-inner img[alt]", ".post-title"] }, init: () => { let share = fn.ge(".entry.share"); if (share) share.classList.remove("share"); fn.gae(".entry-inner p").forEach(e => { let text = e.innerText; if (text.length > 0) { tempEles.push(text); } }); }, imgs: () => { let max = Number(fn.gt("span.pages")?.match(/\d+$/)) || 1; let links = fn.arr(max, (v, i) => i == 0 ? fn.lp : fn.lp + `${i + 1}/`); return fn.getImgCorsA(".entry-inner img[alt]", links); }, button: [4], insertImg: [ [".pagination", 1, ".entry-inner>p:not(#FullPictureLoadEnd),.separator"], 2 ], insertImgAF: (_, bar) => { if (tempEles.length > 0) { tempEles.forEach(t => { let p = document.createElement("p"); p.innerText = t; fragment.append(p); }); bar.before(fragment); } }, customTitle: () => fn.dt({ s: ".post-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: "#tpbr_topbar,.boxzilla-container,.boxzilla-overlay,.sharrre-container", category: "nsfw1" }, { name: "HOTGIRLchina 格式 AD", reg: /^https?:\/\/(hotgirlchina\.com|anhnguoimau\.com|anhnguoidep|anhnguoilon\.com|xinh\.pro|anhkhieudam\.com|hinhsexviet\.com|anhmienphi\.com)\//, hide: ".boxzilla-container,.boxzilla-overlay,.sharrre-container", category: "ad" }, { 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: "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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 0, ".newphoto-list"], 2 ], customTitle: ".album-header a", category: "nsfw1" }, { name: "Nao Kanzaki and a few friends/NYO Cosplay/Navi Cosplay", url: { h: ["aitoda.blogspot.com", "2bcosplay.blogspot.com", "navicosplay.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", url: { h: ["sekushipic.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: [ ["#FullPictureLoadMainImgBox", 0, ".entry-content img[alt='']"], 2 ], customTitle: "h1.entry-title,h3.entry-title", category: "nsfw1" }, { name: "Nude Models", url: () => isPC && fn.lh === "blognudemodels.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", reg: /^https?:\/\/blognudemodels\.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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: "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: "Everia.club", host: ["everia.club", "torayaki.com", "evevoa.com"], url: { e: ["//div[@id='site-logo']//a[@rel='home'][text()='EVERIA.CLUB']", ".wp-block-image img,.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: "h1", 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", host: ["www.sexygirl.cc", "sexygirl.cc"], reg: [ /^https?:\/\/(www\.)?sexygirl\.cc\/a\/\d+\.html$/, /^https?:\/\/(www\.)?sexygirl\.cc\/photo\/([\w-]+\/)?a\/\d+\.html$/, /^https?:\/\/(www\.)?sexygirl\.cc\/(\w{2}\/)?photo\/\d+\.html$/, ], imgs: "div>img.img-f1luid,div>img.img-fluid", button: [4], insertImg: ["//div[img]", 2], next: "//a[text()='Previous']", prev: "//a[text()='Next']", 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']", 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: ".separator 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: "J M G T", url: { h: "www.qiuyeshudian.com", p: "/archives/" }, imgs: () => { thumbnailSrcArray = fn.gae(".feature-box img,.entry-content img").map(e => e.dataset.src ?? e.src); return thumbnailSrcArray.length > 1 ? thumbnailSrcArray.map(e => e.replace(/\?w=\d+&ssl=1/, "").replace(/\?resize.+/, "").replace(/-\d+x\d+\./, ".")) : []; }, capture: () => _this.imgs(), autoDownload: [0], next: "a[rel=prev]", prev: "a[rel=next]", customTitle: () => fn.dt({ s: "article h1", d: /(\d+Photos)\s|\(\d+Photos\)\s|\d+Photos\s|\d+\spics|\(选登\)|(选登\d+P)/ }), 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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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", fetch: 1, category: "nsfw2" }, { name: "NEWSグラビアアイドル.net", url: { h: "news.idolsenka.net", p: "/archives/" }, imgs: () => fn.gae(".entry-content img:not([alt^='DMM'],[alt*='OFF'],[alt^='FANZA']),.blog-content img:not([alt^='DMM'],[alt*='OFF'],[alt^='FANZA'])").map(img => { let src = img.src; if (src.includes("wp.com")) { src = src.replace(/\?resize.+$/, "") + "?ssl=1"; } if (src.includes("blogger.")) { let srcArr = src.split("/"); srcArr[srcArr.length - 2] = "s16000"; src = srcArr.join("/"); } return src; }), capture: () => _this.imgs(), videos: "iframe[title='YouTube video player']", customTitle: ".entry-title,.blog-single-title", category: "nsfw1" }, { name: "グラビア週刊誌 9/グラビア週刊誌 5/グラビア週刊誌 6", url: { h: ["gravurezasshi9.doorblog.jp", "magazinejapanese5.blog.jp", "magazinejapanese6.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()='前の記事']", prev: "//li[text()='次の記事: ']/a | //a[text()='次の記事']", customTitle: "h1.article-title>a,.article-header>h1", category: "nsfw1" }, { name: "グラビア週刊誌 9/グラビア週刊誌 5/グラビア週刊誌 6 - 分類自動翻頁", host: ["gravurezasshi9.doorblog.jp", "magazinejapanese5.blog.jp", "magazinejapanese6.blog.jp"], reg: [ /^https?:\/\/(gravurezasshi9\.doorblog\.jp|magazinejapanese(5|6)\.blog\.jp)\/(\?p=\d+)?$/, /^https?:\/\/(gravurezasshi9\.doorblog\.jp|magazinejapanese(5|6)\.blog\.jp)\/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", 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" }, 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; }); }, capture: () => _this.imgs(), 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: [ ["#FullPictureLoadMainImgBox", 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: () => fn.gt(".topentry_title span,.entry_title h1>strong"), 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_", "")); }, 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", fetch: 1, 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", fetch: 1, 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", fetch: 1, 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", fetch: 1, 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", fetch: 1, 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, fetch: 1, 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", fetch: 1, 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", fetch: 1, 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: ["#FullPictureLoadMainImgBox", 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.su/artists", "https://coomer.su/artists", "https://kemono.su/fantia/user/17148", "https://coomer.su/fansly/user/365239425979916288", "https://coomer.su/onlyfans/user/arty42575619" ], url: { h: ["kemono.su", "coomer.su"] }, page: () => fn.clp("/user/"), SPA: () => _this.page(), observeURL: "head", init: () => fn.waitEle("#main"), getPostJson: url => fetch("/api/v1" + new URL(url).pathname).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; isGotAll = 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-legacy"; 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(); isGotAll = true; isFetching = false; }); }); }, imgs: async () => { if (isGotAll) 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 (document.URL.includes("/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 []; } }, customTitle: "span[itemprop=name],.post__title", 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: ["#FullPictureLoadMainImgBox", 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: ["#FullPictureLoadMainImgBox", 2], customTitle: ".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: [ ["#FullPictureLoadMainImgBox", 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: "YY美女图片/美眉大宝贝", url: { h: ["www.yyzhenshun.com", "www.handands.com"], p: /^\/\d+\.html/ }, imgs: () => { if (fn.ge(".ep-pages a")) { let [, max] = fn.gu("//a[text()='尾页']").match(/(\d+)\.html$/); return fn.getImg(".wzy_body img", max, 3); } else { return fn.gae(".wzy_body img[alt]"); } }, button: [4], insertImg: ["//p[img] | //p[strong[img]] | //div[@class='wzy_body']", 2], autoDownload: [0], next: "//li[contains(text(),'上一篇')]/a", prev: "//li[contains(text(),'下一篇')]/a", customTitle: ".wzy_tit", css: "header{margin-top:0px !important}.wzy_body{text-indent:unset !important}", mcss: ".wzy_body{margin:0px !important}.neiye{margin:0px !important}", hide: "body>section[id],a[href*=download]", category: "nsfw1" }, { 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/" }, init: () => { new MutationObserver((mutations, observer) => { if (fn.ge(".chatra--webkit")) { fn.ge(".chatra--webkit").remove(); observer.disconnect(); } }).observe(document.body, MutationObserverConfig); }, imgs: ".images>a", thums: ".images>a>img", button: [4], insertImg: [ [".images", 2, ".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: () => { thumbnailSrcArray = fn.gae("div[data-src]>img").map(e => e.src); return fn.gae("div[data-src]").map(e => e.dataset.src); }, button: [4], insertImg: [ ["#FullPictureLoadMainImgBox", 0, ".spotlight-group"], 2 ], customTitle: "h1", hide: "#touch_to_see", category: "nsfw2" }, { name: "Digital AI Gallery", url: { h: ["larose.vip"], }, box: [".entry-content p:has(>img)", 1], imgs: ".entry-content img", button: [4], insertImg: [ ["#FullPictureLoadMainImgBox", 0, ".entry-content p:has(>img)"], 2 ], autoDownload: [0], next: "a[rel=prev]", prev: "a[rel=next]", customTitle: () => fn.dt({ s: ".wp-block-post-title", d: " – Larose.VIP" }), category: "nsfw2" }, { 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: [ ["#FullPictureLoadMainImgBox", 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: ".dynamic-entry-content img", 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: "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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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]]" }, imgs: () => { thumbnailSrcArray = fn.getImgSrcArr("//img[@data-src][@data-maxwidth]"); let URLs = fn.gau("//a[img[@data-src][@data-maxwidth]]"); return fn.getImageHost(URLs); }, button: [4], insertImg: [ ["//a[img[@data-src][@data-maxwidth]]", 2, "//a[img[@data-src][@data-maxwidth]]"], 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: [ ["#FullPictureLoadMainImgBox", 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: "Pics-X", url: { h: ["pics-x.com"], p: "/gallery/" }, init: () => fn.waitEle("#images-container img"), imgs: "#images-container img", 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 URLs = aEles.map(a => a.href); return fn.getImageHost(URLs); }, button: [4], insertImg: ["#post-content", 3], autoDownload: [0], next: () => fn.gu("//div[text()='Next Post']/following-sibling::div[1]/a"), prev: 1, 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: [ ["#FullPictureLoadMainImgBox", 0, ".grid"], 2 ], endColor: "white", customTitle: ".gall_title", category: "nsfw2" }, { name: "Boombo!", host: ["hot.boombo.biz", "boombo.biz"], url: { h: "boombo.biz" }, imgs: ".text div[style] img", button: [4], insertImg: [".text div[style]", 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: ["#FullPictureLoadMainImgBox", 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: "VGTimes", url: { h: ["vgtimes.ru"], e: ".slideGallery img" }, imgs: () => { thumbnailSrcArray = fn.getImgSrcArr(".news_item_image_img img,.slideGallery img"); return thumbnailSrcArray.map(src => src.replace("/thumbs/", "/")); }, capture: () => _this.imgs(), customTitle: "h1.news_item_title", 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]+фото/, "слив" ] }), 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: ".post-content>center>a>img,.post-content>p>a>img", button: [4], insertImg: [".post-content>center,.post-content>p", 2], 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: "MinhaMulher", url: { h: "www.minhamulher.com" }, box: [".conteudo p:has(>img)", 1], imgs: ".conteudo img", button: [4], insertImg: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: "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: "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: ["#FullPictureLoadMainImgBox", 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: ".postContent img", 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 srcs = []; 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); } await Promise.all(resArr).then(data => { videoSrcArray = data.filter(obj => "v" in obj)?.map(e => e.v); srcs = data.filter(obj => "i" in obj)?.map(e => e.i); }); return srcs; }, button: [4], insertImg: ["#FullPictureLoadMainImgBox", 3], customTitle: "#title", downloadVideo: true, category: "nsfw2" }, { name: "Good Sex Porn", url: { h: "goodsexporn.org", p: "/galleries/" }, imgs: () => { thumbnailSrcArray = fn.getImgSrcArr(".thumb>img"); return thumbnailSrcArray.map(e => e.replace("thumbs/", "").replace("http://", "https://")); }, button: [4], insertImg: ["#galleryImages", 2], customTitle: ".player-title", 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")); }, 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: [ ["#FullPictureLoadMainImgBox", 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\//, init: () => fn.remove("iframe[src*='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] }, 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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 2, ".photosgrid"], 2 ], endColor: "white", customTitle: "#galleryheader>h1", category: "nsfw2" }, { name: "es606 Photo", url: { h: ["www.epavx.com", "www.es606.com", "es606.com"], p: "/gallery/" }, init: () => fn.waitEle(".gallerygrid img"), decrypt: (str) => { let html = decodeURIComponent("%" + str.match(/.{2}/g).join("%")); let dom = fn.doc(html); let text = [...dom.scripts].find(s => s.type == "application/ld+json").textContent; let json = JSON.parse(text); return json; }, imgs: () => { let fetchNum = 0; fn.showMsg(DL.str_05, 0); let links = fn.gau(".photosgrid a"); let resArr = links.map(url => fn.fetchDoc(url).then(dom => { fn.showMsg(`${DL.str_06}${fetchNum+=1}/${links.length}`, 0); let data = [...dom.scripts][0].textContent.match(/"[^"]+"/)[0].replaceAll('"', ''); return _this.decrypt(data); })); return Promise.all(resArr).then(datas => datas.map(e => e.contentUrl)); }, thums: "#container img", button: [4], insertImgBF: () => fn.createImgBox(".gallerygrid", 2), insertImg: [ ["#FullPictureLoadMainImgBox", 2, ".gallerygrid"], 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: ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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 ], 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: [ ["#FullPictureLoadMainImgBox", 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: ["#FullPictureLoadMainImgBox", 2], customTitle: ".head-title", downloadVideo: true, referer: "", category: "nsfw2" }, { name: "Fapello Leaks/Thothub Leaked/Onlyfans Leaks/Only2leaked/SimpCity TV", url: { h: ["fapello-leaks.com", "thothub-leaked.com", "getofleaks.co", "only2leaked.co", "simpcity.tv"], p: "/album/" }, init: () => fn.waitEle(".album-gallery"), 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], insertImgBF: () => fn.createImgBox(".album-gallery", 2), insertImg: ["#FullPictureLoadMainImgBox", 2], customTitle: "h1.heading", 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: [ ["#FullPictureLoadMainImgBox", 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", 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: "MrDeepFakes", host: ["mrdeepfakes.com"], reg: /^https?:\/\/mrdeepfakes\.com\/photo\/\d+\//, init: () => { fn.remove(".player-adv"); fn.ge(".page-columns").classList.remove("page-columns"); }, imgs: () => { if (fn.ge("#album_view_album_view_pagination")) { fn.showMsg(DL.str_05, 0); let max = Number(fn.gt("//li[@class='next action-item']/preceding-sibling::li[@class='page action-item'][1]//span[@class='text']")); let fetchNum = 0; let resArr = fn.arr(max, (v, i) => { let url = siteUrl + "?mode=async&function=get_block&block_id=album_view_album_view&sort_by=&from=" + (i + 1); return fn.fetchDoc(url).then(dom => { fn.showMsg(`${DL.str_06}${fetchNum+=1}/${max}`, 0); return fn.gae("a[data-fancybox-type=image]", dom).map(a => { let img = fn.ge("img", a); return { original: a.href, thumbnail: img.dataset.original ?? img.src } }); }); }); return Promise.all(resArr).then(arr => { thumbnailSrcArray = arr.flat().map(e => e.thumbnail); return arr.flat().map(e => e.original); }); } else { thumbnailSrcArray = fn.gae(".content img.thumb").map(e => e.dataset.original ?? e.src); return fn.gae("a[data-fancybox-type=image]"); } }, button: [4], insertImg: ["#album_view_album_view", 2], customTitle: ".player-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/" }, imgs: () => { thumbnailSrcArray = fn.getImgSrcArr("img[data-src]"); return thumbnailSrcArray.map(e => e.replace("x160.", ".")); }, button: [4], insertImg: [ [".container>.row", 2], 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: ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: "SexyThots.com", url: { h: ["sexythots.com"], p: "/gallery/" }, srcset: ".gallery_grid img", thums: ".gallery_grid img", button: [4], insertImg: [".gallery_grid", 2], customTitle: () => fn.title(" - SexyThots.com"), 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: [ ["#FullPictureLoadMainImgBox", 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") { 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*='imx.to']:not([href*='/u/i/']), 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: () => 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") { 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*='imx.to']:not([href*='/u/i/']), 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: () => 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); if (event.target.className === "container") { let links = [...event.target.querySelectorAll(` a[href^='https://imgspice.com/'], a[href*='imx.to']:not([href*='/u/i/']), 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: () => 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") { let links = [...event.target.querySelectorAll(` a[href^='https://imgspice.com/'], a[href*='imx.to']:not([href*='/u/i/']), 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: () => 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("/u/t/", "/u/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: ["#FullPictureLoadMainImgBox", 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: ["#FullPictureLoadMainImgBox", 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: ["#FullPictureLoadMainImgBox", 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: ["#FullPictureLoadMainImgBox", 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: ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: "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: [ ["#FullPictureLoadMainImgBox", 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: ["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: ["xxxxn.click"], url: { h: ["xxxxn.click"], p: "/art/detail/id/" }, imgs: ".photoList img", button: [4], insertImg: [".photoList", 2], customTitle: ".title", hide: "div:has(>div[title=Close]),div:has(>span[onclick])", category: "nsfw2" }, { name: "漫画精品 AD", url: { h: ["xxxxn.click"] }, hide: ".colPhotoList:has(>div>a>img[style]),div:has(>div[title=Close]),div:has(>span[onclick])", category: "ad" }, { name: "湿女吧", host: ["shinv.pics"], url: { h: /shinv./, p: "/posts/" }, imgs: "//div[@class='p-1 col-span-12 md:col-span-9']//img[@class='block my-2 mx-auto']", button: [4], insertImg: ["//div[@class='p-1 col-span-12 md:col-span-9']", 2], customTitle: "h1.text-xl", 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" }, { name: "奶PARTTY", host: ["ilk01.com"], url: { t: "奶PARTTY", p: "/detail/id/" }, imgs: "#MyImg img", button: [4], insertImg: ["#MyImg", 2], customTitle: ".content h1", category: "nsfw2" }, { url: { p: "/show/" }, imgs: "#content img[loading]", button: [4], insertImg: ["#content", 2], customTitle: ".container .bg-info", category: "nsfw2" }, { name: "超级资源分享", host: ["www.xiu07.com", "m.xiu07.com"], url: { t: "超级资源分享", p: "/detailimg/" }, imgs: ".images img", button: [4], insertImg: [".images", 2], customTitle: ".srt h5", 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: [ ["#FullPictureLoadMainImgBox", 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)", 1], imgs: "article>img", button: [4], insertImg: [ ["#FullPictureLoadMainImgBox", 0, "article:has(>img)"], 2 ], autoDownload: [0], next: "//em[text()='上一篇:']/a", prev: "//em[text()='下一篇:']/a", customTitle: () => fn.title("-XXAV"), hide: ".suspend", category: "nsfw1" }, { name: "大香蕉", host: ["xx3355.com", "xx7755.com", "xx9955.com"], url: { e: "//ul[@class='logo']//a[text()='大香蕉']", p: "/image/detail/" }, imgs: ".content img", button: [4], insertImg: [".content", 2], autoDownload: [0], next: ".post-link .prev", prev: ".post-link .next", customTitle: ".main h1", hide: "#btmBox,#couplet", category: "nsfw2" }, { name: "福利图/美人图", host: ["fulitu.khm001.xyz", "meitu.khm005.xyz"], url: { e: ".logo img[alt=福利图],.logo img[alt=美人图]", p: "/image/pic/" }, imgs: () => fn.getImgA(".content img", fn.gau(".page a")), button: [4], insertImg: [".content", 2], autoDownload: [0], next: "//span[contains(text(),'上一篇')]/a", prev: "//span[contains(text(),'下一篇')]/a", customTitle: ".item_title h1", hide: ".home-filter", category: "nsfw2" }, { name: "性福里", host: ["sexfull.av3636.com"], url: { h: "sexfull", p: ["/img/detail_", "/manhua/chapter_"] }, imgs: () => fn.getImgA(".left .image img", [fn.lp]), button: [4], insertImg: [".image", 2], customTitle: ".container h2", hide: "#advlist", category: "nsfw2" }, { name: "性屋娱乐/猫咪成人网", host: ["sex5.khm002.xyz", "maomi.av6363.com"], url: { t: ["性屋娱乐", "MAOMI"], p: ["/tupiandetail/", "/meinvdetail/"] }, imgs: () => fn.getImgA("main .content img", [fn.lp]), button: [4], insertImg: ["main .content", 2], customTitle: ".cat_pos_l a:last-child", category: "nsfw2" }, { name: "四虎影院", host: ["4hu.khm005.xyz"], url: { t: "四虎影院", p: "/meinvdetail/" }, imgs: ".details-content img", button: [4], insertImg: [".details-content", 2], customTitle: ".news_details h1", hide: ".top_box", category: "nsfw2" }, { name: "四虎TV", host: ["www.4hu.tv"], url: { h: "4hu.tv", p: "/view/" }, imgs: ".pic img", button: [4], insertImg: [".pic", 2], customTitle: ".main h1", category: "nsfw2" }, { 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", category: "nsfw2" }, { name: "美女写真图集", url: { h: ["www.112ze.com", "112ze.com"], p: ".html" }, imgs: ".post-content img", button: [4], insertImg: [".post-content", 2], customTitle: ".mdui-text-black", fancybox: { v: 3, css: false }, category: "nsfw1" }, { name: "聚姬集", host: ["18jjj.cyou", "18jjj.xyz"], reg: /^https?:\/\/18jjj\.\w+\/chapter\/\d+$/i, include: "#enc_img img", init: () => { fn.clearAllTimer(); fn.remove("//div[@class='comicpage']/a[img[@alt]] | //div[@class='comicpage']/div[script] | //div[@id='cp_img']/a[img[@alt]] | //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;}", hide: "#pubcdnModal", category: "nsfw1" }, { 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: "Ai19 Art/Hentaimama", url: { h: ["ai19.org", "hentaimama.xyz"], p: "/news/" }, imgs: ".entry-content img", button: [4], insertImg: [ ["//p[img]", 2, "//p[img]"], 2 ], endColor: "white", customTitle: () => fn.gt(".entry-header").replaceAll("|", "-"), 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: [ ["#FullPictureLoadMainImgBox", 0, ".entry-content p:has(img),.ts-main-image"], 2 ], endColor: "white", customTitle: ".entry-title", category: "nsfw1" }, { 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: "逆次元逆ACG", host: ["www.nicohentai.com", "www.susmeat.com", "www.freeacg.org", "www.freeacg2.org"], url: { e: "#Comic_Top_Nav img[alt=logo][src$='_nico.png']", p: /^\/(moeupup-\d-\d+\.html|showinfo-\d+-\d+-\d\.html)$/ }, init: () => fn.getNP(".row.thumb-overlay-albums img", ".pagination li.active+li>a:not(.prevnext)"), imgs: ".row.thumb-overlay-albums img", button: [4], insertImg: [".row.thumb-overlay-albums", 2], next: "//a[span[text()='下一页']][@href]", prev: 1, customTitle: () => fn.fetchDoc(fn.gu("//a[span[text()='漫畫簡介']]")).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 ] })), category: "hcomic" }, { name: "Comic18H", host: ["www.comic18h.com"], reg: /^https:\/\/www\.comic18h\.com\/chapter\/\d+\.html$/, imgs: async () => { if (isM) { await fn.getNP("#readerarea>div", "//ul[@class='pagination']//a[text()='Next»']"); } else { await fn.getNP("#readerarea>div", ".pagination li.active+li>a:not(.prevnext)"); } return fn.gae("#readerarea img"); }, button: [4], insertImg: ["#readerarea", 2], next: "//a[text()='Next Article»'][contains(@href,'.html')]", prev: "//a[text()='«Previous Chapter'][contains(@href,'.html')]", customTitle: ".entry-title", hide: ".code-block:has(>.ads),.hidden-xs:has(>.pagination)", observerClick: "#chk_cover", category: "hcomic" }, { reg: /^https?:\/\/www\.comic18h\.com\//, observerClick: "#chk_cover", hide: ".code-block:has(>.ads)", category: "ad" }, { 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", category: "hcomic" }, { name: "Doujindesu", url: { h: "doujindesu.icu" }, 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], next: () => { let chapters = fn.gae("#chapter-list option"); let c_chapter = chapters.find(e => e.value == fn.url); let next = c_chapter?.nextElementSibling; return next ? next.value : null; }, prev: 1, customTitle: () => fn.dt({ t: fn.ge(".container h1").textContent }), 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"], }) && isMobileDeviceUA, //clearLoop: true, page: () => fn.clp("/v2h5/comicContent/"), 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.fgjfghkk.club/api/v3/comic/${word}/chapter/${id}?platform=1&_update=true`; return fetch(api).then(res => res.json()); }, 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: [ ["#FullPictureLoadMainImgBox", 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, 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$/, "www.2024manga.com", "www.manga2024.com" ], e: [ ".disData[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 contentKey = fn.attr(".disData", "contentKey", dom); let images = await fn.copymanga_decrypt(contentKey); return images.map(e => e.url.replace("800x.", "1500x.")); }, button: [4, "24%", 2], insertImg: [ ["#FullPictureLoadMainImgBox", 0, ".comicContent-list"], 2 ], endColor: "white", next: "//a[text()='下一話'][starts-with(@href,'/')]", prev: "//a[text()='上一話'][starts-with(@href,'/')]", customTitle: (dom = document) => fn.dt({ t: dom.title, d: / - 熱辣漫畫.+$/ }), preloadNext: true, infiniteScroll: true, category: "comic" }, { name: "熱辣漫畫 自動翻頁", url: { h: [ /^(www\.)?relamanhua\.org$/, "www.2024manga.com", "www.manga2024.com" ], e: [ ".disData[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 contentKey = fn.attr(".disData", "contentKey", dom); let images = await fn.copymanga_decrypt(contentKey); return images.map(e => e.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$/, "www.2024manga.com", "www.manga2024.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"], p: "/v2h5/comicContent/", i: 1 }, getData: () => { let split = document.URL.split("/"); let word = split.at(-2); let id = split.at(-1); let api = `https://mapi.fgjfghkk.club/api/v3/comic/${word}/chapter/${id}?platform=1&_update=true`; return fetch(api).then(res => res.json()).then(json => { globalImgArray = json.results.chapter.contents.map(e => e.url); customTitle = json.results.chapter.name; let next = json.results.chapter?.next; console.log("\n熱辣漫畫M_JSON\n", json, globalImgArray, customTitle, next); if (!!next) { tempNextLink = document.URL.replace(/[^\/]+$/, "") + next; } else { tempNextLink = null; } }); }, init: async () => { fn.showMsg(DL.str_135, 0); await _this.getData(); let imgs = fn.createImgArray(globalImgArray); let tE = fn.ge("#comicContentMain"); fragment.append(...imgs); tE.append(fragment); 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(globalImgArray), pos: ["#comicContentMain", 0], observer: "#comicContentMain>img", next: () => tempNextLink, wait: async () => await _this.getData(), title: () => customTitle }, 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$/, ], }, 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 }); } }); }, fetch: 1, 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"], 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: ["#FullPictureLoadMainImgBox", 3], customTitle: () => { let t = fn.gt("#gj").replace(/\/|\[\d+[\w\.\+\s-]+\]/i, ""); return t.length > 0 ? t : fn.gt("#gn").replace(/\|.+|\[\d+[\w\.\+\s-]+\]/i, "").trim(); }, 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: "nhentai圖片清單頁", url: { h: [ "nhentai.net", "nyahentai.red", "www.hentai.name", "nhentai.xxx", "nhentai.to", "nhentai.website", "nhentai.moe", "simplyhentai.org" ], p: /^\/g\/\d+\/?$/ }, imgs: async () => { thumbnailSrcArray = fn.getImgSrcArr("a.gallerythumb>img"); if (fn.lh === "nhentai.net") { 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)}`); const hostArray = ["i.nhentai.net", "i5.nhentai.net", "i6.nhentai.net", "i7.nhentai.net", "i1.nhentai.net", "i2.nhentai.net", "i3.nhentai.net", "i4.nhentai.net"]; 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 === "nyahentai.red") { fn.showMsg(DL.str_05, 0); let src = fn.src(".gallerythumb>img"); let dir = fn.dir(src); let url = fn.gu("a.gallerythumb"); return fn.iframeVar(url, "images_ext").then(w => w.images_ext.map((e, i) => `${dir}${(i + 1)}.${fn.ex(e)}`)); } 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.moe"].some(h => fn.lh === h)) { fn.showMsg(DL.str_05, 0); let url = fn.gu("a.gallerythumb"); return fn.iframeVar(url, "reader").then(frame => { const { gallery, image_cache } = frame.reader; const k = "1"; let src = image_cache[k].image.src; let dir = fn.dir(src); return 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", 0], 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", category: "hcomic" }, { name: "nhentai閱讀頁", host: ["nhentai.net"], reg: /^https?:\/\/nhentai\.net\/g\/\d+\/\d+\/$/, init: async () => await 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)}`); const hostArray = ["i.nhentai.net", "i5.nhentai.net", "i6.nhentai.net", "i7.nhentai.net", "i1.nhentai.net", "i2.nhentai.net", "i3.nhentai.net", "i4.nhentai.net"]; //fn.showMsg(DL.str_56, 0); for (let host of hostArray.reverse()) { fn.showMsg(DL.str_56 + "_" + 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: "nyahentai.red閱讀頁", reg: /^https?:\/\/nyahentai\.red\/g\/\d+\/\d+\/$/, imgs: () => { let src = fn.src("#image-container img"); let dir = fn.dir(src); return _unsafeWindow.images_ext.map((e, i) => `${dir}${(i + 1)}.${fn.ex(e)}`); }, button: [4], insertImg: ["#image-container", 2], customTitle: () => fn.title(" » ", 1), 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(document.cookie.replace("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: [ ["#FullPictureLoadMainImgBox", 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.ge(".entry-header>span") ? fn.gt(".entry-header>span") : fn.gt(".entry-title"), category: "hcomic" }, { name: "Cathentai/Hentaibeeg/Hentaicolor/Nyahentai/圖片清單頁", url: { h: [ "cathentai.net", "hentaibeeg.com", "hentaicolor.net", "nyahentai.info" ], p: /^\/[^/]+\/(#collapse)?$/ }, imgs: () => { fn.showMsg(DL.str_05, 0); let url = fn.gu("//a[span[text()='List Read']]"); return fn.fetchDoc(url).then(dom => fn.run(fn.gt("#listImgH", 1, dom).trim())); }, button: [4], insertImg: [ ["#thumbnail-container", 2], 2 ], customTitle: () => fn.getText(["#info>h4", "#info>h1"]), category: "hcomic" }, { name: "Cathentai/Hentaibeeg/Hentaicolor/Nyahentai/List Read頁", url: { h: [ "cathentai.net", "hentaibeeg.com", "hentaicolor.net", "nyahentai.info" ], p: /^\/read\/\d+\.html$/ }, imgs: () => fn.run(fn.gt("#listImgH").trim()), button: [4], insertImg: ["#image-container", 2], customTitle: () => fn.title(/ - Cathentai| - Hentaicolor| - Hentaibeeg| - Nyahentai.info/, 1), category: "hcomic" }, { name: "3hentai/HentaiVox圖片清單頁", host: ["3hentai.net", "hentaivox.com"], reg: [ /^https?:\/\/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", 0], 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?:\/\/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: "山寨3hentai圖片清單頁", host: ["www.hentai321.top"], reg: /^https?:\/\/www\.hentai321\.top\/\?d\/\d+$/, init: () => fn.remove("#header-ban-agsy,#middle-ban-agsy"), box: ["#thumbnail-gallery", 2], imgs: () => fn.getImgA(".js-main-img", ".single-thumb>a"), thums: ".single-thumb img", button: [4], insertImg: ["#FullPictureLoadMainImgBox", 2], customTitle: ".middle-title", css: "#FullPictureLoadMainImgBox{max-width:1140px;margin-left:auto;margin-right:auto}", hide: "ins,#doujin-page-footer-ban-agsy,#main-content+div~*:not([id^='Full'],[class^='Full'],[id^='pv-'],[class^='pv-'],#comicRead,#fab,*[class^=fancybox])", 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: ["#FullPictureLoadMainImgBox", 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: "APE XXX圖片清單頁", host: ["ape.su"], reg: /^https?:\/\/ape\.su\/\d+\/$/, include: "#append_thumbs", box: ["#append_thumbs"], 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: ["#FullPictureLoadMainImgBox", 2], customTitle: ".right_details h1", topButton: true, 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: [ ["#FullPictureLoadMainImgBox", 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: ["#FullPictureLoadMainImgBox", 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: ["#FullPictureLoadMainImgBox", 2], customTitle: () => fn.ge(".subtitle") ? fn.gt(".subtitle") : fn.gt("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: ["hentaienvy.com"], reg: /^https?:\/\/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: ["#FullPictureLoadMainImgBox", 2], customTitle: () => fn.ge(".subtitle") ? fn.gt(".subtitle") : fn.gt("h1"), topButton: true, category: "hcomic" }, { name: "HentaiEnvy閱讀頁", host: ["hentaienvy.com"], reg: /^https?:\/\/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/simplyhentai.red圖片清單頁", host: ["lhentai.com", "simplyhentai.red"], reg: /^https?:\/\/(lhentai\.com|simplyhentai\.red)\/g\/\d+$/, imgs: async () => { thumbnailSrcArray = fn.getImgSrcArr(".gallerythumb img"); fn.showMsg(DL.str_05, 0); let url = fn.gu("a.gallerythumb"); let iframe = await fn.iframeVar(url, "images_ext"); let src = fn.src(".fit-horizontal", iframe.document); let dir = fn.dir(src); return iframe.images_ext.map((e, i) => `${dir}${(i + 1)}.${fn.ex(e)}`); }, button: [4], insertImg: [ [".thumbs", 2], 2 ], customTitle: () => fn.getText(["#info>h2", "#info>h1"]), category: "hcomic" }, { name: "lhentai.com/simplyhentai.red閱讀頁", host: ["lhentai.com", "simplyhentai.red"], reg: /^https?:\/\/(lhentai\.com|simplyhentai\.red)\/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 []; thumbnailSrcArray = siteJson.images.map(e => "https://i.eahentai.com/file/ea-gallery/" + e.thumbnailUri); return siteJson.images.map(e => "https://i.eahentai.com/file/ea-gallery/" + e.imageUri); }, button: [4], insertImgBF: () => fn.waitEle(".gallery-img").then(() => fn.createImgBox(".gallery-container", 2)), insertImg: ["#FullPictureLoadMainImgBox", 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+$/, box: [".bookthumbnailcontainer", 2], 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: ["#FullPictureLoadMainImgBox", 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+$/, box: [".box:has(>.is-multiline)", 2], 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: ["#FullPictureLoadMainImgBox", 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: ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: () => { 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.to/nhentai.website閱讀頁", host: ["nhentai.to", "nhentai.website", "nhentai.moe"], reg: /^https?:\/\/nhentai\.(to|website|moe)\/g\/\d+\/\d+\/?$/, init: () => fn.waitVar("reader"), imgs: () => { const { reader } = _unsafeWindow; let imgDir = reader.media_url + "/galleries/" + reader.gallery.media_id + "/"; return reader.gallery.images.pages.map((e, i) => `${imgDir}${(i + 1)}.${fn.ex(e.t)}`); }, button: [4], insertImg: ["#image-container", 2], customTitle: () => { const { reader } = _unsafeWindow; return reader.gallery.title.japanese ?? reader.gallery.title.english; }, category: "hcomic" }, { name: "The Hentai圖片清單頁", url: { h: "thehentai.net", p: /^\/[^\/]+\/$/ }, init: () => fn.waitVar("imagensbg"), box: [".post_imgs", 2], imgs: () => { thumbnailSrcArray = _unsafeWindow.imagensbg; return thumbnailSrcArray.map(e => fn.lo + e.replace("-300x400.", ".")); }, button: [4], insertImg: ["#FullPictureLoadMainImgBox", 2], 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: ["#FullPictureLoadMainImgBox", 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: [ ["//div[div[@class='well']]", 2], 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, fetch: 1, category: "hcomic" }, { name: "Pururin圖片清單頁", host: ["pururin.me"], reg: /^https?:\/\/pururin\.me\/gallery\/\d+\/.+/, 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: [ [".gallery-preview", 2], 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: ["#FullPictureLoadMainImgBox", 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: "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: "HENTAISET.COM閱讀頁 / HENTAIVID.NET閱讀頁 / HENTAITOP.ORG閱讀頁", host: ["www.hentaiset.com", "hentaivid.net", "hentaitop.org"], reg: [ /^https?:\/\/www\.hentaiset\.com\/\w+\/\w+\//i, /^https?:\/\/hentaivid\.net\/photo\/\w+\/[^\/]+\/$/i, /^https?:\/\/hentaitop\.org\/gallery\// ], box: ["#lightgallery", 2], imgs: "#lightgallery li.thumb,#lightgallery div.thumb", thums: "#lightgallery img[is='lazyload-image']", button: [4], insertImg: [ ["#FullPictureLoadMainImgBox", 0, "#lightgallery"], 2 ], customTitle: ".main-container 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: "HENTAIVSMANGA.COM圖片清單頁", host: ["hentaivsmanga.com"], reg: /^https?:\/\/hentaivsmanga\.com\/content\/\w+\/[^\/]+\/$/i, imgs: () => fn.getImgA("#image-container img", "#thumbnail-container a"), thums: "#thumbnail-container img[is='lazyload-image']", button: [4], insertImg: [ ["#thumbnail-container", 2], 2 ], customTitle: () => fn.getText(["#info>h2", "#info>h1"]), category: "hcomic" }, { name: "HENTAIVSMANGA.COM閱讀頁", host: ["hentaivsmanga.com"], reg: /^https?:\/\/hentaivsmanga\.com\/content\/\w+\/[^\/]+\/\d+\/$/i, imgs: () => { let max = fn.gt(".num-pages"); let url = fn.url.replace(/\d+\/$/, ""); let links = fn.arr(max, (v, i) => url + (i + 1) + "/"); return fn.getImgA("#image-container img", links); }, button: [4], insertImg: ["#image-container", 2], customTitle: () => fn.title(" XXX Manga and Hentai"), 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: () => fn.gt("#detail span") + " - " + fn.gt("#chapter span"), hide: ".afs_ads,[data-type]", category: "hcomic" }, { name: "HentaiPaw圖片清單頁/Hentai-One圖片清單頁", url: { h: ["hentaipaw.com", "ch.hentai-one.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 = [...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("\\", ""); return fn.TextToArray(text, '"slides":').map(e => e.src); }); }, thums: ".grid .group>img", button: [4], insertImg: [ ["#FullPictureLoadMainImgBox", 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 === "ch.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: () => fn.gt(".list-reset li:nth-child(5)>a") + " - " + fn.gt("option[selected]"), category: "hcomic" }, { name: "Doujins圖片清單頁", host: ["doujins.com"], reg: /^https?:\/\/doujins\.com\/.+\/.+/i, include: "#thumbnails", 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"], reg: /^https?:\/\/myhentaigallery\.com\/g\/\d+$/, imgs: () => { thumbnailSrcArray = fn.gae(".comic-thumb>img").map(e => e.src); return thumbnailSrcArray.map(e => e.replace("thumbnail", "original")); }, button: [4], insertImg: [ ["//div[@class='comic-listing'][center[center[ul[@class='comics-grid clear']]]]", 0], 2 ], endColor: "white", customTitle: ".comic-description>h1", category: "hcomic" }, { name: "XYZ PORN COMICS圖片清單頁", host: ["xyzcomics.com"], reg: /^https?:\/\/xyzcomics\.com\/[^\/]+\/$/, include: ".jig-link>img", imgs: ".jig-link", thums: ".jig-link>img", button: [4], insertImg: [ [".entry-content", 0], 2 ], endColor: "white", customTitle: ".entry-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: [ ["#FullPictureLoadMainImgBox", 0, "#thumbnails"], 2 ], endColor: "white", customTitle: "h1.name a:last-child", category: "hcomic" }, { name: "BestPornComix", url: { h: "bestporncomix.com", p: "/gallery/" }, imgs: "figure a", button: [4], insertImg: [".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: ["#FullPictureLoadMainImgBox", 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: ["#FullPictureLoadMainImgBox", 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] = document.cookie.match(/XSRF-TOKEN=(\w+)/); 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: [ ["#FullPictureLoadMainImgBox", 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: "eromanga-kong.com" }, imgs: "//article[@id='article']//a[img]", customTitle: "header>h2", category: "hcomic" }, { name: "エロ漫画 ヌキブックス", url: { h: "nukibooks.com", p: "/articles/" }, init: () => fn.waitEle("#asg-in-page-push-styles"), imgs: ".article-page-list img", button: [4], insertImg: [".article-page-list", 2], customTitle: "h1.detail-ttl", category: "hcomic" }, { name: "H研-成年コミック研究会", url: { h: "www.b-hentai.com", p: ".html" }, box: [".wp-block-table", 2], imgs: () => fn.getImgA(".content img", ".article-pagination a"), button: [4], insertImg: [ ["#FullPictureLoadMainImgBox", 0, ".content>img,.content p:has(img),.article-pagination"], 2 ], 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: "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", 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: "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", host: ["xlecx.one"], reg: /^https?:\/\/xlecx\.one\/[\w-]+\.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", host: ["hentaiporns.net"], reg: /^https?:\/\/hentaiporns\.net\/[^\/]+\/$/, include: ".gallery", box: [".gallery", 2], imgs: ".gallery-item a", thums: ".gallery-item a>img", button: [4], insertImg: [ ["#FullPictureLoadMainImgBox", 0, ".gallery"], 2, 1000 ], customTitle: () => fn.getText(["#gn+h1", "#gn,.entry-title"]), fancybox: { v: 3, css: false }, 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: "Manga18.club/hanman18.com/18PornComic/Doujin18.net/CNdoujin.net", init: async () => { await fn.waitVar("jQuery"); fn.run("jQuery(document).off()"); }, url: { h: [ "manga18.club", "hanman18.com", "18porncomic.com", "doujin18.net", "cndoujin.net" ], st: "slides_p_path" }, imgs: () => _unsafeWindow.slides_p_path.map(e => atob(e)), capture: () => _this.imgs(), autoDownload: [0], next: () => _unsafeWindow.next_chapter === "" ? null : _unsafeWindow.next_chapter, prev: 1, 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: "Hentai.bang14.com", host: ["hentai.bang14.com"], reg: /^https?:\/\/hentai\.bang14\.com\/[^\/]+\/$/, include: ".entry-content", imgs: ".entry-content img", button: [4], insertImg: [".entry-content", 2], autoDownload: [0], next: ".nav-previous a[rel=prev]", prev: ".nav-previous a[rel=next]", customTitle: "h1.entry-title", 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", url: { h: ["mangadistrict.com", "apcomics.org", "ilikecomix.com", "manga18free.com"] }, 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: "Hachirumi.com", url: { h: ["hachirumi.com"] }, page: () => fn.clp("/read/manga/"), SPA: () => _this.page(), observeURL: "head", imgs: () => { if (!_this.page()) return []; fn.showMsg(DL.str_05, 0); let id = fn.clp().split("/").at(3); return fetch(`/api/series/${id}/`).then(res => res.json()).then(json => { let { slug, title, chapters, } = json; apiCustomTitle = title; let srcs = Object.values(chapters).map(({ folder, groups }) => { let i = Object.keys(groups).at(0); let images = Object.values(groups).at(0); return images.map(e => `${fn.lo}/media/manga/${slug}/chapters/${folder}/${i}/${e}`); }).flat(); return srcs; }); }, capture: () => _this.imgs(), 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", host: ["18h.mm-cg.com"], reg: /^https?:\/\/18h\.mm-cg\.com\/(zh\/?)\w+_content\/\d+\/content\.html$/i, imgs: () => _unsafeWindow.Large_cgurl, button: [4], insertImg: ["#show_cg_html", 2], customTitle: () => fn.title("-", 1), 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: () => { let tt = fn.gt(".truyen-title"); let ct = fn.gt(".chapter-title"); if (tt.toLowerCase() == ct.toLowerCase()) { return ct; } else { return tt + " - " + ct; } }, 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: ["#FullPictureLoadMainImgBox", 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: ["#FullPictureLoadMainImgBox", 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: ["#FullPictureLoadMainImgBox", 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(), 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: "紳士漫畫 圖片清單頁", 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: async () => { fn.remove(".dlh,iframe:not(#FullPictureLoadIframe,#FullPictureLoadIframeGallery)"); fn.remove("//body/div[a[img]] | //div[@class='Introduct']/a[div[img]] | //div[a[img[@alt='Game Tip']]]"); fn.addMutationObserver(() => fn.remove(".dlh,iframe:not(#FullPictureLoadIframe,#FullPictureLoadIframeGallery)")); }, imgs: async () => { 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$/ }, 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", 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: [ ["#FullPictureLoadMainImgBox", 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: "紳士漫畫", host: ["www.ssmh.lol"], url: { t: "紳士漫畫", p: /^\/\d+\.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: "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; } else { 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) { return `[${author}] ${title}`; } else { return title; } }); }, category: "hcomic" }, { name: "喜漫漫画/51漫画", url: { h: ["www.favcomic.com", "www.51comics.com"], 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") : [], button: [4], insertImgBF: () => fn.createImgBox(".shadow-md", 1, 1200), insertImg: [ ["#FullPictureLoadMainImgBox", 0, ".shadow-md"], 2 ], customTitle: () => _this.page() ? fn.gt("main h1") : null, 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: [ ["#FullPictureLoadMainImgBox", 0, ".mip-box-body>img"], 2 ], autoDownload: [0], next: () => { if ("nextid" in _unsafeWindow && _unsafeWindow.nextid != 0) { return fn.dir(fn.lp) + _unsafeWindow.nextid + ".html"; } else { return null; } }, prev: 1, customTitle: ".mip-box-heading", fancybox: { blacklist: 1 }, hide: "body>div[class][style]", category: "hcomic" }, { name: "松鼠症倉庫 閱讀頁", host: ["ahri8.top"], url: { e: "//div[@id='logo-group']//a[contains(text(),'松鼠症倉庫') or contains(text(),'松鼠症仓库')]", p: "readOnline" }, 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.top"], url: { e: "//div[@id='logo-group']//a[contains(text(),'松鼠症倉庫') or contains(text(),'松鼠症仓库')]", p: "/post", s: "ID=" }, 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-xfjd-2024-04-25.top", "ahri-gallery-jq5s6-2024-04-29.top", "c922myqccl00207.top"], url: () => fn.checkUrl({ h: "caitlin.top", p: "index", s: "readOnline" }) || fn.checkUrl({ e: "//a[starts-with(text(),'Ahri Gallery')]", p: "index", s: "reader" }), imgs: () => { const { Image_List, IMAGE_SERVER, image_server_id, IMAGE_FOLDER } = _unsafeWindow; const getExtension = ext => { switch (ext) { case "gif": return "gif"; case "webp": return "webp"; default: return "jpg"; } }; let counter = 0; let srcArr = []; for (let Image of Image_List) { let ext = getExtension(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: ".page-header,.gallery_title", hide: "#content>.col-lg-12,[id^=read_online_ads_area],#Big_Image~*", category: "hcomic" }, { name: "Caitlin.top/Ahri Gallery分機 詳情頁", host: ["caitlin.top", "ahri-gallery-xfjd-2024-04-25.top", "ahri-gallery-jq5s6-2024-04-29.top", "c922myqccl00207.top"], url: () => fn.checkUrl({ h: "caitlin.top", p: "index", s: "article" }) || fn.checkUrl({ e: "//a[starts-with(text(),'Ahri Gallery')]", p: "index", s: "article" }), init: () => { if (fn.ge("//a[text()='Read']")) { fn.createImgBox(".container:has(.gallery_card)"); } else { fn.createImgBox("#more-information1>div.row:has(img)", 2); } _unsafeWindow.onscroll = null; }, imgs: async () => { let url; if (fn.ge("//a[text()='Read']")) { url = fn.gu("//a[text()='Read']"); } 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; const getExtension = ext => { switch (ext) { case "gif": return "gif"; case "webp": return "webp"; default: return "jpg"; } }; let counter = 0; let srcArr = []; for (let Image of Image_List) { let ext = getExtension(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: [ ["#FullPictureLoadMainImgBox", 0, "#more-information1>div.row:has(img)"], 2 ], customTitle: () => fn.getText([".row>.col-xs-12>h2", "div.name>h2", ".gallery_title", ".gallery_title2"]), category: "hcomic" }, { name: "蚂蚁搬运网/紳士泛漫畫", links: [ "https://www.antbyw.com/plugin.php?id=jameson_manhua", "https://itsacg.top/" ], url: { h: ["www.antbyw.com", /\.itsacg\./], s: "=read", d: "pc" }, imgs: ".uk-zjimg img", button: [4], insertImg: [".uk-zjimg", 2], autoDownload: [0], next: "//a[contains(text(),'下一章')]", prev: "//a[contains(text(),'上一章')]", customTitle: () => { 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: "imglist", d: "m" }, imgs: () => { let code = fn.gst("imglist"); return fn.TextToArray(code, "imglist").map(e => e.url); }, 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: () => fn.dt({ t: fn.title("_", 3), d: [ /【.+】/g, "_阅读浏览" ] }), category: "comic" }, { name: "紳士泛漫畫M", url: { h: /\.itsacg\./, s: "=read", d: "m" }, imgs: ".zjimg>img", button: [4], insertImg: [ [".zjimg", 1, ".zjimg"], 2 ], customTitle: () => fn.dt({ t: fn.title("_", 3), d: [ /【.+】/g, "_阅读浏览" ] }), 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", fetch: 1, 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", fetch: 1, 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: ["#FullPictureLoadMainImgBox", 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: "开心看漫画 閱讀頁", 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: "凹凸漫/X漫/肉漫天堂 目錄頁", 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: ["#FullPictureLoadMainImgBox", 3], customTitle: ".anime__details__title>h3", hide: ".ad-banner", category: "hcomic" }, { name: "凹凸漫/X漫/肉漫天堂 閱讀頁", host: ["atm333.com", "xman5.com", "rmtt6.com"], url: { h: /atm|xman|rmtt/, 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: () => fn.gt("center>h1") + " - " + fn.gt("center>h2"), category: "hcomic" }, { name: "凹凸漫/X漫/肉漫天堂 目錄頁", host: ["atm333.com", "xman5.com", "rmtt6.com"], url: { h: /atm|xman|rmtt/, 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: ["#FullPictureLoadMainImgBox", 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", "laosiji52.com"], 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: [ ["#FullPictureLoadMainImgBox", 0], 3 ], customTitle: ".detail h1", category: "hcomic" }, { name: "老司機禁漫 閱讀頁", host: ["laosiji6.com", "laosiji52.com"], url: { h: "laosiji", p: /^\/comic\/\d+\/\w+$/i }, box: ["img.lazy", 1], imgs: "img.lazy", button: [4], insertImg: [ ["#FullPictureLoadMainImgBox", 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: () => fn.gt(".breadcrumb-item:nth-child(2) a").trim() + " - " + fn.gt(".breadcrumb-item.active").trim(), 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: [ ["#FullPictureLoadMainImgBox", 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: () => fn.gt("ol.inline-flex>li:nth-child(2) a").trim() + " - " + fn.gt("ol.inline-flex>li:nth-child(3) a").trim(), 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: "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: ["#FullPictureLoadMainImgBox", 2], insertImgAF: () => fn.hideEle(".thumbnail-list,.simplePagerNav"), 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: () => fn.gt("//ol/li[2]/a") + " - " + fn.gt("//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.sesemanhua.com", "www.manhuazuixin.com"], reg: [ /^https:\/\/www\.sesemanhua\.com\/index\.php\/chapter\/\d+/, /^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: ["#FullPictureLoadMainImgBox", 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: [ ["#FullPictureLoadMainImgBox", 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: "免费韩漫看", host: ["www.hanmanm.com"], reg: /^https?:\/\/www\.hanmanm(\w+)?\.com\/index\.php\/chapter\/\d+/, imgs: "#ChapterContent img,.readForm img", button: [4], insertImg: ["#ChapterContent,.readForm", 2], autoDownload: [0], next: "//a[text()='下一章'][starts-with(@href,'/')]", prev: "//a[text()='上一章'][starts-with(@href,'/')]", customTitle: () => fn.ge("#ChapterContent") ? fn.gt(".arthor") + " - " + fn.gt(".title") : fn.title("免费观看 "), category: "hcomic" }, { name: "韩漫推荐", host: ["www.hanmantop.com"], reg: /^https?:\/\/www\.hanman(\w+)?\.com\/index\.php\/chapter\/\d+/, include: "//div/div[@style]/img[@style]", imgs: "//div/div[@style]/img[@style]", button: [4], insertImg: ["//div[div[@style]/img[@style]]", 2], autoDownload: [0], next: "//a[text()='下一章'][starts-with(@href,'/')]", prev: "//a[text()='上一章'][starts-with(@href,'/')]", customTitle: "h1[style]", category: "hcomic" }, { name: "韩漫推荐M", host: ["www.hanmantop.com"], reg: /^https?:\/\/www\.hanman(\w+)?\.com\/index\.php\/chapter\/\d+/, imgs: ".chapterbox img", button: [4], insertImg: [ [".chapterbox>*:first-child", 1, ".pic"], 2 ], autoDownload: [0], next: "//a[text()='继续阅读下一章节']", prev: 1, customTitle: () => fn.title("韩漫 "), 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: ["#FullPictureLoadMainImgBox", 3], customTitle: ".Introduct_Sub h1", category: "hcomic" }, { name: "松鼠韓漫 閱讀頁", host: ["www.songshuhanman.com"], url: { h: "songshuhanman", p: "/ch/" }, imgs: ".more-box img", button: [4], insertImg: [".more-box", 2], autoDownload: [0], next: "//a[text()='下一章'][starts-with(@href,'/ch/')]", prev: "//a[text()='上一章'][starts-with(@href,'/ch/')]", customTitle: "h1", category: "hcomic" }, { name: "松鼠韓漫 目錄頁", host: ["www.songshuhanman.com"], url: { h: "songshuhanman", p: "/com/" }, box: [".contpost2.gap", 2], imgs: () => { let links = fn.gau(".playlist a"); return fn.getImgA(".more-box img", links); }, button: [4], insertImg: ["#FullPictureLoadMainImgBox", 3], customTitle: "article h1", category: "hcomic" }, { name: "野貓韓漫 閱讀頁", url: { e: ".homepage .logo", p: "/read/" }, imgs: ".module img", button: [4], insertImg: [".module", 2], autoDownload: [0], next: "//a[text()='下一章'][starts-with(@href,'/read/')]", prev: "//a[text()='上一章'][starts-with(@href,'/read/')]", customTitle: () => { let text = fn.attr("meta[name=keywords]", "content"); let textArr = text.split(",").map(t => t.trim()); let [, comicName, chapterName] = textArr; return comicName + " - " + chapterName; }, category: "hcomic" }, { name: "野貓韓漫 目錄頁", url: { e: ".module-play-list", p: "/m/" }, box: [".module-info", 2], imgs: () => { let links = fn.gau(".module-play-list a"); return fn.getImgA(".module img", links); }, button: [4], insertImg: ["#FullPictureLoadMainImgBox", 3], customTitle: ".module-info-heading h1", category: "hcomic" }, { name: "A漫 閱讀頁", 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: () => fn.gt("h1") + " - " + fn.gt("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: ["#FullPictureLoadMainImgBox", 3], customTitle: ".hl-dc-title", category: "hcomic" }, { name: "韩漫基地", host: ["hmjidi.com"], url: { t: "韩漫基地", p: "/chapter", s: "Id=" }, init: () => fn.waitVar("getCookie"), box: [".showimg"], imgs: ".showimg img", button: [4], insertImg: [ ["#FullPictureLoadMainImgBox", 0, ".showimg>img"], 2 ], autoDownload: [0], next: "a.next[href*='/chapter']", prev: "a.prev[href*='/chapter']", customTitle: ".showimg h1", category: "hcomic" }, { name: "韩漫基地 目錄頁", url: { t: "韩漫基地", p: "/comic", s: "Id=" }, box: [".chapter_list", 2], imgs: () => { let links = fn.gau("#dataList a"); return fn.getImgA(".showimg img", links); }, button: [4], insertImg: ["#FullPictureLoadMainImgBox", 3], customTitle: ".booktitle", 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: ["www.apexmh.com"], reg: /^https?:\/\/www\.apexmh\.com\/comic\/\d+\.html/, imgs: () => fn.getImg("#showimg img", fn.gt("//p[contains(text(),'图片数量') or contains(text(),'圖片數量')]").match(/\d+/)[0], 9), button: [4], insertImg: ["#showimg", 2], customTitle: "h1", 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: "顶通漫画", link: "https://喜悅.toptooncn.club/學習.html", url: { h: "toptoon", p: /^\/\w+\/\d+\.html$/, e: ".place" }, imgs: "#txtbox img", button: [4], insertImg: ["#txtbox", 2], autoDownload: [0], next: "a.nexturl.on", prev: "a.prevurl.on", customTitle: () => { let arr = fn.gt(".place").split(">").map(s => s.trim()); return arr[2] + " - " + arr[3]; }, hide: ".ads_plugin,.ad-top-info", category: "hcomic" }, { name: "色漫集", host: ["semanji.com"], reg: /^https?:\/\/semanji\.com\/\w+\/[^\.]+\.html/, imgs: ".post-content a", button: [4], insertImg: [".post-content", 2], customTitle: () => fn.title(" - 色漫集"), fancybox: { v: 3, css: false }, category: "hcomic" }, { name: "18H汉化漫画 介紹頁", host: ["manhua.sexbook.top", "18manga.top", "mt91.top", "kk4.top"], url: { e: "//ul[@class='nav-main']//a[text()='18H汉化漫画']", p: "/cont.php", s: "?id=" }, imgs: () => { let [max] = fn.gt("#td-Act+#td-Series").match(/\d+/); let [, dir, , ex] = fn.gu(".article-content a").match(/^(.+\/)(\d+)(\.\w+)$/); return fn.arr(max, (v, i) => dir + (i + 1) + ex); }, button: [4], insertImg: [ [".content", 0, ".article-content>a"], 2 ], endColor: "white", customTitle: () => fn.gt(".article-content>h3").split("|")[1], 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"], url: { e: "//ul[@class='nav-main']//a[text()='18H汉化漫画']", 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", 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" }, { host: ["porn-comic.biz", "slutporn-comic.lol", "wetporn-comic.lol", "groekporn-comic.click"], url: { t: "免費H漫畫同人志在綫閲讀", p: /^\/book\/\d+$/ }, imgs: () => { thumbnailSrcArray = fn.getImgSrcArr("section a[href*='/read/']>img"); return thumbnailSrcArray.map(e => e.replace(/&w=\d+&q=\d+$/, "&w=2048&q=75")); }, button: [4], insertImg: [ ["section:has(>a[href*='/read/'])", 2], 2, 2000 ], customTitle: "main h1", hide: "div:has(>[data-section=readDetailAppBanner])", referer: "src", 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: "漫画御殿", host: ["eromangabigdata.com"], reg: /^https?:\/\/eromangabigdata\.com\/\w+\/\d+\/\w\/[\w-_]+$/i, imgs: () => fn.gae("#imgwrap img").map(e => e.dataset.width ?? e.src), button: [4], insertImg: ["#imgwrap", 2], customTitle: "#pan span.pan", hide: "#chip", 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", "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", fetch: 1, 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(" - 污污漫畫"), fetch: 1, 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: "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)", 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: [ ["#FullPictureLoadMainImgBox", 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, 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; } else { return null; } }, prev: 1, 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; } else { return null; } }, prev: 1, 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']]", 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']]", customTitle: () => fn.title(" - Read Free Manga Online at Bato.To"), hide: ".max-w-screen-2xl:has(button.btn-info)", 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, customTitle: () => fn.title("Dynasty Reader » "), category: "comic" }, { name: "Hiperdex/MangaRead/LHTranslation/MANHUAUS.COM/Novelmic.com/Setsu Scans/ToonGod/HARIMANGA/mangamammy/Manga Online Team", url: { h: [ "hiperdex.com", "www.mangaread.org", "www.lhtranslation.net", "lhtranslation.net", "manhuaus.com", "novelmic.com", "setsuscans.com", "www.toongod.org", "manytoon.com", "harimanga.me", "mangamammy.ru", "mangaonlineteam.com", "lectormanga.top", "brmangas.top" ], p: /^\/(manga|comic|webtoon)\// }, imgs: ".wp-manga-chapter-img", button: [4], insertImg: [".reading-content", 2], autoDownload: [0], next: "a.next_page", prev: "a.prev_page", customTitle: "#chapter-heading", category: "comic" }, { name: "Disaster Scans", url: { h: ["disasterscans.com"] }, page: () => fn.clp("-chapter-"), SPA: () => _this.page() ? fn.waitEle(["section.container img[srcset]", "a[aria-description='next-button']"]) : false, observeURL: "gm", imgs: () => _this.page() ? fn.waitEle(["section.container img[srcset]"]).then(eles => fn.getImgSrcset(eles)) : [], capture: () => _this.imgs(), autoDownload: [0], next: () => _this.page() ? fn.waitEle("a[aria-description='next-button']", 10).then(e => isEle(e) && e?.pathname?.includes("-chapter-") ? e.pathname : null) : null, prev: "a[aria-description='previous-button']", customTitle: () => _this.page() ? fn.title(" - Disaster Scans") : null, category: "comic" }, { name: "Manhuaplus", url: { h: ["manhuaplus.org"], p: /^\/manga\/[\w-]+\/chapter/ }, init: () => fn.waitEle("#chapterContent img[src^=http]"), imgs: () => fn.gae("#chapterContent a.readImg"), button: [4], insertImg: ["#chapterContent", 2], autoDownload: [0], next: "a.nextBtn", prev: "a.prevBtn", customTitle: "h1", category: "comic" }, { name: "KaliScan", url: { h: "kaliscan.io", p: "/chapter" }, init: () => fn.waitEle(".chapter-image"), imgs: () => fn.gae(".chapter-image"), button: [4], insertImg: ["#chapter-images", 2], autoDownload: [0], next: "#btn-next", prev: "#btn-prev", customTitle: ".chapter-info h1", 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: 1, customTitle: () => fn.dt({ d: ["Read", "manga online for free"] }), hide: ".nav__pages,.nav__paginate", category: "comic" }, { name: "MangaFox", url: { h: ["mangafox.fun"] }, page: () => fn.clp("/chapter/"), wait: () => fn.showMsg(DL.str_04, 0).then(() => fn.waitEle("#select-chapter")).then(() => { let num = fn.clp().match(/[\d\.]+/g).at(-1); let s = `#mangareader img[src*='/${num}/']`; return fn.waitEle(s).then(() => fn.hideMsg()); }), json: () => { fn.showMsg(DL.str_05, 0); 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": siteJson.x }; let data = { query: `{chapter(x:mf01,slug:"${slug}",number:${number}){id,title,mangaID,number,slug,pages,manga{id,title,slug}}}`, }; return fetch("https://api.mghcdn.com/graphql", { 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: () => { if (!isAddAjaxHooker) { isAddAjaxHooker = true; const ajaxHooker = addAjaxHookerLibrary(); ajaxHooker.filter([{ url: "/graphql" }]); ajaxHooker.hook(request => (siteJson.x = request.headers["x-mhub-access"])); } if (_this.page()) return _this.wait().then(() => _this.json()); }, 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", customTitle: () => { if (!_this.page()) return null; let { manga: { title: mt }, title: ct } = siteJson; return mt + " - " + ct; }, category: "comic" }, { name: "Mangakakalot/MangaHub", url: { h: ["mangakakalot.fun", "mangahub.io"], }, page: () => fn.clp("/chapter/"), json: () => fn.showMsg(DL.str_05, 0).then(() => { let cArr = document.cookie.split(";").map(e => e.trim()); let cookieObj = {}; for (let c of cArr) { let [k, v] = c.split("="); cookieObj[k] = v; } let mhub_access = cookieObj.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:m01,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", 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"] }, imgs: ".carousel-item img", autoDownload: [0], next: "a#navbar-chapter-control-next", prev: "a#navbar-chapter-control-prev", customTitle: () => fn.ge("#chapter-info")?.textContent, category: "comic" }, { name: "MangaNato/MangaKakalot/MangaNelo", host: ["www.manganato.gg", "www.natomanga.com", "www.mangakakalot.gg", "www.nelomanga.com"], url: { t: ["MangaNato", "MangaKakalot", "MangaNelo"], 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", 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], next: () => { let next = fn.ge(".select-reading [selected]")?.previousElementSibling; return isEle(next) ? next.value : null; }, prev: 1, 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(),'Пред.')]", 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: 1, 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']", 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.fetchDoc(fn.clp()).then(dom => { let code = fn.gt("#__NEXT_DATA__", 1, dom); let json = JSON.parse(code); siteJson = json; return fn.showMsg(DL.str_04, 0).then(() => fn.waitEle("#chapter-image[src]", 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: "head", init: () => _this.page() ? _this.json() : void 0, imgs: () => { if (!_this.page() || !siteJson.host) return []; let srcs = siteJson.props.pageProps.fallbackData.chapter.content.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 mid = siteJson.props.pageProps.fallbackData.title.content.branches[0].id; let cid = siteJson.query.chapter; return fetch(`https://api.remanga.org/api/titles/chapters/?branch_id=${mid}&user_data=0`).then(res => res.json()).then(json => { let chapters = json.content.sort((a, b) => a.index - b.index); let index = chapters.findIndex(e => e.id == cid); let next = chapters[index + 1]; return isObject(next) ? fn.clp().replace(/\d+$/, next.id) : null; }); }, prev: 1, 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").then(() => fn.hideMsg())); }, imgs: () => { 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, customTitle: () => fn.gt("#app a .u8_vb") + " -" + fn.gt("#app a [data-media-down]"), category: "comic" }, { name: "МангаПоиск", url: { h: ["mangapoisk.live"] }, page: () => fn.clp("/chapter/"), 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.chapter.data; }).then(() => fn.hideMsg())), SPA: () => _this.page() ? true : (siteJson = {}) && false, observeURL: "nav", init: () => _this.page() ? _this.json() : void 0, imgs: () => _this.page() ? siteJson.pages.map(e => e.link) : [], capture: () => _this.imgs(), autoDownload: [0], next: () => _this.page() && ("nextChapter" in siteJson) ? siteJson.nextChapter.link : null, prev: 1, customTitle: () => _this.page() ? fn.gt("#page-content h1", 1, doc) : null, category: "comic" }, { name: "Weeb Central", url: { h: "weebcentral.com", p: "/chapters/" }, init: () => fn.waitEle("main section img[alt^=Page]").then(() => fn.createImgBox("section:has(img[alt^=Page])", 1)), imgs: () => fn.gae("main section img[alt^=Page]"), button: [4], insertImg: [ ["#FullPictureLoadMainImgBox", 0, "section:has(img[alt^=Page])"], 2 ], endColor: "white", autoDownload: [0], next: () => { let chapters_url = fn.attr("button[hx-get]", "hx-get"); return fn.fetchDoc(chapters_url).then(dom => { let button = fn.ge("#selected_chapter", dom); let next = button?.previousElementSibling; return next ? next.href : null; }); }, prev: 1, customTitle: () => fn.title(" | Weeb Central"), 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: [".items-center:has(>div[data-name='image-item'])", 2], autoDownload: [0], next: "//a[span[text()='Next Chapter']]", prev: "//a[span[text()='Prev Chapter']]", customTitle: () => fn.title(" - Share Any Manga on MangaPark"), category: "comic" }, { name: "Mangakakalot", host: ["ww8.mangakakalot.tv"], url: { h: "mangakakalot", p: "/chapter/" }, imgs: "#vungdoc img", button: [4], insertImg: ["#vungdoc", 2], autoDownload: [0], next: "//a[starts-with(text(),'NEXT')]", prev: "//a[starts-with(text(),'PREV')]", customTitle: ".info-top-chapter>h2", 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']", 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", }, imgs: ".reader-main img", button: [4], insertImg: [".reader-main", 2], endColor: "white", autoDownload: [0], next: "//a[text()='Next Chapter']", prev: "//a[text()='Pre chapter']", 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: "Komikcast", host: ["komikcast.cz"], url: { h: "komikcast", p: "/chapter/" }, imgs: ".main-reading-area img", button: [4], insertImg: [".main-reading-area", 2], endColor: "white", autoDownload: [0], next: ".nextprev>a[rel=next]", prev: ".nextprev>a[rel=prev]", customTitle: ".chapter_headpost>h1", hide: "center:has(>div):has(a)", category: "comic" }, { name: "Sen Manga", url: { h: ["raw.senmanga.com", "ero.senmanga.com"], p: /^\/[^\/]+\/[\d\.]+$/ }, imgs: () => { let links = [fn.url]; let [pageList] = fn.gae(".page-list"); let pages = fn.gae(".page-list option", pageList).length; if (pages > 1) { links = fn.arr(pages, (v, i) => i == 0 ? fn.url : fn.url + "/" + (i + 1)); } return fn.getImgA(".picture", links); }, button: [4], insertImg: [".reader", 2], insertImgAF: (parent) => { if (nextLink) { fn.addUrlHtml(nextLink, parent, 1, DL.str_143, 10); } fn.remove(".pager>.viewer,.nav-page"); }, autoDownload: [0], next: () => { let next = fn.ge(".custom-select option[selected]")?.previousElementSibling; return next ? fn.url.replace(/[\d\.]+$/, next.value) : null; }, prev: 1, customTitle: () => fn.title(" - Page 1 / Raw | Sen Manga"), hide: "h2:has(>br)", 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(json => fetch(`/api/title/${json.series.id}/chapters`).then(res => res.json()).then(chaptersJson => { Reflect.set(json, "chapters", chaptersJson.data); return json; })), 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 : [], button: [4], insertImg: [".reader", 2], insertImgAF: (parent) => { if (nextLink) { fn.addUrlHtml(nextLink, parent, 1, DL.str_143, 10); } }, 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) ? fn.dir(fn.clp()) + next.id : null; }, prev: 1, customTitle: () => _this.page() ? siteJson.series.title + " - " + siteJson.full_title : null, category: "comic" }, { name: "ReadComicOnline", host: ["readcomiconline.li"], url: { h: "readcomiconline.li", p: /^\/Comic\/[\w-]+\/(Issue|Full|Vol)/i, d: "pc" }, init: () => fn.waitEle("//script[contains(text(),'SetImage')]").then(() => fn.clearAllTimer()), box: ["#divMsg", 1], imgs: () => { let code = fn.gst("currImage"); let s = code.indexOf("SetImage()"); code = code.slice(s); let [keyText] = code.match(/\w+\(_\w+\[currImage\]\)/i); let [fnKey] = keyText.match(/^\w+/i); let [, arrKey] = keyText.match(/\((\w+)/i); let srcArr = _unsafeWindow[arrKey].map(e => _unsafeWindow[fnKey](e)); return srcArr; }, button: [4], insertImg: [ ["#FullPictureLoadMainImgBox", 0, "#divImage,#divMsg,div[id][style]:has(img[onload]),div:has(>div>iframe)"], 2 ], endColor: "white", insertImgAF: (parent) => { if (nextLink) { fn.addUrlHtml(nextLink, parent, 1, DL.str_143, 1); } }, autoDownload: [0], next: () => { let id = fn.getUSP("id"); let c_option = fn.gae("#selectEpisode>option").find(e => e.value.endsWith(id)); let next = c_option?.nextElementSibling; return next ? fn.dir(fn.lp) + next.value : null; }, prev: 1, customTitle: () => fn.title(/ - Read.+$/), fancybox: { blacklist: 1 }, gallery: 1, category: "comic" }, { name: "ReadComicOnline M", host: ["readcomiconline.li"], url: { h: "readcomiconline.li", p: /^\/Comic\/[\w-]+\/(Issue|Full|Vol)/i, d: "m" }, init: () => fn.waitEle("#divImage img").then(() => fn.clearAllTimer()), imgs: () => { let code = fn.gst("currImage"); let [, arrKey] = code.match(/(\w+)\[currImage\]/i); return _unsafeWindow[arrKey]; }, button: [4], insertImgBF: () => fn.createImgBox("#divImage", 1), insertImg: [ ["#FullPictureLoadMainImgBox", 0, "#divImage,#imgLoader"], 2 ], endColor: "white", insertImgAF: (parent) => { if (nextLink) { fn.addUrlHtml(nextLink, parent, 1, DL.str_143, 1); } }, autoDownload: [0], next: () => { let id = fn.getUSP("id"); let c_option = fn.gae(".selectEpisode>option").find(e => e.value.endsWith(id)); let next = c_option?.nextElementSibling; return next ? fn.dir(fn.lp) + next.value : null; }, prev: 1, customTitle: () => fn.title(/ - Read.+$/), fancybox: { blacklist: 1 }, category: "comic" }, { name: "TCB Scans", url: { h: "tcbscans.me", p: "/chapters/" }, imgs: ".items-center>picture>img", button: [4], insertImg: [".items-center:has(>picture)", 2], endColor: "white", autoDownload: [0], next: "//a[contains(text(),'Next')]", prev: "//a[contains(text(),'Prev')]", customTitle: ".container h1", 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']", customTitle: ".div-title-chapter h1", category: "comic" }, { name: "MangaFire", url: { h: ["mangafire.to"] }, page: () => fn.clp("/read/"), json: () => fn.fetchDoc(fn.clp()).then(dom => { let code = fn.gt("#syncData", 1, dom); let json = JSON.parse(code); siteJson = json; }), SPA: () => _this.page() ? true : (siteJson = {}) && false, observeURL: "head", init: () => _this.page() ? _this.json() : void 0, imgs: () => { if (!_this.page()) return []; fn.showMsg(DL.str_05, 0); let [, comic_id, chapter_number] = fn.clp().match(/(\w+)\/\w+\/chapter-(.+)$/i); let headers = new Headers({ "Accept": "application/json, text/javascript, */*; q=0.01", "X-Requested-With": "XMLHttpRequest", }); return fetch(`/ajax/read/${comic_id}/chapter/en`, { headers }).then(res => res.json()).then(json => { let tempDom = fn.doc(json.result.html); let chapter_id = fn.gae("li a", tempDom).find(a => a.dataset.number == chapter_number).dataset.id; return fetch(`/ajax/read/chapter/${chapter_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: () => _this.page() && isURL(siteJson.next_chapter_url) ? new URL(siteJson.next_chapter_url).pathname : null, customTitle: () => _this.page() ? fn.title(/ - Read Manga Online| \| Read Online on MangaFire|Manga, /g) : null, category: "comic" }, { name: "Top Manhua/Toonily/Manga-shi/ManhwaZ/Mangaclash/MANGAGG/Asura Scan", url: { h: ["manhuatop.org", "topmanhua.fan", "toonily.com", "manga-shi.com", "manhwaz.com", "toonclash.com", "mangagg.com", "asurascan.me"], p: ["/chapter", "/glava"], e: ".reading-content img" }, imgs: () => fn.gae(".reading-content img").filter(e => !e.closest("a[href*='/t.me/'],.banner")), 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: "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]", 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: () => { 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], next: () => { let chapters = fn.gae("#top_chapter_list option"); let c_chapter = chapters.find(e => e.value == fn.lp); let next = c_chapter?.nextElementSibling; return next ? next.value : null; }, prev: 1, 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']", 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']]]", 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(e => `https://meo.comick.pictures/${e.b2key}`) : [], capture: () => _this.imgs(), autoDownload: [0], next: () => _this.page() && siteJson?.next?.href ? siteJson.next.href : null, prev: 1, 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: [ ["#FullPictureLoadMainImgBox", 0, ".main-width>*:not(#FullPictureLoadMainImgBox,.chapter-info,center)"], 2 ], autoDownload: [0], next: "a.nextchap", prev: "a.prevchap", hide: "#teaser3", category: "comic" }, { name: "Realm Oasis/Night Scans/Terco Scans/Lua Scans/Drake Scans/Rizz Fables/TresDaos/Lectormiau/Mangagojo/Niraw/漫画ばんく", url: { h: [ "realmoasis.com", "nightsup.net", "tecnoxcomics.xyz", "tercofable.xyz", "luascans.com", "drakecomic.org", "rizzfables.com", "tresdaos.com", "zonamiau.com", "mangagojo.com", "rawkuma.net", "niraw.com", "mangakl.top", "mangaku.win", "phoenixmanga.com" ] }, init: () => fn.addMutationObserver(() => fn.remove("#radio_content,#teaserbottom")), imgs: "#readerarea img[class*='wp-image'],#readerarea .ts-main-image,#readerarea img[loading],#readerarea .chapter-img", button: [4], insertImg: ["#readerarea", 2], endColor: () => fn.ge(".darkmode") ? "white" : "black", autoDownload: [0], next: "a.ch-next-btn", prev: "a.ch-prev-btn", hide: ".ver-src.chapter,.blox,div[style]:has(>div>script)", customTitle: ".entry-title", 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]", customTitle: "h1.entry-title", category: "comic" }, { name: "NOVATO SCANS", //葡萄牙文 url: { h: "www.novatoscans.top", p: "capitulo" }, imgs: ".check-box img", button: [4], insertImg: [".check-box", 2], autoDownload: [0], next: "//a[span[text()='Next']]", prev: "//a[span[text()='Prev']]", customTitle: "h1", category: "comic" }, { name: "MangaToons", url: { h: "mangatoon.mobi", p: "/watch/", e: ".episode" }, 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", customTitle: () => fn.dt({ t: fn.gt(".title") + " - " + fn.gt(".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/']", 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.fetchDoc(fn.clp()).then(dom => { let code = fn.gt("#__NEXT_DATA__", 1, dom); let json = JSON.parse(code); siteJson = json.props.pageProps; }), page: () => fn.clp(/^\/series\/\w+\/\w+/), SPA: () => _this.page() ? true : (siteJson = {}) && false, observeURL: "nav", init: () => _this.page() ? _this.json() : void 0, imgs: () => { if (!_this.page()) return []; let cdn = "https://cdn.flamecomics.xyz/series"; let { chapter: { series_id, images, token, release_date, title, chapter_title, chapter } } = siteJson; apiCustomTitle = title + " - " + (chapter_title ?? "Chapter " + Number(chapter)); return Object.keys(images).map(i => `${cdn}/${series_id}/${token}/${images[i].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, hide: "div[class^='Radio_radio_content']", category: "comic" }, { name: "Voids Scans", url: { h: ["hivecomic.com"] }, 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); code = code.replaceAll("\\", ""); return fn.TextToArray(code, '"images":').map(e => e.url); }, capture: () => _this.imgs(), autoDownload: [0], next: "//a[button[div[p[text()='Next']]]]", prev: "//a[button[div[p[text()='Prev']]]]", customTitle: () => _this.page() ? fn.title(" - Void Scans hivetoon", 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]", customTitle: () => fn.dt({ d: /page 1.+$/ }), category: "comic" }, { name: "ReadComicsOnline", url: { h: "readcomicsonline.ru", p: "/comic/" }, imgs: "#all img", button: [4], insertImg: [".imagecnt", 2], autoDownload: [0], next: () => _unsafeWindow.next_chapter ? _unsafeWindow.next_chapter : null, prev: 1, customTitle: () => fn.dt({ d: " - Page 1" }), category: "comic" }, { name: "ReaperScans/Omega Scans", host: ["www.reaperscans.com", "www.omegascans.org"], url: { h: [/^(www\.)?reaperscans\.com$/, /^(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)", customTitle: () => _this.page() ? fn.dt({ d: [" - Reaper Scans", " - Omega Scans"] }) : null, category: "comic" }, { name: "Vortex Scans", url: { h: /^(www\.)?vortexscans\.org$/, }, page: () => fn.clp("/chapter"), SPA: () => _this.page(), observeURL: "gm", init: () => _this.page() ? fn.waitEle(".image-container img") : void 0, imgs: () => _this.page() ? fn.gae(".image-container img") : [], capture: () => _this.imgs(), autoDownload: [0], next: "//a[button[div[p[text()='Next']]]][starts-with(@href,'/series/')]", prev: "//a[button[div[p[text()='Prev']]]][starts-with(@href,'/series/')]", customTitle: () => _this.page() ? fn.dt({ d: " - Vortex 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.at(0); 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, customTitle: () => _this.page() ? fn.waitEle(".v-breadcrumbs").then(e => fn.dt({ t: fn.gt(e), d: "Comics" })) : null, 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], next: () => { let next = fn.ge("#ChapList option:checked+option"); return next ? _unsafeWindow.pageController._containers.chapterUrl.replace("chapterNumber", next.innerText.replace(".", "-")).replace("identification", next.value) : null; }, prev: 1, 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], next: () => { let chapters = fn.gae("#c_list option"); let c_chapter = chapters.find(e => e.value == _unsafeWindow.url_lector); let next = c_chapter?.previousElementSibling; return next ? next.value : null; }, prev: 1, customTitle: () => fn.dt({ d: " — Manga en línea | MangaOni" }), category: "comic" }, { name: "Big raw", url: { h: "www.rawbig.com", p: /^\/comic-\d+\/\d+\.html$/ }, imgs: ".chapter-imgs img", button: [4], insertImg: [".chapter-imgs", 2], endColor: "white", autoDownload: [0], next: "#next-chapter[href$=html]", prev: "#prev-chapter[href$=html]", customTitle: ".chapter-title", category: "comic" }, { name: "L漫画", url: { h: "www.lmanga.com", p: /^\/comic-\d+\/\d+\.html$/ }, init: () => fn.waitVar("nextChap").then(() => _unsafeWindow.jQuery(document).off()), imgs: ".ImageGallery img", button: [4], insertImg: [".ImageGallery", 2], endColor: "white", autoDownload: [0], next: "#next-chapter[href$=html]", prev: "#prev-chapter[href$=html]", customTitle: () => fn.title(/ - 異世界漫画.+$/), category: "comic" }, { name: "Fire Manga", url: { h: "www.firemanga.com", p: /^\/comic-\d+\/\d+\.html$/ }, imgs: "#chapter_boxImages img", button: [4], insertImg: ["#chapter_boxImages", 2], endColor: "white", autoDownload: [0], next: "a[href$=html]:has(>i.ti-angle-right)", prev: "a[href$=html]:has(>i.ti-angle-left)", customTitle: ".breadcrumb", category: "comic" }, { name: "漫画スイカ Manga Suika", url: { h: "www.mangasuika.com", p: /^\/comic-\d+\/\d+\.html$/ }, imgs: ".reading-detail img", button: [4], insertImg: [".reading-detail", 2], endColor: "white", autoDownload: [0], next: "a.next[href$=html]", prev: "a.prev[href$=html]", customTitle: "h1.txt-primary", category: "comic" }, { name: "Manga Raw", host: ["klmanga.ax", "klmanga.my"], url: { t: "Manga Raw", st: ["var zing", "chapter_id"] }, box: [".manga_nav_footer", 1], imgs: async () => { 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_a: json.nonce_a, action: "z_do_ajax", _action: "decode_images_100", 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]; }, button: [4], insertImg: ["#FullPictureLoadMainImgBox", 2], insertImgAF: () => fn.hideEle(".br-content,div:has(>.go-open-popup-wrap)"), autoDownload: [0], next: ".nav-links a.next_page", prev: ".nav-links a.prev_page", customTitle: () => fn.dt({ d: ["(Raw – Free)", " - Manga Raw"] }), category: "comic" }, { name: "KLManga", host: ["klz9.com", "jestful.net", "hachiraw.win", "cmoa1.top"], url: { t: [" - KL", " - 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: ["#FullPictureLoadMainImgBox", 2], insertImgAF: () => fn.hideEle("#list-imga"), endColor: "white", autoDownload: [0], next: () => { let cc = fn.ge(".select-chapter option[selected]"); let next = cc?.previousElementSibling; return next ? fn.dir(fn.url) + next.value : null; }, prev: 1, customTitle: () => fn.dt({ s: ".breadcrumb", d: "Home Manga List" }), category: "comic" }, { name: "RawKuro", url: { h: ["rawkuro.net", "manga1000.top", "kakuyomu.in", "mangakoma01.net"], st: "CHAPTER_ID" }, box: ["#chapterContent", 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); 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")); }); }, button: [4], insertImg: ["#FullPictureLoadMainImgBox", 2], insertImgAF: () => fn.hideEle("#chapterContent"), endColor: "white", autoDownload: [0], next: "a.nextBtn[href*='/']", prev: "a.prevBtn[href*='/']", customTitle: "main h1", category: "comic" }, { name: "RawOtaku/JManga/Momon-Ga", host: ["rawotaku.org", "jmanga.sh", "momon-ga.org", "jpraw.xyz"], url: { t: ["RawOtaku", "jmanga", "Momon-Ga", "MomonGa", "JP Raw"], h: [/^rawotaku/, /^jmanga/, /^momon-ga/, /^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", 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: 1, 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 }; }); }, 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.chapterSiguientes : null, prev: 1, 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: [ ["#FullPictureLoadMainImgBox", 0, "#imgs"], 2 ], endColor: "white", autoDownload: [0], next: "a.nav_button.next[href^=http]", prev: "a.nav_button.prev[href^=http]", customTitle: () => fn.dt({ s: ".uk-breadcrumb", d: "Home" }), category: "comic" }, { name: "ManhuaPlus", url: { h: ["www.manhuaplus.com", "manhuaplus.com"], p: "/chapter-" }, imgs: ".wp-block-gallery img", button: [4], insertImg: [".wp-block-gallery", 2], autoDownload: [0], next: ".nav-next >a", prev: ".nav-previous>a", customTitle: "#chapter-heading", category: "comic" }, { name: "Ikigai Mangas - EltaNews/Ikigai Mangas - Ajaco", url: { h: ["visorikigai.eltanews.com", "visorikigai.ajaco.net"], p: "/capitulo/" }, init: () => fn.waitEle("img[loading][alt^=Page]"), box: ["div.w-full:has(div>img[loading][alt^=Page])", 1], imgs: () => fn.gae("img[loading][alt^=Page]"), button: [4], insertImg: [ ["#FullPictureLoadMainImgBox", 0, "div.w-full:has(div>img[loading][alt^=Page])"], 2 ], autoDownload: [0], next: "//a[span[text()='Siguiente']]", prev: "//a[span[text()='Anterior']]", customTitle: "ul:has(.line-clamp-1)", hide: "div[id]:has(.adclose)", category: "comic" }, { name: "KuManga", url: { h: "www.kumanga.com", p: "/manga/leer/" }, init: () => fn.waitEle("#lector img").then(() => fn.clearAllTimer(3)), imgs: () => _unsafeWindow.pUrl.map(e => e.imgURL), button: [4], insertImg: ["#lector", 2], autoDownload: [0], next: () => { let id = fn.lp.split("/").at(-1); let control = fn.gae("select.form-control").at(1); let chapters = fn.gae("option", control); let c_chapter = chapters.find(e => e.value == id); let next = c_chapter?.nextElementSibling; return next ? "/manga/leer/" + next.value : null; }, prev: 1, customTitle: ".container h2", category: "comic" }, { name: "嗨皮漫畫閱讀", enable: 0, url: { h: ["m.happymh.com", "hihimanga.com"], p: "/mangaread/", ee: ".captcha-area" }, 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, { "headers": { "accept": "application/json, text/plain, */*", "x-requested-id": new Date().getTime(), "x-requested-with": "XMLHttpRequest" } }).then(res => res.json()); }, init: async () => { let json = await _this.fetchJson(); debug("\n此頁JSON資料\n", json); siteJson = json; fn.picPreload(json.data.scans.map(e => e.url), json.data.manga_name + " - " + json.data.chapter_name); await fn.waitEle("footer a[href^='/mangaread/'],footer a[href^='/readMore/']"); }, imgs: () => { if (siteJson.status == 0) { let srcs = siteJson.data.scans.map(e => e.url); if (srcs.length == 2 && ("next_cid" in siteJson.data)) { srcs = srcs.slice(0, -1); } if (srcs.length > 2 && ("next_cid" in siteJson.data)) { srcs = srcs.slice(0, -2); } return srcs; } else { return []; } }, referrerpolicy: "origin", button: [4], insertImg: ["//article[div[contains(@id,'imageLoader')]]", 3], autoDownload: [0], next: "//a[text()='下一话' or text()='下一話'][starts-with(@href,'/mangaread/')]", prev: "//a[text()='上一话' or text()='上一話'][starts-with(@href,'/mangaread/')]", customTitle: () => siteJson.data.manga_name + " - " + siteJson.data.chapter_name, preloadNext: async () => { let json = await _this.fetchJson(nextLink); json.status == 0 ? fn.picPreload(json.data.scans.map(e => e.url), json.data.manga_name + " - " + json.data.chapter_name, "next") : debug("預讀下一頁失敗"); }, category: "comic" }, { name: "COLAMANHUA", //方向鍵上一章下一章、反反偵錯,下載需先手動觸發全部載入圖片,圖址如為blob函式會使用到canvas需要繪製過程會有點卡。 url: { h: "www.colamanga.com", p: /^\/manga-.+\.html$/ }, init: () => { fn.clearAllTimer(1); if (autoScrollAllElement === 1) _this.scrollEle(); }, imgs: async () => { if (options.autoDownload == 1 || options.shadowGallery == 1 || options.mobileGallery == 1) { await _this.scrollEle(); } return fn.ge(".mh_comicpic img[src^=blob]") ? fn.imgBlobUrlArr(".mh_comicpic img[src^=blob]") : fn.gae(".mh_comicpic img[src]"); }, scrollEle: () => fn.aotoScrollEles({ ele: ".mh_comicpic", cb: (ele) => isEle(fn.ge("img[src]", ele)), time: 10000, top: 1, end: ".mh_footpager", end_time: 3000 }), autoDownload: [0], next: "//a[text()='下一章']", prev: "//a[text()='上一章']", customTitle: () => fn.title(" COLAMANGA", 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: [ ["#FullPictureLoadMainImgBox", 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')]", 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')]", 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')]", 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()='上一章']", 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()='上一章']", 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: ["www.dm5.com", "m.dm5.com", "www.dm5.cn", "m.dm5.cn", "en.dm5.com", "cnc.dm5.com", "hk.dm5.com", "www.1kkk.com", "m.1kkk.com", "tel.1kkk.com", "en.1kkk.com", "cnc.1kkk.com", "hk.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='上一章']]", 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/.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", getData: async () => { await fn.delay(500, 0); await fn.wait((dom, win) => win?.__NUXT__?.data?.getChapters && win?.__NUXT__?.data?.getCationDetails); let { chapter_order, title: chapterName, page_url: srcs } = _unsafeWindow.__NUXT__.data.getChapters.data.chapterInfo; let { title: comicName, chapterList } = _unsafeWindow.__NUXT__.data.getCationDetails.data.comicInfo; siteJson = { srcs, chapter_order, comicName, chapterName, chapterList: chapterList[0].data.sort((a, b) => a.chapter_order - b.chapter_order) } debug("\n此頁JSON資料\n", siteJson); apiCustomTitle = siteJson.comicName + " - " + siteJson.chapterName; let index = siteJson.chapterList.findIndex(e => e.chapter_order == siteJson.chapter_order); let next = siteJson.chapterList[index + 1]; if (isObject(next)) { nextLink = fn.dir(fn.dlp()) + next.chapter_id; } }, init: () => _this.page() ? _this.getData() : void 0, imgs: () => siteJson.srcs, autoDownload: [0], category: "comic" }, { name: "再漫画M", url: { h: "m.zaimanhua.com", d: "m" }, page: () => fn.clp("/pages/comic/page"), json: () => { 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(`https://v4api.zaimanhua.com/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(`https://v4api.zaimanhua.com/app/v1/comic/detail/${comic_id}?_v=15`).then(res => res.json()).then(json => { let { chapters, title: comic_title } = json.data.data; siteJson.comic_title = comic_title; siteJson.chapters = chapters[0].data.sort((a, b) => a.chapter_order - b.chapter_order); }); return Promise.all([res_a, res_b]); }, 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; }, 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], next: () => { let next = fn.ge("//select[@data-kind='publication']/option[@selected]/preceding-sibling::option[1]"); return next ? next.value : null; }, prev: 1, 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: ["#FullPictureLoadMainImgBox", 2], insertImgBF: () => fn.waitEle("#manga img[src*=hamreus]"), insertImgAF: () => fn.css("#manga{display:none!important;}"), autoDownload: [0], next: () => siteJson.nextId == 0 ? null : fn.ge("#mangaTitle a").href + siteJson.nextId + ".html", prev: "//a[text()='上一章']", 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()='上一章']", 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, 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 [, chapterId] = fn.clp().match(/chapter\/(\d+)\/images/); siteJson.chapterId = 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()).then(json => (siteJson.images = json.data.imagesByChapterId)); if ("chapters" in siteJson) return res_a.then(() => fn.hideMsg()); let [, mhId] = fn.clp().match(/comic\/(\d+)/); siteJson.mhId = mhId; 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()).then(json => (siteJson.chapters = json.data.chaptersByComicId)); return Promise.all([res_a, res_b]).then(() => 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 chapters = siteJson.chapters; let index = chapters.findIndex(e => e.id == siteJson.chapterId); let next = chapters[index + 1]; return isObject(next) ? fn.clp().replace(siteJson.chapterId, next.id) : null; }, prev: 1, 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]; }, fetch: 1, 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", 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", 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: "古风漫画网", host: ["www.gufengmh.com", "m.gufengmh.com", "www.gufengmh9.com", "m.gufengmh9.com"], url: { h: "gufengmh", p: /^\/manhua\/\w+\/\d+\.html/, i: 0 }, init: () => { fn.run("$(document).off() && $('#images').off()"); return fetch("/js/config.js").then(res => res.text()).then(text => { let domain = String(fn.TextToArray(text, "domain")); siteJson.domain = domain; }); }, box: ["#images", 2], imgs: (dom = document) => { let code = fn.gst("chapterImages", dom); let chapterImages = fn.TextToArray(code, "chapterImages"); let chapterPath = fn.textVar(code, "chapterPath"); return chapterImages.map(e => siteJson.domain + "/" + chapterPath + e); }, button: [4], insertImg: [ ["#FullPictureLoadMainImgBox", 0, "#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); 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[contains(text(),'上一章')]", customTitle: (dom = document) => { if (/^https?:\/\/www/.test(siteUrl)) { return fn.gt(".title h1", 1, dom) + " - " + fn.gt(".title h2", 1, dom); } else { let code = fn.gst("SinMH.initChapter", dom); let [, chapterName, , comicName, ] = code.match(/SinMH.initChapter\(([^\)]+)\)/)[1].replaceAll('"', "").split(","); return comicName + " - " + chapterName; } }, preloadNext: true, css: "#action li{width:50%!important}", hide: ".nav-pagination,.pageSelect,.nav-pagination,.img_land_prev,.img_land_next,#action li:nth-child(2),#action li:nth-child(3),.control_bottom~*,.chapter-view~*:not(.footer,[id^='Full'],[class^='Full'],[id^='pv-'],[class^='pv-'],[id^='pagetual'],[class^='pagetual'],#comicRead,#fab[class^=fancybox]),.img_info", infiniteScroll: true, category: "comic" }, { name: "古风漫画网 自動翻頁", url: { h: "gufengmh", p: /^\/manhua\/\w+\/\d+\.html/, i: 1 }, getSrcs: (dom) => { let code = fn.gst("chapterImages", dom); let cImages = fn.TextToArray(code, "chapterImages"); let cPath = fn.textVar(code, "chapterPath"); return cImages.map(e => siteJson.domain + "/" + cPath + e); }, getImgs: (dom = document) => { let srcs = _this.getSrcs(dom); return fn.createImgArray(srcs); }, init: async () => { await fetch("/js/config.js").then(res => res.text()).then(text => { let domain = String(fn.TextToArray(text, "domain")); siteJson.domain = domain; }); let code = fn.gst("comicUrl", doc); let comicUrl = fn.textVar(code, "comicUrl"); await fn.fetchDoc(new URL(comicUrl).pathname).then(dom => { let chapters = fn.gau("ul[id^=chapter-list] a", dom); if (isM) { chapters = chapters.reverse(); } siteJson.chapters = chapters; }); fn.run("$(document).off() && $('#images').off()"); fn.remove("#skin"); let tE = fn.createImgBox("#images", 2); fn.remove("#images"); let imgs = _this.getImgs(); fragment.append(...imgs); tE.append(fragment); await fn.lazyload(); }, autoPager: { script: "//script[contains(text(),'chapterImages')]", ele: (dom) => _this.getImgs(dom), pos: ["#FullPictureLoadMainImgBox", 0], observer: "#FullPictureLoadMainImgBox>img", next: (dom, r = 1) => { let chapters = siteJson.chapters; let index = chapters.findIndex(url => url.includes((nextLink ?? fn.lp).match(/\d+/g).at(-1))); let next = chapters[index + 1]; return isString(next) ? next : null; if (next) { return next; } else { if (/^m\./.test(fn.lh) && r === 1) { let n = fn.ge("//a[text()='下一章']"); n.href = fn.lp.replace(/\d+\.html$/, ""); n.innerText = "返回目录"; } return null; } }, re: ".title,.BarTit", title: (dom) => { if (/^https?:\/\/www/.test(siteUrl)) { return fn.gt(".title>h1>a", 1, dom) + " - " + fn.gt(".title>h2", 1, dom); } else { let code = fn.gst("SinMH.initChapter", dom); let [, chapterName] = code.match(/SinMH.initChapter\(([^\)]+)\)/)[1].replaceAll('"', "").split(","); return chapterName; } }, hide: ".comic-comment,.chapter-content+.imgBox", preloadNextPage: 1 }, css: "#action li{width:50%!important}", hide: ".nav-pagination,.pageSelect,.nav-pagination,.img_land_prev,.img_land_next,#action li:nth-child(2),#action li:nth-child(3),.control_bottom~*,.chapter-view~*:not(.footer,[id^='Full'],[class^='Full'],[id^='pv-'],[class^='pv-'],[id^='pagetual'],[class^='pagetual'],#comicRead,#fab,[class^=fancybox]),.img_info", 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; }); return Promise.all([res_a, res_b]).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: () => 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))); let next = chapters[index + 1]; return isString(next) ? next : null; }), prev: 1, 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: () => fn.fetchDoc(fn.url).then(dom => (doc = dom)).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 chapterImageHost = fn.textVar(code, "chapterImageHost"); return chapterImages.map(e => e.startsWith("http") ? e : chapterImageHost + 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); 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("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: [ ["#FullPictureLoadMainImgBox", 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", 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(), 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 => images_domain + e); }, button: [4], insertImg: ["#FullPictureLoadMainImgBox", 2], endColor: "white", autoDownload: [0], next: "a.j-chapter-next[href$=html]", prev: "a.j-chapter-prev[href$=html]", 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 => 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.obq8.com", "comics.veryim.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\.obq8\.com\/index\.php\/chapter-\d+.html$/i, /^https?:\/\/comics\.veryim\.com\/\w+\/\d+\/\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: "新新漫画", host: ["www.77mh.nl", "m.77mh.nl", "www.77mh.xyz", "m.77mh.xyz", "www.77mh.me", "m.77mh.me"], enable: 0, url: { h: ".77mh.", p: /^\/\d+\/\d+\.html/ }, init: async () => await fn.waitVar("msg"), imgs: async () => { let status; if (fn.ge(".FullPictureLoadImage")) { status = 200; } else { let src = fn.attr("#comicImg img,.mg-co img", "src"); status = await fn.xhrHEAD(src).then(res => res.status); } return status === 200 ? _unsafeWindow.msg.split("|").map(e => fn.lh.includes("m.77mh") ? _unsafeWindow.ImgSvrList + e : _unsafeWindow.img_qianz + e) : []; }, button: [4], insertImg: ["#comicImg,.mg-co", 2], insertImgAF: () => { if (fn.lh.includes("m.77mh")) { let p = fn.ge(".page_num"); let m = fn.ge(".mg-co"); p ? insertAfter(m, p.cloneNode(true)) : null; let selectors = [".pagelist", "//div[div[@style and a[img[@width]]]]"]; fn.remove(selectors); } else { let str = "try{$(document).unbind('keydown');$(document).unbind('keyup')}catch(e){}"; new Function(str)(); let p = fn.ge("#pnpage"); let m = fn.ge("#main"); p ? insertAfter(m, p.cloneNode(true)) : null; let selectors = [".qrcode_div", "#bdcotopnew", "#main>*:not(#comicImg)"]; fn.remove(selectors); } }, autoDownload: [0], next: () => { const { nextLink_b } = _unsafeWindow; return nextLink_b == "" ? null : location.origin + nextLink_b; }, prev: "//a[contains(text(),'上一章')]", customTitle: (dom = document) => fn.title(" - ", 3, dom), preloadNext: async (nextDoc, obj) => { let code = fn.gst("eval", nextDoc); fn.script(code, 0, 1); fn.picPreload(await obj.imgs(), obj.customTitle(nextDoc), "next"); }, category: "comic" }, { name: "漫漫聚/KuKu动漫", url: { h: [ "www.manmanju.cc", "a.manmanju.cc", "b.manmanju.cc", "manhua.dididm.cc", "a.ikukudm.cc", "b.ikukudm.cc" ], p: /^\/comiclist\/\d+\/\d+\/1\.htm$/, i: 0 }, include: "td img", cors: true, comicListUrl: () => `/comiclist/${siteUrl.split("/")[4]}/index.htm`, imgs: () => fn.getKukudmSrc(), button: [4], insertImg: ["//td[input]", 2], insertImgAF: async () => { let cUrl = _this.comicListUrl(); if (nextLink) { fn.addUrlHtml(nextLink, "body", 2); fn.addUrlHtml(cUrl, "body", 2, "目錄"); } else { fn.addUrlHtml(cUrl, "body", 2, "目錄"); fn.addUrlHtml(location.origin, "body", 2, "首頁"); } }, autoDownload: [0], next: () => { let chapterId = siteUrl.split("/")[5]; let host = 1; if (/^a\./.test(fn.lh)) { host = 2; } else if (/^b\./.test(fn.lh)) { host = 3; } let nextXPath = `//dd[a[contains(@href,'${chapterId}')]]/following-sibling::dd[1]/a[${host}]`; return fn.xhrDoc(_this.comicListUrl()).then(dom => { let next = fn.ge(nextXPath, dom, dom); return next ? next.href : null; }); }, prev: 1, preloadNext: async (nextDoc, obj) => fn.picPreload(await fn.getKukudmSrc(nextLink, nextDoc, 0), nextDoc.title, "next"), css: "body{background-image:unset}body>table:nth-child(2),body>table:nth-child(2)>tbody>tr>td{width:100%!important;}body{scrollbar-width:none;-ms-overflow-style:none;overflow-x:hidden;overflow-y:auto}", hide: "body>table:nth-child(1),body>table:nth-child(3)", infiniteScroll: true, category: "comic" }, { name: "漫漫聚/KuKu动漫 自動翻頁", url: { h: [ "www.manmanju.cc", "a.manmanju.cc", "b.manmanju.cc", "manhua.dididm.cc", "a.ikukudm.cc", "b.ikukudm.cc" ], p: /^\/comiclist\/\d+\/\d+\/1\.htm$/, i: 1 }, include: "td img", cors: true, comicListUrl: () => `/comiclist/${siteUrl.split("/")[4]}/index.htm`, init: async () => { fn.showMsg(DL.str_135, 0); await fn.getKukudmSrc(siteUrl, document, 0).then(srcs => fn.createImgArray(srcs)).then(async imgs => { let tE = fn.ge("//td[input]"); tE.innerHTML = ""; fragment.append(...imgs); tE.append(fragment); fn.hideMsg(); await fn.lazyload(); }); let cUrl = _this.comicListUrl(); fn.addUrlHtml(cUrl, "body", 2, "目錄"); fn.addUrlHtml(location.origin, "body", 2, "首頁"); }, autoPager: { ele: (dom) => fn.getKukudmSrc(nextLink, dom, 0).then(srcs => fn.createImgArray(srcs)), pos: ["//td[img]", 0], observer: "//td[img]/img", next: () => { let chapterId = (nextLink ?? siteUrl).split("/")[5]; let host = 1; if (/^a\./.test(fn.lh)) { host = 2; } else if (/^b\./.test(fn.lh)) { host = 3; } let nextXPath = `//dd[a[contains(@href,'${chapterId}')]]/following-sibling::dd[1]/a[${host}]`; return fn.xhrDoc(_this.comicListUrl()).then(dom => { let next = fn.ge(nextXPath, dom, dom); return next ? next.href : null; }); }, stop: (dom) => !fn.ge("//td[input]//img", dom), preloadNextPage: async (dom) => { let next = await _this.autoPager.next(); if (!!next) { fn.xhrDoc(next).then(async nextDoc => { let srcs = await fn.getKukudmSrc(next, nextDoc, 0); fn.picPreload(srcs, nextDoc.title, "next"); }); } } }, css: "body{background-image:unset}body>table:nth-child(2),body>table:nth-child(2)>tbody>tr>td{width:100%!important;}body{scrollbar-width:none;-ms-overflow-style:none;overflow-x:hidden;overflow-y:auto}", hide: "body>table:nth-child(1),body>table:nth-child(3)", category: "comic autoPager" }, { name: "漫漫聚M/KuKu动漫M", url: { h: [ "m.manmanju.cc", "s1.m.manmanju.cc", "s2.m.manmanju.cc", "s3.m.manmanju.cc", "m.dididm.cc", "wap.dididm.cc", "s1.wap.ikukudm.cc", "s2.wap.ikukudm.cc", "s3.wap.ikukudm.cc" ], p: /^\/comiclist\/\d+\/\d+\/1\.htm$/, i: 0 }, include: ".classBox img,.imgBox", cors: true, init: () => fn.remove("//center[iframe]"), imgs: () => fn.getKukudmSrc(), button: [4], insertImg: [".imgBox", 2], insertImgAF: async () => { fn.remove("//a[img[not(@class='FullPictureLoadImage')]] | //ul[center[li]]"); fn.remove(".bottom .subNav~div[style*=height],.bottom .pageLine,.bottom .subNav"); let nav = fn.ge("ul.subNav").cloneNode(true); let tE = fn.ge("div.bottom"); insertBefore(tE, nav); await fn.remove("meta[name=viewport]"); const meta = document.createElement("meta"); meta.name = "viewport"; meta.content = "width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=2.0,user-scalable=no"; document.head.append(meta); if (nextLink) fn.addUrlHtml(nextLink, ".bottom", 0); }, autoDownload: [0], next: () => { let comicListUrl = fn.gu(".subNav a"); let chapterId = siteUrl.split("/")[5]; let nextXPath = `//li[a[contains(@href,'${chapterId}')]]/preceding-sibling::li[1]/a`; return fn.xhrDoc(comicListUrl).then(dom => { let next = fn.ge(nextXPath, dom, dom); return next ? next.href : null; }); }, prev: 1, customTitle: () => fn.title("在线", 1), preloadNext: async (nextDoc, obj) => fn.picPreload(await fn.getKukudmSrc(nextLink, nextDoc, 0), nextDoc.title.split("在线")[0], "next"), css: ".imgBox{margin-bottom:0px!important}.subNav{border-top:1px solid #dcdcde}body{scrollbar-width:none;overflow-x:hidden;overflow-y:auto}", infiniteScroll: true, category: "comic" }, { name: "漫漫聚/KuKu动漫M 404", url: { h: [ "m.manmanju.cc", "s1.m.manmanju.cc", "s2.m.manmanju.cc", "s3.m.manmanju.cc", "m.dididm.cc", "wap.dididm.cc", "s1.wap.ikukudm.cc", "s2.wap.ikukudm.cc", "s3.wap.ikukudm.cc" ], p: /^\/comiclist\/\d+\/\d+\/1\.htm$/, e: [ "td img", "iframe[src='/top.htm']" ], i: 0 }, cors: true, comicListUrl: () => `/comiclist/${siteUrl.split("/")[4]}/index.htm`, imgs: () => fn.getKukudmSrc(), button: [4], insertImg: ["//td[input]", 2], insertImgAF: async () => { let cUrl = _this.comicListUrl(); if (nextLink) { fn.addUrlHtml(nextLink, "body", 2); fn.addUrlHtml(cUrl, "body", 2, "目錄"); } else { fn.addUrlHtml(cUrl, "body", 2, "目錄"); fn.addUrlHtml(location.origin, "body", 2, "首頁"); } }, autoDownload: [0], next: () => { let chapterId = siteUrl.split("/")[5]; let nextXPath = `//li[a[contains(@href,'${chapterId}')]]/preceding-sibling::li[1]/a`; return fn.xhrDoc(_this.comicListUrl()).then(dom => { let next = fn.ge(nextXPath, dom, dom); return next ? next.href : null; }); }, prev: 1, preloadNext: async (nextDoc, obj) => fn.picPreload(await fn.getKukudmSrc(nextLink, nextDoc, 0), nextDoc.title.split("在线")[0], "next"), css: "body{background-image:unset}body>table:nth-child(2),body>table:nth-child(2)>tbody>tr>td{width:100%!important;}body{scrollbar-width:none;-ms-overflow-style:none;overflow-x:hidden;overflow-y:auto}", hide: "body>table:nth-child(1),body>table:nth-child(3)", infiniteScroll: true, category: "comic" }, { name: "漫漫聚M/KuKu动漫M 自動翻頁", url: { h: [ "m.manmanju.cc", "s1.m.manmanju.cc", "s2.m.manmanju.cc", "s3.m.manmanju.cc", "m.dididm.cc", "wap.dididm.cc", "s1.wap.ikukudm.cc", "s2.wap.ikukudm.cc", "s3.wap.ikukudm.cc" ], p: /^\/comiclist\/\d+\/\d+\/1\.htm$/, i: 1 }, include: ".classBox img,.imgBox", cors: true, init: async () => { fn.remove("//center[iframe] | //a[img] | //ul[center[li[@class='txtA']]]"); fn.showMsg(DL.str_135, 0); await fn.getKukudmSrc(siteUrl, document, 0).then(srcs => fn.createImgArray(srcs)).then(async imgs => { let tE = fn.ge(".imgBox"); tE.innerHTML = ""; fragment.append(...imgs); tE.append(fragment); fn.hideMsg(); await fn.lazyload(); }); fn.remove(".bottom .subNav~div[style*=height],.bottom .pageLine,.bottom .subNav"); let nav = fn.ge("ul.subNav").cloneNode(true); let tE = fn.ge("div.bottom"); insertBefore(tE, nav); await fn.remove("meta[name=viewport]"); const meta = document.createElement("meta"); meta.name = "viewport"; meta.content = "width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=2.0,user-scalable=no"; document.head.append(meta); }, autoPager: { ele: (dom) => fn.getKukudmSrc(nextLink, dom, 0).then(srcs => fn.createImgArray(srcs)), pos: [".imgBox", 0], observer: ".imgBox>img", next: () => { let comicListUrl = fn.gu(".subNav a"); let chapterId = (nextLink ?? siteUrl).split("/")[5]; let nextXPath = `//li[a[contains(@href,'${chapterId}')]]/preceding-sibling::li[1]/a`; return fn.xhrDoc(comicListUrl).then(dom => { let next = fn.ge(nextXPath, dom, dom); return next ? next.href : null; }); }, title: (dom) => { let text = dom.title.replace(/在线漫画.+$/, ""); if (isM) { return text.split(" ").at(-1); } else { return text; } }, preloadNextPage: async (dom) => { let next = await _this.autoPager.next(); if (!!next) { fn.xhrDoc(next).then(async nextDoc => { let srcs = await fn.getKukudmSrc(next, nextDoc, 0); let text = _this.autoPager.title(nextDoc); fn.picPreload(srcs, text, "next"); }); } } }, css: ".imgBox{margin-bottom:0px!important}.subNav{border-top:1px solid #dcdcde}body{scrollbar-width:none;overflow-x:hidden;overflow-y:auto}", category: "comic autoPager" }, { name: "大树漫画/世伦漫画/如烟漫画", url: { h: ["www.dashumanhua.com", "www.shilunart.com", "www.ruyanmh.com"], p: /^\/(comic|manhua)\/\w+\/.+\.html/i, i: 0 }, imgs: (dom = document) => { let code = fn.gst("picTree", dom); let m; let srcs; if (fn.lh === "www.ruyanmh.com") { [m] = code.match(/JSON\.parse\([^;]+/); srcs = fn.run(m); } else { code = fn.stringSlicer(code, "eval", "{}))"); code = fn.run(code); srcs = fn.TextToArray(code, "picTree"); } return srcs; }, button: [4], insertImg: ["#pic-list", 2], autoDownload: [0], next: "//a[text()='下一话' and not(contains(@href,'--1'))]", prev: "//a[text()='上一话' and not(contains(@href,'--1'))]", customTitle: (dom = document) => fn.gt(".setnmh-bookname h1", 1, dom) + " - " + fn.gt(".setnmh-bookname h2", 1, dom), preloadNext: true, infiniteScroll: true, hide: "div[id^=shadouyouAsfile],body>div[id][style^=position]", category: "comic" }, { name: "大树漫画/世伦漫画/如烟漫画 自動翻頁", url: { h: ["www.dashumanhua.com", "www.shilunart.com", "www.ruyanmh.com"], p: /^\/(comic|manhua)\/\w+\/.+\.html/i, i: 1 }, getSrcs: (dom) => { let code = fn.gst("picTree", dom); let m; let srcs; if (fn.lh === "www.ruyanmh.com") { srcs = fn.TextToArray(code, "JSON.parse"); } else { code = fn.stringSlicer(code, "eval", "{}))"); code = fn.run(code); srcs = fn.TextToArray(code, "picTree"); } return srcs; }, getImgs: (dom = document) => { let srcs = _this.getSrcs(dom); return fn.createImgArray(srcs); }, init: async () => { let tE = fn.createImgBox("#pic-list", 2); fn.remove("#pic-list,.loading-box"); 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[text()='下一话' and not(contains(@href,'--1'))]", re: ".setnmh-headsee,.setnmh-controlbottomn>.prev,.setnmh-controlbottomn>.huiname,.setnmh-controlbottomn>.next", aF: () => { let n = fn.ge(".next>.tandiv>a"); if (n) { fn.ge(".next>a").href = n.href; fn.remove(".next>a+span,a[v-if=booknext]+span"); } else { fn.ge(".next>a").classList.add("hui"); fn.remove("div[v-if=booknext]"); } }, title: (dom) => { if (isM) { return fn.gt(".setnmh-bookname h2", 1, dom); } else { return fn.gt(".setnmh-bookname h1", 1, dom) + " - " + fn.gt(".setnmh-bookname h2", 1, dom); } }, hide: ".setnmh-detailspage,#setnmh-footer>nav", preloadNextPage: 1 }, hide: "div[id^=shadouyouAsfile],body>div[id][style^=position]", category: "comic autoPager" }, { 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: [ ["#FullPictureLoadMainImgBox", 0, "#comicContain"], 2 ], autoDownload: [0], next: "a:has(>img[alt=下一章])", prev: "a:has(>img[alt=上一章])", 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: [ ["#FullPictureLoadMainImgBox", 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(document.cookie.match(/setdata[\s=]+([^;]+)/)[1]); 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(document.cookie.match(/setdata[\s=]+([^;]+)/)[1]); 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", 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-v2.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/']", 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-v2.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-v2.mgsearcher.com/api/chapter/getinfo?m=${ms}&c=${siteJson.data.info.next}`; } else { return `https://api-get-v2.mgsearcher.com/api/chapter/getinfo?m=${ms}&c=${cs}`; } }, getSrcs: (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); }, getImgs: () => { let srcs = _this.getSrcs(); 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(); 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: () => _this.getImgs(), 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 = siteJson) => json.data.info.title, history: 0, hide: ".justify-center:has(>.border-t),div:has(>.banners),div:has(>div>.cardlist)", preloadNextPage: () => { let 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: "www.mangajikan.com", p: "chapter-" }, imgs: ".more-box img", button: [4], insertImg: [".more-box", 2], autoDownload: [0], next: "//a[text()='次の章'][starts-with(@href,'/')]", prev: "//a[text()='前の章'][starts-with(@href,'/')]", customTitle: (dom) => fn.title(" - 無料読み - Manga Jikan", 0, dom), preloadNext: true, category: "comic" }, { name: "漫画RAW", url: { h: ["tokiraw.com"], p: "/read", s: "id=" }, imgs: ".page-img", button: [4], insertImg: ["#viewer", 2], autoDownload: [0], next: () => { let mid = fn.gu("main a[href^='/manga/']").split("/").at(-1); let cid = fn.getUSP("id"); return fetch("/api/v1/chapters?id=" + mid).then(res => res.text()).then(text => fn.html(text)).then(fragment => { let chapters = fn.gae("option", fragment); let c_chapter = chapters.find(p => p.value == cid); let next = c_chapter?.previousElementSibling; return next ? "/read?id=" + next.value : null; }); }, prev: 1, customTitle: "main h1", category: "comic" }, { name: "ゼロサムオンライン", url: { h: "zerosumonline.com" }, data: () => { fn.showMsg(DL.str_05, 0); let [id] = localStorage.getItem("history_chapter_ids").match(/\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: "アルファポリス", 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; }, capture: () => _this.imgs(), next: () => { 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); let next = c_episode?.previousElementSibling; return next ? fn.dir(fn.lp) + next.dataset.order : null; }, prev: 1, 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: "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: () => fn.gt(".manga-title") + " - " + fn.gt(".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.dumanwu.com", "dumanwu.com", "m.dumanwu.com"], url: { h: [/rumanhua\.com$/, /dumanwu\.com$/], p: /^\/\w+\/\w+.html$/i, i: 0 }, init: () => fn.waitEle(".main_img img[data-src]"), imgs: ".main_img img", 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)", 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\.com$/, /dumanwu\.com$/], p: /^\/\w+\/\w+.html$/i, 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(),'上')]", 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", "manhuami.cc"], 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: [ ["#FullPictureLoadMainImgBox", 0, "#pics"], 2 ], autoDownload: [0], next: "//a[text()='下一章'][starts-with(@href,'/')]", prev: "//a[text()='上一章'][starts-with(@href,'/')]", 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: [ ["#FullPictureLoadMainImgBox", 0, "#images"], 2 ], autoDownload: [0], next: "a[href$=html]:has(>img[alt=下一章])", prev: "a[href$=html]:has(>img[alt=上一章])", 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: [ ["#FullPictureLoadMainImgBox", 0, "#cp_img"], 2 ], autoDownload: [0], next: "//li[p[text()='下一章']]/a", prev: "//li[p[text()='上一章']]/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: "天天漫画", host: ["www.ortzn.com", "m.ortzn.com", "www.smkj88.com", "m.smkj88.com"], url: { t: ["天天漫画", "新新漫画"], p: ["/ttmanhua/", "/88comics/"], ee: ".chapter-list" }, imgs: ".chapter-content img,.hide-scrollbars img", 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)", customTitle: (dom = document) => { if (fn.lp.includes("88comics")) { return fn.gt(".header-center a:nth-child(2)", 1, dom) ?? fn.attr(".chapter-footer a", "alt", dom) + " - " + fn.gt(".header-center span,h1.title", 1, dom); } return 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.rcirr.com", p: "/read_" }, imgs: ".acgn-reader-chapter__item-box img, .comic-list img", next: (dom = document) => { let next = fn.ge("#js_pageNextBtn[_href$=html],li.next-chapter[_href$=html]", dom); return next ? next.getAttribute("_href") : null; }, prev: "#js_pagePrevBtn[_href$=html],li.prev-chapter[_href$=html]", customTitle: (dom = document) => { if (isM) { return dom.title.split("漫画")[0] + " - " + fn.gt(".comic-name", 1, dom); } else { return fn.gt("#crumbComicLink", 1, dom) + " - " + fn.gt("#js_headChapterName", 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,'/')]", 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: "喵趣漫画", host: ["www.miaoqumh.org", "m.miaoqumh.org"], url: { t: "喵趣漫画", 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,'/')]", 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"); }); }, 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: [ ["#FullPictureLoadMainImgBox", 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,'/')]", 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: "wujinmh.com", st: "params" }, init: () => fn.wait(() => isArray(_unsafeWindow?.params?.images)), box: [".rd-article-wr,.comic-list", 1], imgs: () => _unsafeWindow.params.images.map(src => "https://img1.baipiaoguai.org" + src), button: [4, "24%", 3], insertImg: [ ["#FullPictureLoadMainImgBox", 0, ".rd-article-wr,.comic-list"], 2 ], insertImgAF: () => { if (isM) { let $ = _unsafeWindow.jQuery; $("body").on("click", ".FullPictureLoadImage", () => { if ($(".top-tool-bar").css("top") == "0px") { $(".top-tool-bar").animate({ top: "-100px" }, 500); $(".bottom-tool-bar").animate({ bottom: "-100px" }, 500); } else { $(".top-tool-bar").animate({ top: "0px" }, 500); $(".bottom-tool-bar").animate({ bottom: "0px" }, 500); } }); } }, autoDownload: [0], next: () => { let next = fn.ge("a.j-rd-next[_href]:not([style]),.next-chapter[_href]:not([style])"); if (next) { let href = fn.attr("a.j-rd-next[_href],.next-chapter[_href]:not([style])", "_href"); return href == "" ? null : location.origin + href; } else { return null; } }, prev: ".j-rd-prev,.prev-chapter", customTitle: () => fn.dt({ d: "在线阅读-无尽漫画" }), fancybox: { blacklist: 1 }, category: "comic" }, { host: ["www.aitaocomic.com", "aitaocomic.com"], url: { t: "爱淘漫画" }, page: () => fn.clp(/^\/detail\/\w+\/\d+/), SPA: () => _this.page(), observeURL: "nav", init: () => _this.page() ? fetch(fn.clp).then(() => fn.waitEle([".mx-auto.flex.flex-col.items-center img[data-src]", "img[alt='收藏圖示']"])) : void 0, imgs: (dom = document) => _this.page() ? fn.getImgSrcArr(".mx-auto.flex.flex-col.items-center img[data-src]", dom) : [], capture: () => _this.imgs(), autoDownload: [0], next: "a:has(>img[alt=下一話圖示])", prev: "a:has(>img[alt=上一話圖示])", customTitle: (dom = document) => _this.page() ? dom.title.replace("- 爱淘漫画 - 免费线上看", "") : null, frame: ".mx-auto.flex.flex-col.items-center img[data-src]", preloadNext: true, 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: [ ["#FullPictureLoadMainImgBox", 0, ".more-box"], 2 ], autoDownload: [0], next: "//a[text()='下一章'][starts-with(@href,'/chapter/')]", prev: "//a[text()='上一章'][starts-with(@href,'/chapter/')]", 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: [ ["#FullPictureLoadMainImgBox", 0, ".chapter-images"], 2 ], autoDownload: [0], next: "#k_Pic_nextArr[href^='/']", prev: "#k_Pic_backArr[href^='/']", 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']", 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 !== "") ? location.origin + 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: "聚合漫画屋/酷看漫画/去去漫画/皮皮漫画/六漫画/有品漫画", url: { h: ["www.52hah.com", /^www.kukanmanhua./, "www.ququmh.com", "www.mh369.com", "www.pipiman.com", /cicoo\.cc$/, /liumanhua\.cc$/, "www.ypdsm.com"], p: ["/chapter/", "/book/"], d: "pc" }, imgs: ".comiclist img", button: [4], insertImg: [".comicpage", 2], autoDownload: [0], next: "//a[text()='下一章']", prev: "//a[text()='上一章']", 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/有品漫画M", url: { h: ["www.52hah.com", /^www.kukanmanhua./, "www.ququmh.com", "www.mh369.com", "www.pipiman.com", /cicoo\.cc$/, /liumanhua\.cc$/, "www.ypdsm.com"], 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", button: [4], insertImg: [ ["#FullPictureLoadMainImgBox", 0, ".comicpage>div[style^=width],.comicpage>img[data-original]"], 2 ], autoDownload: [0], next: "//a[text()='下一章']", prev: "//a[text()='上一章']", 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: [ ["#FullPictureLoadMainImgBox", 0, "div:has(>img.page)"], 2 ], insertImgAF: (p) => p.after(fn.ge("div:has(>div[data-flux-button-group])").cloneNode(true)), autoDownload: [0], next: "//a[contains(text(),'下一話')][contains(@href,'chapters')]", prev: "//a[contains(text(),'上一話')][contains(@href,'chapters')]", 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", 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.bcloudmerge.com", p: "/bmergechapter/" }, init: () => fn.remove("//div[p[@class='open']] | //div[p[contains(text(),'小贴士')]] | //div[div[button[text()='无删韩漫']]]"), imgs: ".mh_list img,#content img", button: [4], insertImg: [".mh_list,#content", 2], insertImgAF: () => fn.hideEle(".jump-list"), autoDownload: [0], next: "//a[text()='下一章']", prev: "//a[text()='上一章']", customTitle: (dom = document) => { let code = fn.gst("read", dom); let read = fn.TextToObject(code, "read"); return read.articlename + " - " + read.cname; }, preloadNext: true, category: "comic" }, { name: "最次元/野蛮/优乐漫画/次元/脉赛漫画/格雷漫/开心漫画", url: { h: ["zcymh.com", "yemancomic.com", "www.beston-test.com", "www.yydskxs.com", "www.myselfcar.com", "www.briangary.net", "www.source-ex.com"], p: /^\/\w+\/\d+\/\d+\.html$/ }, imgs: "#img-box img,#imgsec img", button: [4], insertImg: ["#img-box,#imgsec", 2], autoDownload: [0], next: "#js_pageNextBtn>a,a#next", prev: "#js_pagePrevBtn>a,a#prev", customTitle: (dom = document) => { let code = fn.gst("read", dom); let read = fn.TextToObject(code, "read"); return read.articlename + " - " + read.chaptername; }, preloadNext: true, css: "#reader-scroll{overflow:hidden}", hide: "div[style*='background-color'],.down-app,div:has(button[onclick*='/buy']),body>div[style^='position:fixed;']", category: "comic" }, { name: "爱看漫", url: { h: "ikmmh.com", p: /^\/\w+\/\d+\/\d+\.html$/, d: "pc" }, imgs: () => { fn.showMsg(DL.str_05, 0); return fn.xhrDoc(siteUrl, { headers: { "User-Agent": Mobile_UA } }).then(dom => { fn.hideMsg(); return fn.gae(".episode-detail img", dom); }); }, button: [4, "24%", 4], insertImg: ["#img-box", 2], autoDownload: [0], next: "#js_pageNextBtn>a", prev: "#js_pagePrevBtn>a", customTitle: () => { let code = fn.gst("read"); let read = fn.TextToObject(code, "read"); return read.articlename + " - " + read.chaptername; }, css: "#img-box{max-width:800px;margin:0 auto}", category: "comic" }, { name: "爱看漫M/众飞漫画", url: { h: [/ikmmh\.com$/, "www.zonfibra.com"], p: [/^\/\w+\/\d+\/\d+\.html$/, "/zonfchapter/"], d: "m" }, imgs: ".episode-detail img", button: [4], insertImg: [".episode-detail", 2], autoDownload: [0], next: "a#next", prev: "a#prev", customTitle: (dom = document) => { let code = fn.gst("read", dom); let read = fn.TextToObject(code, "read"); return read.articlename + " - " + read.chaptername; }, preloadNext: true, hide: "body>div[class][style^='position:fixed;'],body>div[style]:has(>p),.epContent+.z-index-99:has(>.down-app),.down-app,.z-index-99 div:has(p>br),.z-index-99 div[style]:has(>button[style][onclick])", fancybox: { blacklist: 1 }, category: "comic" }, { name: "灰狗漫画", url: { h: "www.greyhoundsoul.com", p: "/greychapter/" }, imgs: "#imgsec img", button: [4], insertImg: ["#imgsec", 2], endColor: "white", autoDownload: [0], next: "#next", prev: "#prev", customTitle: (dom = document) => { let code = fn.gst("read", dom); let read = fn.TextToObject(code, "read"); return read.articlename + " - " + read.chaptername; }, preloadNext: true, hide: ".imgbg,.mask,body>div[class][style^='position:fixed;'],body>div[style]:has(>p),.epContent+.z-index-99:has(>.down-app),.down-app,.z-index-99 div:has(p>br),.z-index-99 div[style]:has(>button[style][onclick])", fancybox: { blacklist: 1 }, category: "comic" }, { 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, customTitle: () => document.title.trim().slice(0, -5), preload: 0, fancybox: { blacklist: 1 }, category: "comic" }, { name: "拷貝漫畫M SPA", url: () => fn.checkUrl({ h: ["www.copymanga.tv", "copymanga.tv", "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 = `/api/v3/comic/${name}/chapter2/${id}?platform=3`; return fn.xhr(api, { 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 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)), insertImg: [ ["#FullPictureLoadMainImgBox", 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, 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: "拷貝漫畫", host: ["www.copymanga.tv", "copymanga.tv", "www.mangacopy.com", "mangacopy.com"], url: { h: /copymanga|mangacopy/, p: /^\/comic\/\w+\/chapter\//, i: 0 }, delay: 300, fetchJson: (url = siteUrl) => { //let host = fn.lh.replace("www.", ""); //let api = siteUrl.replace(/.*?(?=\/comic\/)/, `https://api.${host}/api/v3`); let [, , name, , id] = new URL(url).pathname.split("/"); let api = `/api/v3/comic/${name}/chapter2/${id}?platform=3`; return fetch(api).then(res => res.json()); }, init: async () => { fn.copymangaUI(); fn.showMsg(DL.str_05, 0); let fetchJson = await _this.fetchJson(); siteJson = fetchJson; debug("\n此頁JSON資料\n", fetchJson); 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)); }, //imgs: () => siteJson.results.chapter.contents.map(e => e.url.replace("c800x.", "c1500x.")), imgs: (json = siteJson) => { const srcs = []; const { words, contents } = siteJson.results.chapter; words.forEach((w, i) => (srcs[w] = contents[i].url.replace("c800x.", "c1500x."))); return srcs; }, button: [4], insertImg: [".comicContent-list", 2], endColor: "white", autoDownload: [0], next: "//a[text()='下一話'][starts-with(@href,'/comic/')]", prev: "//a[text()='上一話'][starts-with(@href,'/comic/')]", customTitle: (json = siteJson) => json.results.comic.name + " - " + json.results.chapter.name, preloadNext: () => { _this.fetchJson(nextLink).then(json => { let srcs = _this.imgs(json); let title = _this.customTitle(json); fn.picPreload(srcs, title, "next"); }); }, topButton: true, hide: ".header+div[style],.comicContainerAds", infiniteScroll: true, category: "comic" }, { name: "拷貝漫畫 自動翻頁", url: { h: /copymanga|mangacopy/, p: /^\/comic\/\w+\/chapter\//, i: 1 }, delay: 300, getImgs: (url = siteUrl) => { let [, , comic, , chapter] = new URL(url).pathname.split("/"); let api = `/api/v3/comic/${comic}/chapter2/${chapter}?platform=3`; return fetch(api).then(res => res.json()).then(json => { const srcArr = []; const { words, contents } = json.results.chapter; words.forEach((w, i) => (srcArr[w] = contents[i].url.replace("c800x.", "c1500x."))); customTitle = json.results.comic.name + " - " + json.results.chapter.name; let readHistoryData = localStorage.getItem("copymangaReadHistory"); let obj; readHistoryData ? obj = JSON.parse(readHistoryData) : obj = {}; obj[comic] = chapter; localStorage.setItem("copymangaReadHistory", JSON.stringify(obj)); return srcArr; }).then(srcs => fn.createImgArray(srcs)); }, init: async () => { fn.copymangaUI(); fn.showMsg(DL.str_135, 0); await _this.getImgs().then(async imgs => { let tE = fn.ge(".comicContent-list"); tE.innerHTML = ""; fragment.append(...imgs); tE.append(fragment); fn.hideMsg(); await fn.lazyload(); }); fn.addMutationObserver(() => { if (fn.ge("//li[img[@data-src]]")) { fn.remove("//li[img[@data-src]]"); } }); }, autoPager: { ele: () => _this.getImgs(nextLink), pos: [".comicContent-list", 0], observer: ".comicContent-list>img", next: "//a[text()='下一話'][starts-with(@href,'/comic/')]", re: ".header,.footer", title: () => customTitle }, hide: ".header+div[style],.comicContainerAds", category: "comic autoPager" }, { name: "拷貝漫畫 目錄頁", reg: /^https?:\/\/(www\.)?(copymanga\.tv|mangacopy\.com)\/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: "拷貝漫畫 清除不給開啟開發人員工具", enable: 0, reg: () => isPC && /^(www\.)?(copymanga\.tv|mangacopy\.com)$/.test(fn.lh) && !fn.ge("//title[text()='漫畫觀看']"), delay: 300, init: () => { fn.clearAllTimer(3); if ("aboutBlank" in _unsafeWindow) _unsafeWindow.aboutBlank = null; fn.gae("img[data-src]").forEach(img => (img.src = img.dataset.src)); }, category: "none" }, { name: "拷貝漫畫M", host: ["www.copymanga.tv", "copymanga.tv", "www.mangacopy.com", "mangacopy.com"], url: { h: /copymanga|mangacopy/, p: /^\/h5\/comicContent\/\w+\//, i: 0 }, xhrJson: (url = siteUrl) => { //let [name, id] = url.split("/").slice(-2); //let host = fn.lh.replace("www.", ""); //let api = `https://api.${host}/api/v3/comic/${name}/chapter/${id}`; let [name, id] = url.split("/").slice(-2); let api = `/api/v3/comic/${name}/chapter2/${id}?platform=3`; 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: () => siteJson.results.chapter.contents.map(e => e.url.replace("c800x.", "c1500x.")), imgs: (json = siteJson) => { const srcs = []; const { words, contents } = json.results.chapter; words.forEach((w, i) => (srcs[w] = contents[i].url)); return srcs; }, button: [4], insertImg: [".comicContentPopupImageList", 2], insertImgAF: () => { 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: /copymanga|mangacopy/, p: /^\/h5\/comicContent\/\w+\//, i: 1 }, getData: () => { let [name, id] = new URL(document.URL).pathname.split("/").slice(-2); let api = `/api/v3/comic/${name}/chapter2/${id}?platform=3`; return fn.xhr(api, { responseType: "json", headers: { "Referer": `https://${fn.lh}/comic/${name}/chapter/${id}`, "User-Agent": PC_UA } }).then(json => { const srcs = []; const { words, contents } = json.results.chapter; words.forEach((w, i) => (srcs[w] = contents[i].url)); globalImgArray = srcs; customTitle = json.results.chapter.name; let next = json.results.chapter?.next; console.log("\n拷貝漫畫M_JSON\n", json, globalImgArray, customTitle, next); if (!!next) { tempNextLink = document.URL.replace(/[^\/]+$/, "") + next; } else { tempNextLink = null; } }); }, init: async () => { fn.showMsg(DL.str_135, 0); await _this.getData(); let imgs = fn.createImgArray(globalImgArray); let tE = fn.ge(".comicContentPopupImageList"); tE.innerHTML = ""; fragment.append(...imgs); tE.append(fragment); 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(globalImgArray), pos: [".comicContentPopupImageList", 0], observer: ".comicContentPopupImageList>img", next: () => tempNextLink, wait: async () => await _this.getData(), title: () => customTitle }, 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: "拷貝漫畫M 清除不給開啟開發人員工具", enable: 0, reg: /^https?:\/\/(www\.)?(copymanga\.tv|mangacopy\.com)\/h5/, init: async () => { fn.clearAllTimer(3); if ("aboutBlank" in _unsafeWindow) _unsafeWindow.aboutBlank = null; }, category: "none" }, { name: "二次元動漫/看漫畫", host: ["www.2animx.com", "www.k886.net"], enable: 0, reg: /^https?:\/\/(www\.2animx\.com|www\.k886\.net)\/index-look-name-.+/, init: "$(document).unbind('click')", imgs: (url = siteUrl, dom = document, msg = 1, request = 0) => { let max = fn.ge("#total", dom).value; let links = fn.arr(max, (v, i) => fn.getModeUrl(url, 20, (i + 1))); return fn.getImgA("#ComicPic", links, 100, null, msg, request); }, button: [4], insertImg: ["//div[img[@id='ComicPic']]", 2], autoDownload: [0], next: ".n.zhangjie", prev: ".p.zhangjie", customTitle: dom => { let [, , comic_name, comic_chapter] = fn.gt(".b", 1, dom).split(" - "); return comic_name + " - " + comic_chapter.replace(/(\d+P)/i, ""); }, preloadNext: async (nextDoc, obj) => fn.picPreload(await obj.imgs(nextLink, nextDoc, 0, 1), obj.customTitle(nextDoc), "next"), css: "#ComicPic{display:block!important;margin: 0 auto !important;}", hide: ".c>*:not(.n.zhangjie):not(.p.zhangjie)", category: "comic" }, { name: "看漫畫M", enable: 0, url: { h: "m.k886.net", p: "/cid/" }, imgs: (url = siteUrl, dom = document, msg = 1, request = 0) => { let max = fn.gt(".manga-page", 1, dom).match(/\d+/g).at(-1); let links = fn.arr(max, (v, i) => i == 0 ? url : url + "/p/" + (i + 1)); return fn.getImgA("#manga img[alt]", links, 100, null, msg, request); }, button: [4], insertImg: ["#manga", 2], autoDownload: [0], next: "//a[text()='下一章'][not(starts-with(@href,'java'))]", prev: "//a[text()='下一章'][not(starts-with(@href,'java'))]", customTitle: dom => fn.gt("#mangaTitle", 1, dom), preloadNext: async (nextDoc, obj) => fn.picPreload(await obj.imgs(nextLink, nextDoc, 0, 1), obj.customTitle(nextDoc), "next"), css: ".action-list li{width:50% !important}", category: "comic" }, { name: "漫画DB", url: { h: "www.manhuadb.com", p: /^\/manhua\/\d+\/\w+\.html$/, i: 0 }, imgs: (frame = _unsafeWindow) => { const { img_data_arr, img_host, img_pre } = frame; return img_data_arr.map(e => img_host + img_pre + e.img); }, button: [4], insertImg: ["#all", 2], autoDownload: [0], next: () => { const { p_ccid, p_id, vg_r_data, p_d } = _unsafeWindow; return fetch("/book/goNumPage", { "headers": { "content-type": "application/x-www-form-urlencoded; charset=UTF-8" }, "body": `ccid=${p_ccid}&id=${p_id}&num=${Number(vg_r_data.data("num")) + 1}&d=${p_d}&type=next`, "method": "POST" }).then(res => res.json()).then(json => json.state == 0 ? null : location.origin + json.url); }, prev: "//a[text()='上集']", customTitle: (dom) => fn.title("-漫画DB", 0, dom), preloadNext: () => { fn.iframe(nextLink, { waitVar: "img_data_arr", cb: async (dom, frame) => { let srcs = _this.imgs(frame); let text = _this.customTitle(dom); fn.picPreload(srcs, text, "next"); } }); }, infiniteScroll: true, category: "comic" }, { name: "漫画DB 自動翻頁", url: { h: "www.manhuadb.com", p: /^\/manhua\/\d+\/\w+\.html$/, i: 1 }, getSrcs: (dom) => { let code = fn.gst("img_data", dom); let base64Text = code.slice(16, -2); //let decodeBase64 = atob(base64Text); let decodeBase64 = _unsafeWindow.jQuery.base64.decode(base64Text); let imgDataArr = JSON.parse(decodeBase64); let vgData = fn.ge(".vg-r-data", dom); let imgHost = vgData.dataset.host; let imgPre = vgData.dataset.img_pre; return imgDataArr.map(e => imgHost + imgPre + e.img); }, getImgs: (dom = document) => { let srcs = _this.getSrcs(dom); return fn.createImgArray(srcs); }, init: async () => { let imgs = _this.getImgs(); let tE = fn.ge("#all"); tE.innerHTML = ""; fragment.append(...imgs); tE.append(fragment); await fn.lazyload(); }, autoPager: { ele: (dom) => _this.getImgs(dom), pos: ["#all", 0], observer: "#all>img", next: (dom) => { let vgData = fn.ge(".vg-r-data", dom); let ccid = vgData.dataset.ccid; let id = vgData.dataset.id; let num = vgData.dataset.num; let d = vgData.dataset.d; return fetch("/book/goNumPage", { "headers": { "content-type": "application/x-www-form-urlencoded; charset=UTF-8" }, "body": `ccid=${ccid}&id=${id}&num=${Number(num) + 1}&d=${d}&type=next`, "method": "POST" }).then(res => res.json()).then(json => json.state == 0 ? null : json.url); }, title: (dom) => { let m = fn.gt("h1.h2>a", 1, dom); let c = fn.gt("h2.h4", 1, dom).replace(/\[|\]/g, ""); return isM ? c : m + " - " + c; }, hide: ".comic-viewer-toc", preloadNextPage: 1 }, hide: ".form-inline>.pre,.form-inline>.next,div:has(>#page-selector)", category: "comic autoPager" }, { name: "快岸漫画", enable: 0, url: { h: "ikanbook.net", p: /^\/comic\/\d+\/\d+/ }, init: async () => { await fn.waitVar("x_tokens"); fn.run("$(document).unbind('keydown') && $(document).unbind('keyup')"); }, imgs: () => { const { is_refresh, x_tokens, Gm, comic_id, version_id, part_id, my_sha2, data } = _unsafeWindow; return is_refresh == 0 ? x_tokens.map(e => Gm.getImgUrl(comic_id + "/" + version_id + "/" + part_id + "/" + my_sha2(e))) : data.url.map(e => Gm.getImgUrl(e)); }, button: [4], insertImg: ["#all", 2], endColor: "white", autoDownload: [0], next: "//a[text()='下一章' and not(starts-with(@href,'javascript'))]", prev: "//a[text()='上一章' and not(starts-with(@href,'javascript'))]", customTitle: () => fn.gt("h2.h2>a") + " - " + fn.gt("span.h4:nth-child(5)"), category: "comic" }, { 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])", 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"; } else { return null; } }, prev: 1, customTitle: () => siteJson.data.comic_name + " - " + siteJson.data.current_chapter.chapter_name, category: "comic" }, { name: "zero搬运网", host: ["www.zerobywrar.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(),'上一章')]", 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", fetch: 1, 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')]", customTitle: (dom = document) => fn.attr("meta[name='keywords']", "content", dom).replace(",", " - "), preloadNext: true, hide: "#prePage,#nextPage,select[onchange],.jump-list,.apjg,a[href*=taobao]", 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'))]", preloadNext: async (nextDoc, obj) => fn.picPreload(fn.getImgSrcArr(obj.imgs, nextDoc), nextDoc.title, "next"), 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: ["#FullPictureLoadMainImgBox", 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: ["#FullPictureLoadMainImgBox", 2], insertImgAF: () => fn.hideEle("#TopPage"), autoDownload: [0], next: () => { let cc = fn.ge("div:has(>.btn-success)"); let next = cc?.previousElementSibling?.firstElementChild; return next ? next.href : null; }, prev: 1, category: "comic" }, { name: "KKRAW", url: { h: ["kkraw.com"], p: "/chapter" }, box: [".more-box", 2], imgs: ".more-box img", button: [4], insertImg: ["#FullPictureLoadMainImgBox", 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: "コミックシーモア", url: { h: ["syosetu.gs"], p: "-chapter-" }, imgs: ".entry-content img", button: [4], insertImg: [".entry-content", 2], autoDownload: [0], next: "a.nextchapter", prev: "a.prevchapter", customTitle: "h1.entry-title", 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: "漫畫類 自動展開目錄", 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.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"], url: { h: "m.4khd.com", p: /^\/\w+$|^\/link\/|^\/vip\//i }, init: () => { 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) { return Object.prototype.toString.call(object).replace("[object ", "").replace("]", ""); } 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"); 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 = (() => isFn(GM_addElement) ? GM_addElement : GM.addElement)(); const UI_zIndex = Number(_GM_getValue("UI_zIndex", 2147483647)); const ajaxHookerJS = _GM_getResourceText("ajaxHookerJS"); 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 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"); 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); } }, 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); } }, 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 "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%掛掉,可以調低下載線程數或重新載入網頁後重新下載試試看。", str_30: "圖片extension錯誤", str_31: "壓縮進度: ", str_32: "自動下載倒數", str_33: "秒", str_34: "nextJS前往下一頁", 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&ViewerJs燈箱功能", 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: "💬 Github 反饋", str_112: "提示", str_113: "滾動煞車:", str_114: "E/EX-HENTAI 載入原始圖片連結", str_115: "自動滾動至首張圖片", str_116: "自動滾動所有惰性載入的圖片元素", str_117: "顯示浮動選單", str_118: "圖集標題已更新", str_119: "FancyboxV5滾輪圖片縮放", str_120: "此網站分頁畫廊使用ViewerJs插件", 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: "離開畫廊 (Esc)", str_143: "下一話", str_144: "下一篇", str_145: "Fancybox5&ViewerJs幻燈片播放間隔:", 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: "懸停提示✨", str_204: "⚙️ 腳本UI最外層堆疊順序", str_205: "請輸入z-index值(7 ~ 2147483647)", 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: "圖片切換" }, backgroundColor: { l: "淺色", d: "深色" } }; 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%挂掉,可以调低下载线程数或重新加载网页后重新下载试试看。", str_30: "图片extension错误", str_31: "压缩进度: ", str_32: "自动下载倒数", str_33: "秒", str_34: "nextJS前往下一页", 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&ViewerJs灯箱功能", 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: "💬 Github 反馈", str_112: "提示", str_113: "滚动煞车:", str_114: "E/EX-HENTAI 加载原始图片链接", str_115: "自动滚动至首张图片", str_116: "自动滚动所有懒加载的图片元素", str_117: "显示浮动菜单", str_118: "图集标题已更新", str_119: "FancyboxV5滚轮图片缩放", str_120: "此网站标签画廊使用ViewerJs插件", 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: "离开画廊 (Esc)", str_143: "下一话", str_144: "下一篇", str_145: "Fancybox5&ViewerJs幻灯片播放间隔:", 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: "悬停提示✨", str_204: "⚙️ 脚本UI最外层堆叠顺序", str_205: "请输入z-index值(7 ~ 2147483647)", 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: "图片切换" }, backgroundColor: { l: "浅色", d: "深色" } }; 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.", str_30: "Image Extension Error", str_31: "Compression Progress: ", str_32: "Countdown ", str_33: " sec", str_34: "JS Go To Next 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&ViewerJs 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: "💬 Github Feedback", 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: "FancyboxV5 Wheel Toggle Zoom", str_120: "This Website New Tab View uses ViewerJs Plug-in", 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: "This website downloads 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: "Close (Esc)", str_143: "Next Chapter", str_144: "Next Post", str_145: "FB5&ViewerJs Play Delay:", str_146: "FB5 Wheel:", str_147: "Gallery (0、1、3) Wheel:", str_148: "FB5 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)", 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" }, backgroundColor: { l: "Light", d: "Dark" } }; break; } const FullPictureLoadBlacklist = localStorage.getItem("FullPictureLoadBlacklist") ?? 0; _GM_registerMenuCommand(DL.str_66, () => _GM_openInTab("https://greasyfork.org/scripts/463305/feedback")); _GM_registerMenuCommand(DL.str_111, () => _GM_openInTab("https://github.com/skofkyo/AutoPager/issues")); _GM_registerMenuCommand("📓 Github README.md", () => _GM_openInTab("https://github.com/skofkyo/AutoPager/blob/main/CustomPictureDownload/README.md")); _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 ""; }, 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 => { const object = { j: "jpg", p: "png", g: "gif", w: "webp", b: "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 { h: hosts, p: pathname, s: search, st: script_text, e: elements, ee: exclude_elements, t: title, d: device, i: comicInfiniteScroll } = obj; const { box, imgs: imgSelector, srcset: srcsetSelector, customTitle: titleSelector } = tempData; let checkH = true; let checkP = true; let checkS = true; let checkE = true; let checkI = true; let checkT = true; let checkD = 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 ("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 ("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) && !("SPA" in tempData)) { checkT = !!fn.ge(titleSelector); if (!checkT) { debug("\n頁面沒有指定的標題元素", titleSelector); } } return checkH && checkP && checkS && checkE && checkI && checkT; }, 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; } else { fn.remove("#FullPictureLoadIframe"); } } 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]); } 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-bgset", "data-bigsrc", "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 ? src.replace("https://wsrv.nl/?url=", "") : 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 src.replace("https://wsrv.nl/?url=", ""); //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"); if (srcset && /[xw],/.test(srcset)) { let splitArr = srcset.split(",").map(src => src.trim()).filter(Boolean); splitArr = splitArr.sort((a, b) => a.match(/\s([\d\.]+)(w|x)$/)[1] - b.match(/\s([\d\.]+)(w|x)$/)[1]); let [src] = splitArr.at(-1).trim().split(" "); if (/^https:\/\/i\d\.wp\.com/.test(src)) { src = src.replace(/\?.+$/, "?ssl=1"); } //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 { 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; } else { fn.remove("#FullPictureLoadIframe"); } } } 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 (/imx\.to/.test(url)) { return fn.imxXHR(url).then(dom => { fn.showMsg(`${DL.str_02}${xhrNum+=1}/${arr.length}`, 0); let img = fn.ge("#container img", dom); return img ? img.src : null; }); } else 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; if (isString(mode) && mode == "json") { siteJson = await fetch(url, { cache: "no-cache" }).then(res => res.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 (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" ? siteJson : 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(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) 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" ].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(); } }]; 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 = 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; 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)) { targetEle = fn.ge(insertTargetEle); 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 (options.viewMode == 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 (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); 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); text = ele?.innerText; if (!!ele && !!text && text?.length > 0) { return fn.dt({ t: text }); } } } return text; }, //根據關鍵字串或正則搜索符合條件的script,返回script字串 gst: (searchValue, dom = document) => { try { return [...dom.scripts].find(script => { if (isString(searchValue)) { return script.textContent.includes(searchValue); } else if (isRegExp(searchValue)) { return script.textContent.search(searchValue) > -1; } }).textContent; } catch { return ""; } }, //刪除指定字串返回字串 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]?[\(\[[(【“]\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(/\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 + ')')(), //將字串解析為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); 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) => { 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(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 }); }); }, //用Promise封裝GM_xmlhttpRequest imxXHR: url => { return new Promise((resolve, reject) => { _GM_xmlhttpRequest({ method: "POST", url: url, responseType: "document", headers: { "content-type": "application/x-www-form-urlencoded" }, data: "imgContinue=Continue+to+image+...+", onload: data => { resolve(data.response); }, onerror: error => { reject(error); } }); }); }, //用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); }); }); }, //IMHentai網站用的取得圖片網址 getImhentaiSrc: async () => { await fn.waitVar("g_th"); const findServer = cId => { if (cId > 0 && cId <= 274825) return "m1.imhentai.xxx"; if (cId > 274825 && cId <= 403818) return "m2.imhentai.xxx"; if (cId > 403818 && cId <= 527143) return "m3.imhentai.xxx"; if (cId > 527143 && cId <= 632481) return "m4.imhentai.xxx"; if (cId > 632481 && cId <= 816010) return "m5.imhentai.xxx"; if (cId > 816010 && cId <= 970098) return "m6.imhentai.xxx"; if (cId > 970098 && cId <= 1121113) return "m7.imhentai.xxx"; if (cId > 1121113 && cId <= 1259410) return "m8.imhentai.xxx"; return "m9.imhentai.xxx"; }; 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 cId = Number(fn.ge("#u_id,#load_dir+#gallery_id").value ?? ""); const randomServer = _unsafeWindow.random_server ?? findServer(cId); return fn.arr(num, (v, i) => `//${randomServer}/${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; }); }, //漫漫聚和KuKu动漫取得圖片網址的函式 getKukudmSrc: (url = siteUrl, dom = document, msg = 1) => { if (url === null) return []; if (fn.ge("//title[contains(text(),'404')]", dom, dom)) return []; if (!getImgFnProcessRecord.includes("getKukudmSrc")) getImgFnProcessRecord += " > fn.getKukudmSrc()"; let timeId = setTimeout(() => msg === 1 ? location.reload() : null, 20000); if (msg == 1) fn.showMsg(DL.str_05, 0); let max; fn.ge("//td[input]", dom, dom) ? max = fn.gt("//td[input]", 1, dom).match(/共(\d+)/)[1] : max = fn.gt(".bottom .subNav", 1, dom).match(/\/(\d+)/)[1]; url = url.replace(new URL(url).search, ""); url = url.replace("1.htm", ""); let links = fn.arr(max, (v, i) => url + (i + 1) + ".htm"); let xhrNum = 0; let resArr = links.map(url => fn.xhrDoc(url).then(dom => { if (msg == 1) fn.showMsg(`${DL.str_06}${xhrNum+=1}/${links.length}`, 0); let code = fn.gst(".write", dom); let s = code.indexOf("(") + 1; let e = code.lastIndexOf(")"); let htmlCode = code.slice(s, e); let htmlText = fn.run(htmlCode); let tempDom = fn.doc(htmlText); let srcs = [...tempDom.images].map(img => decodeURIComponent(img.src)); let [src1, src2] = srcs; if (srcs.length > 1) { return { src1, src2 }; } else if (srcs.length > 0) { return src1; } else { return null; } })); return Promise.all(resArr).then(async srcs => { clearTimeout(timeId); if (msg == 1) fn.hideMsg(); try { const [first] = srcs; if (isString(first)) { return srcs; } else { msg == 1 ? fn.showMsg(DL.str_56, 0) : null; let status = await fn.xhrHEAD(first.src1).then(res => res.status); return status == 200 ? srcs.map(e => e.src1) : srcs.map(e => e.src2); } } catch { return []; } }); }, 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 => e.remove()); } else if (isArray(p)) { let selectors = p; await delay(time); selectors.forEach(selector => fn.gae(selector).forEach(e => 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 = 1) => { 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 n = 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 ${n += 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 (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]); } }, 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]); } }, 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: async (raw) => { //解密代碼來自https://greasyfork.org/scripts/397848 const encoder = new TextEncoder(); const decoder = new TextDecoder(); const dioKey = encoder.encode("xxxmanga.woo.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)); } }; 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; } if (fn.lh.includes("myreadingmanga")) { return myreadingmanga_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.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)]; 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); 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 convertQuality = _GM_getValue("convertQuality", 9); //圖片影片下載函式 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 = []); siteData.fetch == 1 ? 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; } siteData.fetch == 1 ? 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 (/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 (convertQuality == 0) { quality = 0; } else if (convertQuality == 10) { quality = 1; } else { quality = Number("0." + convertQuality); } 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+/); } } 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 = 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, backgroundColor: "l", 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("UI_zIndex", 2147483647) _GM_setValue("FullPictureLoadMsgPos", 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("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("convertQuality", 9); _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"); }; //新分頁空白頁檢視圖片 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.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: #000000; width: ${isM ? "102px" : "144px"}; height: auto; padding: 5px 5px 2px 5px; position: fixed; left: ${isM ? "0px" : "-150px"}; bottom: 0px; border: #ccc 1px solid; border-radius: 3px; background-color: #fff; z-index: 2; &:hover { left: 0px; } } .FixedMenuitem { width: ${isM ? "90px" : "132px"}; height: 24px; line-height: 24px; overflow: hidden; font-size: 14px; border: #ccc 1px solid; background-color: #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: #000; background-color: #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: 2; } .setting-btn { width: 48px; height: 48px; text-align: center; user-select:none; color: #000; margin: 5px 0; overflow: hidden; border: rgb(51, 51, 51) 1px solid; background: 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]); } }, 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); } }, 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(); 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" viewBox="0 0 1024 1024" version="1.1" 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" viewBox="0 0 1024 1024" version="1.1" 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; //創建影子畫廊 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); const mainHtml = `<div id="FullPictureLoadShadowGallery" style="overflow: clip !important;display: initial !important;position: fixed !important;z-index: ${UI_zIndex - 3} !important;"></div>`; document.body.insertAdjacentHTML("beforeend", mainHtml); const FullPictureLoadShadowGallery = ge("#FullPictureLoadShadowGallery"); const shadow = FullPictureLoadShadowGallery.attachShadow({ mode: "closed" }); const increaseWidth = () => { 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")); } }; const reduceWidth = () => { 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")); } }; 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 (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); 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") 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 === "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(` 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: #000000; width: ${isM ? "102px" : "144px"}; height: auto; padding: 5px 5px 2px 5px; position: fixed; left: ${isM ? "0px" : "-150px"}; bottom: 0px; border: #ccc 1px solid; border-radius: 3px; background-color: #fff; z-index: 2147483647; &:hover { left: 0px; } } .FixedMenuitem { width: ${isM ? "90px" : "132px"}; height: 24px; line-height: 24px; overflow: hidden; font-size: 14px; border: #ccc 1px solid; background-color: #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: 142px; padding: 0px; } .FixedMenuitem.active { color: #fff; background: #1790e6; } #setting-btn { width: auto; height: auto; position: fixed; right: ${isM ? "10px" : "30px"}; bottom: 150px; z-index: 2147483647; } .setting-btn { width: 48px; height: 48px; text-align: center; user-select:none; color: #000; margin: 5px 0; overflow: hidden; border: rgb(51, 51, 51) 1px solid; background: 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: #000; background-color: #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 { 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: 2147483647; 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; } `); 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", zIndex: UI_zIndex - 3, 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 }); 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); } }, 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.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: "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 (!!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); 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); 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); mainElement.focus(); }); } if (isM) { menuDiv.classList.add("hide"); gae("#MenuBehaviorItem,#MenuJumpItem,#MenuHorizontalItem", menuDiv).forEach(e => e.classList.add("hide")); } } addFixedMenu(); let btnDiv; function addButtons() { btnDiv = document.createElement("div"); btnDiv.id = "setting-btn"; btnDiv.className = "hide"; const btnObj = [{ id: "addBtn", svg: '<svg class="icon" viewBox="0 0 1024 1024" version="1.1" 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" viewBox="0 0 1024 1024" version="1.1" 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); 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", zIndex: UI_zIndex - 3, 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 = () => { 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")); } }; const reduceWidth = () => { 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")); } }; 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 (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") 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 === "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: ` 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: #000000; width: ${isM ? "102px" : "144px"}; height: auto; padding: 5px 5px 2px 5px; position: fixed; left: ${isM ? "0px" : "-150px"}; bottom: ${isM ? "54px" : "0px"}; border: #ccc 1px solid; border-radius: 3px; background-color: #fff; z-index: 2147483647; &:hover { left: 0px; } } .FixedMenuitem { width: ${isM ? "90px" : "132px"}; height: 24px; line-height: 24px; overflow: hidden; font-size: 14px; border: #ccc 1px solid; background-color: #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: 142px; padding: 0px; } .FixedMenuitem.active { color: #fff; background: #1790e6; } #setting-btn { width: auto; height: auto; position: fixed; right: ${isM ? "10px" : "30px"}; bottom: 150px; z-index: 2147483647; } .setting-btn { width: 48px; height: 48px; text-align: center; user-select:none; color: #000; margin: 5px 0; overflow: hidden; border: rgb(51, 51, 51) 1px solid; background: 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: #000; background-color: #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 { 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: 2147483647; 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; } ` }); 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", zIndex: UI_zIndex - 3, 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 }); 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); } }, 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.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" viewBox="0 0 1024 1024" version="1.1" 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" viewBox="0 0 1024 1024" version="1.1" 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: "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 (!!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); 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); 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); mainElement.focus(); }); } if (isM) { menuDiv.classList.add("hide"); gae("#MenuBehaviorItem,#MenuJumpItem,#MenuHorizontalItem", menuDiv).forEach(e => e.classList.add("hide")); } } addFixedMenu(); 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 () => { 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 exclude_ex_config = _GM_getValue("exclude_ex_config", extensions); exclude_ex_config = Object.assign(extensions, exclude_ex_config); let threading = Number(config.threading); let backgroundColor = config.backgroundColor; let showSize = config.showSize; let move = config.move; 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;z-index: ${UI_zIndex - 5} !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; } input.dark,select.dark { color: #fff; background-color: #333; } input.dark { border: 1px solid #575757; } .show { display: block !important; } .hide { display: none !important; } .row { display: block; margin: 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, #close { display: inline-block; width: 48px; } .number { display: inline-block; margin-top: 4px; padding: 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; } 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: ${(!isFirefox && isPC) ? "16px" : "17px"}; height: ${(!isFirefox && isPC) ? "16px" : "17px"}; vertical-align: text-bottom; margin: 0 4px 0 2px; } label.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 ? "-7px" : "-26px"}; width: ${isCh ? "90px" : "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; } #scroll_U,#scroll_D { position: fixed; z-index: 2147483647; right: 20px; color: rgba(143, 143, 143); font-size: 40px; width: 48px; height: 48px; text-align: center; /*align-content: center;*/ overflow: hidden; border: #ccc 1px solid; background: rgba(255, 255, 255, 0.8); border-radius: 12px; opacity: 0.8; backdrop-filter: saturate(5) blur(100px); } #scroll_U { bottom: 160px; } #scroll_D { bottom: 100px; transform: rotate(180deg); } #scroll_U.dark,#scroll_D.dark { color: rgba(255, 255, 255, 0.8); border: rgb(0, 204, 255) 1px solid; background: rgb(37, 36, 44, 0.8); opacity: 0.5; } .UDSVG { width: 40px; height: 40px; margin-top: 4px; } #next { display: block; text-align: center; margin: 5px; padding: 10px 0; border: solid #666; 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; } #next.dark { border: solid #7cffcb; } @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="backgroundColor"></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 class="number"><input id="auto-exclude-error" type="checkbox"></input>${DL.str_185}</label> <label class="number" title="${DL.str_173}"><input id="move" type="checkbox"></input>${DL.str_172}</label> <label class="number"><input id="size" type="checkbox"></input>${DL.str_171}</label> <label id="more" class="number">${DL.str_186} ☰<ul id="more-menu"></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> `; const UD_Buttons = ["scroll_U", "scroll_D"].map(id => { let html = ` <a id="${id}" class="hide" href="javascript:void(0);"> <svg class="UDSVG" 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); 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,.image-item,.image-item p,#excludeList,.excludeItem,#more-menu,.more-item,#scroll_U,#scroll_D,#next"; 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) => { cancelDefault(event); if (moreE.classList.contains("active")) { moreE.classList.remove("active"); moreMenu.classList.remove("show"); } else { moreE.classList.add("active"); moreMenu.classList.add("show"); } }); [{ id: "combineDownload", text: DL.str_181 }, { id: "copy", text: DL.str_105.replace(/\(.\)/, "") }, { id: "export", text: DL.str_104.replace(/\(.\)/, "") }, { id: "export_json", text: DL.str_193, cfn: 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); } }, { id: "copy_md", text: DL.str_194, cfn: 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); } }, { id: "export_md", text: DL.str_195, cfn: 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); } }, { id: "settings", text: DL.str_85.replace(/\(.\)/, "") }].forEach(({ id, text, cfn }) => { const li = document.createElement("li"); li.id = id; li.className = "more-item"; li.innerText = text; if (isFn(cfn)) li.addEventListener("click", cfn); fragment.append(li); }); moreMenu.append(fragment); if (isM) { ge("label:has(>#move)", main).classList.add("hide"); gae(".mobile_toggle_filter_gallery_btn,#scroll_U,#scroll_D", main).forEach(e => e.classList.remove("hide")); 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 => { if (main.scrollTop > lastScrollTop) { gae("#scroll_U,#scroll_D", main).forEach(e => e.classList.add("hide")); } else if (main.scrollTop < lastScrollTop) { gae("#scroll_U,#scroll_D", main).forEach(e => e.classList.remove("hide")); } lastScrollTop = main.scrollTop; }); } 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 backgroundSelect = ge("#backgroundColor", main); Object.keys(DL.backgroundColor).forEach((k, i) => { const option = document.createElement("option"); option.value = k; option.innerText = DL.backgroundColor[k]; fragment.append(option); }); backgroundSelect.append(fragment); backgroundSelect.value = config.backgroundColor; backgroundSelect.addEventListener("change", () => { config.backgroundColor = backgroundSelect.value; saveConfig(config); backgroundColor = config.backgroundColor; if (backgroundColor === "d") { gae(ui_selector, shadow).forEach(e => e.classList.add("dark")); } else { gae(ui_selector, shadow).forEach(e => e.classList.remove("dark")); } main.focus(); }); if (backgroundColor === "d") { 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; 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(); } 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; })); 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; fn.remove("#overflowYHidden"); shadowElement.remove(); isOpenFilter = false; 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(); } 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(); } 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(); } main.focus(); }); } const imageList = ge("#image-list", main); const ViewerOptions = { navbar: false, title: false, initialCoverage: 0.99, interval: FancyboxSlideshowTimeoutNum, url: "data-src", 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 (["www.mmxxdd.com", "mmxxdd.com"].some(h => fn.lh == h)) { 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 (backgroundColor === "d") { 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); if (Viewer && ViewerJsInstance) { ViewerJsInstance.update(); } 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 (["www.mmxxdd.com", "mmxxdd.com"].some(h => fn.lh == h)) { 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"; if (backgroundColor === "d") { 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 (options.mobileGallery == 1) { let button = ge(".mobile_toggle_filter_gallery_btn", main); EClick(button); } }; 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;z-index: ${UI_zIndex - 1} !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: 360px; height: auto; position: fixed; top: 10%; left: calc((100% - 362px) / 2); border: 1px solid #a0a0a0; border-radius: 3px; box-shadow: -2px 2px 5px rgb(0 0 0 / 30%); background-color: #fafafb; 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 * { 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: 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; } .tip { color: #0075ff !important; cursor: help; } `); 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="iconDIV" style="width: 348px; display: flex;"> <input id="icon" type="checkbox"> <label>${DL.str_69}</label> </div> <div id="ShowEyeDIV" style="width: 348px; display: none;"> <input id="ShowEye" type="checkbox"> <label>${DL.str_123}</label> </div> <div id="ShowFixedMenuDIV" style="width: 348px; display: flex;"> <input id="ShowFixedMenu" type="checkbox"> <label>※ ${DL.str_117}</label> </div> <div style="width: 348px; display: flex; margin-left: 7px;"> <label>${DL.str_108}</label> <select id="MsgPos"></select> </div> <div style="width: 348px; display: flex;"> <input id="FavorNewTab" type="checkbox"> <label>※ ${DL.str_50}</label> </div> <div id="AutoInsertImgDIV" style="width: 348px; display: flex;"> <input id="AutoInsertImg" type="checkbox"> <label>${DL.str_139}</label> </div> <div id="GoToFirstDIV" style="width: 348px; display: flex;"> <input id="GoToFirst" type="checkbox"> <label>※ ${DL.str_115}</label> </div> <div id="noPageNavDIV" style="width: 348px; display: flex;"> <input id="noPageNav" type="checkbox"> <label>※ ${DL.str_121}</label> </div> <div id="ZoomDIV" style="width: 348px; display: flex; margin-left: 7px;"> <label>${DL.str_79}</label> <select id="Zoom"></select> </div> <div id="viewModeDIV" style="width: 348px; display: flex;"> <input id="viewMode" type="checkbox"> <label>${DL.str_103}</label> </div> <div id="ColumnDIV" style="width: 348px; display: flex; margin-left: 7px;"> <label>${DL.str_80}</label> <select id="Column" title="${DL.str_81}"></select> </div> <div id="ShadowGalleryModeDIV" style="width: 348px; display: flex;"> <input id="ShadowGalleryMode" type="checkbox"> <label>${DL.str_140}</label> </div> <div id="MobileGalleryModeDIV" style="width: 348px; display: flex;"> <input id="MobileGalleryMode" type="checkbox"> <label>${DL.str_192}</label> </div> <div id="GalleryInIconDIV" style="width: 348px; display: flex;"> <input id="GalleryInIcon" type="checkbox"> <label>※ ${DL.str_77}</label> </div> <div id="autoExportDIV" style="width: 348px; display: flex;"> <input id="autoExport" type="checkbox"> <label>${DL.str_180}</label> </div> <div id="ShadowGalleryloopViewDIV" style="width: 348px; display: flex;"> <input id="loopView" type="checkbox"> <label>${DL.str_182}</label> </div> <div id="ShadowGalleryWheelDIV" style="width: 348px; display: flex; margin-left: 7px;"> <label>${DL.str_147}</label> <select id="ShadowGalleryWheel"></select> </div> <div id="horizontalWheelDIV" style="width: 348px; display: flex; margin-left: 7px;"> <label>${DL.str_198}</label> <select id="horizontalWheel"></select> </div> <div id="FancyboxDIV" style="width: 348px; display: flex;"> <input id="Fancybox" type="checkbox"> <label>${DL.str_78}</label> </div> <div id="FancyboxWheelDIV" style="width: 348px; display: flex; margin-left: 7px;"> <label>※ ${DL.str_146}</label> <select id="FancyboxWheel"></select> </div> <div id="FancyboxSlideshowTimeoutDIV" style="width: 348px; display: flex; margin-left: 7px;"> <label>※ ${DL.str_145}</label> <select id="FancyboxSlideshowTimeout"></select> </div> <div id="FancyboxTransitionDIV" style="width: 348px; display: flex; margin-left: 7px;"> <label>※ ${DL.str_148}</label> <select id="FancyboxTransition"></select> </div> <div id="ComicDIV" style="width: 348px; display: none;"> <input id="Comic" type="checkbox"> <label>${DL.str_76}</label> </div> <div id="DoubleDIV" style="width: 348px; display: flex;"> <input id="Double" type="checkbox"> <label>※ ${DL.str_199}</label> </div> <div id="AutoDownloadDIV" style="width: 348px; display: flex;" 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" style="width: 348px; display: flex; margin-left: 7px;"> <label>${DL.str_75}</label> <select id="Countdown"></select> </div> <div style="width: 348px; display: flex; margin-left: 7px;"> <label>${DL.str_70}</label> <select id="Threading"></select> </div> <div style="width: 348px; display: flex;"> <input id="Zip" type="checkbox"> <label>${DL.str_71}</label> </div> <div style="width: 348px; display: flex;"> <input id="zipFolder" type="checkbox"> <label>※ ${DL.str_187}</label> </div> <div style="width: 348px; display: flex; margin-left: 7px;"> <label>※ ${DL.str_72}</label> <select id="Extension"></select> </div> <div id="HitomiDIV" style="width: 348px; display: flex; margin-left: 7px;"> <label>${DL.str_202}</label> <select id="Hitomi"></select> </div> <div id="EHentaiDIV" style="width: 348px; display: flex;"> <input id="EHentai" type="checkbox"> <label>${DL.str_114}</label> </div> <div style="width: 348px; display: flex;"> <input id="ConvertWEBP" type="checkbox"> <label>※ ${DL.str_110}</label> </div> <div style="width: 348px; display: flex;"> <input id="ConvertAVIF" type="checkbox"> <label>※ ${DL.str_200}</label> </div> <div style="width: 348px; display: flex; margin-left: 7px;"> <label>※ ${DL.str_201}:</label> <select id="Quality"></select> </div> <div id="CustomDownloadVideoDIV" style="width: 348px; display: none;"> <input id="CustomDownloadVideo" type="checkbox"> <label>${DL.str_124}</label> </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> `; main.innerHTML = FullPictureLoadOptionsMainHtmlStr; 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 <= 10; i++) { const option = document.createElement("option"); option.value = i; if (i == 0) { option.innerText = 0; } else if (i == 10) { option.innerText = 1; } else { option.innerText = "0." + i; } fragment.append(option); } QualitySelect.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("#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("#EHentai", main).checked = _GM_getValue("E_HENTAI_LoadOriginalImage", 0) == 1 ? true : false; ge("#Hitomi", main).value = _GM_getValue("hitomi_img_type", "webp"); 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("convertQuality", 9); 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 => (ge(s, main).style.display = "none")); }; 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 (!["e-hentai.org", "exhentai.org"].some(h => fn.lh == h)) { hide(["#EHentaiDIV"]); } if (fn.lh != "hitomi.la") { hide(["#HitomiDIV"]); } if (isSimpleMode) { hide([ "#MobileGalleryModeDIV", "#autoExportDIV" ]); } if (isBoolean(siteData.SPA)) { hide([ "#ShadowGalleryModeDIV", "#ShadowGalleryWheelDIV", "#horizontalWheelDIV", "#ShadowGalleryloopViewDIV" ]); } if (isSimpleMode || siteData.aeg == 0) { hide(["#ShadowGalleryModeDIV"]); } if (isSimpleMode) { hide([ "#iconDIV", "#AutoDownloadDIV", "#CountdownDIV" ]); } 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("#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("#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); 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("E_HENTAI_LoadOriginalImage", ge("#EHentai", main).checked == true ? 1 : 0); _GM_setValue("hitomi_img_type", ge("#Hitomi", 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("convertQuality", 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; _GM_setValue("FancyboxSlideshowTimeout", ge("#FancyboxSlideshowTimeout", main).value); _GM_setValue("FancyboxWheel", ge("#FancyboxWheel", main).value); _GM_setValue("FancyboxSlideshowTransition", ge("#FancyboxTransition", main).value); options.zoom = ge("#Zoom", main).value; options.column = ge("#Column", main).value; options.viewMode = 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, .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; } .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; 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; 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); if (fn.url === "yinaw.com") { _GM_registerMenuCommand(setYinawSinaOriginalURL == 0 ? "❌ 壹纳网使用原始新浪图床链接" : "✔️ 壹纳网使用原始新浪图床链接", () => { setYinawSinaOriginalURL == 0 ? _GM_setValue("setYinawSinaOriginalURL", 1) : _GM_setValue("setYinawSinaOriginalURL", 0); location.reload(); }); } const copymangaSPA_Mode = _GM_getValue("copymangaSPA_Mode", 1); if (["www.copymanga.tv", "copymanga.tv", "www.mangacopy.com", "mangacopy.com"].some(h => fn.lh === h) && isMobileDeviceUA) { _GM_registerMenuCommand(copymangaSPA_Mode == 0 ? "❌ 拷貝漫畫SPA模式" : "✔️ 拷貝漫畫SPA模式", () => { copymangaSPA_Mode == 0 ? _GM_setValue("copymangaSPA_Mode", 1) : _GM_setValue("copymangaSPA_Mode", 0); location.reload(); }); } 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 "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 "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 ("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; isFn(next) ? tempLink = await 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 getTitle = async (title) => { let text; if (isString(title)) { text = fn.dt({ s: title }); } 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; const historyEvent = () => { setTimeout(() => { if (currentURL !== document.URL.replace(new URL(document.URL).hash, "")) { currentURL = document.URL; 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) 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; toggleUI_B(); } } }); }; const observer = new MutationObserver(callback); observer.observe(document.head, config); historyObserver(); }; const navEvent = event => { if (isGoToNext) 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; toggleUI_B(); } }; const navObserver = () => { //Firefox、Safari尚未支持Navigation API _unsafeWindow.navigation.addEventListener("navigate", navEvent); historyObserver(); }; const gmUrlEvent = event => { if (isGoToNext) return; const url = event.url.replace(new URL(event.url).hash, ""); if (currentURL !== url) { currentURL = url; toggleUI_B(); } }; const gmUrlObserver = () => { window.addEventListener("urlchange", gmUrlEvent); historyObserver(); }; const loopObserver = () => { setInterval(() => { if (isGoToNext) return; const url = document.URL.replace(new URL(document.URL).hash, ""); if (currentURL !== url) { currentURL = url; 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); } } 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; isGotAll = false; 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 ("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")) return; } if ("observeURL" in siteData && isString(nextLink)) { fn.showMsg(DL.str_34, 0); return (location.href = nextLink); } if (isFn(next)) { fn.showMsg(DL.str_34, 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, 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; const prev = siteData.prev; 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 === "ArrowLeft" || event.key === "ArrowLeft") { event.preventDefault(); if (prev === 1) { fn.showMsg(DL.str_38); history.back(); return; } let ele = fn.ge(prev); if (ele) { EClick(ele); 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()) { setTimeout(() => createShadowGallery(), 200); } } else { setTimeout(() => createShadowGallery(), 200); } } 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()) { setTimeout(() => createFilterUI(), 200); } } else { setTimeout(() => createFilterUI(), 200); } } 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(() => { let preloadNext = siteData.preloadNext; try { if ("page" in siteData) { if (!siteData.page()) return; } if (!!nextLink && !!preloadNext && !isDownloading) { let _fetch; if ("frame" in siteData) { _fetch = fn.iframeDoc(nextLink, siteData.frame); } else if ("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(siteData.imgs) && isFn(siteData.customTitle)) { fn.picPreload(await siteData.imgs(nextDoc), await siteData.customTitle(nextDoc), "next"); } else if (isBoolean(preloadNext) && preloadNext === true && isString(siteData.imgs) && isFn(siteData.customTitle)) { let arr = fn.getImgSrcArr(siteData.imgs, nextDoc); fn.picPreload(arr, await siteData.customTitle(nextDoc), "next"); } else 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 && ["nsfw1", "nsfw2", "hcomic", "comic"].some(c => c === siteData.category)) { _GM_registerMenuCommand(newTabViewLightGallery == 0 ? "❌ " + DL.str_120 : "✔️ " + DL.str_120, () => { newTabViewLightGallery == 0 ? localStorage.setItem("newTabViewLightGallery", 1) : localStorage.setItem("newTabViewLightGallery", 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,#fafafa text-color,#000 background-color,#aceebb 小黃書,https://xchina.biz/ 紳士会所,https://www.hentaiclub.net/ 图宅网,https://www.tuzac.com/ 丝袜客,https://siwake.cc/ 萌图社,http://www.446m.com/ 美女图册,https://www.mntuce.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/ SexyAsianGirl,https://www.sexyasiangirl.xyz/ Cup2D,https://cup2d.com/ Mega Gallery,https://www.ecy8.com/ 二刺猿地帶,https://cosplay-nextjs.vercel.app/ 紳士漫畫,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;z-index: ${UI_zIndex - 2} !important;"></div>`; document.body.insertAdjacentHTML("beforeend", mainHtml); const FavorSitesShadowElement = ge("#FullPictureLoadFavorSites"); const shadow = FavorSitesShadowElement.attachShadow({ mode: "closed" }); hidePageScrollbarY(); const style = createStyle(` #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"); Object.assign(FavorSitesElement.style, { left: "0", right: "0", top: "0", bottom: "0", width: "99%", height: "98%", margin: "auto", padding: "10px", position: "fixed", opacity: "1", zIndex: UI_zIndex - 2, 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% - 10px)"; textarea.style.height = "calc(100% - 30px)"; editFavorDiv.append(textarea); FavorSitesElement.appendChild(editFavorDiv); [{ text: DL.str_132, id: "editFavorCloseBtn", cfn: event => { cancelDefault(event); editFavorDiv.remove(); createFavor(); } }, { text: DL.str_131, id: "editFavorSaveBtn", cfn: event => { cancelDefault(event); _GM_setValue("favorData", textarea.value); 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 = "#fafafa"; 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 = "#000"; let backgroundColor = "#aceebb"; 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) 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); } }); } 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); } }); } })(JSZip);