// ==UserScript== // @name JHS-enhance // @namespace JHS-enhance // @version 3.3.7 // @author xie bro,fireinrain // @description Jav-鉴黄师 增强脚本。列表页:作品状态标签、一键筛选、新作品检测、演员黑名单过滤;详情页:磁力链接高亮、DMM 多画质预览视频、标题翻译、整合字幕搜索(迅雷+SubTitleCat)并支持 115 直传、多源预览图(javfree/projectjav/javstore)含来源切换;数据:115 网盘目录匹配与多目录选择、云盘备份/恢复、跨 Tab 同步;其他:自动翻页、分类折叠、Top250、以图识图、热门榜单、评论查看、相关清单。支持 JavDB / JavBus / JavSee / SeeJav / FC2 / JavTrailers // @license MIT // @icon https://www.google.com/s2/favicons?sz=64&domain=javdb.com // @include https://javdb*.com/* // @include https://*javbus*/* // @include https://*javsee*/* // @include https://*seejav*/* // @include https://javtrailers.com/* // @include https://subtitlecat.com/* // @include https://www.aliyundrive.com/* // @include https://www.alipan.com/* // @include https://115.com/* // @match https://javdb.com/* // @match https://www.javbus.com/* // @exclude https://*javbus*/forum/* // @exclude https://*javbus*/*actresses // @exclude https://*javsee*/forum/* // @exclude https://*javsee*/*actresses // @exclude https://*seejav*/forum/* // @exclude https://*seejav*/*actresses // @require https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js // @require https://cdn.jsdelivr.net/npm/tabulator-tables@6.5.2/dist/js/tabulator.min.js // @require https://cdn.jsdelivr.net/npm/layui-layer@1.0.9/dist/layer.min.js // @require https://cdn.jsdelivr.net/npm/blueimp-md5@2.19.0/js/md5.min.js // @require https://cdn.jsdelivr.net/npm/toastify-js@1.12.0/src/toastify.min.js // @require https://cdn.jsdelivr.net/npm/localforage@1.10.0/dist/localforage.min.js // @require https://cdn.jsdelivr.net/npm/viewerjs@1.11.1/dist/viewer.min.js // @require https://cdn.jsdelivr.net/npm/qrcodejs@1.0.0/qrcode.min.js // @require https://cdn.jsdelivr.net/npm/systemjs@6.15.1/dist/system.min.js // @require https://cdn.jsdelivr.net/npm/systemjs@6.15.1/dist/extras/named-register.min.js // @require data:application/javascript,%3B(typeof%20System!%3D'undefined')%26%26(System%3Dnew%20System.constructor())%3B // @connect xunlei.com // @connect geilijiasu.com // @connect aliyundrive.com // @connect aliyundrive.net // @connect ja.wikipedia.org // @connect beta.magnet.pics // @connect jdforrepam.com // @connect cc3001.dmm.co.jp // @connect cc3001.dmm.com // @connect www.dmm.co.jp // @connect www.dmm.com // @connect api.dmm.com // @connect special.dmm.co.jp // @connect adult.contents.fc2.com // @connect fc2ppvdb.com // @connect 123av.com // @connect u3c3.com // @connect u9a9.com // @connect btsow.lol // @connect sukebei.nyaa.si // @connect javstore.net // @connect javbest.net // @connect missav.live // @connect jable.tv // @connect www.av.gl // @connect jav.rs // @connect javtrailers.com // @connect javdb.com // @connect javbus.com // @connect supjav.com // @connect 115.com // @connect jianguoyun.com // @connect 127.0.0.1 // @connect * // @grant GM_addStyle // @grant GM_info // @grant GM_openInTab // @grant GM_xmlhttpRequest // @grant unsafeWindow // @grant window.close // @run-at document-idle // ==/UserScript== (a => { if (typeof GM_addStyle == "function") { GM_addStyle(a); return } const A = document.createElement("style"); A.textContent = a, document.head.append(A) })(" html #layuicss-skinlayercss{display:none;position:absolute;width:1989px}.layui-layer-shade,.layui-layer{position:fixed;_position:absolute;pointer-events:auto}.layui-layer-shade{top:0;left:0;width:100%;height:100%}.layui-layer{-webkit-overflow-scrolling:touch}.layui-layer{top:150px;left:0;margin:0;padding:0;background-color:#fff;-webkit-background-clip:content;box-shadow:1px 1px 50px #0000004d}.layui-layer-close{position:absolute}.layui-layer-content{position:relative}.layui-layer-border{border:1px solid #B2B2B2;border:1px solid rgba(0,0,0,.1);box-shadow:1px 1px 5px #0003}.layui-layer-load{background:url(data:image/gif;base64,R0lGODlhJQAlAJECAL3L2AYrTv///wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFCgACACwAAAAAJQAlAAACi5SPqcvtDyGYIFpF690i8xUw3qJBwUlSadmcLqYmGQu6KDIeM13beGzYWWy3DlB4IYaMk+Dso2RWkFCfLPcRvFbZxFLUDTt21BW56TyjRep1e20+i+eYMR145W2eefj+6VFmgTQi+ECVY8iGxcg35phGo/iDFwlTyXWphwlm1imGRdcnuqhHeop6UAAAIfkEBQoAAgAsEAACAAQACwAAAgWMj6nLXAAh+QQFCgACACwVAAUACgALAAACFZQvgRi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwXABEADAADAAACBYyPqcsFACH5BAUKAAIALBUAFQAKAAsAAAITlGKZwWoMHYxqtmplxlNT7ixGAQAh+QQFCgACACwQABgABAALAAACBYyPqctcACH5BAUKAAIALAUAFQAKAAsAAAIVlC+BGL3Z3IlxUmUuhtR2LzHhsiEFACH5BAUKAAIALAEAEQAMAAMAAAIFjI+pywUAIfkEBQoAAgAsBQAFAAoACwAAAhOUYJnAagwdjGq2amXGU1PuLEYBACH5BAUKAAIALBAAAgAEAAsAAAIFhI+py1wAIfkEBQoAAgAsFQAFAAoACwAAAhWUL4AIvdnciXFSZS6G1HYvMeGyIQUAIfkEBQoAAgAsFwARAAwAAwAAAgWEj6nLBQAh+QQFCgACACwVABUACgALAAACE5RgmcBqDB2MarZqZcZTU+4sRgEAIfkEBQoAAgAsEAAYAAQACwAAAgWEj6nLXAAh+QQFCgACACwFABUACgALAAACFZQvgAi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwBABEADAADAAACBYSPqcsFADs=) #eee center center no-repeat}.layui-layer-ico{background:url(data:image/png;base64,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) no-repeat}.layui-layer-dialog .layui-layer-ico,.layui-layer-setwin a,.layui-layer-btn a{display:inline-block;*display: inline;*zoom: 1;vertical-align:top}.layui-layer-move{display:none;position:fixed;*position: absolute;left:0;top:0;width:100%;height:100%;cursor:move;opacity:0;filter:alpha(opacity=0);background-color:#fff;z-index:2147483647}.layui-layer-resize{position:absolute;width:15px;height:15px;right:0;bottom:0;cursor:se-resize}.layui-layer{border-radius:2px;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.3s;animation-duration:.3s}@-webkit-keyframes bounceIn{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}to{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes bounceIn{0%{opacity:0;-webkit-transform:scale(.5);-ms-transform:scale(.5);transform:scale(.5)}to{opacity:1;-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim{-webkit-animation-name:bounceIn;animation-name:bounceIn}@-webkit-keyframes zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);-ms-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);-ms-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-01{-webkit-animation-name:zoomInDown;animation-name:zoomInDown}@-webkit-keyframes fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);transform:translateY(2000px)}to{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);-ms-transform:translateY(2000px);transform:translateY(2000px)}to{opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}}.layer-anim-02{-webkit-animation-name:fadeInUpBig;animation-name:fadeInUpBig}@-webkit-keyframes zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);transform:scale(.1) translate(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);transform:scale(.475) translate(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);-ms-transform:scale(.1) translateX(-2000px);transform:scale(.1) translate(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);-ms-transform:scale(.475) translateX(48px);transform:scale(.475) translate(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-03{-webkit-animation-name:zoomInLeft;animation-name:zoomInLeft}@-webkit-keyframes rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);transform:translate(-100%) rotate(-120deg)}to{opacity:1;-webkit-transform:translateX(0px) rotate(0deg);transform:translate(0) rotate(0)}}@keyframes rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);-ms-transform:translateX(-100%) rotate(-120deg);transform:translate(-100%) rotate(-120deg)}to{opacity:1;-webkit-transform:translateX(0px) rotate(0deg);-ms-transform:translateX(0px) rotate(0deg);transform:translate(0) rotate(0)}}.layer-anim-04{-webkit-animation-name:rollIn;animation-name:rollIn}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.layer-anim-05{-webkit-animation-name:fadeIn;animation-name:fadeIn}@-webkit-keyframes shake{0%,to{-webkit-transform:translateX(0);transform:translate(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);transform:translate(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);transform:translate(10px)}}@keyframes shake{0%,to{-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translate(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);-ms-transform:translateX(-10px);transform:translate(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);-ms-transform:translateX(10px);transform:translate(10px)}}.layer-anim-06{-webkit-animation-name:shake;animation-name:shake}@-webkit-keyframes fadeIn{0%{opacity:0}to{opacity:1}}@-webkit-keyframes bounceOut{to{opacity:0;-webkit-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes bounceOut{to{opacity:0;-webkit-transform:scale(.7);-ms-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);-ms-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-close{-webkit-animation-name:bounceOut;animation-name:bounceOut;-webkit-animation-duration:.2s;animation-duration:.2s}.layui-layer-title{padding:0 80px 0 20px;height:42px;line-height:42px;border-bottom:1px solid #eee;font-size:14px;color:#333;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;background-color:#f8f8f8;border-radius:2px 2px 0 0}.layui-layer-setwin{position:absolute;right:15px;*right: 0;top:15px;font-size:0;line-height:initial}.layui-layer-setwin a{position:relative;width:16px;height:16px;margin-left:10px;font-size:12px;_overflow:hidden}.layui-layer-setwin .layui-layer-min cite{position:absolute;width:14px;height:2px;left:0;top:50%;margin-top:-1px;background-color:#2e2d3c;cursor:pointer;_overflow:hidden}.layui-layer-setwin .layui-layer-min:hover cite{background-color:#2d93ca}.layui-layer-setwin .layui-layer-max{background-position:-32px -40px}.layui-layer-setwin .layui-layer-max:hover{background-position:-16px -40px}.layui-layer-setwin .layui-layer-maxmin{background-position:-65px -40px}.layui-layer-setwin .layui-layer-maxmin:hover{background-position:-49px -40px}.layui-layer-setwin .layui-layer-close1{background-position:0 -40px;cursor:pointer}.layui-layer-setwin .layui-layer-close1:hover{opacity:.7}.layui-layer-setwin .layui-layer-close2{position:absolute;right:-28px;top:-28px;width:30px;height:30px;margin-left:0;background-position:-149px -31px;*right: -18px;_display:none}.layui-layer-setwin .layui-layer-close2:hover{background-position:-180px -31px}.layui-layer-btn{text-align:right;padding:0 10px 12px;pointer-events:auto;user-select:none;-webkit-user-select:none}.layui-layer-btn a{height:28px;line-height:28px;margin:0 6px;padding:0 15px;border:1px #dedede solid;background-color:#f1f1f1;color:#333;border-radius:2px;font-weight:400;cursor:pointer;text-decoration:none}.layui-layer-btn a:hover{opacity:.9;text-decoration:none}.layui-layer-btn a:active{opacity:.8}.layui-layer-btn .layui-layer-btn0{border-color:#4898d5;background-color:#2e8ded;color:#fff}.layui-layer-btn-l{text-align:left}.layui-layer-btn-c{text-align:center}.layui-layer-dialog{min-width:260px}.layui-layer-dialog .layui-layer-content{position:relative;padding:20px;line-height:24px;word-break:break-all;overflow:hidden;font-size:14px;overflow-x:hidden;overflow-y:auto}.layui-layer-dialog .layui-layer-content .layui-layer-ico{position:absolute;top:16px;left:15px;width:30px;height:30px}.layui-layer-ico1{background-position:-30px 0}.layui-layer-ico2{background-position:-60px 0}.layui-layer-ico3{background-position:-90px 0}.layui-layer-ico4{background-position:-120px 0}.layui-layer-ico5{background-position:-150px 0}.layui-layer-ico6{background-position:-180px 0}.layui-layer-rim{border:6px solid #8D8D8D;border:6px solid rgba(0,0,0,.3);border-radius:5px;box-shadow:none}.layui-layer-msg{min-width:180px;border:1px solid #D3D4D3;box-shadow:none}.layui-layer-hui{min-width:100px;background-color:#000;filter:alpha(opacity=60);background-color:#0009;color:#fff;border:none}.layui-layer-hui .layui-layer-content{padding:12px 25px;text-align:center}.layui-layer-dialog .layui-layer-padding{padding:20px 20px 20px 55px;text-align:left}.layui-layer-page .layui-layer-content{position:relative;overflow:auto}.layui-layer-page .layui-layer-btn,.layui-layer-iframe .layui-layer-btn{padding-top:10px}.layui-layer-nobg{background:none}.layui-layer-iframe iframe{display:block;width:100%}.layui-layer-loading{border-radius:100%;background:none;box-shadow:none;border:none}.layui-layer-loading .layui-layer-content{width:60px;height:24px;background:url(data:image/gif;base64,R0lGODlhPAAYALMPAPPJp/HYxfSwkf50Df5TD/+HAPe5bvqHR/twOviZavyrMu/m3f9EAP9mAP+ZAO7u7iH/C05FVFNDQVBFMi4wAwEAAAAh/wtYTVAgRGF0YVhNUDw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wUmlnaHRzPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvcmlnaHRzLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcFJpZ2h0czpNYXJrZWQ9IkZhbHNlIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6QUNDRERBRjMxRTIwNjgxMTg4QzZERjVGQ0I0MDI1NDkiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NTlDMEI5MzU5RTY2MTFFMTkxRDY5NkVCMDBGOTBFRUYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NTlDMEI5MzQ5RTY2MTFFMTkxRDY5NkVCMDBGOTBFRUYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpENzU2N0YwMTMyMjA2ODExODhDNkRGNUZDQjQwMjU0OSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpBQ0NEREFGMzFFMjA2ODExODhDNkRGNUZDQjQwMjU0OSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PgH//v38+/r5+Pf29fTz8vHw7+7t7Ovq6ejn5uXk4+Lh4N/e3dzb2tnY19bV1NPS0dDPzs3My8rJyMfGxcTDwsHAv769vLu6ubi3trW0s7KxsK+urayrqqmop6alpKOioaCfnp2cm5qZmJeWlZSTkpGQj46NjIuKiYiHhoWEg4KBgH9+fXx7enl4d3Z1dHNycXBvbm1sa2ppaGdmZWRjYmFgX15dXFtaWVhXVlVUU1JRUE9OTUxLSklIR0ZFRENCQUA/Pj08Ozo5ODc2NTQzMjEwLy4tLCsqKSgnJiUkIyIhIB8eHRwbGhkYFxYVFBMSERAPDg0MCwoJCAcGBQQDAgEAACH5BAkFAA8ALAAAAAA8ABgAAATy8MlJq7046827/2AWCEdpCkGodkHSvHCcLGttLUOsw0NqW4EDYog4+CyInbJxwAQMiqjCcMQkGNgsNmFxLZXcisFBLpMNGYF2zRBQAt9vFWCuOwCXAJt9FMSXbhILdnY0FQd7a00SB39Kiw9jhGZoFQSJWgQTjksTCpNmChaYa5ucOxOgdaOkWaanMamqZRaXrZoSObAvA56zDqKHrQyQjbtME5KqlW/DRwbHDcwBv1UTV5hhEnDHVcqEzF2J2te75BLflBsCCFoIgRU4pwOGFQCfZQp4PxUBSX8IrPELscDLkhkDB7bQxQthwocQI0rMEAEAIfkECQUADwAsAAAAADwAGAAABOjwyUmrvTjrzbv/ILcAiWCUQKh+y9G88DsIa40JcQ4ji30JCIZQeAhcAgOdMvEYKZ5PQA8UHFoZtEpSuVQ4vmCHwuhJXK+EqcTA5YbfYrUmcD4jKNt2rAB/GzoHdWdTAXo6fXByGASCV1k4hjADiG8pG41XTA9skS98lGB/l5hDmgmdnqChHIykWBKQnZOqDpYaVaRkAKgvtA6KFwCudxO8DZ+UCh64grYPp7yqwBgLzFYEWRNIvAlecGMhAq1DCGQVu7JNBn7THQDvAObBeVwJ7T4gLW2i+P0PAQkOCBQoxZ/BgwgTYogAACH5BAkFAA8ALAAAAAA8ABgAAATV8MlJq7046827/2AojmMgHE2aIslCckAcb8Kg3umQvFhCMEAgYXcR4HCFpEJhCPAkiKAUiLAEbMdGwcHtcg28w3R8qKCyA6/aASABxvC2JJBNrdcuURQ+rUqMWVt3XmAhC3xweWdHg2oKIm+IU3KLOI1qkJKTEpU3l14iAZpSTg+dKp9cjyKjQRMGdYKXhSFio2VzdQ2ppSEBP5IEvQ9YR7J3tCICmgIVALrHhE+/cMIXCboDxwpy0z5BQ8POxUcD3U88CwnkKQni6E8yMXnw9fb3+BURACH5BAkFAA8ALAAAAAA8ABgAAATe8MlJq7046827/2AojqQUCEeaJkC5CUgcJ0G2JE2u60jrVgICY0gcIhaXQ25QaDp1vt8jUKwaLbhGwcHtcgeNQe23EFqrAkogt/W6cwlp4mwlICW4gXvvyI1LZnRFaRJgfHtghCRUglUIJjmHbgUNBy4AjY4SAGGSXpSWJZiZRI8PnHqeXKAujKQMpmsNqquVP4GZioa0iT8Hrwx/Sqmefj8BuHRxE5xanmChPwKZRxVKznxgDX8/AAh00RQL18S1YYpSDzffpVEXAjvxB9zpiwnaOQfo9fz9/v8ApUQAACH5BAkFAA8ALAAAAAA8ABgAAATO8MlJq7046827/2AojmS1AIkhJEBQasFBMDRDHC62JE3v97iXJVEr1hKThUHBdBQGv99gIZwIjFiG4AFweL/eQtSHqD4Cs2yR0AW7xeOGoXpQYwvuPHQ8FabtNA15g3ENWyUBgEUDg3mFBy8AijV4jWB7UZAlkpMMlZZemD+aJImdjKBej0KdDIKpDoWHJXWdn42iPzmIrQagcGOkL0SKSG15wFF9ZgJ/WLMBvpeFCLtmMVhBOjxxB1RmJgDiAN8bAQkH6Qcs4O3u7/Dx4BEAIfkECQUADwAsAAAAADwAGAAABMrwyUmrvTjrzbv/YCiOV5AgKCosZIsFCCPPc5KZQ6M3QxK4lgWBRuMVFEgDS5LYOXc24CRGlBUc2CwW8BA8vw2BtFuVDbRoByAHdg6WrmG1kU63v9EWoMy41rVsdzoDQAllBH9oBYJOPy2GVYiJWYuMOlyPh5OUlpcuApqbDpWWjiQBfH6TgYxSVER0m50NeS2gZap1BrOmLpBVuVpcTYy1QLdzuQamAqxuYmMTMGUJcBYmeL3REgAJ3gkC2hgLAOUA1tvp6uvs7R8RACH5BAkFAA8ALAAAAAA8ABgAAATs8MlJq7046827/2AojpmQICgqBGSLCQgjz3OyZEFy7LvgXoDZoEAsDBoyxGWRaDifzgHgNwkQGA2HdqstyBKWA3TsZFEPDAJ37RjIzBIBmTy4uQKyAnuNPEwWR3NjPi4CWHtrXgQTcoJjAz8xA4hrbxJijmNwIzF6lFtXUw+YmU+iJJ2foAyipKUNp5wMk6oOV2aupZsihlmqioyvUT94DJ6USEoSAcINYJGHlF6sFE2lA7sjxQ3HXNN+FAu5ZIRUAlcEtF1IDAh2FQaC2FQUATE0NOVACYENAyv0LMCgQeBAtoAIEypcyLDhhAgAIfkECQUADwAsAAAAADwAGAAABODwyUmrvTjrzbv/YCiOWiAgTJoiSUC+V0KodEokZWIIugtPAYNCUSgMZjWV4BI4NJ7QxsH3Mjiu2OsgqaJKFoOoeLB4AbJoR4PLQFQQ4rh7tEin2QyqIM5fiqx2WVtcfg9hfGMjCoFZBWxzC4h8Xh6MaI8SAJJxACKWWZgPmptRnSGLn45ccwGkUWUhgJaDSTgSh6QDIwGfDkhJeq4Ntn+zbAQUYLmwI7Joa2ymQLhxA5QiAKhXBdBcBxcLcHEHzD+Zv0kEhRcACQfvCdLmFAEytdfzZgD7AOX5/wADCrwQAQAh+QQJBQAPACwAAAAAPAAYAAAE6fDJSau9OOvNu/8gFiQkKSxh+gkE474uEqj0tSBw/gq1twCKYBCAOuiOhJllkRg0no0BDxRQOK5YhyJx7BIsAKj4ifgsrNlsodtNUBbOsdjgMaTvA7buOznI5UoaC3eELXowSgF/cm4bAIR3DYcwUwKLYwMcdpBZkpMujQaXY5qcnZ+gEgmjYhyPpleen42WrFEcg7AOqC4AEoq2Bx1onGu8FAi2vriwvAzCE2Gj0B1VhApGqEkVAnFyByhmm1gGKDifUxULfmN0PerZbATLGD8A9+8ZLF0y+f4PAhAIFJgg0L+DCBMqrBABACH5BAkFAA8ALAAAAAA8ABgAAATz8MlJq7046827/2AWCEhpCkGodkHCvHCcpGtdBUSswwRt3waFUGHwVRC7JAOBaR2eh9nG4KhaqwaLS5lMaBvgMNiLAVzPDgAlwOUaBeJ4Q3BZoNGLiaCtpEsWcnJGElR3V1kSSHw7TBIJgXFkFAqGVwoTi0oTA5BiAxaVZ5iZOxOdcaChVqOkMaanYRaUqpcSOa0vBJuwDZ8VhaGID4q4jQ+PsJITAaoOPlu4kgG8g4TBa7gvRsiQyr+GwhMHuAcWBpDhFwCzVQpqFgu3iwR5FgAHYgfvP2vEXAj7+K1YMI7LgXoCf7SQx4CAlIQQI0qcmCECACH5BAkFAA8ALAAAAAA8ABgAAATe8MlJq7046827/2AXACQZnuCSEEzrEkmAzpjAunhLCDRmKI5g0LC4BHJIl+wRSByeh1hKSBUWKYtbMkdQNb7gb+IDrFIVlcR2iwi7GzwOwGwGTI7r5Pu91NDpEwJ5SAR7bmMaC39mVweDOYZuAxsBi1VLCI84kW6UllSYmi6cYZ6fQaGiDKRfkxunQRNqqoWkiBoGpwaBqi2sfRmKn1cPWb21hreUZWYKwA+zogkGhrsguVVEF5maCBIAB2EHdicLAecBxBYL3HkI6j0zgmvK8T1NWgwwz/b9/v8AMUQAACH5BAkFAA8ALAAAAAA8ABgAAATY8MlJq7046827/+AXACQQhCi4CATjvoSwpFww2nMWtG/vEieaZQFwGI8ORbCy4Pl6hMZhmlimFMiswypBPKGNsDicoBm02pxE8IWN3w0BaoHWGijOLxzO5RTrWRMBbT97b2UgWIBIQQmEDIZvAyGKi0aNj5FvlJZHmISaYyFnnVtrmaENkyCknRMAj1GhiB90nXcTeU+pfRytgGoPjoSyhrQqlWgATLo+xW+4NH9ZCsGCzT5vB8tCEkQG4Aa9EwtehAjW3TQLCdgJ6erdAgn0CXLx+Pn6+xwRACH5BAkFAA8ALAAAAAA8ABgAAATM8MlJq7046827/2AojuSzCAeiqsJSaoChzIoBaALB7DyfvJaAwkEsEhWBS6LHIDQaTt0PKFkMjViFiwLoOZ/gJ0FAfVyx2Ypu9w2HB9QAeu5ISgQ9t75BfhnoaAYTCDxte08HQIBzE2sMh25wL4toE3mQYYqURpY8mJmTm0WdO59gQH+ighKEbKaJLwCiDjd3l5h9L2eAChQBjoZ7di9ylMMSS4WHBFNUVnRaSkx6DM1lDwC7CgBbFwCOTAy51yQLCeDM3eTr7O3u7yMRACH5BAkFAA8ALAAAAAA8ABgAAATO8MlJq7046827/2AojiQVCEmaCEGpLYbizI5iLFlwMHzPHy1XJSCjGRVBU6JBYDZ8PEJSuCgaj7jJssHtMqGIrKt6LdeyAq/660sIHwaz2fBYrNdQxnRkldMUD1t3XQRQAi4BfmYBA4NqYIiKZQGOjz4IkZJGlJVdkCULmkYLjZ1Pl0KiNIGmhT6HLnGidJyVeXsioaJZgneuPZhviZJicIO/UcVjfVgWAAeWl7hjskY3GQsIeTxhbxcLAeEByhjPCOcIBwDe7O3u7/DxEhEAIfkECQUADwAsAAAAADwAGAAABMHwyUmrvTjrzbv/YCiOWGACgbcALEpygeHMtGNoAsLsPCG8GEBt6FAAEofkIRE48J68A7ASIBILjay2QYB6f9PHQmElDrbarveZmsrKRLR2/USE4dazXE1ntElVeENYcg19O2CAgoOFhocJQIGLM4RyhwyQL5KTlWiXiSSTNHpofHR/JG+TjZcEYQuinWmfYQ9CgrJZpmtStQ+bRAYAB1sHAAKHoLUxVjcZOV4+vhYxBtYACx0CCdwJytPg4eLj5B8RACH5BAkFAA8ALAAAAAA8ABgAAATI8MlJq7046827/2AojtgCGKgBLGSbLYojz7LClgnC7AyS3C7KgkacJQKWAIHHZBCQQQmsSG0khMsmkwB0GajUQkMg1WmbiO5oCKYOGsjE+Xz1tt3WR3a+DX7vRGIDAXxnUCQxgDRiDQCFWgAuiYoyjI6PTJEtk5SChJg8hyMAlDNvV3uPBEFspQ1wD3KgdZKlYnULqXNcUa2ADQYUn3xPURIBnFQHmkJmWmnGE1NUNi+yTD/RFQEGCt4KBqIvAOQr2ufo6errIhEAIfkECQUADwAsAAAAADwAGAAABLTwyUmrvTjrzbv/YCiO2QIYSqoYxkK+GODMdG1owoHsyCHAF0NtSLtZAgiGcqlEBIATGXEKqCwIzCyD4IIqplNFJanNIqBSMLEqAZTL7NdXTRRLDm/tAUgHT7B5TAR8fUQTgVqEhTWHiEyKizN/jkqDMHORdg9kjmcwaYtxApQMPzALkTNdEpx5nkBCi0YTAYgEcbCFsxQLrUwIq1APAXS4Fjm/AsHCDwsoQy3M0tPU1dbXGBEAIfkECQUADwAsAAAAADwAGAAABNbwyUmrvTjrzbv/4BWMZGiCC+CsrKMYyyljQWuvSqAFQA/os0kgcSjejoqYRYBgOJ8EQDDRqDYKR6Ql8ew+EzKBtTHIZqUTgHfNQKPGDXNWQWmyuwgTdSzPAgN3a0AfA2NYfTcGEgKBXgIhcIeILYoPXI1fkIaTNpWXmAxgIIVWZZwsaIygDI8ge1Wmpw5/qwyDHgFwsisUBKAEJ69XspUSapitJgabk0kVB40HQQAHsJy3ab5eUUEWCwpyzhkCCeUJbt0VCwZZMOnvxgbyBujw9vf4+RcRACH5BAUFAA8ALAAAAAA8ABgAAATi8MlJq7046827/2AWjGRogovirKyjAMspY0Zrr0owe0Fy/IeE7gG4GRWxS4LAaDIIiaQn0ahaq0KjVmEJMJ1gwpAjuJob2jSgggC7GYjO4nwdpLcUwfst4FDpVQV3WlJfe04EHAOAVYNaaw8Bh29jGIyNjjcGEgCTbpAZl2iZNptEnmCgGIuMpKUSkqhNlUqXgq4roIaTiRsBtrgrUgmyCR1/dHa4XBMLu28EUhsGgAYqrrReh2IgAAdXB2sLrqYWS24H0juR13flFwsA8jDr8DVq9fkB9ywKBur5AgocSPBCBAA7) no-repeat}.layui-layer-loading .layui-layer-loading1{width:37px;height:37px;background:url(data:image/gif;base64,R0lGODlhJQAlAJECAL3L2AYrTv///wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFCgACACwAAAAAJQAlAAACi5SPqcvtDyGYIFpF690i8xUw3qJBwUlSadmcLqYmGQu6KDIeM13beGzYWWy3DlB4IYaMk+Dso2RWkFCfLPcRvFbZxFLUDTt21BW56TyjRep1e20+i+eYMR145W2eefj+6VFmgTQi+ECVY8iGxcg35phGo/iDFwlTyXWphwlm1imGRdcnuqhHeop6UAAAIfkEBQoAAgAsEAACAAQACwAAAgWMj6nLXAAh+QQFCgACACwVAAUACgALAAACFZQvgRi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwXABEADAADAAACBYyPqcsFACH5BAUKAAIALBUAFQAKAAsAAAITlGKZwWoMHYxqtmplxlNT7ixGAQAh+QQFCgACACwQABgABAALAAACBYyPqctcACH5BAUKAAIALAUAFQAKAAsAAAIVlC+BGL3Z3IlxUmUuhtR2LzHhsiEFACH5BAUKAAIALAEAEQAMAAMAAAIFjI+pywUAIfkEBQoAAgAsBQAFAAoACwAAAhOUYJnAagwdjGq2amXGU1PuLEYBACH5BAUKAAIALBAAAgAEAAsAAAIFhI+py1wAIfkEBQoAAgAsFQAFAAoACwAAAhWUL4AIvdnciXFSZS6G1HYvMeGyIQUAIfkEBQoAAgAsFwARAAwAAwAAAgWEj6nLBQAh+QQFCgACACwVABUACgALAAACE5RgmcBqDB2MarZqZcZTU+4sRgEAIfkEBQoAAgAsEAAYAAQACwAAAgWEj6nLXAAh+QQFCgACACwFABUACgALAAACFZQvgAi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwBABEADAADAAACBYSPqcsFADs=) no-repeat}.layui-layer-loading .layui-layer-loading2,.layui-layer-ico16{width:32px;height:32px;background:url(data:image/gif;base64,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) no-repeat}.layui-layer-tips{background:none;box-shadow:none;border:none}.layui-layer-tips .layui-layer-content{position:relative;line-height:22px;min-width:12px;padding:5px 10px;font-size:12px;_float:left;border-radius:2px;box-shadow:1px 1px 3px #0003;background-color:#000;color:#fff}.layui-layer-tips .layui-layer-close{right:-2px;top:-1px}.layui-layer-tips i.layui-layer-TipsG{position:absolute;width:0;height:0;border-width:8px;border-color:transparent;border-style:dashed;*overflow: hidden}.layui-layer-tips i.layui-layer-TipsT,.layui-layer-tips i.layui-layer-TipsB{left:5px;border-right-style:solid;border-right-color:#000}.layui-layer-tips i.layui-layer-TipsT{bottom:-8px}.layui-layer-tips i.layui-layer-TipsB{top:-8px}.layui-layer-tips i.layui-layer-TipsR,.layui-layer-tips i.layui-layer-TipsL{top:1px;border-bottom-style:solid;border-bottom-color:#000}.layui-layer-tips i.layui-layer-TipsR{left:-8px}.layui-layer-tips i.layui-layer-TipsL{right:-8px}.layui-layer-lan[type=dialog]{min-width:280px}.layui-layer-lan .layui-layer-title{background:#4476a7;color:#fff;border:none}.layui-layer-lan .layui-layer-btn{padding:10px;text-align:right;border-top:1px solid #E9E7E7}.layui-layer-lan .layui-layer-btn a{background:#bbb5b5;border:none}.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background:#c9c5c5}.layui-layer-molv .layui-layer-title{background:#009f95;color:#fff;border:none}.layui-layer-molv .layui-layer-btn a{background:#009f95}.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92b8b1}.layui-layer-iconext{background:url(data:image/png;base64,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) no-repeat}.layui-layer-prompt .layui-layer-input{display:block;width:220px;height:30px;margin:0 auto;line-height:30px;padding:0 5px;border:1px solid #ccc;box-shadow:1px 1px 5px #0000001a inset;color:#333}.layui-layer-prompt textarea.layui-layer-input{width:300px;height:100px;line-height:20px}.layui-layer-prompt .layui-layer-content{padding:20px}.layui-layer-prompt .layui-layer-btn{padding-top:0}.layui-layer-tab{box-shadow:1px 1px 50px #0006}.layui-layer-tab .layui-layer-title{padding-left:0;border-bottom:1px solid #ccc;background-color:#eee;overflow:visible}.layui-layer-tab .layui-layer-title span{position:relative;float:left;min-width:80px;max-width:260px;padding:0 20px;text-align:center;cursor:default;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-layer-tab .layui-layer-title span.layui-layer-tabnow{height:43px;border-left:1px solid #ccc;border-right:1px solid #ccc;background-color:#fff;z-index:10}.layui-layer-tab .layui-layer-title span:first-child{border-left:none}.layui-layer-tabmain{line-height:24px;clear:both}.layui-layer-tabmain .layui-layer-tabli{display:none}.layui-layer-tabmain .layui-layer-tabli.xubox_tab_layer{display:block}.xubox_tabclose{position:absolute;right:10px;top:5px;cursor:pointer}.layui-layer-photos{-webkit-animation-duration:1s;animation-duration:1s}.layui-layer-photos .layui-layer-content{overflow:hidden;text-align:center}.layui-layer-photos .layui-layer-phimg img{position:relative;width:100%;display:inline-block;*display: inline;*zoom: 1;vertical-align:top}.layui-layer-imguide,.layui-layer-imgbar{display:none}.layui-layer-imgprev,.layui-layer-imgnext{position:absolute;top:50%;width:27px;_width:44px;height:44px;margin-top:-22px;outline:none;blr:expression(this.onFocus=this.blur())}.layui-layer-imgprev{left:10px;background-position:-5px -5px}.layui-layer-imgprev:hover{background-position:-33px -5px}.layui-layer-imgnext{right:10px;background-position:-5px -50px}.layui-layer-imgnext:hover{background-position:-33px -50px}.layui-layer-imgbar{position:absolute;left:0;bottom:0;width:100%;height:32px;line-height:32px;background-color:#000c;background-color:#000 \\ ;filter:Alpha(opacity=80);color:#fff;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;font-size:0}.layui-layer-imgtit *{display:inline-block;*display: inline;*zoom: 1;vertical-align:top;font-size:12px}.layui-layer-imgtit a{max-width:65%;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;color:#fff}.layui-layer-imgtit a:hover{color:#fff;text-decoration:underline}.layui-layer-imgtit em{padding-left:10px;font-style:normal}@media screen and (max-width:1100px){.layui-layer-iframe{overflow-y:auto;-webkit-overflow-scrolling:touch}} "); System.addImportMap({ imports: { "jquery": "user:jquery", "localforage": "user:localforage", "toastify-js": "user:toastify-js", "blueimp-md5": "user:blueimp-md5", "viewerjs": "user:viewerjs", "qrcodejs": "user:qrcodejs" } }); System.set("user:jquery", (() => { const _ = jQuery; ('default' in _) || (_.default = _); return _ })()); System.set("user:localforage", (() => { const _ = localforage; ('default' in _) || (_.default = _); return _ })()); System.set("user:toastify-js", (() => { const _ = Toastify; ('default' in _) || (_.default = _); return _ })()); System.set("user:blueimp-md5", (() => { const _ = md5; ('default' in _) || (_.default = _); return _ })()); System.set("user:viewerjs", (() => { const _ = Viewer; ('default' in _) || (_.default = _); return _ })()); System.set("user:qrcodejs", (() => { const _ = QRCode; ('default' in _) || (_.default = _); return _ })()); System.register("./__entry.js", ['jquery', 'localforage', 'toastify-js', 'blueimp-md5', 'viewerjs', 'qrcodejs'], (function (exports, module) { 'use strict'; var $$1, localforage$1, Toastify$1, md5$1, Viewer$1, QRCode$1; return { setters: [module => { $$1 = module.default; }, module => { localforage$1 = module.default; }, module => { Toastify$1 = module.default; }, module => { md5$1 = module.default; }, module => { Viewer$1 = module.default; }, module => { QRCode$1 = module.default; }], execute: (async function () { var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); const scriptRel = /* @__PURE__ */ (function detectScriptRel() { const relList = typeof document !== "undefined" && document.createElement("link").relList; return relList && relList.supports && relList.supports("modulepreload") ? "modulepreload" : "preload"; })(); const assetsURL = function (dep) { return "/" + dep; }; const seen = {}; const __vitePreload = function preload(baseModule, deps, importerUrl) { let promise = Promise.resolve(); if (deps && deps.length > 0) { let allSettled2 = function (promises) { return Promise.all( promises.map( (p) => Promise.resolve(p).then( (value) => ({status: "fulfilled", value}), (reason) => ({status: "rejected", reason}) ) ) ); }; document.getElementsByTagName("link"); const cspNonceMeta = document.querySelector( "meta[property=csp-nonce]" ); const cspNonce = (cspNonceMeta == null ? void 0 : cspNonceMeta.nonce) || (cspNonceMeta == null ? void 0 : cspNonceMeta.getAttribute("nonce")); promise = allSettled2( deps.map((dep) => { dep = assetsURL(dep); if (dep in seen) return; seen[dep] = true; const isCss = dep.endsWith(".css"); const cssSelector = isCss ? '[rel="stylesheet"]' : ""; if (document.querySelector(`link[href="${dep}"]${cssSelector}`)) { return; } const link = document.createElement("link"); link.rel = isCss ? "stylesheet" : scriptRel; if (!isCss) { link.as = "script"; } link.crossOrigin = ""; link.href = dep; if (cspNonce) { link.setAttribute("nonce", cspNonce); } document.head.appendChild(link); if (isCss) { return new Promise((res, rej) => { link.addEventListener("load", res); link.addEventListener( "error", () => rej(new Error(`Unable to preload CSS for ${dep}`)) ); }); } }) ); } function handlePreloadError(err) { const e = new Event("vite:preloadError", { cancelable: true }); e.payload = err; window.dispatchEvent(e); if (!e.defaultPrevented) { throw err; } } return promise.then((res) => { for (const item of res || []) { if (item.status !== "rejected") continue; handlePreloadError(item.reason); } return baseModule().catch(handlePreloadError); }); }; var __defProp2 = Object.defineProperty, __typeError = (msg) => { throw TypeError(msg); }, __publicField2 = (obj, key, value) => ((obj2, key2, value2) => key2 in obj2 ? __defProp2(obj2, key2, { enumerable: true, configurable: true, writable: true, value: value2 }) : obj2[key2] = value2)(obj, "symbol" != typeof key ? key + "" : key, value), __privateMethod = (obj, member, method) => (((obj2, member2, msg) => { member2.has(obj2) || __typeError("Cannot " + msg); })(obj, member, "access private method"), method); const currentHref$1 = window.location.href, isJavDb$1 = currentHref$1.includes("javdb"), isJavBus$1 = currentHref$1.includes("javbus") || currentHref$1.includes("seejav") || currentHref$1.includes("bus") || currentHref$1.includes("javsee") || "javbus" === (() => { try { const _alt = $(".hidden-xs").attr("alt"); return _alt ? _alt.trim().toLowerCase() : void 0; } catch (_e) { return void 0; } })(), isSearchPage = currentHref$1.includes("/search?q") || currentHref$1.includes("/search/") || currentHref$1.includes("/users/"), Status_RUNNING = "RUNNING", Status_SUCCESS = "SUCCESS", Status_FAIL = "FAIL", Status_LOADING = "LOADING", Status_FILTER$1 = "filter", Status_FAVORITE$1 = "favorite", Status_HAS_DOWN$1 = "hasDown", Status_HAS_WATCH$1 = "hasWatch", NO = "no", YES$1 = "yes", qualityOptions = [{ id: "video-mhb", quality: "dmb_w", text: "旧视频源-中画质宽版 (404p)", canSelect: false }, { id: "video-mhb", quality: "sm_s", text: "旧视频源-低画质 (240p)", canSelect: false }, { id: "video-mhb", quality: "dm_s", text: "旧视频源-中画质 (360p)", canSelect: false }, { id: "video-mhb", quality: "dmb_s", text: "旧视频源-中画质 (480p)", canSelect: false }, { id: "video-mhb", quality: "mhb_w", text: "旧视频源-高画质宽版 (404p)", canSelect: false }, { id: "video-mmb", quality: "mmb", text: "中画质 (432p)", canSelect: true }, { id: "video-mhb", quality: "mhb", text: "高画质 (576p)", canSelect: true }, { id: "video-hmb", quality: "hmb", text: "HD (720p)", canSelect: true }, { id: "video-hhb", quality: "hhb", text: "FullHD (1080p)", canSelect: true }, { id: "video-hhbs", quality: "hhbs", text: "FullHD (1080p60fps)", canSelect: true }, { id: "video-4k", quality: "4k", text: "4K (2160p)", canSelect: true }, { id: "video-4ks", quality: "4ks", text: "4K (2160p60fps)", canSelect: true }]; let detailPageCss$1 = ""; window.location.href.includes("hideNav=1") && (detailPageCss$1 = "\n .navbar-default {\n display: none !important;\n }\n body {\n padding-top:0px!important;\n }\n "); const javBusStyle = ` `; let detailPageCss = ""; window.location.href.includes("hideNav=1") && (detailPageCss = "\n .main-nav,#search-bar-container {\n display: none !important;\n }\n \n html {\n padding-top:0px!important;\n }\n "); const javdbStyle = ` `; const mainCss = ` `; const subtitleModalCss = ` `; function insertStyle(css) { if (css) if (css.includes("\n" ); insertStyle(mainCss); insertStyle(subtitleModalCss); window.$ = window.jQuery = $$1; if (typeof $$1.trim !== "function") { $$1.trim = function (text) { return text == null ? "" : (text + "").trim(); }; } if (typeof jQuery !== "undefined" && typeof layer === "undefined") { await __vitePreload(() => module.import('./layer-npqWxmx4-BZXOsKge.js').then((n) => n.l), void 0); } window.localforage = localforage$1; window.Toastify = Toastify$1; window.md5 = md5$1; window.Viewer = Viewer$1; window.QRCode = QRCode$1; window.currentHref = currentHref$1; window.isJavDb = isJavDb$1; window.isJavBus = isJavBus$1; window.isSearchPage = isSearchPage; window.Status_RUNNING = Status_RUNNING; window.Status_SUCCESS = Status_SUCCESS; window.Status_FAIL = Status_FAIL; window.Status_LOADING = Status_LOADING; window.Status_FILTER = Status_FILTER$1; window.Status_FAVORITE = Status_FAVORITE$1; window.Status_HAS_DOWN = Status_HAS_DOWN$1; window.Status_HAS_WATCH = Status_HAS_WATCH$1; window.NO = NO; window.YES = YES$1; const HAS_GM = typeof GM !== "undefined"; const NEW_GM = ((scope, GM2) => { if (typeof GM_info === "undefined" || GM_info.scriptHandler !== "Tampermonkey" || compareVersions(GM_info.version, "5.3.2") < 0) return; const GM_xmlhttpRequestOrig = GM_xmlhttpRequest; const GM_xmlHttpRequestOrig = GM2.xmlHttpRequest; function compareVersions(v1, v2) { const parts1 = v1.split(".").map(Number); const parts2 = v2.split(".").map(Number); const length = Math.max(parts1.length, parts2.length); for (let i = 0; i < length; i++) { const num1 = parts1[i] || 0; const num2 = parts2[i] || 0; if (num1 > num2) return 1; if (num1 < num2) return -1; } return 0; } function GM_xmlhttpRequestWrapper(odetails) { if (odetails.redirect !== void 0) { return GM_xmlhttpRequestOrig(odetails); } if (odetails.onprogress || odetails.fetch === false) { console.warn("Fetch mode does not support onprogress in the background."); } const { onload, onloadend, onerror, onabort, ontimeout, ...details } = odetails; const handleRedirects = (initialDetails) => { const request = GM_xmlhttpRequestOrig({ ...initialDetails, redirect: "manual", onload: function (response) { if (response.status >= 300 && response.status < 400) { const m = response.responseHeaders.match(/Location:\s*(\S+)/i); const redirectUrl = m && m[1]; if (redirectUrl) { const absoluteUrl = new URL(redirectUrl, initialDetails.url).href; handleRedirects({...initialDetails, url: absoluteUrl}); return; } } if (onload) onload.call(this, response); if (onloadend) onloadend.call(this, response); }, onerror: function (response) { if (onerror) onerror.call(this, response); if (onloadend) onloadend.call(this, response); }, onabort: function (response) { if (onabort) onabort.call(this, response); if (onloadend) onloadend.call(this, response); }, ontimeout: function (response) { if (ontimeout) ontimeout.call(this, response); if (onloadend) onloadend.call(this, response); } }); return request; }; return handleRedirects(details); } function GM_xmlHttpRequestWrapper(odetails) { let abort; const p = new Promise((resolve, reject) => { const {onload, ontimeout, onerror, ...send} = odetails; send.onerror = function (r) { if (onerror) { resolve(r); onerror.call(this, r); } else { reject(r); } }; send.ontimeout = function (r) { if (ontimeout) { resolve(r); ontimeout.call(this, r); } else { reject(r); } }; send.onload = function (r) { resolve(r); if (onload) onload.call(this, r); }; const a = GM_xmlhttpRequestWrapper(send).abort; if (abort === true) { a(); } else { abort = a; } }); p.abort = () => { if (typeof abort === "function") { abort(); } else { abort = true; } }; return p; } GM_xmlhttpRequest = GM_xmlhttpRequestWrapper; scope.GM_xmlhttpRequestOrig = GM_xmlhttpRequestOrig; const gopd = Object.getOwnPropertyDescriptor(GM2, "xmlHttpRequest"); if (gopd && gopd.configurable === false) { return { __proto__: GM2, xmlHttpRequest: GM_xmlHttpRequestWrapper, xmlHttpRequestOrig: GM_xmlHttpRequestOrig }; } else { GM2.xmlHttpRequest = GM_xmlHttpRequestWrapper; GM2.xmlHttpRequestOrig = GM_xmlHttpRequestOrig; } })(globalThis, HAS_GM ? GM : {}); if (HAS_GM && NEW_GM) GM = NEW_GM; var _StorageManager_instances, setItem_fn, saveFilterItem_fn; _StorageManager_instances = /* @__PURE__ */ new WeakSet(); setItem_fn = async function (key, data) { key === this.favorite_actresses_key && window.clean_cacheFavoriteActressList(); key === this.blacklist_car_list_key && window.clean_cacheBlacklistCarList(); key === this.setting_key && window.clean_cacheSettingObj(); key === this.car_list_key && window.clean_cacheCarList(); await this.forage.setItem(key, data); }; saveFilterItem_fn = async function (items, storageKey, itemName) { let itemList; if (Array.isArray(items)) itemList = [...items]; else { itemList = await this.forage.getItem(storageKey) || []; if (itemList.includes(items)) { const errorMsg = `${items} ${itemName}已存在`; show.error(errorMsg); throw new Error(errorMsg); } itemList.push(items); } await __privateMethod(this, _StorageManager_instances, setItem_fn).call(this, storageKey, itemList); return itemList; }; let StorageManager = class _StorageManager { constructor() { obj = this, (member = _StorageManager_instances).has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value); var obj, member, value; __publicField2(this, "car_list_key", "car_list"); __publicField2(this, "filter_keyword_title_key", "filter_keyword_title"); __publicField2(this, "filter_keyword_review_key", "filter_keyword_review"); __publicField2(this, "setting_key", "setting"); __publicField2(this, "blacklist_key", "blacklist"); __publicField2(this, "blacklist_car_list_key", "blacklist_car_list"); __publicField2(this, "favorite_actresses_key", "favorite_actresses"); __publicField2(this, "highlighted_tags_key", "highlighted_tags"); __publicField2(this, "forage", localforage.createInstance({ driver: localforage.INDEXEDDB, name: "JAV-JHS", version: 1, storeName: "appData" })); __publicField2(this, "cacheCarList", null); __publicField2(this, "cacheBlacklistCarList", null); __publicField2(this, "cacheFavoriteActressList", null); __publicField2(this, "cacheSettingObj", null); if (_StorageManager.instance) throw new Error("StorageManager已被实例化过了!"); _StorageManager.instance = this; } async getCarList() { if (this.cacheCarList) return utils.copyObj(this.cacheCarList); this.cacheCarList = await this.forage.getItem(this.car_list_key) || []; return utils.copyObj(this.cacheCarList); } async getCar(carNum2) { return (await this.getCarList()).find(((item) => item.carNum === carNum2)); } _handleSingleCar(carParam, carList) { let {carNum: carNum2, url, names, actionType, publishTime, starId} = carParam; if (!carNum2) { show.error("番号为空!"); throw new Error("番号为空!"); } if (!url) { show.error("url为空!"); throw new Error("url为空!"); } url.includes("http") || (url = window.location.origin + url); names && (names = names.trim()); let carData = carList.find(((item) => item.carNum === carNum2)); if (carData) { names && (carData.names = names); url && (carData.url = url); publishTime && (carData.publishTime = publishTime); carData.updateDate = utils.getNowStr(); } else { let nowStr = utils.getNowStr(); carData = { carNum: carNum2, url, names, status: "", createDate: nowStr, updateDate: nowStr, publishTime }; starId && (carData.starId = starId); carList.push(carData); } switch (actionType) { case Status_FILTER: if (carData.status === Status_FILTER) { const msg2 = `${carNum2} 已在屏蔽列表中`; show.error(msg2); throw new Error(msg2); } carData.status = Status_FILTER; break; case Status_FAVORITE: if (carData.status === Status_FAVORITE) { const msg2 = `${carNum2} 已在收藏列表中`; show.error(msg2); throw new Error(msg2); } carData.status = Status_FAVORITE; break; case Status_HAS_DOWN: carData.status = Status_HAS_DOWN; break; case Status_HAS_WATCH: carData.status = Status_HAS_WATCH; break; default: const msg = "actionType错误, 请联系作者更正: " + actionType; show.error(msg); throw new Error(msg); } } async saveCar(carData) { const carList = await this.forage.getItem(this.car_list_key) || []; this._handleSingleCar(carData, carList); await __privateMethod(this, _StorageManager_instances, setItem_fn).call(this, this.car_list_key, carList); await this.removeNewVideoList([carData.carNum]); } async updateCarInfo(carParam) { let {carNum: carNum2, url, names, actionType, publishTime, remark} = carParam; if (!carNum2) { show.error("番号为空!"); throw new Error("番号为空!"); } if (!url) { show.error("url为空!"); throw new Error("url为空!"); } names && (names = names.trim()); const carList = await this.forage.getItem(this.car_list_key) || []; let carData = carList.find(((item) => item.carNum === carNum2)); if (!carData) { const msg = "数据不存在: " + carNum2; show.error(msg); throw new Error(msg); } carData.names = names; carData.url = url; carData.remark = remark; carData.updateDate = utils.getNowStr(); switch (actionType) { case Status_FILTER: carData.status = Status_FILTER; break; case Status_FAVORITE: carData.status = Status_FAVORITE; break; case Status_HAS_DOWN: carData.status = Status_HAS_DOWN; break; case Status_HAS_WATCH: carData.status = Status_HAS_WATCH; break; default: const msg = "actionType错误, 请联系作者更正: " + actionType; show.error(msg); throw new Error(msg); } await __privateMethod(this, _StorageManager_instances, setItem_fn).call(this, this.car_list_key, carList); } async saveCarList(carRecords) { if (!carRecords || !Array.isArray(carRecords) || 0 === carRecords.length) { show.error("记录列表为空!"); throw new Error("记录列表为空!"); } const carList = await this.forage.getItem(this.car_list_key) || []; for (const record of carRecords) try { this._handleSingleCar(record, carList); } catch (error) { throw error; } await __privateMethod(this, _StorageManager_instances, setItem_fn).call(this, this.car_list_key, carList); } async removeNewVideoList(carNumList) { const favoriteActressesList = await this.getFavoriteActressList(); let hasAnyListBeenModified = false; const updatedActressList = favoriteActressesList.map(((actress) => { if (!actress.newVideoList || !Array.isArray(actress.newVideoList)) return actress; const newFilteredVideoList = actress.newVideoList.filter(((carNumString) => { const isRemoved = carNumList.includes(carNumString); if (isRemoved) { clog.log("移除关联女优新作品", actress.name, carNumString); hasAnyListBeenModified = true; } return !isRemoved; })); return { ...actress, newVideoList: newFilteredVideoList }; })); hasAnyListBeenModified && await __privateMethod(this, _StorageManager_instances, setItem_fn).call(this, this.favorite_actresses_key, updatedActressList); } async removeCar(carNum2) { const carList = await this.getCarList(), initialLength = carList.length, updatedList = carList.filter(((car) => car.carNum !== carNum2)); if (updatedList.length === initialLength) { show.error(`${carNum2} 不存在`); return false; } await __privateMethod(this, _StorageManager_instances, setItem_fn).call(this, this.car_list_key, updatedList); return true; } async batchRemoveCars(carNumList) { if (!carNumList || 0 === carNumList.length) throw new Error("未传入参数"); const carList = await this.getCarList(), initialLength = carList.length, carNumsSet = new Set(carNumList), updatedList = carList.filter(((car) => !carNumsSet.has(car.carNum))), removedCount = initialLength - updatedList.length; if (0 === removedCount) return removedCount; await __privateMethod(this, _StorageManager_instances, setItem_fn).call(this, this.car_list_key, updatedList); return removedCount; } async getBlacklist() { return await this.forage.getItem(this.blacklist_key) || []; } async addBlacklistItem(item) { let {starId, name: name2, allName, role, movieType, url} = item; if (!starId) throw new Error("缺失starId"); if (!name2) throw new Error("缺失name"); if (!role) throw new Error("缺失role"); const blacklist = await this.getBlacklist(), existData = blacklist.find(((item2) => item2.starId === starId)); if (existData) { existData.url = url; existData.role = role; existData.movieType = movieType; clog.log("更新黑名单演员信息", existData); } else { const info = { starId, name: name2, allName: allName || [name2], createTime: utils.getNowStr(), role, movieType, url }; blacklist.push(info); clog.log("增加黑名单演员信息", info); } await __privateMethod(this, _StorageManager_instances, setItem_fn).call(this, this.blacklist_key, blacklist); } async updateBlacklistItem(item) { if (!item || !item.starId) throw new Error("参数不全"); const filterActorActressInfoList = await this.getBlacklist(), waitUpdateObj = filterActorActressInfoList.find(((i) => i.starId === item.starId)); if (!waitUpdateObj) throw new Error(`未找到黑名单演员信息:${item.name} ${item.starId}`); item.checkTime && (waitUpdateObj.checkTime = item.checkTime); item.lastPublishTime && (waitUpdateObj.lastPublishTime = item.lastPublishTime); await __privateMethod(this, _StorageManager_instances, setItem_fn).call(this, this.blacklist_key, filterActorActressInfoList); } async deleteBlacklistItem(starId) { const blacklist = await this.getBlacklist(), updatedList = blacklist.filter(((item) => item.starId !== starId)); blacklist.length !== updatedList.length && await __privateMethod(this, _StorageManager_instances, setItem_fn).call(this, this.blacklist_key, updatedList); } async getBlacklistCarList() { if (this.cacheBlacklistCarList && this.cacheBlacklistCarList.length > 0) return utils.deepFreeze(this.cacheBlacklistCarList); this.cacheBlacklistCarList = await this.forage.getItem(this.blacklist_car_list_key) || []; setTimeout((() => { utils.deepFreeze(this.cacheBlacklistCarList); }), 0); return this.cacheBlacklistCarList; } async batchSaveBlacklistCarList(carDataList) { const carList = await this.getCarList(); let blacklistCarList = await this.getBlacklistCarList(), hasChanged = false, copyBlacklistCarList = null, carNumList = []; for (const carData of carDataList) { let existBlacklistCarData = blacklistCarList.find(((item) => item.carNum === carData.carNum)); if (existBlacklistCarData) { console.log("已在鉴定记录中", existBlacklistCarData); continue; } let existCarData = carList.find(((item) => item.carNum === carData.carNum)); if (existCarData) console.log("已在鉴定记录中", existCarData); else { copyBlacklistCarList || (copyBlacklistCarList = utils.copyObj(blacklistCarList)); this._handleSingleCar(carData, copyBlacklistCarList); clog.log(`屏蔽演员番号: ${carData.names} ${carData.carNum}`); hasChanged = true; carNumList.push(carData.carNum); } } if (hasChanged) { if (!copyBlacklistCarList) throw new Error("程序异常, 黑名单番号数据对象为空!"); await __privateMethod(this, _StorageManager_instances, setItem_fn).call(this, this.blacklist_car_list_key, copyBlacklistCarList); await this.removeNewVideoList(carNumList); } } async removeBlacklistCarList(starId) { const filterActorActressCarList = await this.getBlacklistCarList(), newList = filterActorActressCarList.filter(((car) => car.starId !== starId)); newList.length !== filterActorActressCarList.length && await __privateMethod(this, _StorageManager_instances, setItem_fn).call(this, this.blacklist_car_list_key, newList); } async batchRemoveBlacklistCars(carNumList) { if (!carNumList || 0 === carNumList.length) throw new Error("未传入参数"); const blacklistCarList = await this.getBlacklistCarList(), initialLength = blacklistCarList.length, carNumsSet = new Set(carNumList), updatedList = blacklistCarList.filter(((car) => !carNumsSet.has(car.carNum))), removedCount = initialLength - updatedList.length; if (0 === removedCount) return removedCount; await __privateMethod(this, _StorageManager_instances, setItem_fn).call(this, this.blacklist_car_list_key, updatedList); return removedCount; } async getFavoriteActressList() { if (this.cacheFavoriteActressList) return utils.copyObj(this.cacheFavoriteActressList); this.cacheFavoriteActressList = await this.forage.getItem(this.favorite_actresses_key) || []; return utils.copyObj(this.cacheFavoriteActressList); } async addFavoriteActressList(actressList) { const favoriteActressesInfoList = await this.getFavoriteActressList(); let resultCount = 0; for (const actress of actressList) { let { starId, name: name2, allName, avatar, lastCheckTime, lastPublishTime, actressType } = actress; if (!starId) throw new Error("缺失starId"); if (!name2) throw new Error("缺失name"); allName || (allName = [name2]); const uncensoredText = "(無碼)"; if (!actressType) { actressType = name2.includes(uncensoredText) || allName.some(((element) => element.includes(uncensoredText))) ? "uncensored" : "censored"; } name2 = name2.replace(uncensoredText, ""); allName = allName.map(((n) => n.replace(uncensoredText, ""))); let favoriteActresses = favoriteActressesInfoList.find(((item) => item.starId === starId)); if (favoriteActresses) { if ((!favoriteActresses.avatar || !favoriteActresses.avatar.includes("https")) && avatar) { clog.log(avatar); favoriteActresses.avatar = avatar; clog.log(`补全女优头像: ${name2}`); resultCount++; } if (!favoriteActresses.actressType && actressType) { favoriteActresses.actressType = actressType; clog.log(`补全女优类别: ${name2} ${actressType}`); resultCount++; } if (favoriteActresses.name.includes(uncensoredText)) { favoriteActresses.name = name2; favoriteActresses.allName = allName; clog.log(`更正女优名字: ${name2} ${allName}`); resultCount++; } continue; } const nowStr = utils.getNowStr(); favoriteActressesInfoList.push({ starId, name: name2, allName, avatar, lastCheckTime, lastPublishTime, createDate: nowStr, updateDate: nowStr, actressType }); clog.log(`同步JavDB已收藏的演员: ${name2}`); resultCount++; } resultCount > 0 ? await __privateMethod(this, _StorageManager_instances, setItem_fn).call(this, this.favorite_actresses_key, favoriteActressesInfoList) : clog.log("信息已记录, 无需要进行同步收藏的演员"); return resultCount; } async removeFavoriteActress(starId) { const favoriteActressesInfoList = await this.getFavoriteActressList(), initialLength = favoriteActressesInfoList.length, updatedList = favoriteActressesInfoList.filter(((car) => car.starId !== starId)); if (updatedList.length === initialLength) { clog.error(`移除演员失败, ${starId} 不存在`); return false; } await __privateMethod(this, _StorageManager_instances, setItem_fn).call(this, this.favorite_actresses_key, updatedList); return true; } async updateFavoriteActress(actress) { const favoriteActressesInfoList = await this.getFavoriteActressList(), { starId, name: name2, allName, avatar, lastCheckTime, newVideoList, lastPublishTime, actressType, remark } = actress; if (!starId) throw new Error("缺失starId"); let favoriteActresses = favoriteActressesInfoList.find(((item) => item.starId === starId)); if (!favoriteActresses) { clog.error("未找到演员信息", starId, name2); return false; } name2 && (favoriteActresses.name = name2); allName && (favoriteActresses.allName = allName); avatar && (favoriteActresses.avatar = avatar); null != actressType && (favoriteActresses.actressType = actressType); lastCheckTime && (favoriteActresses.lastCheckTime = lastCheckTime); newVideoList && (favoriteActresses.newVideoList = newVideoList); lastPublishTime && (favoriteActresses.lastPublishTime = lastPublishTime); remark && (favoriteActresses.remark = remark); favoriteActresses.updateDate = utils.getNowStr(); await __privateMethod(this, _StorageManager_instances, setItem_fn).call(this, this.favorite_actresses_key, favoriteActressesInfoList); } async getHighlightedTags() { return await this.forage.getItem(this.highlighted_tags_key) || []; } async setHighlightedTags(highlightedTags) { return await __privateMethod(this, _StorageManager_instances, setItem_fn).call(this, this.highlighted_tags_key, highlightedTags); } async saveTitleFilterKeyword(keywords) { await __privateMethod(this, _StorageManager_instances, saveFilterItem_fn).call(this, keywords, this.filter_keyword_title_key, "标题关键词"); if (Array.isArray(keywords)) return null; const favoriteActressesList = await this.getFavoriteActressList(); let hasAnyListBeenModified = false; const updatedActressList = favoriteActressesList.map(((actress) => { if (!actress.newVideoList || !Array.isArray(actress.newVideoList)) return actress; const newFilteredVideoList = actress.newVideoList.filter(((carNumString) => { const isRemoved = carNumString.startsWith(keywords); if (isRemoved) { clog.log("移除关联女优新作品", actress.name, carNumString); hasAnyListBeenModified = true; } return !isRemoved; })); return { ...actress, newVideoList: newFilteredVideoList }; })); hasAnyListBeenModified && await __privateMethod(this, _StorageManager_instances, setItem_fn).call(this, this.favorite_actresses_key, updatedActressList); } async getTitleFilterKeyword() { return await this.forage.getItem(this.filter_keyword_title_key) || []; } async getReviewFilterKeywordList() { return await this.forage.getItem(this.filter_keyword_review_key) || []; } async saveReviewFilterKeyword(keywords) { return __privateMethod(this, _StorageManager_instances, saveFilterItem_fn).call(this, keywords, this.filter_keyword_review_key, "评论关键词"); } async getSetting(attribute = null, defaultVal) { this.cacheSettingObj || (this.cacheSettingObj = await this.forage.getItem(this.setting_key) || {}); let settingObj = utils.copyObj(this.cacheSettingObj); if (null === attribute) return settingObj; const value = settingObj[attribute]; return value ? "true" === value || "false" === value ? "true" === value.toLowerCase() : "string" != typeof value || "" === value.trim() || isNaN(Number(value)) ? value : Number(value) : defaultVal; } async saveSetting(settingObj) { settingObj ? await __privateMethod(this, _StorageManager_instances, setItem_fn).call(this, this.setting_key, settingObj) : show.error("设置对象为空"); } async saveSettingItem(key, value) { if (!key) { show.error("key 不能为空"); return; } let settingObj = await this.getSetting(); settingObj[key] = value; await this.saveSetting(settingObj); } async importData(jsonData) { await this.forage.clear(); const importPromises = []; for (const key in jsonData) { const value = jsonData[key], setPromise = __privateMethod(this, _StorageManager_instances, setItem_fn).call(this, key, value); importPromises.push(setPromise); } await Promise.all(importPromises); } async exportData() { const dataMap = {}; await this.forage.iterate(((value, key) => { dataMap[key] = value; })); if (0 === Object.keys(dataMap).length) throw new Error("没有可导出的数据"); return dataMap; } }; const apiUrl = "https://jdforrepam.com/api"; function buildSignature() { const curr = Math.floor(Date.now() / 1e3), stored_sign = localStorage.getItem("jhs_jdsignature"); if (stored_sign) { const parts = stored_sign.split("."); if (3 === parts.length) { if (curr - parseInt(parts[0]) <= 300) return stored_sign; } } const sign = `${curr}.lpw6vgqzsp.${md5(`${curr}71cf27bb3c0bcdf207b64abecddc970098c7421ee7203b9cdae54478478a199e7d5a6e1a57691123c1a931c057842fb73ba3b3c83bcd69c17ccf174081e3d8aa`)}`; localStorage.setItem("jhs_jdsignature", sign); return sign; } const javDbApi = { getReviews: async (movieId, pageNum = 1, pageSize = 20) => { let url = `${apiUrl}/v1/movies/${movieId}/reviews`, headers = { jdSignature: await buildSignature() }; return (await gmHttp.get(url, { page: pageNum, sort_by: "hotly", limit: pageSize }, headers)).data.reviews; }, searchMovie: async (keyword) => { let url = `${apiUrl}/v2/search`, headers = { "user-agent": "Dart/3.5 (dart:io)", "accept-language": "zh-TW", host: "jdforrepam.com", jdsignature: await buildSignature() }, params = { q: keyword, page: 1, type: "movie", limit: 1, movie_type: "all", from_recent: "false", movie_filter_by: "all", movie_sort_by: "relevance" }; return (await gmHttp.get(url, params, headers)).data.movies; }, getMovieDetail: async (movieId) => { let url = `${apiUrl}/v4/movies/${movieId}`, headers = { jdSignature: await buildSignature() }; const res = await gmHttp.get(url, null, headers); if (!res.data) { show.error("获取视频详情失败: " + res.message); throw new Error(res.message); } const movie = res.data.movie, preview_images = movie.preview_images, imgList = []; preview_images.forEach(((item) => { imgList.push(item.large_url.replace("https://tp.spfcas.com/rhe951l4q", "https://c0.jdbstatic.com")); })); return { movieId: movie.id, actors: movie.actors, duration: movie.duration, title: movie.origin_title, carNum: movie.number, score: movie.score, releaseDate: movie.release_date, watchedCount: movie.watched_count, imgList }; }, related: async (movieId, page = 1, limit = 20) => { let url = `${apiUrl}/v1/lists/related?movie_id=${movieId}&page=${page}&limit=${limit}`, headers = { jdSignature: await buildSignature() }; const res = await gmHttp.get(url, null, headers), dataList = []; res.data.lists.forEach(((item) => { dataList.push({ relatedId: item.id, name: item.name, movieCount: item.movies_count, collectionCount: item.collections_count, viewCount: item.views_count, createTime: utils.formatDate(item.created_at) }); })); return dataList; }, getMagnets: async (movieId) => { let url = `${apiUrl}/v1/movies/${movieId}/magnets`, headers = { jdSignature: await buildSignature() }; return (await gmHttp.get(url, null, headers)).data.magnets; }, playback: async (period = "daily", filter_by = "high_score") => { let url = `${apiUrl}/v1/rankings/playback?period=${period}&filter_by=${filter_by}`, headers = { jdSignature: await buildSignature() }; return (await gmHttp.get(url, null, headers)).data.movies; }, login: async (username, password) => { let url = `${apiUrl}/v1/sessions?username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}&device_uuid=04b9534d-5118-53de-9f87-2ddded77111e&device_name=iPhone&device_model=iPhone&platform=ios&system_version=17.4&app_version=official&app_version_number=1.9.29&app_channel=official`, headers = { "user-agent": "Dart/3.5 (dart:io)", "accept-language": "zh-TW", "content-type": "multipart/form-data; boundary=--dio-boundary-2210433284", jdsignature: await buildSignature() }; return await gmHttp.post(url, null, headers); }, top250: async (type = "all", type_value = "", page = 1, limit = 40) => { let url = `${apiUrl}/v1/movies/top?start_rank=1&type=${type}&type_value=${type_value}&ignore_watched=false&page=${page}&limit=${limit}`, headers = { "user-agent": "Dart/3.5 (dart:io)", "accept-language": "zh-TW", host: "jdforrepam.com", authorization: "Bearer " + localStorage.getItem("jhs_appAuthorization"), jdsignature: await buildSignature() }; return await gmHttp.get(url, null, headers); }, buildSignature, markDataListHtml: (movies) => { let moviesHtml = ""; movies.forEach(((movie) => { moviesHtml += `
`; })); return moviesHtml; } }; var _GM_openInTab = /* @__PURE__ */ (() => typeof GM_openInTab != "undefined" ? GM_openInTab : void 0)(); var _GM_xmlhttpRequest = /* @__PURE__ */ (() => typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : void 0)(); class Utils { constructor() { __publicField2(this, "intervalContainer", {}); __publicField2(this, "mimeTypes", { txt: "text/plain", html: "text/html", css: "text/css", csv: "text/csv", json: "application/json", xml: "application/xml", jpg: "image/jpeg", jpeg: "image/jpeg", png: "image/png", gif: "image/gif", webp: "image/webp", svg: "image/svg+xml", pdf: "application/pdf", doc: "application/msword", docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", xls: "application/vnd.ms-excel", xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ppt: "application/vnd.ms-powerpoint", pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation", zip: "application/zip", rar: "application/x-rar-compressed", "7z": "application/x-7z-compressed", mp3: "audio/mpeg", wav: "audio/wav", mp4: "video/mp4", webm: "video/webm", ogg: "audio/ogg" }); __publicField2(this, "timers", /* @__PURE__ */ new Map()); __publicField2(this, "insertStyle", ((css) => { if (css) { -1 === css.indexOf(""); $("head").append(css); } })); __publicField2(this, "layerIndexStack", []); Utils.instance || (Utils.instance = this); return Utils.instance; } importResource(url) { let tag; if (url.indexOf("css") >= 0) { tag = document.createElement("link"); tag.setAttribute("rel", "stylesheet"); tag.href = url; } else { tag = document.createElement("script"); tag.setAttribute("type", "text/javascript"); tag.src = url; } document.documentElement.appendChild(tag); } openPage(url, title, shadeClose, event) { if (!url) throw new Error("未传入url"); shadeClose = shadeClose ?? true; if (event && (event.ctrlKey || event.metaKey)) { _GM_openInTab(url.includes("http") ? url : window.location.origin + url, { insert: 0 }); return; } let finalUrl = url; url.includes("/actors/") || url.includes("/star/") || (finalUrl = url.includes("?") ? `${url}&hideNav=1` : `${url}?hideNav=1`); layer.open({ type: 2, title, content: finalUrl, scrollbar: false, shadeClose, area: this.getResponsiveArea(["85%", "90%"]), isOutAnim: false, anim: -1, success: (layero, index) => { this.setupEscClose(index); } }); } _handleGlobalEscKey(e) { if ("Escape" !== e.key && 27 !== e.keyCode) return; if (0 === this.layerIndexStack.length) return; const topLayerIndex = this.layerIndexStack[this.layerIndexStack.length - 1], $layer = $(`#layui-layer${topLayerIndex}`); let viewerExists = false; if ($layer.find(".viewer-container").length > 0) viewerExists = true; else { const iframe = $layer.find(`#layui-layer-iframe${topLayerIndex}`)[0]; if (iframe && iframe.contentDocument) try { $(iframe.contentDocument).find(".viewer-container").length > 0 && (viewerExists = true); } catch (error) { clog.warn("无法检查跨域 iframe 内的 .viewer-container"); } } if (!viewerExists) { this.layerIndexStack.pop(); typeof layer !== "undefined" && layer.close(topLayerIndex); } } setupEscClose(layerIndex) { var _a2; if (!this._boundHandler) { this._boundHandler = this._handleGlobalEscKey.bind(this); $(document).off("keydown.globalLayerEsc"); $(document).on("keydown.globalLayerEsc", this._boundHandler); } -1 === this.layerIndexStack.indexOf(layerIndex) && this.layerIndexStack.push(layerIndex); const $iframe = $(`#layui-layer-iframe${layerIndex}`), eventNamespace = `keydown.layerEsc${layerIndex}`; try { const iframeDocument = null == (_a2 = $iframe[0]) ? void 0 : _a2.contentDocument; if (iframeDocument) { if ("yes" === $iframe.attr("data-esc-bound")) return; $(iframeDocument).off(eventNamespace); $(iframeDocument).on(eventNamespace, this._boundHandler); $iframe.attr("data-esc-bound", "yes"); } } catch (e) { clog.error("iframe监听失败 (跨域或未加载完毕):", e); } } closePage() { storageManager.getSetting("needClosePage", "yes").then(((needClosePage) => { if ("yes" !== needClosePage) return; parent.document.documentElement.style.overflow = "auto"; [".layui-layer-shade", ".layui-layer-move", ".layui-layer"].forEach((function (selector) { const elements = parent.document.querySelectorAll(selector); if (elements.length > 0) { const elementToRemove = elements.length > 1 ? elements[elements.length - 1] : elements[0]; elementToRemove.parentNode.removeChild(elementToRemove); } })); window.close(); })); } loopDetector(condition, after, detectInterval = 20, timeout = 1e4, runWhenTimeout = true) { const uuid = Math.random(), start = (/* @__PURE__ */ new Date()).getTime(), stopAndRun = (shouldRun) => { clearInterval(this.intervalContainer[uuid]); shouldRun && after && after(); delete this.intervalContainer[uuid]; }; this.intervalContainer[uuid] = setInterval((() => { const timeElapsed = (/* @__PURE__ */ new Date()).getTime() - start; condition() ? stopAndRun(true) : timeElapsed >= timeout && stopAndRun(runWhenTimeout); }), detectInterval); } rightClick(container, targetSelector, callback) { let containerElement; "string" == typeof container ? containerElement = document.querySelector(container) : container instanceof HTMLElement && (containerElement = container); if (!containerElement) { console.warn("rightClick(), 容器无效或未提供,将使用 document.body 进行全局委托。"); containerElement = document.body; } "string" == typeof targetSelector && "" !== targetSelector.trim() ? containerElement.addEventListener("contextmenu", ((event) => { const targetElement = event.target.closest(targetSelector); targetElement && callback(event, targetElement); })) : console.error("rightClick(), 必须提供有效的 targetSelector。"); } q(event, msg, fun, cancelFun) { let x, y; if (event) { x = event.clientX - 130; y = event.clientY - 120; } else { x = window.innerWidth / 2 - 120; y = window.innerHeight / 2 - 120; } let confirmIndex = layer.confirm(msg, { offset: [y, x], title: "提示", btn: ["确定", "取消"], shade: 0, zIndex: 999999991 }, (function () { fun && fun(); layer.close(confirmIndex); }), (function () { cancelFun && cancelFun(); })); } alert(event, msg, yesFun) { let offset; event && (offset = [event.clientX - 200, event.clientY - 120]); let confirmIndex = layer.alert(msg, { offset, shade: 0, zIndex: 999999991 }, (function () { yesFun && yesFun(); layer.close(confirmIndex); })); } getNowStr(dateSplitStr = "-", timeSplitStr = ":", dateString = null) { let now; now = dateString ? new Date(dateString) : /* @__PURE__ */ new Date(); const year = now.getFullYear(), month = String(now.getMonth() + 1).padStart(2, "0"), day = String(now.getDate()).padStart(2, "0"), hours = String(now.getHours()).padStart(2, "0"), minutes = String(now.getMinutes()).padStart(2, "0"), seconds = String(now.getSeconds()).padStart(2, "0"); return `${[year, month, day].join(dateSplitStr)} ${[hours, minutes, seconds].join(timeSplitStr)}`; } formatDate(date, dateSplitStr = "-", timeSplitStr = ":") { let targetDate; if (date instanceof Date) targetDate = date; else { if ("string" != typeof date) throw new Error("Invalid date input: must be Date object or date string"); targetDate = new Date(date); if (isNaN(targetDate.getTime())) throw new Error("Invalid date string"); } const year = targetDate.getFullYear(), month = String(targetDate.getMonth() + 1).padStart(2, "0"), day = String(targetDate.getDate()).padStart(2, "0"), hours = String(targetDate.getHours()).padStart(2, "0"), minutes = String(targetDate.getMinutes()).padStart(2, "0"), seconds = String(targetDate.getSeconds()).padStart(2, "0"); return `${[year, month, day].join(dateSplitStr)} ${[hours, minutes, seconds].join(timeSplitStr)}`; } getHourDifference(date1, date2) { const timestamp1 = date1.getTime(), timestamp2 = date2.getTime(), differenceInHours = Math.abs(timestamp2 - timestamp1) / 36e5; return Math.floor(differenceInHours); } download(data, fileName) { show.info("开始请求下载..."); const fileExtension = fileName.split(".").pop().toLowerCase(); let blob, mimeType = this.mimeTypes[fileExtension] || "application/octet-stream"; if (data instanceof Blob) blob = data; else if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) blob = new Blob([data], { type: mimeType }); else if ("string" == typeof data && data.startsWith("data:")) { const byteString = atob(data.split(",")[1]), arrayBuffer = new ArrayBuffer(byteString.length), uintArray = new Uint8Array(arrayBuffer); for (let i = 0; i < byteString.length; i++) uintArray[i] = byteString.charCodeAt(i); blob = new Blob([uintArray], { type: mimeType }); } else blob = new Blob([data], { type: mimeType }); const url = URL.createObjectURL(blob), a = document.createElement("a"); a.href = url; a.download = fileName; document.body.appendChild(a); a.click(); setTimeout((() => { document.body.removeChild(a); URL.revokeObjectURL(url); }), 100); } smoothScrollToTop(duration = 500) { return new Promise(((resolve) => { const start = performance.now(), startPosition = window.pageYOffset; window.requestAnimationFrame((function scrollStep(timestamp) { const elapsed = timestamp - start, progress = Math.min(elapsed / duration, 1), easeInOutCubic = progress < 0.5 ? 4 * progress * progress * progress : 1 - Math.pow(-2 * progress + 2, 3) / 2; window.scrollTo(0, startPosition * (1 - easeInOutCubic)); progress < 1 ? window.requestAnimationFrame(scrollStep) : resolve(); })); })); } simpleId() { return crypto.randomUUID().replace("-", ""); } isUrl(urlString) { try { new URL(urlString); return true; } catch (_) { return false; } } setHrefParam(key, val) { const newUrl = new URL(window.location.href); newUrl.searchParams.set(key, val); window.history.pushState({}, "", newUrl.toString()); } getUrlParam(url, key) { const searchString = url.split("?")[1]; if (!searchString) return null; const regex = new RegExp(`(?:^|&)${key}=([^&]*)`), match = searchString.match(regex); let value = ""; match && match[1] && (value = decodeURIComponent(match[1].replace(/\+/g, " "))); return value ? "true" === value || "false" === value ? "true" === value.toLowerCase() : "string" != typeof value || "" === value.trim() || isNaN(Number(value)) ? value : Number(value) : value; } reBuildSignature() { return javDbApi.buildSignature(); } getResponsiveArea(defaultArea) { const screenWidth = window.innerWidth; return screenWidth >= 1200 ? defaultArea || this.getDefaultArea() : screenWidth >= 768 ? ["70%", "90%"] : ["95%", "95%"]; } getDefaultArea() { return ["85%", "90%"]; } isMobile() { const userAgent = navigator.userAgent.toLowerCase(); return ["iphone", "ipod", "ipad", "android", "blackberry", "windows phone", "nokia", "webos", "opera mini", "mobile", "mobi", "tablet"].some(((keyword) => userAgent.includes(keyword))); } copyToClipboard(type, text) { navigator.clipboard.writeText(text).then((() => show.info(`${type}已复制到剪切板, ${text}`))).catch(((err) => console.error("复制失败: ", err))); } htmlTo$dom(html) { const parser = new DOMParser(); return $(parser.parseFromString(html, "text/html")); } addCookie(cookieStr, options = {}) { const {maxAge = 604800, path = "/", domain = "", secure = false, sameSite = "Lax"} = options; cookieStr.split(";").forEach(((cookie) => { const trimmed = cookie.trim(); if (trimmed) { const parts = trimmed.split("="); if (parts.length >= 2 && parts[0].trim()) { let cookieParts = [`${parts[0].trim()}=${parts.slice(1).join("=")}`]; maxAge > 0 && cookieParts.push(`max-age=${maxAge}`); cookieParts.push(`path=${path}`); domain && cookieParts.push(`domain=${domain}`); secure && cookieParts.push("Secure"); sameSite && cookieParts.push(`SameSite=${sameSite}`); console.log("document.cookie = '" + cookieParts.join("; ") + "'"); document.cookie = cookieParts.join("; "); } } })); } isHidden(el) { const element = el.jquery ? el[0] : el; return !element || (element.offsetWidth <= 0 && element.offsetHeight <= 0 || "none" === window.getComputedStyle(element).display); } time(label = "default", unit = "s", precision = 2) { if (this.timers.has(label)) { const timer = this.timers.get(label), elapsedTime = performance.now() - timer.startTime; let formattedTime, unitLabel; if ("s" === timer.unit) { formattedTime = (elapsedTime / 1e3).toFixed(timer.precision); unitLabel = "秒"; } else { formattedTime = elapsedTime.toFixed(timer.precision); unitLabel = "毫秒"; } this.timers.delete(label); return `${label}: ${formattedTime}${unitLabel}`; } this.timers.set(label, { startTime: performance.now(), unit, precision }); } sleep(ms = 1e3) { return new Promise(((resolve) => setTimeout(resolve, ms))); } genericSort(arr, sortRules, emptyLast = true) { if (!Array.isArray(arr) || 0 === arr.length) return []; if (!Array.isArray(sortRules) || 0 === sortRules.length) return [...arr]; const sortedArr = [...arr], safeDateConvert = (value) => { if (value instanceof Date) return value; if ("string" == typeof value) { const date = new Date(value); if (!isNaN(date.getTime())) return date; } return value; }; return sortedArr.sort(((a, b) => { for (const rule of sortRules) { const {key, order = "asc"} = rule; let valA = a, valB = b; if (null != key) if ("function" == typeof key) { valA = key(a); valB = key(b); } else { valA = a && "object" == typeof a ? a[key] : void 0; valB = b && "object" == typeof b ? b[key] : void 0; } const dateA = safeDateConvert(valA), dateB = safeDateConvert(valB); let comparison = 0; const aIsNull = null == valA, bIsNull = null == valB; if (aIsNull && bIsNull) return 0; if (aIsNull) return emptyLast ? 1 : -1; if (bIsNull) return emptyLast ? 1 : -1; comparison = dateA instanceof Date && dateB instanceof Date ? dateA.getTime() - dateB.getTime() : "number" == typeof valA && "number" == typeof valB ? valA - valB : "string" == typeof valA && "string" == typeof valB ? valA.localeCompare(valB) : String(valA).localeCompare(String(valB)); "desc" === order && (comparison *= -1); if (0 !== comparison) return comparison; } return 0; })); } async retry(fun, tryCount = 3) { let runCount = 0; for (; runCount < tryCount;) try { const result = await fun(); runCount > 0 && clog.debug(`[重试] 成功,共发起 ${runCount + 1} 次。`); return result; } catch (e) { let errorString = String(e); errorString.startsWith("Error: ") && (errorString = errorString.replace("Error: ", "")); if (errorString.includes("Just a moment") || errorString.includes("重定向") || errorString.toLowerCase().includes("404 page not found") || errorString.toLowerCase().includes("404 not found")) throw e; runCount++; if (runCount === tryCount) { clog.debug(`[重试] 达到最大重试次数 (${tryCount}),最终失败:`, e); throw e; } clog.debug(`[重试] 准备第 ${runCount + 1} 次重试, 错误信息: ${errorString}`); } } copyObj(data) { return JSON.parse(JSON.stringify(data)); } deepFreeze(obj) { if (null === obj || "object" != typeof obj || Object.isFrozen(obj)) return obj; const propNames = Object.getOwnPropertyNames(obj); for (const name2 of propNames) { const value = obj[name2]; value && "object" == typeof value && this.deepFreeze(value); } return Object.freeze(obj); } } class AsyncQueue { constructor() { this.queue = Promise.resolve(); } addTask(fun) { this.queue = this.queue.then((() => fun())).catch(((e) => { console.error("执行异步队列任务失败:", e); })); } async waitAllFinished() { return this.queue; } } class GmHttp { async get(url, params = {}, headers = {}, noRedirect) { return this.gmRequest("GET", url, null, params, headers, noRedirect); } post(url, data = {}, headers = {}) { headers = { "Content-Type": "application/json", ...headers }; let jsonData = JSON.stringify(data); return this.gmRequest("POST", url, jsonData, null, headers); } postForm(url, data = {}, headers = {}) { headers || (headers = {}); headers["Content-Type"] || (headers["Content-Type"] = "application/x-www-form-urlencoded"); let body = ""; data && Object.keys(data).length > 0 && (body = Object.entries(data).map((([key, value]) => `${key}=${value}`)).join("&")); return this.gmRequest("POST", url, body, null, headers); } postFileFormData(url, data = {}, headers = {}) { headers || (headers = {}); const boundary = `----WebKitFormBoundary${Math.random().toString(36).substring(2)}`; headers["Content-Type"] = `multipart/form-data; boundary=${boundary}`; let body = ""; data && Object.keys(data).length > 0 && (body = Object.entries(data).map((([key, value]) => `--${boundary}\r Content-Disposition: form-data; name="${key}"\r \r ${value}\r `)).join("")); body += `--${boundary}--`; return this.gmRequest("POST", url, body, null, headers); } async downloadFileInChunks(url, headers = {}) { const httpTimeout = await storageManager.getSetting("httpTimeout", 5e3), httpRetryCount = await storageManager.getSetting("httpRetryCount", 3); clog.log("正在获取文件大小..."); let fileSize, mimeType; try { const sizeResponse = await utils.retry((() => new Promise(((resolve, reject) => { _GM_xmlhttpRequest({ method: "GET", url, headers: { ...headers, Range: "bytes=0-0" }, timeout: httpTimeout, onload: resolve, onerror: (e) => reject(new Error("网络错误:无法获取文件大小")), ontimeout: () => reject(new Error("超时:获取文件大小")) }); }))), httpRetryCount); if (206 !== sizeResponse.status && 200 !== sizeResponse.status) throw new Error(`请求文件大小失败,状态码: ${sizeResponse.status}`); { const rangeHeader = sizeResponse.responseHeaders.match(/content-range:\s*bytes\s*\d+-\d+\/(\d+)/i), typeHeader = sizeResponse.responseHeaders.match(/content-type:\s*([^\s;]+)/i); if (rangeHeader && rangeHeader[1]) fileSize = parseInt(rangeHeader[1], 10); else { if (!sizeResponse.responseHeaders.match(/content-length:\s*(\d+)/i) || 200 !== sizeResponse.status) throw new Error("无法从响应头中获取文件总大小,服务器可能不支持 Range 请求。"); { const lengthHeader = sizeResponse.responseHeaders.match(/content-length:\s*(\d+)/i); fileSize = parseInt(lengthHeader[1], 10); clog.warn("服务器返回 200 状态码,可能不支持 Range 请求。将尝试完整下载。"); } } typeHeader && typeHeader[1] && (mimeType = typeHeader[1]); clog.log(`文件总大小:${(fileSize / 1024 / 1024).toFixed(2)} MB, MIME 类型: ${mimeType || "未知"}`); } } catch (e) { clog.error("获取文件大小失败:", e.message); throw e; } if (!fileSize || fileSize <= 0) throw new Error("获取到的文件大小无效或服务器拒绝提供大小信息。"); const numChunks = Math.ceil(fileSize / 1048576), chunkPromises = [], downloadedChunks = new Array(numChunks); clog.log(`文件将被分为 ${numChunks} 块进行下载 (每块约 ${1.toFixed(2)} MB)`); for (let i = 0; i < numChunks; i++) { const start = 1048576 * i, rangeHeader = `bytes=${start}-${Math.min(start + 1048576 - 1, fileSize - 1)}`, chunkPromise = await utils.retry((() => new Promise(((resolve, reject) => { const currentHeaders = { ...headers, Range: rangeHeader, Accept: "application/octet-stream" }; _GM_xmlhttpRequest({ method: "GET", url, headers: currentHeaders, timeout: httpTimeout, responseType: "arraybuffer", onload: (response) => { if (206 === response.status || 200 === response.status) if (response.response instanceof ArrayBuffer) { downloadedChunks[i] = response.response; clog.log(`成功下载第 ${i + 1}/${numChunks} 块 (${rangeHeader})`); resolve(); } else reject(new Error(`第 ${i + 1} 块响应不是 ArrayBuffer。`)); else reject(new Error(`第 ${i + 1} 块请求失败,状态码: ${response.status}`)); }, onerror: (error) => reject(new Error(`第 ${i + 1} 块网络错误: ${error.error}`)), ontimeout: () => reject(new Error(`第 ${i + 1} 块超时。`)) }); }))), httpRetryCount); chunkPromises.push(chunkPromise); } try { await Promise.all(chunkPromises); clog.log("所有分块下载完成,开始合并..."); } catch (e) { clog.error("分块下载过程中发生错误:", e.message); throw e; } const finalBlob = new Blob(downloadedChunks); finalBlob.size !== fileSize && clog.warn(`警告:合并后的 Blob 大小 (${finalBlob.size}) 与预期文件大小 (${fileSize}) 不匹配!`); return await finalBlob.text(); } async gmRequest(method, url, data = {}, params = {}, headers = {}, noRedirect = false) { if (params && Object.keys(params).length) { const queryString = new URLSearchParams(params).toString(); url += (url.includes("?") ? "&" : "?") + queryString; } const httpTimeout = await storageManager.getSetting("httpTimeout", 5e3), httpRetryCount = await storageManager.getSetting("httpRetryCount", 3); data || (data = void 0); return await utils.retry((() => new Promise(((resolve, reject) => { _GM_xmlhttpRequest({ method, url, headers, timeout: httpTimeout, data, onload: (response) => { try { noRedirect && response.finalUrl !== url && reject("请求被重定向了,URL是:" + response.finalUrl); if (response.status >= 200 && response.status < 300) if (response.responseText) try { resolve(JSON.parse(response.responseText)); } catch (e) { resolve(response.responseText); } else resolve(response.responseText || response); else { clog.error("请求失败,状态码:", response.status, url); if (response.responseText) try { const errorData = JSON.parse(response.responseText); reject(errorData); } catch { reject(new Error(response.responseText || `请求发生错误 ${response.status}`)); } else reject(new Error(`请求发生错误 ${response.status}`)); } } catch (e) { reject(e); } }, onerror: (error) => { clog.error("网络错误:", url); reject(new Error(error.error || "网络错误")); }, ontimeout: () => { reject(new Error("请求超时: " + url)); } }); }))), httpRetryCount); } } class PluginManager { constructor() { this.plugins = /* @__PURE__ */ new Map(); } register(pluginClass) { if ("function" != typeof pluginClass) throw new Error("插件必须是一个类"); const instance = new pluginClass(); instance.pluginManager = this; const lowerName = instance.getName(); if (this.plugins.has(lowerName)) throw new Error(`插件"${name}"已注册`); this.plugins.set(lowerName, instance); } getBean(name2) { return this.plugins.get(name2); } async processCss() { const failedCssLoads = (await Promise.allSettled(Array.from(this.plugins).map((async ([name2, instance]) => { try { if ("function" == typeof instance.initCss) { const css = await instance.initCss(); css && utils.insertStyle(css); return { name: name2, status: "fulfilled" }; } return { name: name2, status: "skipped" }; } catch (e) { console.error(`插件 ${name2} 加载 CSS 失败`, e); return { name: name2, status: "rejected", error: e }; } })))).filter(((r) => "rejected" === r.status)); failedCssLoads.length && console.error("以下插件的 CSS 加载失败:", failedCssLoads.map(((p) => p.value.name))); } async processPlugins() { const failedPlugins = (await Promise.allSettled(Array.from(this.plugins).map((async ([name2, instance]) => { try { if ("function" == typeof instance.handle) { await instance.handle(); return { name: name2, status: "fulfilled" }; } } catch (e) { clog.error(`插件 ${name2} 执行失败`, e); return { name: name2, status: "rejected", error: e }; } })))).filter(((r) => "rejected" === r.status)); failedPlugins.length && console.error("以下插件执行失败:", failedPlugins.map(((p) => p.value.name))); } } class BasePlugin { constructor() { __publicField2(this, "pluginManager", null); __publicField2(this, "settingSvg", ''); __publicField2(this, "editSvg", ''); __publicField2(this, "deleteSvg", ''); __publicField2(this, "checkSvg", ''); __publicField2(this, "actressSvg", ''); __publicField2(this, "newSvg", ''); __publicField2(this, "refreshSvg", ''); __publicField2(this, "blacklistSvg", ''); __publicField2(this, "removeSvg", ''); __publicField2(this, "copySvg", ''); __publicField2(this, "titleSvg", ''); __publicField2(this, "carNumSvg", ''); __publicField2(this, "downSvg", ''); __publicField2(this, "handleSvg", ''); __publicField2(this, "siteSvg", ''); __publicField2(this, "videoSvg", ''); __publicField2(this, "screenSvg", ''); __publicField2(this, "recoveryVideoSvg", ''); __publicField2(this, "markDeleteSvg", ''); } getName() { throw new Error(`${this.constructor.name} 未显示getName()`); } getBean(name2) { return this.pluginManager.getBean(name2); } async initCss() { return ""; } async handle() { } getPageInfo() { let carNum2, url, actress, actors, publishTime, currentHref2 = window.location.href; if (isJavDb) { carNum2 = $('a[title="複製番號"]').attr("data-clipboard-text"); url = currentHref2.split("?")[0].split("#")[0]; actress = $(".female").prev().map(((i, el) => $(el).text())).get().join(" "); actors = $(".male").prev().map(((i, el) => $(el).text())).get().join(" "); publishTime = $('strong:contains("日期:")').parent(".panel-block").find(".value").text().trim(); } if (isJavBus) { url = currentHref2.split("?")[0]; carNum2 = url.split("/").filter(Boolean).pop().replace(/_\d{4}-\d{2}-\d{2}$/, ""); actress = $('span[onmouseover*="star_"] a').map(((i, el) => $(el).text())).get().join(" "); actors = ""; publishTime = $('span.header:contains("發行日期:")').parent("p").text().trim().replace("發行日期:", "").trim(); } return { carNum: carNum2, url, actress, actors, publishTime }; } getActressId() { const match = currentHref.match(/\/actors\/([^/?]+)/); return match && match.length > 1 ? match[1] : null; } getActressPageInfo() { let currentHref2 = window.location.href; if (!currentHref2.includes("/actors/") && !currentHref2.includes("/star/")) throw new Error("接口调用错误, 非演员详情页"); let nameList = [], $actor = isJavDb ? $(".actor-section-name") : $(".avatar-box .photo-info .pb10"); $actor.length && $actor.text().trim().split(",").forEach(((name2) => { nameList.push(name2.trim()); })); let $sectionMeta = $(".section-meta:not(:contains('影片'))"); $sectionMeta.length && $sectionMeta.text().trim().split(",").forEach(((name2) => { nameList.push(name2.trim()); })); let role = $(".section-meta:contains('男優')").length > 0 ? "actor" : "actress", movieType = "censored"; nameList.some(((n) => n.includes("無碼"))) && (movieType = "uncensored"); currentHref2.includes("uncensored") && (movieType = "uncensored"); let blacklistUrl = null, starId = null; const urlObj = new URL(currentHref2); if (isJavDb) { starId = urlObj.pathname.split("/").filter(((segment) => "" !== segment.trim())).pop(); const params = urlObj.searchParams; params.delete("sort_type"); params.delete("page"); blacklistUrl = urlObj.toString(); } else if (isJavBus) { const splitStr = "/star/", parts = currentHref2.split(splitStr); if (parts.length < 2) throw new Error("提取演员url失败"); const host = parts[0]; starId = parts[1].split("/")[0]; blacklistUrl = host + splitStr + starId; } return { starId, name: nameList[0], allName: nameList, role, movieType, blacklistUrl }; } getSelector(type) { const key = type || (isJavDb ? "javdb" : isJavBus ? "javbus" : null), selectors = { javdb: { boxSelector: ".movie-list", itemSelector: ".movie-list .item", coverImgSelector: ".cover img", requestDomItemSelector: ".movie-list .item", nextPageSelector: ".pagination-next" }, javbus: { boxSelector: ".masonry", itemSelector: ".masonry .item", coverImgSelector: ".masonry .movie-box .photo-frame img", requestDomItemSelector: "#waterfall .item", nextPageSelector: "#next" } }; if (!key || !selectors[key]) throw new Error("类型错误: 无法确定选择器类型 (JavDb 或 JavBus)"); return selectors[key]; } parseMovieId(href) { return href.split("/").pop().split(/[?#]/)[0]; } getBoxCarInfo($box2) { var _a2, _b, _c; const $aLink = $box2.find("a"), url = $aLink.attr("href"); let carNum2 = null, title = null, publishTime = null; const $videoTitleEle = $box2.find(".video-title"); if ($videoTitleEle.length > 0) { const $strongEle = $videoTitleEle.find("strong"); $strongEle.length > 0 && (carNum2 = $strongEle.text().trim()); title = null == (_a2 = $aLink.attr("title")) ? void 0 : _a2.trim(); if (!title) { const fullTitleText = $videoTitleEle.text().trim(); title = carNum2 && fullTitleText.includes(carNum2) ? fullTitleText.replace(carNum2, "").trim() : fullTitleText; } publishTime = $box2.find(".meta").text().trim(); } if (!carNum2) { const $imgEle = $box2.find("img"); $imgEle.length > 0 && (title = (null == (_b = $imgEle.attr("title")) ? void 0 : _b.trim()) || (null == (_c = $imgEle.attr("data-title")) ? void 0 : _c.trim())); const dateElements = $box2.find("date").map(((i, el) => $(el).text().trim())).get(), isDate = (s) => /^\d{4}-\d{1,2}-\d{1,2}$/.test(s); publishTime = dateElements.find(isDate) || null; carNum2 = dateElements.find(((i) => !isDate(i))) || null; } if (!carNum2) { const msg = "提取番号信息失败: carNum 为空"; console.error("Error in getBoxCarInfo:", msg, "Box Element:", $box2.get(0)); show.error(msg); throw new Error(msg); } return { carNum: carNum2, url: url || "", aHref: url || "", title: title || "", publishTime: publishTime || "" }; } getBoxCarInfoList($boxList = null) { $boxList || ($boxList = $(this.getSelector().itemSelector)); if (0 === $boxList.length) { clog.error("获取当前列表页所有item的番号信息失败!"); return []; } const results = []; $boxList.each(((index, element) => { const $box2 = $(element); try { const carInfo = this.getBoxCarInfo($box2); results.push(carInfo); } catch (error) { clog.error("[getBoxCarInfoList] 提取单个 boxCar 信息失败:", error.message, "元素索引:", index); } })); return results; } checkDuplicateCarNumbers(currentList, newList) { if (!isJavDb) return false; if (!currentList || 0 === currentList.length || !newList || 0 === newList.length) return false; const currentCarNums = new Set(currentList.map(((item) => item.carNum)).filter(((n) => n))); if (0 === currentCarNums.size) return false; let consecutiveDuplicates = 0; for (let i = 0; i < newList.length; i++) { const newCarNum = newList[i] ? newList[i].carNum : null; if (newCarNum && currentCarNums.has(newCarNum)) { consecutiveDuplicates++; if (consecutiveDuplicates >= 2) { clog.warn("警告: 检测到连续番号信息重复, 该类别可能已被限制页码。"); return true; } } else consecutiveDuplicates = 0; } return false; } } const DMM_GRAPHQL_URL = "https://api.video.dmm.co.jp/graphql"; const dmmGraphQLKeyword = (code) => { const match = String(code || "").trim().toUpperCase().match(/^([A-Z0-9]{2,10})-(\d{1,6})$/); if (!match) return ""; return `${match[1].toLowerCase()}${match[2].padStart(5, "0")}`; }; const dmmGraphQLRequest = (query) => { return new Promise((resolve, reject) => { _GM_xmlhttpRequest({ method: "POST", url: DMM_GRAPHQL_URL, data: JSON.stringify({query}), timeout: 12e3, headers: { Accept: "application/json", "Content-Type": "application/json", Referer: "https://video.dmm.co.jp/", "Fanza-Device": "BROWSER", "Cache-Control": "no-cache" }, onload: (response) => { if (response.status < 200 || response.status >= 400) { reject(new Error(`DMM GraphQL HTTP ${response.status || 0}`)); return; } try { const json = JSON.parse(response.responseText || "{}"); if (Array.isArray(json.errors) && json.errors.length) { reject(new Error(json.errors[0].message || "DMM GraphQL error")); return; } resolve(json.data || {}); } catch (e) { reject(new Error(`DMM GraphQL JSON parse error: ${e.message}`)); } }, onerror: () => reject(new Error("DMM GraphQL network error")), ontimeout: () => reject(new Error("DMM GraphQL timeout")) }); }); }; const searchDmmContentIdsByGraphQL = async (code) => { const keyword = dmmGraphQLKeyword(code); if (!keyword) return []; const carNumNoHyphen = String(code || "").replace(/-/g, "").toLowerCase(); const results = []; const searchKeywords = [.../* @__PURE__ */ new Set([keyword, `${keyword}#`])]; for (const searchKeyword of searchKeywords) { const query = `{ legacySearchPPV(limit: 10, offset: 0, sort: SALES_RANK_SCORE, floor: AV, queryWord: ${JSON.stringify(searchKeyword)}) { result { contents { contentId serviceCode floorCode } } } }`; const data = await dmmGraphQLRequest(query); const contents = Array.isArray(data && data.legacySearchPPV && data.legacySearchPPV.result && data.legacySearchPPV.result.contents) ? data.legacySearchPPV.result.contents : []; for (const item of contents) { const contentId = String(item.contentId || ""); if (contentId.replace(/[^a-z0-9]/gi, "").toLowerCase().includes(carNumNoHyphen)) { results.push({ serviceCode: item.serviceCode || "digital", floorCode: item.floorCode || "AV", contentId }); } } if (results.length > 0) break; } return results; }; const getDmmGraphQLVideoUrls = async (code) => { const contentItems = await searchDmmContentIdsByGraphQL(code); if (!contentItems.length) return null; const results = await Promise.allSettled( contentItems.map((item) => extractTrailerLinks(item)) ); for (const result of results) { if (result.status === "fulfilled" && result.value) { return result.value; } } return null; }; const extractTrailerLinks = (item) => { const {contentId, serviceCode, floorCode} = item; return new Promise((resolve, reject) => { const trailerPageUrl = `https://www.dmm.co.jp/service/digitalapi/-/html5_player/=/cid=${contentId}/mtype=AhRVShI_/service=${serviceCode}/floor=${floorCode}/mode=/`; _GM_xmlhttpRequest({ method: "GET", url: trailerPageUrl, timeout: 15e3, headers: { "accept-language": "ja-JP,ja;q=0.9", Cookie: "age_check_done=1" }, onload: (response) => { const htmlContent = response.responseText || ""; if (htmlContent.includes("このサービスはお住まいの地域からは")) { reject(new Error("节点不可用,请将DMM域名分流到日本ip")); return; } const match = htmlContent.match(/const\s+args\s+=\s+(.*);/); if (!match) { reject(new Error("未在脚本中找到 const args = ... 变量")); return; } let bitrates; try { bitrates = JSON.parse(match[1]).bitrates; } catch (e) { reject(new Error(`解析播放器脚本 JSON 失败: ${e.message}`)); return; } if (!Array.isArray(bitrates)) { reject(new Error("解析画质链接失败: bitrates 字段不是一个数组或不存在")); return; } const qualityKeys = [ "4ks", "4k", "hhbs", "hhb", "hmb", "mhb", "mmb", "dmb_w", "dmb_s", "dm_s", "sm_s", "mhb_w" ]; const qualityNameRegex = new RegExp(`(${qualityKeys.join("|")})\\.mp4$`); const finalQualityMap = {}; for (const bitrate of bitrates) { const url = bitrate && bitrate.src; if (!url || typeof url !== "string" || !url.endsWith(".mp4")) continue; const qualityMatch = url.match(qualityNameRegex); let qualityKey = ""; if (qualityMatch && qualityMatch[1]) qualityKey = qualityMatch[1]; if (qualityKey && !finalQualityMap[qualityKey]) { finalQualityMap[qualityKey] = url; } } if (Object.keys(finalQualityMap).length === 0) { reject(new Error("未找到匹配要求的预览画质视频")); return; } resolve(finalQualityMap); }, onerror: () => reject(new Error("DMM 播放页请求网络错误")), ontimeout: () => reject(new Error("DMM 播放页请求超时")) }); }); }; const selectDefaultQuality = (dmmVideoQualityList, intendedDefault) => { if (!dmmVideoQualityList || 0 === dmmVideoQualityList.length) return null; const availableSet = new Set(dmmVideoQualityList); if (availableSet.has(intendedDefault)) return intendedDefault; const priorityOrder = qualityOptions.map(((option) => option.quality)).reverse(); for (const quality of priorityOrder) if (availableSet.has(quality)) return quality; return dmmVideoQualityList[0]; }, CACHE_KEY = "jhs_dmm_video"; class DmmVideoFetcher { constructor(carNum2, showErrorMessages = true) { this.carNum = carNum2; this.showErrorMessages = showErrorMessages; } _checkCache() { const cachedData = localStorage.getItem(CACHE_KEY) ? JSON.parse(localStorage.getItem(CACHE_KEY)) : {}; if (cachedData[this.carNum]) { clog.debug("缓存中存在预览视频信息", cachedData[this.carNum]); return cachedData[this.carNum]; } return null; } _updateCache(videoMap) { const cachedData = localStorage.getItem(CACHE_KEY) ? JSON.parse(localStorage.getItem(CACHE_KEY)) : {}; cachedData[this.carNum] = videoMap; clog.debug("成功解析出预览视频并已缓存:", videoMap); localStorage.setItem(CACHE_KEY, JSON.stringify(cachedData)); } async _searchContentIds() { const carNum2 = this.carNum, carNumNoHyphen = carNum2.replace(/-/g, ""), keywordAttempts = [{ keyword: carNum2.replace("-", "00"), name: "00-替换关键词" }, { keyword: carNum2, name: "原始番号关键词" }, { keyword: carNumNoHyphen, name: "无连字符关键词" }], carNumLower = carNum2.toLowerCase(); for (const attempt of keywordAttempts) { const {keyword, name: name2} = attempt, currentTempCarNumLower = keyword.toLowerCase(), apiUrl2 = `https://api.dmm.com/affiliate/v3/ItemList?${new URLSearchParams({ api_id: "UrwskPfkqQ0DuVry2gYL", affiliate_id: "10278-996", output: "json", site: "FANZA", sort: "match", keyword }).toString()}`; let response; try { response = await gmHttp.get(apiUrl2); } catch (e) { clog.error(`API 请求失败,跳过 ${name2}:`, e); continue; } if (!response || !response.result || !response.result.result_count) { clog.debug(`使用 ${name2} (${keyword}) 进行 API 搜索 返回无结果,尝试下一个关键词。`); continue; } const newItems = []; for (const item of response.result.items) { if (newItems.length >= 2) break; const contentId = item.content_id || "", makerProduct = item.maker_product || ""; if (contentId.includes(currentTempCarNumLower.replace("-", "")) || carNumLower === makerProduct.toLowerCase() || contentId.includes(carNumNoHyphen.toLowerCase())) { newItems.push({ serviceCode: item.service_code, floorCode: item.floor_code, contentId, pageUrl: item.URL }); clog.debug(`[${name2}] cid|makerProduct 匹配成功:`, contentId, makerProduct); } } if (newItems.length > 0) { clog.debug(`--- 成功通过 ${name2} 找到 Content IDs ---`); const $btn2 = $("#fanzaBtn"); let url = `https://www.dmm.co.jp/search/=/searchstr=${keyword}`, type = "single"; if (newItems.length > 1) { $btn2.attr("href", url); $btn2.append('多结果'); $btn2.css("backgroundColor", "#7bc73b"); type = "multiple"; } else { url = newItems[0].pageUrl; $btn2.attr("href", url); $btn2.css("backgroundColor", "#7bc73b"); } const dmmCacheKey = "jhs_other_site_dmm", dmmCacheData = localStorage.getItem(dmmCacheKey) ? JSON.parse(localStorage.getItem(dmmCacheKey)) : {}; dmmCacheData[this.carNum] = { type, url }; localStorage.setItem(dmmCacheKey, JSON.stringify(dmmCacheData)); return newItems; } clog.debug(`[${name2}] API 返回结果数 ${response.result.result_count},但无精确匹配的 Content ID。`); } clog.warn("所有关键词尝试均未找到匹配的Content ID, 解析Dmm视频失败"); const $btn = $("#fanzaBtn"); $btn.attr("href", `https://www.dmm.co.jp/search/=/searchstr=${this.carNum}`); $btn.attr("title", "未查询到, 点击前往搜索页"); $btn.css("backgroundColor", "#de3333"); return null; } async _extractTrailerLinks({contentId, serviceCode, floorCode}) { const trailerPageUrl = `https://www.dmm.co.jp/service/digitalapi/-/html5_player/=/cid=${contentId}/mtype=AhRVShI_/service=${serviceCode}/floor=${floorCode}/mode=/`, htmlContent = await gmHttp.get(trailerPageUrl, null, { "accept-language": "ja-JP,ja;q=0.9", Cookie: "age_check_done=1" }); if ("string" != typeof htmlContent) { clog.error(htmlContent); throw new Error("解析播放页内容失败, 非文本内容"); } if (htmlContent.includes("このサービスはお住まいの地域からは")) throw new Error("节点不可用,请将DMM域名分流到日本ip"); const match = htmlContent.match(/const\s+args\s+=\s+(.*);/); if (!match) throw new Error("未在脚本中找到 const args = ... 变量"); let bitrates; try { ({bitrates} = JSON.parse(match[1])); } catch (e) { throw new Error(`解析播放器脚本 JSON 失败: ${e.message}`); } const finalQualityMap = {}, qualityKeys = qualityOptions.map(((o) => o.quality)).join("|"), qualityNameRegex = new RegExp(`(${qualityKeys})\\.mp4$`); if (!Array.isArray(bitrates)) { clog.error("解析画质链接失败: bitrates 字段不是一个数组或不存在"); throw new Error("解析画质链接失败: bitrates 字段不是一个数组或不存在"); } clog.debug("原始数据返回:", bitrates); for (const item of bitrates) { const url = null == item ? void 0 : item.src; if (!url || "string" != typeof url || !url.endsWith(".mp4")) continue; const qualityMatch = url.match(qualityNameRegex); let qualityKey = ""; qualityMatch && qualityMatch[1] && (qualityKey = qualityMatch[1]); qualityKey && !finalQualityMap[qualityKey] && (finalQualityMap[qualityKey] = url); } if (0 === Object.keys(finalQualityMap).length) throw new Error("未找到匹配要求的预览画质视频"); return finalQualityMap; } async _searchViaGraphQL() { clog.debug("尝试通过 GraphQL API 搜索视频..."); const videoMap = await getDmmGraphQLVideoUrls(this.carNum); if (videoMap && Object.keys(videoMap).length > 0) { this._updateCache(videoMap); clog.debug("GraphQL 成功解析出预览视频:", videoMap); const dmmCacheKey = "jhs_other_site_dmm"; const dmmCacheData = localStorage.getItem(dmmCacheKey) ? JSON.parse(localStorage.getItem(dmmCacheKey)) : {}; dmmCacheData[this.carNum] = { type: "graphql", url: `https://www.dmm.co.jp/search/=/searchstr=${this.carNum}` }; localStorage.setItem(dmmCacheKey, JSON.stringify(dmmCacheData)); return videoMap; } return null; } async fetchVideo() { const cachedResult = this._checkCache(); if (cachedResult) return cachedResult; let contentItems; try { const testCarNum = this.carNum.toLowerCase(); if (testCarNum.startsWith("heyzo") || /^(n\d+|\d+(-\d+)*)$/.test(testCarNum) || /^n\d+$/.test(testCarNum)) throw new Error("无码番号类型, 取消dmm解析"); if (this.carNum.includes("VR-")) throw new Error("VR类型, 取消dmm解析"); contentItems = await this._searchContentIds(); } catch (e) { clog.error("DMM API 搜索失败:", e); } if (!contentItems || 0 === contentItems.length) { clog.warn("Affiliate API 未找到视频,尝试 GraphQL API..."); const graphQLResult = await this._searchViaGraphQL(); if (graphQLResult) return graphQLResult; const $btn = $("#fanzaBtn"); $btn.attr("href", `https://www.dmm.co.jp/search/=/searchstr=${this.carNum}`); $btn.attr("title", "未查询到, 点击前往搜索页"); $btn.css("backgroundColor", "#de3333"); return null; } try { const finalVideoMap = await Promise.any(contentItems.map(((item) => this._extractTrailerLinks(item)))); this._updateCache(finalVideoMap); return finalVideoMap; } catch (error) { const errors = error.errors || [error]; clog.error(`Affiliate 解析失败: ${errors[0] && errors[0].message || errors[0]}`, errors); clog.warn("尝试 GraphQL API 作为 fallback..."); const graphQLResult = await this._searchViaGraphQL(); if (graphQLResult) return graphQLResult; if (errors.some(((err) => err.message.includes("节点不可用")))) this.showErrorMessages && show.error("节点不可用,请将DMM域名分流到日本ip"); else { const displayError = errors[0].message || errors[0]; this.showErrorMessages && show.error(`解析失败: ${displayError}`); } const $btn = $("#fanzaBtn"); $btn.attr("href", `https://www.dmm.co.jp/search/=/searchstr=${this.carNum}`); $btn.attr("title", "未查询到, 点击前往搜索页"); $btn.css("backgroundColor", "#de3333"); return null; } } } const getDmmVideo = async (carNum2, showErrorMessages = true) => new DmmVideoFetcher(carNum2, showErrorMessages).fetchVideo(); class AutoPagePlugin extends BasePlugin { constructor() { super(...arguments); __publicField2(this, "preloadDistance", 500); __publicField2(this, "currentPage", this.getInitialPageNumber()); __publicField2(this, "pageItems", []); } getName() { return "AutoPagePlugin"; } async initCss() { return "\n \n "; } async handle() { this.waterfall().then(); } getInitialPageNumber() { if (isJavBus$1) { const match = currentHref$1.match(/\/(page|star\/[^/]+)\/(\d+)/); return match ? parseInt(match[2], 10) : 1; } if (isJavDb$1) { const match = currentHref$1.match(/[?&]page=(\d+)/); return match ? parseInt(match[1], 10) : 1; } return 1; } async waterfall() { if (await this.shouldDisablePaging()) return; const selector = this.getSelector(); this.container = document.querySelector(selector.boxSelector); if (!this.container) { console.error("没有找到容器节点,停止瀑布流!"); return; } this.loader = document.createElement("div"); this.loader.className = "jhs-scroll"; this.container.parentNode.insertBefore(this.loader, this.container.nextSibling); this.pageItems.push({ page: this.currentPage, top: 0, url: window.location.href }); this.loader.addEventListener("click", (() => { this.loader.classList.contains("waterfall-error") && this.loadNextPage().then(); })); window.addEventListener("scroll", (() => { this.checkLoad(); this.checkScrollPosition(); })); const nextLink = document.querySelector(selector.nextPageSelector); this.nextUrl = null == nextLink ? void 0 : nextLink.href; this.hasMore = !!this.nextUrl; setTimeout((() => { this.checkLoad(); }), 1e3); this.hasMore || this.setState("waterfall-no-more", "已经到底了"); } async loadNextPage() { var _a2; if (await storageManager.getSetting("autoPage", YES$1) === NO) { this.setState("waterfall-loading", ""); return; } if (this.isLoading || !this.nextUrl) return; this.isLoading = true; this.setState("waterfall-loading", "加载中..."); const selector = this.getSelector(); try { const pageNum = utils.getUrlParam(this.nextUrl, "page"); let maxPage = 60; currentHref$1.includes("c11") && (maxPage = 30); if (isJavDb$1 && pageNum > maxPage || currentHref$1.includes("month")) { const beyond60Plugin = this.getBean("Beyond60Plugin"); if (beyond60Plugin) { const { html: html2, nextUrl, hasMore } = await beyond60Plugin.handleBeyond60(this.nextUrl); if (html2) { const pageTop2 = this.container.scrollHeight; this.pageItems.push({ page: this.currentPage + 1, top: pageTop2, url: this.nextUrl }); $(".movie-list").append(html2); } this.hasMore = hasMore; this.nextUrl = nextUrl; const $ul = beyond60Plugin.createPagination(pageNum, hasMore); $(".pagination").html($ul); this.setState("waterfall-loading", ""); this.hasMore || this.setState("waterfall-no-more", "已经到底了"); return; } } const html = await gmHttp.get(this.nextUrl); clog.log("请求下一页内容:", this.nextUrl); const $dom = utils.htmlTo$dom(html); isJavBus$1 && $dom.find(".avatar-box").length > 0 && $dom.find(".avatar-box").parent().remove(); let itemList = $dom.find(this.getSelector().requestDomItemSelector); const currentBoxCarInfoList = this.getBoxCarInfoList(), nextPageBoxCarInfoList = this.getBoxCarInfoList(itemList); if (this.checkDuplicateCarNumbers(currentBoxCarInfoList, nextPageBoxCarInfoList)) { this.nextUrl = null; this.hasMore = false; this.setState("waterfall-error", "翻页内容出现重复数据, 可能首页已更新了新视频 或 页码受JavDB限制, 停止瀑布流"); return; } const pageTop = this.container.scrollHeight; this.pageItems.push({ page: this.currentPage + 1, top: pageTop, url: this.nextUrl }); const listPagePlugin = this.getBean("ListPagePlugin"); let coverImgNodeList = $dom.find(this.getSelector().coverImgSelector); listPagePlugin.replaceHdImg(coverImgNodeList); $(this.getSelector().boxSelector).append(itemList); this.nextUrl = null == (_a2 = $dom.find(selector.nextPageSelector)) ? void 0 : _a2.attr("href"); this.hasMore = !!this.nextUrl; let pagination = $dom.find(".pagination"); $(".pagination").replaceWith(pagination); this.setState("waterfall-loading", ""); this.hasMore || this.setState("waterfall-no-more", "已经到底了"); } catch (e) { clog.error("加载失败:", e); this.setState("waterfall-error", "加载失败,点击重试"); } finally { this.isLoading = false; } } checkScrollPosition() { const scrollPosition = window.scrollY; for (let i = this.pageItems.length - 1; i >= 0; i--) { const page = this.pageItems[i]; if (scrollPosition >= page.top) { if (this.currentPage !== page.page) { this.currentPage = page.page; this.updatePageUrl(page.url); } break; } } } checkLoad() { if (!this.loader) return; this.loader.getBoundingClientRect().top < window.innerHeight + this.preloadDistance && this.loadNextPage().then(); } async shouldDisablePaging() { if (!window.isListPage) return true; await storageManager.getSetting("autoPage", YES$1); return ["search?q", "handlePlayback=1", "handleTop=1", "/want_watch_videos", "/watched_videos", "/advanced_search?type=100"].some(((path) => currentHref$1.includes(path))); } updatePageUrl_old(href) { window.history.pushState({}, "", href); if (isJavBus$1) { const match = href.match(/\/(page|star\/.*?)\/(\d+)/), pageNumber = match ? parseInt(match[2], 10) : null; document.title = document.title.replace(/第\d+頁/, "第" + pageNumber + "頁"); } } updatePageUrl(url) { window.history.replaceState({}, "", url); isJavBus$1 && (document.title = document.title.replace(/第\d+頁/, `第${this.currentPage}頁`)); } setState(state, text) { this.loader.className = `jhs-scroll ${state}`; this.loader.textContent = text; } } class AliyunApi { constructor(refresh_token) { this.baseApiUrl = "https://api.aliyundrive.com"; this.refresh_token = refresh_token; this.authorization = null; this.default_drive_id = null; this.backupFolderId = null; } async getDefaultDriveId() { if (this.default_drive_id) return this.default_drive_id; this.userInfo = await this.getUserInfo(); this.default_drive_id = this.userInfo.default_drive_id; return this.default_drive_id; } async getHeaders() { if (this.authorization) return { authorization: this.authorization }; this.authorization = await this.getAuthorization(); return { authorization: this.authorization }; } async getAuthorization() { let url = this.baseApiUrl + "/v2/account/token", data = { refresh_token: this.refresh_token, grant_type: "refresh_token" }; try { return "Bearer " + (await gmHttp.post(url, data)).access_token; } catch (e) { throw e.message.includes("is not valid") ? new Error("refresh_token无效, 请重新填写并保存") : e; } } async getUserInfo() { const headers = await this.getHeaders(); let url = this.baseApiUrl + "/v2/user/get"; return await gmHttp.post(url, {}, headers); } async deleteFile(file_id, drive_id = null) { if (!file_id) throw new Error("未传入file_id"); drive_id || (drive_id = await this.getDefaultDriveId()); let data = { file_id, drive_id }, url = this.baseApiUrl + "/v2/recyclebin/trash"; const headers = await this.getHeaders(); await gmHttp.post(url, data, headers); return {}; } async createFolder(name2, drive_id = null, parent_folder_id = "root") { drive_id || (drive_id = await this.getDefaultDriveId()); let url = this.baseApiUrl + "/adrive/v2/file/createWithFolders", data = { name: name2, type: "folder", parent_file_id: parent_folder_id, check_name_mode: "auto_rename", content_hash_name: "sha1", drive_id }; const headers = await this.getHeaders(); return await gmHttp.post(url, data, headers); } async getFileList(parent_folder_id = "root", drive_id = null) { drive_id || (drive_id = await this.getDefaultDriveId()); let url = this.baseApiUrl + "/adrive/v3/file/list"; const data = { drive_id, parent_file_id: parent_folder_id, limit: 200, all: false, url_expire_sec: 14400, image_thumbnail_process: "image/resize,w_256/format,avif", image_url_process: "image/resize,w_1920/format,avif", video_thumbnail_process: "video/snapshot,t_120000,f_jpg,m_lfit,w_256,ar_auto,m_fast", fields: "*", order_by: "updated_at", order_direction: "DESC" }, headers = await this.getHeaders(); return (await gmHttp.post(url, data, headers)).items; } async uploadFile(folder_id, fileName, uploadContent, drive_id = null) { show.info("请求存储空间中..."); let createFileUrl = this.baseApiUrl + "/adrive/v2/file/createWithFolders"; drive_id || (drive_id = await this.getDefaultDriveId()); let data = { drive_id, part_info_list: [{ part_number: 1 }], parent_file_id: folder_id, name: fileName, type: "file", check_name_mode: "auto_rename" }; const headers = await this.getHeaders(), createFileResult = await gmHttp.post(createFileUrl, data, headers), upload_id = createFileResult.upload_id, upload_file_id = createFileResult.file_id, upload_url = createFileResult.part_info_list[0].upload_url; show.info("开始上传文件..."); await this._doUpload(upload_url, uploadContent); await gmHttp.post("https://api.aliyundrive.com/v2/file/complete", data = { drive_id, file_id: upload_file_id, upload_id }, headers); } _doUpload(upload_url, uploadContent) { return new Promise(((resolve, reject) => { $.ajax({ type: "PUT", url: upload_url, data: uploadContent, contentType: " ", processData: false, success: (res, status, xhr) => { 200 === xhr.status ? resolve({}) : reject(xhr); }, error: (xhr) => { clog.error("上传失败", xhr.responseText); reject(xhr); } }); })); } async getDownloadUrl(file_id, drive_id = null) { drive_id || (drive_id = await this.getDefaultDriveId()); let url = this.baseApiUrl + "/v2/file/get_download_url"; const headers = await this.getHeaders(); let data = { file_id, drive_id }; return (await gmHttp.post(url, data, headers)).url; } async _createBackupFolder(folderName) { const fileList = await this.getFileList(); let folderObj = null; for (let i = 0; i < fileList.length; i++) { let file = fileList[i]; if (file.name === folderName) { folderObj = file; break; } } if (!folderObj) { show.info("不存在备份目录, 进行创建"); folderObj = await this.createFolder(folderName); } this.backupFolderId = folderObj.file_id; } async backup(folderName, fileName, uploadContent) { if (this.backupFolderId) await this.uploadFile(this.backupFolderId, fileName, uploadContent); else { await this._createBackupFolder(folderName); await this.uploadFile(this.backupFolderId, fileName, uploadContent); } } async getBackupList(folderName) { let dataList; if (this.backupFolderId) dataList = await this.getFileList(this.backupFolderId); else { await this._createBackupFolder(folderName); dataList = await this.getFileList(this.backupFolderId); } const fileList = []; dataList.forEach(((data) => { fileList.push({ name: data.name, fileId: data.file_id, createTime: data.created_at, size: data.size }); })); return fileList; } } class WebDavApi { constructor(davUrl, username, password) { this.davUrl = davUrl.endsWith("/") ? davUrl : davUrl + "/"; this.username = username; this.password = password; this.folderName = null; } _getAuthHeaders() { return { Authorization: `Basic ${btoa(`${this.username}:${this.password}`)}`, Depth: "1" }; } _sendRequest(method, path, headers = {}, data) { return new Promise(((resolve, reject) => { const url = this.davUrl + path, allHeaders = { ...this._getAuthHeaders(), ...headers }; _GM_xmlhttpRequest({ method, url, headers: allHeaders, data, onload: (response) => { if (response.status >= 200 && response.status < 300) resolve(response); else { console.error(response); reject(new Error(`请求失败 ${response.status}: ${response.statusText}`)); } }, onerror: (response) => { console.error("请求WebDav发生错误:", response); reject(new Error("请求WebDav失败, 请检查服务是否启动, 凭证是否正确")); } }); })); } async backup(folderName, fileName, uploadContent) { await this._sendRequest("MKCOL", folderName); const path = folderName + "/" + fileName; await this._sendRequest("PUT", path, { "Content-Type": "text/plain" }, uploadContent); } async getFileList(folderName) { var _a2, _b, _c; const xmlResponse = (await this._sendRequest("PROPFIND", folderName, { "Content-Type": "application/xml" }, '\nJavDB限制日本IP的访问,而预览视频来自DMM,需要日本IP才能访问。
这样会导致二者无法同时使用,需要对其一进行代理转发。
将 cc3001.dmm.co.jp 及 dmm.co 分流到日本ip。
Clash Verge分流规则设置 (如果你是别的代理软件,自行搜索如何分流)
方法一:设置中-添加视频标题关键词,如: VENX-
方法二:进入详情页,选中标题文字,右键可加入
屏蔽演员前,先筛选分类,再点屏蔽
① 访问115登录页, 选择JHS-扫码面板, 并扫码登录
② 进入网盘后, 右下角悬浮按钮, 复制Cookie
③ 打开另一个浏览器(需装JHS脚本), 进入登录页面, 选择JHS-扫码面板, 输入Cookie并回车
请选择头像数据源 (当前: ${CDN_SOURCES[initialIndex].name}):
${radioOptions}切换源会清除本地缓存的数据,并在下次搜索时重新加载。
点击图片即可选择(初始共 ${imageLinks.length} 张)
| 来源 | 原始字幕名称 | 语言 | 格式 | 操作 |
|---|