JAV-JSH

Jav-鉴黄师 收藏、屏蔽、标记已下载; 免VIP查看热榜、Top250排行榜、Fc2ppv等数据; 可查看所有评论信息; 支持云盘备份; 以图识图

// ==UserScript==
// @name         JAV-JSH
// @namespace    https://sleazyfork.org/zh-CN/scripts/533695-jav-jhs
// @version      1.6.8
// @author       xie bro
// @description  Jav-鉴黄师 收藏、屏蔽、标记已下载; 免VIP查看热榜、Top250排行榜、Fc2ppv等数据; 可查看所有评论信息; 支持云盘备份; 以图识图
// @license      MIT
// @icon         https://www.google.com/s2/favicons?sz=64&domain=javdb.com
// @include      https://javdb*.com/*
// @include      https://www.javbus.com/*
// @include      https://javtrailers.com/*
// @include      https://subtitlecat.com/*
// @include      https://www.aliyundrive.com/*
// @exclude      https://www.javbus.com/forum/*
// @exclude      https://www.javbus.com/*actresses
// @require      data:application/javascript,;(function%20hookBody()%20%7B%20if%20(document.readyState%20!%3D%3D%20%22loading%22)%20%7B%20return%3B%20%7D%20const%20initialHideStyle%20%3D%20document.createElement(%22style%22)%3B%20initialHideStyle.textContent%20%3D%20%60%20body%20%7B%20opacity%3A%200%20!important%3B%20visibility%3A%20hidden%20!important%3B%20%7D%20body.script-ready%20%7B%20opacity%3A%201%20!important%3B%20visibility%3A%20visible%20!important%3B%20%7D%20%60%3B%20document.head.appendChild(initialHideStyle)%3B%20setTimeout(()%20%3D%3E%20%7B%20document.body.classList.add(%22script-ready%22)%3B%20%7D%2C%203e3)%3B%20%7D)()%3B
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/layer.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/js/md5.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/src/toastify.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/localforage.min.js
// @connect      hohoj.tv
// @connect      xunlei.com
// @connect      geilijiasu.com
// @connect      aliyundrive.com
// @connect      aliyundrive.net
// @connect      ja.wikipedia.org
// @connect      beta.magnet.pics
// @connect      jdforrepam.com
// @connect      *
// @grant        GM_xmlhttpRequest
// @grant        GM_download
// @run-at       document-start
// ==/UserScript==

var __defProp = Object.defineProperty, __typeError = e => {
    throw TypeError(e);
}, __defNormalProp = (e, t, n) => t in e ? __defProp(e, t, {
    enumerable: !0,
    configurable: !0,
    writable: !0,
    value: n
}) : e[t] = n, __publicField = (e, t, n) => __defNormalProp(e, "symbol" != typeof t ? t + "" : t, n), __accessCheck = (e, t, n) => t.has(e) || __typeError("Cannot " + n), __privateAdd = (e, t, n) => t.has(e) ? __typeError("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(e) : t.set(e, n), __privateMethod = (e, t, n) => (__accessCheck(e, t, "access private method"), 
n);

!function() {
    "use strict";
    var e, t, n, a, i;
    const r = {
        boxSelector: ".masonry",
        itemSelector: ".masonry .item",
        coverImgSelector: ".item .photo-frame img",
        requestDomItemSelector: "#waterfall .item"
    }, o = {
        boxSelector: ".movie-list",
        itemSelector: ".movie-list .item",
        coverImgSelector: ".cover img",
        requestDomItemSelector: ".movie-list .item"
    }, s = window.location.href.includes("javdb"), l = window.location.href.includes("javbus"), c = "favorite", d = "filter", p = "hasDown", g = 2592e6;
    function h(e) {
        if (e) if (e.includes("<style>")) document.head.insertAdjacentHTML("beforeend", e); else {
            const t = document.createElement("style");
            t.textContent = e;
            document.head.appendChild(t);
        }
    }
    l && h("\n<style>\n    .masonry {\n        height: 100% !important;\n        width: 100% !important;\n        padding: 0 15px !important;\n    }\n    .masonry {\n        display: grid;\n        column-gap: 10px; /* 列间距*/\n        row-gap: 10px; /* 行间距 */\n        grid-template-columns: repeat(4, minmax(0, 1fr));\n    }\n    .masonry .item {\n        /*position: initial !important;*/\n        top: initial !important;\n        left: initial !important;\n        float: none !important;\n        background-color:#c4b1b1;\n        position: relative !important;\n    }\n    \n    .masonry .item:hover {\n        box-shadow: 0 .5em 1em -.125em rgba(10, 10, 10, .1), 0 0 0 1px #485fc7;\n    }\n    .masonry .movie-box{\n        width: 100% !important;\n        height: 100% !important;\n        margin: 0 !important;\n    }\n    .masonry .movie-box .photo-frame {\n        height: 70% !important;\n        margin: 0 !important;\n    }\n    .masonry .movie-box img {\n        max-height: 300px;\n        height: 100% !important;\n        object-fit: cover; /* 保持比例,裁剪多余部分 */\n        object-position: top; /* 从中间裁剪(可调整:top, bottom, left, right) */\n    }\n    .masonry .movie-box img:hover {\n      transform: scale(1.04);\n      transition: transform 0.3s;\n    }\n    .masonry .photo-info{\n        height: 30% !important;\n    }\n    .masonry .photo-info span {\n      display: inline-block; /* 或者 block */\n      max-width: 100%;      /* 根据父容器限制宽度 */\n      white-space: nowrap;  /* 禁止换行 */\n      overflow: hidden;     /* 隐藏溢出内容 */\n      text-overflow: ellipsis; /* 显示省略号 */\n    }\n    \n    /* 无码页面的样式 */\n    .photo-frame .mheyzo,\n    .photo-frame .mcaribbeancom2{\n        margin-left: 0 !important;\n    }\n    .avatar-box{\n        width: 100% !important;\n        display: flex !important;\n        margin:0 !important;\n    }\n    .avatar-box .photo-info{\n        display: flex;\n        justify-content: center;\n        align-items: center;\n        gap: 30px;\n        flex-direction: row;\n        background-color:#fff !important;\n    }\n    /*.photo-info .item-tag{\n        position: relative;\n    }*/\n    footer,#related-waterfall{\n        display: none!important;\n    }\n</style>\n");
    s && h('\n<style>\n    .navbar {\n        z-index: 12345679 !important;\n    }\n    \n    .sub-header,\n    #search-bar-container, /*搜索框*/\n    #footer,\n    .search-recent-keywords, /*搜索框底部热搜词条*/\n    .app-desktop-banner,\n    div[data-controller="movie-tab"] .tabs,\n    h3.main-title,\n    div.video-meta-panel > div > div:nth-child(2) > nav > div.review-buttons > div:nth-child(2), /* 下载 订正 按钮*/\n    div.video-detail > div:nth-child(4) > div > div.tabs.no-bottom > ul > li:nth-child(3), /* 相关清单*/\n    div.video-detail > div:nth-child(4) > div > div.tabs.no-bottom > ul > li:nth-child(2), /* 短评按钮*/\n    div.video-detail > div:nth-child(4) > div > div.tabs.no-bottom > ul > li:nth-child(1), /*磁力面板 按钮*/\n    .top-meta,\n    .float-buttons {\n        display: none !important;\n    }\n    \n    div.tabs.no-bottom,\n    .tabs ul {\n        border-bottom: none !important;\n    }\n    \n    \n    /* 视频列表项 相对相对 方便标签绝对定位*/\n    .movie-list .item {\n        position: relative !important;\n    }\n\n</style>\n');
    h("\n<style>\n    .a-primary, /* 主按钮 - 浅蓝色 */\n    .a-success, /* 成功按钮 - 浅绿色 */\n    .a-danger, /* 危险按钮 - 浅粉色 */\n    .a-warning, /* 警告按钮 - 浅橙色 */\n    .a-info, /* 信息按钮 - 浅青色 */\n    .a-dark, /* 深色按钮 - 改为中等灰色(保持浅色系中的对比) */\n    .a-outline, /* 轮廓按钮 - 浅灰色边框 */\n    .a-disabled /* 禁用按钮 - 极浅灰色 */\n    {\n        display: inline-flex;\n        align-items: center;\n        justify-content: center;\n        padding: 6px 14px;\n        margin-left: 10px;\n        border-radius: 6px;\n        text-decoration: none;\n        font-size: 13px;\n        font-weight: 500;\n        transition: all 0.2s ease;\n        cursor: pointer;\n        border: 1px solid rgba(0, 0, 0, 0.08);\n        white-space: nowrap;\n    }\n    \n    .a-primary {\n        background: #e0f2fe;\n        color: #0369a1;\n        border-color: #bae6fd;\n    }\n    \n    .a-primary:hover {\n        background: #bae6fd;\n    }\n    \n    .a-success {\n        background: #dcfce7;\n        color: #166534;\n        border-color: #bbf7d0;\n    }\n    \n    .a-success:hover {\n        background: #bbf7d0;\n    }\n    \n    .a-danger {\n        background: #fee2e2;\n        color: #b91c1c;\n        border-color: #fecaca;\n    }\n    \n    .a-danger:hover {\n        background: #fecaca;\n    }\n    \n    .a-warning {\n        background: #ffedd5;\n        color: #9a3412;\n        border-color: #fed7aa;\n    }\n    \n    .a-warning:hover {\n        background: #fed7aa;\n    }\n    \n    .a-info {\n        background: #ccfbf1;\n        color: #0d9488;\n        border-color: #99f6e4;\n    }\n    \n    .a-info:hover {\n        background: #99f6e4;\n    }\n    \n    .a-dark {\n        background: #e2e8f0;\n        color: #334155;\n        border-color: #cbd5e1;\n    }\n    \n    .a-dark:hover {\n        background: #cbd5e1;\n    }\n    \n    .a-outline {\n        background: transparent;\n        color: #64748b;\n        border-color: #cbd5e1;\n    }\n    \n    .a-outline:hover {\n        background: #f8fafc;\n    }\n    \n    .a-disabled {\n        background: #f1f5f9;\n        color: #94a3b8;\n        border-color: #e2e8f0;\n        cursor: not-allowed;\n    }\n    \n    .a-disabled:hover {\n        transform: none;\n        box-shadow: none;\n        background: #f1f5f9;\n    }\n</style>\n");
    h("\n<style>\n    /* 全局通用样式 */\n    .fr-btn {\n        float: right;\n        margin-left: 4px !important;\n    }\n    \n    .menu-box {\n        position: fixed;\n        right: 10px;\n        top: 50%;\n        transform: translateY(-50%);\n        display: flex;\n        flex-direction: column;\n        z-index: 1000;\n        gap: 6px;\n    }\n    \n    .menu-btn {\n        display: inline-block !important;\n        min-width: 80px;\n        padding: 7px 12px;\n        border-radius: 4px;\n        color: white !important;\n        text-decoration: none;\n        font-weight: bold;\n        font-size: 12px;\n        text-align: center;\n        cursor: pointer;\n        transition: all 0.3s ease;\n        box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);\n        text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);\n        border: none;\n        line-height: 1.3;\n        margin: 0;\n    }\n    \n    .menu-btn:hover {\n        transform: translateY(-1px);\n        box-shadow: 0 3px 6px rgba(0, 0, 0, 0.15);\n        opacity: 0.9;\n    }\n    \n    .menu-btn:active {\n        transform: translateY(0);\n        box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);\n    }\n    \n    .do-hide {\n        display: none !important;\n    }\n</style>\n");
    e = new WeakSet;
    t = async function() {
        if (!window.location.hostname.includes("javdb")) return;
        (await this.forage.keys()).forEach((e => e.startsWith("SCORE_") && this.forage.removeItem(e)));
        const e = Date.now();
        try {
            const t = await this.forage.getItem("lastCleanupTime");
            if (t && e - t < 864e5) return;
            const n = await this.forage.keys();
            for (const e of n) {
                if (this.interceptedKeys.includes(e)) continue;
                const t = await this.forage.getItem(e);
                if ("object" == typeof t && "expires" in t && "expiresStr" in t && Date.now() > t.expires) {
                    console.log("清理过期数据:", e);
                    await this.forage.removeItem(e);
                }
            }
            await this.forage.setItem("lastCleanupTime", e);
        } catch (t) {
            console.error("[自动清理失败]", t);
            await this.forage.setItem("lastCleanupTime", e);
        }
    };
    n = async function(e, t, n) {
        let a;
        if (Array.isArray(e)) a = [ ...e ]; else {
            a = await this.forage.getItem(t) || [];
            if (a.includes(e)) {
                const t = `${e} ${n}已存在`;
                show.error(t);
                throw new Error(t);
            }
            a.push(e);
        }
        await this.forage.setItem(t, a);
        return a;
    };
    let u = class _StorageManager {
        constructor() {
            __privateAdd(this, e);
            __publicField(this, "car_list_key", "car_list");
            __publicField(this, "filter_actor_key", "filter_actor");
            __publicField(this, "title_filter_keyword_key", "title_filter_keyword");
            __publicField(this, "review_filter_keyword_key", "review_filter_keyword");
            __publicField(this, "setting_key", "setting");
            __publicField(this, "auto_page_key", "autoPage");
            __publicField(this, "fold_category_key", "foldCategory");
            __publicField(this, "review_ts_key", "review_ts");
            __publicField(this, "review_sign_key", "review_sign");
            __publicField(this, "actress_prefix_key", "z_actress_");
            __publicField(this, "score_prefix_key", "z_score_");
            __publicField(this, "forage", localforage.createInstance({
                driver: localforage.INDEXEDDB,
                name: "JAV-JSH",
                version: 1,
                storeName: "appData"
            }));
            __publicField(this, "interceptedKeys", [ this.car_list_key, this.filter_actor_key, this.title_filter_keyword_key, this.review_filter_keyword_key, this.setting_key ]);
            if (_StorageManager.instance) throw new Error("LocalStorageManager已被实例化过了!");
            _StorageManager.instance = this;
            __privateMethod(this, e, t).call(this).then();
        }
        async saveFilterActor(t) {
            return __privateMethod(this, e, n).call(this, t, this.filter_actor_key, "演员");
        }
        async saveReviewFilterKeyword(t) {
            return __privateMethod(this, e, n).call(this, t, this.review_filter_keyword_key, "评论关键词");
        }
        async saveTitleFilterKeyword(t) {
            return __privateMethod(this, e, n).call(this, t, this.title_filter_keyword_key, "标题关键词");
        }
        async getFilterActorList() {
            return await this.forage.getItem(this.filter_actor_key) || [];
        }
        async getTitleFilterKeyword() {
            return await this.forage.getItem(this.title_filter_keyword_key) || [];
        }
        async getSetting(e = null, t) {
            const n = await this.forage.getItem(this.setting_key) || {};
            if (null === e) return n;
            const a = n[e];
            return a ? "true" === a || "false" === a ? "true" === a.toLowerCase() : "string" != typeof a || isNaN(Number(a)) ? a : Number(a) : t;
        }
        async saveSetting(e) {
            await this.forage.setItem(this.setting_key, e);
        }
        async getReviewFilterKeywordList() {
            return await this.forage.getItem(this.review_filter_keyword_key) || [];
        }
        async saveCar(e, t, n, a) {
            if (!e) {
                show.error("番号为空!");
                throw new Error("番号为空!");
            }
            if (!t) {
                show.error("url为空!");
                throw new Error("url为空!");
            }
            t.includes("http") || (t = window.location.origin + t);
            const i = await this.forage.getItem(this.car_list_key) || [];
            let r = i.find((t => t.carNum === e));
            if (r) r.createDate = utils.getNowStr(); else {
                r = {
                    carNum: e,
                    url: t,
                    actress: n,
                    status: "",
                    createDate: utils.getNowStr()
                };
                i.push(r);
            }
            switch (a) {
              case d:
                if (r.status === d) {
                    const t = `${e} 已在屏蔽列表中`;
                    show.error(t);
                    throw new Error(t);
                }
                r.status = d;
                break;

              case c:
                if (r.status === c) {
                    const t = `${e} 已在收藏列表中`;
                    show.error(t);
                    throw new Error(t);
                }
                r.status = c;
                break;

              case p:
                r.status = p;
                break;

              default:
                const t = "actionType错误";
                show.error(t);
                throw new Error(t);
            }
            await this.forage.setItem(this.car_list_key, i);
        }
        async getCarList() {
            return (await this.forage.getItem(this.car_list_key) || []).sort(((e, t) => {
                if (!e || !t) return 0;
                const n = e.createDate ? new Date(e.createDate).getTime() : 0;
                return (t.createDate ? new Date(t.createDate).getTime() : 0) - n;
            }));
        }
        async getCar(e) {
            return (await this.getCarList()).find((t => t.carNum === e));
        }
        async removeCar(e) {
            const t = await this.getCarList(), n = t.length, a = t.filter((t => t.carNum !== e));
            if (a.length === n) {
                show.error(`${e} 不存在`);
                return !1;
            }
            await this.forage.setItem(this.car_list_key, a);
            return !0;
        }
        async overrideCarList(e) {
            if (!Array.isArray(e)) throw new TypeError("必须传入数组类型数据");
            const t = e.filter((e => !e || "object" != typeof e || !e.carNum));
            if (t.length > 0) throw new Error(`缺少必要字段 carNum 的数据项: ${t.length} 条`);
            const n = new Set, a = e.filter((e => {
                if (n.has(e.carNum)) return !0;
                n.add(e.carNum);
                return !1;
            }));
            if (a.length > 0) throw new Error(`发现重复: ${a.slice(0, 3).map((e => e.carNum)).join(", ")}${a.length > 3 ? "..." : ""}`);
            await this.forage.setItem(this.car_list_key, e);
        }
        async getItem(e) {
            if (this.interceptedKeys.includes(e)) {
                let t = `危险操作, 改key已有方法实现获取, 请用内部方法调用!  key: ${e}`;
                show.error(t);
                throw new Error(t);
            }
            const t = await this.forage.getItem(e);
            if (null == t) return null;
            if ("object" == typeof t && "expires" in t && "expiresStr" in t) {
                if (Date.now() > t.expires) {
                    await this.forage.removeItem(e);
                    return null;
                }
                return t.value;
            }
            return t;
        }
        async setItem(e, t, n = null) {
            if (this.interceptedKeys.includes(e)) {
                let t = `危险操作, 改key已有方法实现获取, 请用内部方法调用!  key: ${e}`;
                show.error(t);
                throw new Error(t);
            }
            let a = t;
            if (null !== n) {
                const e = Date.now() + n;
                a = {
                    value: t,
                    expires: e,
                    expiresStr: utils.formatDate(new Date(e))
                };
            }
            return await this.forage.setItem(e, a);
        }
        async removeItem(e) {
            if (this.interceptedKeys.includes(e)) {
                let t = `危险操作, 改key不可删除!  key: ${e}`;
                show.error(t);
                throw new Error(t);
            }
            return await this.forage.removeItem(e);
        }
        async importData(e) {
            let t = e.filterKeywordList;
            Array.isArray(t) && await this.forage.setItem(this.title_filter_keyword_key, t);
            t = e.filterActorList;
            Array.isArray(t) && await this.forage.setItem(this.filter_actor_key, t);
            t = e.reviewKeywordList;
            Array.isArray(t) && await this.forage.setItem(this.review_filter_keyword_key, t);
            e.dataList && await this.overrideCarList(e.dataList);
            t = e[this.title_filter_keyword_key];
            Array.isArray(t) && await this.forage.setItem(this.title_filter_keyword_key, t);
            t = e[this.filter_actor_key];
            Array.isArray(t) && await this.forage.setItem(this.filter_actor_key, t);
            t = e[this.review_filter_keyword_key];
            Array.isArray(t) && await this.forage.setItem(this.review_filter_keyword_key, t);
            e[this.car_list_key] && await this.overrideCarList(e[this.car_list_key]);
            e.setting && await this.saveSetting(e.setting);
        }
        async exportData() {
            return {
                car_list: await this.getCarList(),
                filter_actor: await this.getFilterActorList(),
                title_filter_keyword: await this.getTitleFilterKeyword(),
                review_filter_keyword: await this.getReviewFilterKeywordList(),
                setting: await this.getSetting()
            };
        }
    };
    class Utils {
        constructor() {
            __publicField(this, "intervalContainer", {});
            __publicField(this, "insertStyle", (e => {
                if (e) {
                    -1 === e.indexOf("<style>") && (e = "<style>" + e + "</style>");
                    $("head").append(e);
                }
            }));
            Utils.instance || (Utils.instance = this);
            return Utils.instance;
        }
        importResource(e) {
            let t;
            if (e.indexOf("css") >= 0) {
                t = document.createElement("link");
                t.setAttribute("rel", "stylesheet");
                t.href = e;
            } else {
                t = document.createElement("script");
                t.setAttribute("type", "text/javascript");
                t.src = e;
            }
            document.documentElement.appendChild(t);
        }
        openPage(e, t, n, a) {
            n || (n = !0);
            if (a && (a.ctrlKey || a.metaKey)) window.open(e); else {
                e.includes("?") ? e += "&hideNav=1" : e += "?hideNav=1";
                layer.open({
                    type: 2,
                    title: t,
                    content: e,
                    scrollbar: !1,
                    shadeClose: n,
                    area: [ "80%", "90%" ],
                    isOutAnim: !1,
                    anim: -1
                });
            }
        }
        closePage() {
            parent.document.documentElement.style.overflow = "auto";
            [ ".layui-layer-shade", ".layui-layer-move", ".layui-layer" ].forEach((function(e) {
                parent.document.querySelectorAll(e).forEach((function(e) {
                    e.parentNode.removeChild(e);
                }));
            }));
            window.close();
        }
        loopDetector(e, t, n = 20, a = 1e4, i = !0) {
            let r = !1;
            const o = Math.random(), s = (new Date).getTime();
            this.intervalContainer[o] = setInterval((() => {
                if ((new Date).getTime() - s > a) {
                    console.warn("loopDetector timeout!", e, t);
                    r = i;
                }
                if (e() || r) {
                    clearInterval(this.intervalContainer[o]);
                    t && t();
                    delete this.intervalContainer[o];
                }
            }), n);
        }
        rightClick(e, t) {
            if (e) {
                e.jquery ? e = e.toArray() : e instanceof HTMLElement ? e = [ e ] : Array.isArray(e) || (e = [ e ]);
                e && 0 !== e.length ? e.forEach((e => {
                    e && e.addEventListener("contextmenu", (e => {
                        t(e);
                    }));
                })) : console.error("rightClick(), 找不到元素");
            }
        }
        q(e, t, n, a) {
            let i, r;
            if (e) {
                i = e.clientX - 130;
                r = e.clientY - 120;
            } else {
                i = window.innerWidth / 2 - 120;
                r = window.innerHeight / 2 - 120;
            }
            let o = layer.confirm(t, {
                offset: [ r, i ],
                title: "提示",
                btn: [ "确定", "取消" ],
                zIndex: 999999991
            }, (function() {
                n();
                layer.close(o);
            }), (function() {
                a && a();
            }));
        }
        getNowStr(e = "-", t = ":", n = null) {
            let a;
            a = n ? new Date(n) : new Date;
            const i = a.getFullYear(), r = String(a.getMonth() + 1).padStart(2, "0"), o = String(a.getDate()).padStart(2, "0"), s = String(a.getHours()).padStart(2, "0"), l = String(a.getMinutes()).padStart(2, "0"), c = String(a.getSeconds()).padStart(2, "0");
            return `${[ i, r, o ].join(e)} ${[ s, l, c ].join(t)}`;
        }
        formatDate(e, t = "-", n = ":") {
            let a;
            if (e instanceof Date) a = e; else {
                if ("string" != typeof e) throw new Error("Invalid date input: must be Date object or date string");
                a = new Date(e);
                if (isNaN(a.getTime())) throw new Error("Invalid date string");
            }
            const i = a.getFullYear(), r = String(a.getMonth() + 1).padStart(2, "0"), o = String(a.getDate()).padStart(2, "0"), s = String(a.getHours()).padStart(2, "0"), l = String(a.getMinutes()).padStart(2, "0"), c = String(a.getSeconds()).padStart(2, "0");
            return `${[ i, r, o ].join(t)} ${[ s, l, c ].join(n)}`;
        }
        download(e, t) {
            const n = new Blob([ e ], {
                type: "application/json"
            }), a = URL.createObjectURL(n), i = document.createElement("a");
            i.href = a;
            i.download = t;
            document.body.appendChild(i);
            i.click();
            setTimeout((() => {
                document.body.removeChild(i);
                URL.revokeObjectURL(a);
            }), 100);
        }
        smoothScrollToTop(e = 500) {
            return new Promise((t => {
                const n = performance.now(), a = window.pageYOffset;
                window.requestAnimationFrame((function i(r) {
                    const o = r - n, s = Math.min(o / e, 1), l = s < .5 ? 4 * s * s * s : 1 - Math.pow(-2 * s + 2, 3) / 2;
                    window.scrollTo(0, a * (1 - l));
                    s < 1 ? window.requestAnimationFrame(i) : t();
                }));
            }));
        }
        simpleId() {
            return Date.now().toString(36) + Math.random().toString(36).substr(2, 5);
        }
        log(...e) {
            console.groupCollapsed("📌", ...e);
            const t = (new Error).stack.split("\n").slice(2).map((e => e.trim())).filter((e => e.trim()));
            console.log(t.join("\n"));
            console.groupEnd();
        }
        isUrl(e) {
            try {
                new URL(e);
                return !0;
            } catch (t) {
                return !1;
            }
        }
    }
    window.utils = new Utils;
    window.http = new class {
        get(e, t = {}, n = {}) {
            return this.jqueryRequest("GET", e, null, t, n);
        }
        post(e, t = {}, n = {}) {
            return this.jqueryRequest("POST", e, t, null, n);
        }
        put(e, t = {}, n = {}) {
            return this.jqueryRequest("PUT", e, t, null, n);
        }
        del(e, t = {}, n = {}) {
            return this.jqueryRequest("DELETE", e, null, t, n);
        }
        jqueryRequest(e, t, n = {}, a = {}, i = {}) {
            "POST" === e && (i = {
                "Content-Type": "application/json",
                ...i
            });
            return new Promise(((r, o) => {
                $.ajax({
                    method: e,
                    url: t,
                    data: "GET" === e || "DELETE" === e ? a : JSON.stringify(n),
                    headers: i,
                    success: (e, t, n) => {
                        var a;
                        if (null == (a = n.getResponseHeader("Content-Type")) ? void 0 : a.includes("application/json")) try {
                            r("object" == typeof e ? e : JSON.parse(e));
                        } catch (i) {
                            r(e);
                        } else r(e);
                    },
                    error: (e, t, n) => {
                        let a = n;
                        if (e.responseText) try {
                            const t = JSON.parse(e.responseText);
                            a = t.message || t.msg || e.responseText;
                        } catch {
                            a = e.responseText;
                        }
                        o(new Error(a));
                    }
                });
            }));
        }
    };
    window.gmHttp = new class {
        get(e, t = {}, n = {}) {
            return this.gmRequest("GET", e, null, t, n);
        }
        post(e, t = {}, n = {}) {
            return this.gmRequest("POST", e, t, null, n);
        }
        put(e, t = {}, n = {}) {
            return this.gmRequest("PUT", e, t, null, n);
        }
        del(e, t = {}, n = {}) {
            return this.gmRequest("DELETE", e, null, t, n);
        }
        gmRequest(e, t, n = {}, a = {}, i = {}) {
            if (("GET" === e || "DELETE" === e) && a && Object.keys(a).length) {
                const e = new URLSearchParams(a).toString();
                t += (t.includes("?") ? "&" : "?") + e;
            }
            "POST" !== e && "PUT" !== e || (i = {
                "Content-Type": "application/json",
                ...i
            });
            return new Promise(((a, r) => {
                GM_xmlhttpRequest({
                    method: e,
                    url: t,
                    headers: i,
                    data: "POST" === e || "PUT" === e ? JSON.stringify(n) : void 0,
                    onload: e => {
                        var t;
                        try {
                            if (e.status >= 200 && e.status < 300) if (e.responseText && (null == (t = e.responseHeaders) ? void 0 : t.toLowerCase().includes("application/json"))) try {
                                a(JSON.parse(e.responseText));
                            } catch (n) {
                                a(e.responseText);
                            } else a(e.responseText || e); else if (e.responseText) try {
                                const t = JSON.parse(e.responseText);
                                r(t);
                            } catch {
                                r(new Error(e.responseText || `HTTP Error ${e.status}`));
                            } else r(new Error(`HTTP Error ${e.status}`));
                        } catch (n) {
                            r(n);
                        }
                    },
                    onerror: e => {
                        r(new Error(e.error || "Network Error"));
                    },
                    ontimeout: () => {
                        r(new Error("Request Timeout"));
                    }
                });
            }));
        }
    };
    window.storageManager = new u;
    const m = new BroadcastChannel("channel-refresh");
    window.refresh = function() {
        m.postMessage({
            type: "refresh"
        });
    };
    !function() {
        document.head.insertAdjacentHTML("beforeend", '\n        <style>\n            .loading-container {\n                position: fixed;\n                top: 0;\n                left: 0;\n                width: 100%;\n                height: 100%;\n                display: flex;\n                justify-content: center;\n                align-items: center;\n                background-color: rgba(0, 0, 0, 0.1);\n                z-index: 99999999;\n            }\n    \n            .loading-animation {\n                position: relative;\n                width: 60px;\n                height: 12px;\n                background: linear-gradient(90deg, #4facfe 0%, #00f2fe 100%);\n                border-radius: 6px;\n                animation: loading-animate 1.8s ease-in-out infinite;\n                box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n            }\n    \n            .loading-animation:before,\n            .loading-animation:after {\n                position: absolute;\n                display: block;\n                content: "";\n                animation: loading-animate 1.8s ease-in-out infinite;\n                height: 12px;\n                border-radius: 6px;\n                box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n            }\n    \n            .loading-animation:before {\n                top: -20px;\n                left: 10px;\n                width: 40px;\n                background: linear-gradient(90deg, #ff758c 0%, #ff7eb3 100%);\n            }\n    \n            .loading-animation:after {\n                bottom: -20px;\n                width: 35px;\n                background: linear-gradient(90deg, #ff9a9e 0%, #fad0c4 100%);\n            }\n    \n            @keyframes loading-animate {\n                0% {\n                    transform: translateX(40px);\n                }\n                50% {\n                    transform: translateX(-30px);\n                }\n                100% {\n                    transform: translateX(40px);\n                }\n            }\n        </style>\n    ');
        window.loading = function() {
            const e = document.createElement("div");
            e.className = "loading-container";
            const t = document.createElement("div");
            t.className = "loading-animation";
            e.appendChild(t);
            document.body.appendChild(e);
            return {
                close: () => {
                    e && e.parentNode && e.parentNode.removeChild(e);
                }
            };
        };
    }();
    !function() {
        document.head.insertAdjacentHTML("beforeend", "\n        <style>\n            .data-table {\n                width: 100%;\n                border-collapse: separate;\n                border-spacing: 0;\n                font-family: 'Helvetica Neue', Arial, sans-serif;\n                background: #fff;\n                overflow: hidden;\n                box-shadow: 0 4px 20px rgba(0, 0, 0, 0.03);\n                margin: 0 auto; /* 表格整体水平居中 */\n            }\n    \n            .data-table thead tr {\n                background: #f8fafc;\n            }\n            \n            /* 表头居中 */\n            .data-table th {\n                padding: 16px 20px;\n                text-align: center !important; /* 表头文字居中 */\n                color: #64748b;\n                font-weight: 500;\n                font-size: 14px;\n                text-transform: uppercase;\n                letter-spacing: 0.5px;\n                border-bottom: 1px solid #e2e8f0;\n            }\n            \n            /* 单元格内容居中 */\n            .data-table td {\n                padding: 14px 20px;\n                color: #334155;\n                font-size: 15px;\n                border-bottom: 1px solid #f1f5f9;\n                text-align: center !important; /* 单元格文字居中 */\n                vertical-align: middle; /* 垂直居中 */\n            }\n            \n            .data-table tbody tr:last-child td {\n                border-bottom: none;\n            }\n            \n            /* 行hover 变色*/\n            .data-table tbody tr {\n                transition: all 0.2s ease;\n            }\n            \n            .data-table tbody tr:hover {\n                background: #f8fafc;\n            }\n            \n            /* 可选:特定列左对齐/右对齐的示例 */\n            .data-table .text-left {\n                text-align: left;\n            }\n            \n            .data-table .text-right {\n                text-align: right;\n            }\n            \n            /* 添加.show-border时显示边框 */\n            .data-table.show-border {\n                border: 1px solid #e2e8f0;\n            }\n            \n            .data-table.show-border th,\n            .data-table.show-border td {\n            border: 1px solid #e2e8f0;\n        }\n        </style>\n    ");
        window.TableGenerator = class {
            constructor(e) {
                this.defaults = {
                    tableClass: "data-table",
                    showBorder: !1,
                    buttons: []
                };
                this.config = {
                    ...this.defaults,
                    ...e
                };
                this.validateConfig() && this.init();
            }
            validateConfig() {
                if (!(this.config.containerId && this.config.columns && Array.isArray(this.config.columns) && Array.isArray(this.config.data))) {
                    console.error("缺少必要参数或参数类型不正确");
                    return !1;
                }
                this.container = document.getElementById(this.config.containerId);
                if (!this.container) {
                    console.error(`未找到ID为${this.config.containerId}的容器`);
                    return !1;
                }
                return !0;
            }
            init() {
                this.container.innerHTML = "";
                this.table = document.createElement("table");
                this.table.className = this.config.showBorder ? `${this.config.tableClass} show-border` : this.config.tableClass;
                this.createHeader();
                this.createBody();
                this.container.appendChild(this.table);
            }
            createHeader() {
                const e = document.createElement("thead"), t = document.createElement("tr");
                this.config.columns.forEach((e => {
                    const n = document.createElement("th");
                    n.textContent = e.title || e.key;
                    e.width && (n.style.width = e.width);
                    e.headerClass && (n.className = e.headerClass);
                    t.appendChild(n);
                }));
                if (this.config.buttons && this.config.buttons.length > 0) {
                    const e = document.createElement("th");
                    e.textContent = "操作";
                    this.config.buttonColumnWidth && (e.style.width = this.config.buttonColumnWidth);
                    t.appendChild(e);
                }
                e.appendChild(t);
                this.table.appendChild(e);
            }
            createBody() {
                const e = document.createElement("tbody");
                0 === this.config.data.length ? this.renderEmptyData(e) : this.renderDataRows(e);
                this.table.appendChild(e);
            }
            renderEmptyData(e) {
                const t = document.createElement("tr"), n = document.createElement("td");
                n.colSpan = this.config.columns.length + (this.config.buttons.length > 0 ? 1 : 0);
                n.textContent = "暂无数据";
                n.style.textAlign = "center";
                t.appendChild(n);
                e.appendChild(t);
            }
            renderDataRows(e) {
                this.config.data.forEach(((t, n) => {
                    const a = document.createElement("tr");
                    this.renderDataCells(a, t, n);
                    this.config.buttons && this.config.buttons.length > 0 && this.renderButtonCells(a, t, n);
                    e.appendChild(a);
                }));
            }
            renderDataCells(e, t, n) {
                this.config.columns.forEach((a => {
                    const i = document.createElement("td");
                    a.render ? i.innerHTML = a.render(t, n) : i.textContent = t[a.key] || "";
                    a.cellClass && (i.className = a.cellClass);
                    e.appendChild(i);
                }));
            }
            renderButtonCells(e, t, n) {
                const a = document.createElement("td");
                this.config.buttons.forEach((e => {
                    const i = document.createElement("a");
                    i.textContent = e.text;
                    i.className = e.class || "a-primary";
                    i.addEventListener("click", (a => {
                        if (e.onClick) {
                            const i = e.onClick.length;
                            3 === i ? e.onClick(a, t, n) : 2 === i ? e.onClick(a, t) : e.onClick(t);
                        }
                    }));
                    a.appendChild(i);
                }));
                e.appendChild(a);
            }
            update(e) {
                this.config.data = e;
                this.init();
            }
            getTableElement() {
                return this.table;
            }
        };
    }();
    !function() {
        const e = (e, t, n, a, i) => {
            let r;
            if ("object" == typeof n) r = n; else {
                r = "object" == typeof a ? a : i || {};
                r.gravity = n || "top";
                r.position = "string" == typeof a ? a : "center";
            }
            r.gravity && "center" !== r.gravity || (r.offset = {
                y: "calc(50vh - 150px)"
            });
            const o = "#60A5FA", s = "#93C5FD", l = "#10B981", c = "#6EE7B7", d = "#EF4444", p = "#FCA5A5", g = {
                borderRadius: "12px",
                color: "white",
                padding: "12px 16px",
                boxShadow: "0 4px 6px rgba(0,0,0,0.1)",
                minWidth: "150px",
                textAlign: "center",
                zIndex: 999999999
            }, h = {
                text: e,
                duration: 2e3,
                close: !1,
                gravity: "top",
                position: "center",
                style: {
                    info: {
                        ...g,
                        background: `linear-gradient(to right, ${o}, ${s})`
                    },
                    success: {
                        ...g,
                        background: `linear-gradient(to right, ${l}, ${c})`
                    },
                    error: {
                        ...g,
                        background: `linear-gradient(to right, ${d}, ${p})`
                    }
                }[t],
                stopOnFocus: !0,
                oldestFirst: !1,
                ...r
            };
            Toastify(h).showToast();
        };
        window.show = {
            ok: (t, n = "center", a, i) => {
                e(t, "success", n, a, i);
            },
            error: (t, n = "center", a, i) => {
                e(t, "error", n, a, i);
            },
            info: (t, n = "center", a, i) => {
                e(t, "info", n, a, i);
            }
        };
    }();
    class PluginManager {
        constructor() {
            this.plugins = new Map;
        }
        register(e) {
            if ("function" != typeof e) throw new Error("插件必须是一个类");
            const t = e.name;
            if (!t) throw new Error("类必须要有名称");
            const n = t.toLowerCase();
            if (this.plugins.has(n)) throw new Error(`插件"${t}"已注册`);
            const a = new e;
            a.pluginManager = this;
            this.plugins.set(n, a);
        }
        getBean(e) {
            return this.plugins.get(e.toLowerCase());
        }
        _getDependencies(e) {
            const t = e.toString();
            return t.slice(t.indexOf("(") + 1, t.indexOf(")")).split(",").map((e => e.trim())).filter((e => e));
        }
        async process() {
            const e = (await Promise.allSettled(Array.from(this.plugins).map((async ([e, t]) => {
                try {
                    if ("function" == typeof t.handle) {
                        const n = await t.initCss();
                        utils.insertStyle(n);
                        await t.handle();
                        return {
                            name: e,
                            status: "fulfilled"
                        };
                    }
                    console.log("加载插件", e);
                } catch (n) {
                    console.error(`插件 ${e} 执行失败`, n);
                    return {
                        name: e,
                        status: "rejected",
                        error: n
                    };
                }
            })))).filter((e => "rejected" === e.status));
            e.length && console.error("以下插件执行失败:", e.map((e => e.name)));
            document.body.classList.add("script-ready");
        }
    }
    class BasePlugin {
        constructor() {
            __publicField(this, "pluginManager", null);
        }
        getBean(e) {
            let t = this.pluginManager.getBean(e);
            if (!t) {
                let t = "容器中不存在: " + e;
                show.error(t);
                throw new Error(t);
            }
            return t;
        }
        async initCss() {
            return "";
        }
        async handle() {}
        getPageInfo() {
            let e, t, n, a, i, r = window.location.href;
            if (s) {
                e = $('a[title="複製番號"]').attr("data-clipboard-text");
                t = r.split("?")[0].split("#")[0];
                n = $(".female").prev().map(((e, t) => $(t).text())).get().join(" ");
                a = $(".male").prev().map(((e, t) => $(t).text())).get().join(" ");
                const o = window.location.href.split("?")[0].split("/");
                i = o[o.length - 1].split("#")[0];
            }
            if (l) {
                t = r.split("?")[0];
                e = t.split("/").filter(Boolean).pop();
                n = $('span[onmouseover*="star_"] a').map(((e, t) => $(t).text())).get().join(" ");
                a = "";
            }
            return {
                carNum: e,
                url: t,
                actress: n,
                actors: a,
                movieId: i
            };
        }
        getSelector() {
            return s ? o : l ? r : null;
        }
    }
    class DetailPagePlugin extends BasePlugin {
        constructor() {
            super();
        }
        async initCss() {
            return window.isDetailPage && window.location.href.includes("hideNav=1") ? "\n                .main-nav,#search-bar-container {\n                    display: none !important;\n                }\n                \n                html {\n                    padding-top:0px!important;\n                }\n            " : "";
        }
        handle() {
            window.isDetailPage && this.checkFilterActor().then();
        }
        async checkFilterActor() {
            if (!window.isDetailPage) return;
            const e = await storageManager.getFilterActorList();
            let t = this.getPageInfo().actors;
            e.forEach((e => {
                if (t.indexOf(e) > -1) {
                    const e = this.getBean("detailPageButtonPlugin");
                    e.answerCount++;
                    utils.q(null, "存在xxx演员, 是否屏蔽?", (() => {
                        e.filterOne(null, !0);
                    }));
                }
            }));
        }
    }
    class PreviewVideoPlugin extends BasePlugin {
        async initCss() {
            return "\n            .video-control-btn {\n                position: absolute;\n                bottom: 10px;\n                right: 10px;\n                z-index: 99999999999;\n                min-width:100px;\n                padding: 8px 16px;\n                background: rgba(0,0,0,0.7);\n                color: white;\n                border: none;\n                border-radius: 4px;\n                cursor: pointer;\n            }\n            .video-control-btn.active {\n                background-color: #1890ff; /* 选中按钮的背景色 */\n                color: white;             /* 选中按钮的文字颜色 */\n                font-weight: bold;        /* 加粗显示 */\n                border: 2px solid #096dd9; /* 边框样式 */\n            }\n        ";
        }
        handle() {
            let e = $(".preview-video-container");
            e.on("click", (e => {
                utils.loopDetector((() => $(".fancybox-content #preview-video").length > 0), (() => {
                    this.handleVideo().then();
                }));
            }));
            utils.loopDetector((() => $(".fancybox-content #preview-video").length > 0), (() => {
                $(".fancybox-content #preview-video").length > 0 && this.handleVideo().then();
            }));
            window.location.href.includes("autoPlay=1") && e[0].click();
        }
        async handleVideo() {
            const e = $("#preview-video"), t = e.find("source"), n = e.parent();
            if (!e.length || !t.length) return;
            const a = e[0];
            a.muted = !1;
            n.css("position", "relative");
            const i = t.attr("src"), r = [ "hhb", "hmb", "mhb", "mmb" ], o = r.find((e => i.includes(e))) || "mhb", s = [ {
                id: "video-mmb",
                text: "低画质",
                quality: "mmb"
            }, {
                id: "video-mhb",
                text: "中画质",
                quality: "mhb"
            }, {
                id: "video-hmb",
                text: "高画质",
                quality: "hmb"
            }, {
                id: "video-hhb",
                text: "超高清",
                quality: "hhb"
            } ];
            const l = `videoQualities_${this.getPageInfo().carNum}`;
            let c = JSON.parse(sessionStorage.getItem(l));
            if (!c) {
                c = (await Promise.all(s.map((async e => {
                    const t = i.replace(new RegExp(r.join("|"), "g"), e.quality);
                    try {
                        return (await fetch(t, {
                            method: "HEAD"
                        })).ok ? e : null;
                    } catch {
                        return null;
                    }
                })))).filter(Boolean);
                sessionStorage.setItem(l, JSON.stringify(c));
            }
            if (c.length <= 1) return;
            const d = c.map(((e, t) => `\n                <button class="video-control-btn${e.quality === o ? " active" : ""}" \n                        id="${e.id}" \n                        data-quality="${e.quality}"\n                        style="bottom: ${50 * t}px; right: -105px;">\n                    ${e.text}\n                </button>\n            `)).join("");
            n.append(d);
            const p = n.find(".video-control-btn");
            n.on("click", ".video-control-btn", (async e => {
                const n = $(e.currentTarget), o = n.data("quality");
                if (!n.hasClass("active")) try {
                    const e = i.replace(new RegExp(r.join("|"), "g"), o);
                    t.attr("src", e);
                    a.load();
                    a.muted = !1;
                    await a.play();
                    p.removeClass("active");
                    n.addClass("active");
                } catch (s) {
                    console.error("切换画质失败:", s);
                }
            }));
            p.last().trigger("click");
        }
    }
    const f = class _HotkeyManager {
        constructor() {
            if (new.target === _HotkeyManager) throw new Error("HotkeyManager cannot be instantiated.");
        }
        static registerHotkey(e, t, n = null) {
            if (Array.isArray(e)) {
                let a = [];
                e.forEach((e => {
                    if (!this.isHotkeyFormat(e)) throw new Error("快捷键格式错误");
                    let i = this.recordHotkey(e, t, n);
                    a.push(i);
                }));
                return a;
            }
            if (!this.isHotkeyFormat(e)) throw new Error("快捷键格式错误");
            return this.recordHotkey(e, t, n);
        }
        static recordHotkey(e, t, n) {
            let a = Math.random().toString(36).substr(2);
            this.registerHotKeyMap.set(a, {
                hotkeyString: e,
                callback: t,
                keyupCallback: n
            });
            return a;
        }
        static unregisterHotkey(e) {
            this.registerHotKeyMap.has(e) && this.registerHotKeyMap.delete(e);
        }
        static isHotkeyFormat(e) {
            return e.toLowerCase().split("+").map((e => e.trim())).every((e => [ "ctrl", "shift", "alt" ].includes(e) || 1 === e.length));
        }
        static judgeHotkey(e, t) {
            const n = e.toLowerCase().split("+").map((e => e.trim())), a = n.includes("ctrl"), i = n.includes("shift"), r = n.includes("alt"), o = n.find((e => "ctrl" !== e && "shift" !== e && "alt" !== e));
            return (this.isMac ? t.metaKey : t.ctrlKey) === a && t.shiftKey === i && t.altKey === r && t.key.toLowerCase() === o;
        }
    };
    __publicField(f, "isMac", 0 === navigator.platform.indexOf("Mac"));
    __publicField(f, "registerHotKeyMap", new Map);
    __publicField(f, "handleKeydown", (e => {
        for (const [t, n] of f.registerHotKeyMap) {
            let t = n.hotkeyString, a = n.callback;
            f.judgeHotkey(t, e) && a(e);
        }
    }));
    __publicField(f, "handleKeyup", (e => {
        for (const [t, n] of f.registerHotKeyMap) {
            let t = n.hotkeyString, a = n.keyupCallback;
            a && (f.judgeHotkey(t, e) && a(e));
        }
    }));
    let w = f;
    document.addEventListener("keydown", (e => {
        w.handleKeydown(e);
    }));
    document.addEventListener("keyup", (e => {
        w.handleKeyup(e);
    }));
    class JavTrailersPlugin extends BasePlugin {
        constructor() {
            super();
            this.hasBand = !1;
        }
        handle() {
            let e = window.location.href;
            if (!e.includes("handle=1")) return;
            if ($("h1:contains('Page not found')").length) {
                let t = e.split("?")[0].split("video/")[1].toLowerCase().replace("00", "-");
                window.location.href = "https://javtrailers.com/search/" + t + "?handle=1";
                return;
            }
            let t = $(".videos-list .video-link").toArray();
            if (t.length) {
                const n = e.split("?")[0].split("search/")[1].toLowerCase(), a = t.find((e => $(e).find(".vid-title").text().toLowerCase().includes(n)));
                if (a) {
                    window.location.href = $(a).attr("href") + "?handle=1";
                    return;
                }
            }
            this.handlePlayJavTrailers();
            $("#videoPlayerContainer").on("click", (() => {
                this.handlePlayJavTrailers();
            }));
            window.addEventListener("message", (e => {
                let t = document.getElementById("vjs_video_3_html5_api");
                t && (t.currentTime += 5);
            }));
            w.registerHotkey("z", (() => {
                const e = document.getElementById("vjs_video_3_html5_api");
                e && (e.currentTime += 5);
            }));
            w.registerHotkey("a", (() => window.parent.postMessage("a", "*")));
            w.registerHotkey("s", (() => window.parent.postMessage("s", "*")));
        }
        handlePlayJavTrailers() {
            this.hasBand || utils.loopDetector((() => 0 !== $("#vjs_video_3_html5_api").length), (() => {
                setTimeout((() => {
                    this.hasBand = !0;
                    let e = document.getElementById("vjs_video_3_html5_api");
                    e.play();
                    e.currentTime = 5;
                    e.addEventListener("timeupdate", (function() {
                        e.currentTime >= 14 && e.currentTime < 16 && (e.currentTime += 2);
                    }));
                    $("#vjs_video_3_html5_api").css({
                        position: "fixed",
                        width: "100vw",
                        height: "100vh",
                        objectFit: "cover",
                        zIndex: "999999999"
                    });
                    $(".vjs-control-bar").css({
                        position: "fixed",
                        bottom: "20px",
                        zIndex: "999999999"
                    });
                }), 0);
            }));
        }
    }
    class SubTitleCatPlugin extends BasePlugin {
        handle() {
            $(".t-banner-inner").hide();
            $("#navbar").hide();
            let e = window.location.href.split("=")[1].toLowerCase();
            $(".sub-table tr td a").toArray().forEach((t => {
                let n = $(t);
                n.text().toLowerCase().includes(e) || n.parent().parent().hide();
            }));
        }
    }
    const b = "https://jdforrepam.com/api";
    async function v() {
        const e = Math.floor(Date.now() / 1e3);
        if (e - (await storageManager.getItem(storageManager.review_ts_key) || 0) <= 20) return await storageManager.getItem(storageManager.review_sign_key);
        const t = `${e}.lpw6vgqzsp.${md5(`${e}71cf27bb3c0bcdf207b64abecddc970098c7421ee7203b9cdae54478478a199e7d5a6e1a57691123c1a931c057842fb73ba3b3c83bcd69c17ccf174081e3d8aa`)}`;
        await storageManager.setItem(storageManager.review_ts_key, e);
        await storageManager.setItem(storageManager.review_sign_key, t);
        return t;
    }
    const y = async (e, t = 1, n = 20) => {
        let a = `${b}/v1/movies/${e}/reviews`, i = {
            jdSignature: await v()
        };
        return (await http.get(a, {
            page: t,
            sort_by: "hotly",
            limit: n
        }, i)).data.reviews;
    }, x = async e => {
        let t = `${b}/v4/movies/${e}`, n = {
            jdSignature: await v()
        };
        const a = await http.get(t, null, n);
        if (!a.data) {
            show.error("获取视频详情失败: " + a.message);
            throw new Error(a.message);
        }
        const i = a.data.movie, r = i.preview_images, o = [];
        r.forEach((e => {
            o.push(e.large_url.replace("https://tp-iu.cmastd.com/rhe951l4q", "https://c0.jdbstatic.com"));
        }));
        return {
            movieId: i.id,
            actors: i.actors,
            title: i.origin_title,
            carNum: i.number,
            score: i.score,
            releaseDate: i.release_date,
            watchedCount: i.watched_count,
            imgList: o
        };
    }, k = async (e, t = 1, n = 20) => {
        let a = `${b}/v1/lists/related?movie_id=${e}&page=${t}&limit=${n}`, i = {
            jdSignature: await v()
        };
        const r = await gmHttp.get(a, null, i), o = [];
        r.data.lists.forEach((e => {
            o.push({
                relatedId: e.id,
                name: e.name,
                movieCount: e.movies_count,
                collectionCount: e.collections_count,
                viewCount: e.views_count,
                createTime: utils.formatDate(e.created_at)
            });
        }));
        return o;
    };
    class Fc2Plugin extends BasePlugin {
        handle() {
            let e = "/advanced_search?type=3&score_min=3&d=1";
            $('.navbar-item:contains("FC2")').attr("href", e);
            $('.tabs a:contains("FC2")').attr("href", e);
            if (window.location.href.includes("collection_codes?movieId")) {
                const e = new URLSearchParams(window.location.search);
                let t = e.get("movieId"), n = e.get("carNum"), a = e.get("url");
                t && n && a && this.openFc2Page(t, n, a);
            }
        }
        async initCss() {
            return "\n            /* 弹层样式 */\n            .movie-detail-layer .layui-layer-title {\n                font-size: 18px;\n                color: #333;\n                background: #f8f8f8;\n            }\n            \n            \n            /* 容器样式 */\n            .movie-detail-container {\n                display: flex;\n                height: 100%;\n                background: #fff;\n            }\n            \n            .movie-poster-container {\n                flex: 0 0 60%;\n                padding: 15px;\n            }\n            \n            .right-box {\n                flex: 1;\n                padding: 20px;\n                overflow-y: auto;\n            }\n            \n            /* 预告片iframe */\n            .movie-trailer {\n                width: 100%;\n                height: 100%;\n                min-height: 400px;\n                background: #000;\n                border-radius: 4px;\n            }\n            \n            /* 电影信息样式 */\n            .movie-title {\n                font-size: 24px;\n                margin-bottom: 15px;\n                color: #333;\n            }\n            \n            .movie-meta {\n                margin-bottom: 20px;\n                color: #666;\n            }\n            \n            .movie-meta span {\n                margin-right: 15px;\n            }\n            \n            /* 演员列表 */\n            .actor-list {\n                display: flex;\n                flex-wrap: wrap;\n                gap: 8px;\n                margin-top: 10px;\n            }\n            \n            .actor-tag {\n                padding: 4px 12px;\n                background: #f0f0f0;\n                border-radius: 15px;\n                font-size: 12px;\n                color: #555;\n            }\n            \n            /* 图片列表 */\n            .image-list {\n                display: flex;\n                flex-wrap: wrap;\n                gap: 10px;\n                margin-top: 10px;\n            }\n            \n            .movie-image-thumb {\n                width: 120px;\n                height: 80px;\n                object-fit: cover;\n                border-radius: 4px;\n                cursor: pointer;\n                transition: transform 0.3s;\n            }\n            \n            .movie-image-thumb:hover {\n                transform: scale(1.05);\n            }\n            \n            /* 加载中和错误状态 */\n            .search-loading, .movie-error {\n                padding: 40px;\n                text-align: center;\n                color: #999;\n            }\n            \n            .movie-error {\n                color: #f56c6c;\n            }\n            \n            .fancybox-container{\n                z-index:99999999\n             }\n             \n             \n             /* 错误提示样式 */\n            .movie-not-found, .movie-error {\n                text-align: center;\n                padding: 30px;\n                color: #666;\n            }\n            \n            .movie-not-found h3, .movie-error h3 {\n                color: #f56c6c;\n                margin: 15px 0;\n            }\n            \n            .icon-warning, .icon-error {\n                font-size: 50px;\n                color: #e6a23c;\n            }\n            \n            .icon-error {\n                color: #f56c6c;\n            }\n\n        ";
        }
        openFc2Page(e, t, n) {
            layer.open({
                type: 1,
                title: "影片详情",
                content: '\n            <div class="movie-detail-container">\n                <div class="movie-poster-container">\n                    <iframe class="movie-trailer" frameborder="0" allowfullscreen scrolling="no"></iframe>\n                </div>\n                <div class="right-box">\n                    <div class="movie-info-container">\n                        <div class="search-loading">加载中...</div>\n                    </div>\n                    <div style="margin: 10px 0">\n                        <a id="favoriteBtn" class="menu-btn" style="background-color:#25b1dc"><span>收藏</span></a>\n                        <a id="filterBtn" class="menu-btn" style="background-color:#de3333"><span>屏蔽</span></a>\n                        <a id="hasDownBtn" class="menu-btn" style="background-color:#7bc73b"><span>加入已下载</span></a>\n                    </div>\n                    <div class="message video-panel" style="margin-top:20px">\n                        <div id="magnets-content" class="magnet-links" style="margin: 0 0.75rem">\n                            <div class="search-loading">加载中...</div>\n                        </div>\n                    </div>\n                    <div id="reviews-content">\n                    </div>\n                    <span id="data-actress" style="display: none"></span>\n                </div>\n            </div>\n        ',
                area: [ "80%", "90%" ],
                skin: "movie-detail-layer",
                scrollbar: !1,
                success: (a, i) => {
                    this.loadData(e, t);
                    $("#favoriteBtn").on("click", (async e => {
                        const a = $("#data-actress").text();
                        await storageManager.saveCar(t, n, a, c);
                        window.refresh();
                        layer.closeAll();
                    }));
                    $("#filterBtn").on("click", (e => {
                        utils.q(e, `是否屏蔽${t}?`, (async () => {
                            const e = $("#data-actress").text();
                            await storageManager.saveCar(t, n, e, d);
                            window.refresh();
                            layer.closeAll();
                            window.location.href.includes("collection_codes?movieId") && utils.closePage();
                        }));
                    }));
                    $("#hasDownBtn").on("click", (async e => {
                        const a = $("#data-actress").text();
                        await storageManager.saveCar(t, n, a, p);
                        window.refresh();
                        layer.closeAll();
                    }));
                },
                end() {
                    window.location.href.includes("collection_codes?movieId") && utils.closePage();
                }
            });
        }
        loadData(e, t) {
            this.handleVideo(t.replace("FC2-", ""));
            this.handleMovieDetail(e);
            this.handleMagnets(e);
            this.getBean("reviewPlugin").showReview(e, $("#reviews-content")).then();
        }
        handleMovieDetail(e) {
            x(e).then((e => {
                const t = e.actors || [], n = e.imgList || [];
                let a = "";
                if (t.length > 0) {
                    let e = "";
                    for (let n = 0; n < t.length; n++) {
                        let i = t[n];
                        a += `<span class="actor-tag"><a href="/actors/${i.id}" target="_blank">${i.name}</a></span>`;
                        0 === i.gender && (e += i.name);
                    }
                    $("#data-actress").text(e);
                } else a = '<span class="no-data">暂无演员信息</span>';
                let i = "";
                i = Array.isArray(n) && n.length > 0 ? n.map(((e, t) => `\n                <a href="${e}" data-fancybox="movie-gallery" data-caption="剧照 ${t + 1}">\n                    <img src="${e}" class="movie-image-thumb"  alt=""/>\n                </a>\n            `)).join("") : '<div class="no-data">暂无剧照</div>';
                $(".movie-info-container").html(`\n                <h3 class="movie-title">${e.title || "无标题"}</h3>\n                <div class="movie-meta">\n                    <span>番号: ${e.carNum || "未知"}</span>\n                    <span>年份: ${e.releaseDate || "未知"}</span>\n                    <span>评分: ${e.score || "无"}</span>\n                </div>\n                <div class="movie-actors">\n                    <div class="actor-list">主演: ${a}</div>\n                </div>\n                <div class="movie-gallery" style="margin-top:10px">\n                    <h4>剧照: </h4>\n                    <div class="image-list">${i}</div>\n                </div>\n            `);
            })).catch((e => {
                console.error(e);
                $(".movie-info-container").html(`\n                <div class="movie-error">加载失败: ${e.message}</div>\n            `);
            }));
        }
        handleMagnets(e) {
            (async e => {
                let t = `${b}/v1/movies/${e}/magnets`, n = {
                    jdSignature: await v()
                };
                return (await http.get(t, null, n)).data.magnets;
            })(e).then((e => {
                let t = "";
                if (e.length > 0) for (let n = 0; n < e.length; n++) {
                    let a = e[n], i = "";
                    n % 2 == 0 && (i = "odd");
                    t += `\n                        <div class="item columns is-desktop ${i}">\n                            <div class="magnet-name column is-four-fifths">\n                                <a href="magnet:?xt=urn:btih:${a.hash}" title="右鍵點擊並選擇「複製鏈接地址」">\n                                    <span class="name">${a.name}</span>\n                                    <br>\n                                    <span class="meta">\n                                        ${(a.size / 1024).toFixed(2)}GB, ${a.files_count}個文件 \n                                     </span>\n                                    <br>\n                                    <div class="tags">\n                                        ${a.hd ? '<span class="tag is-primary is-small is-light">高清</span>' : ""}\n                                        ${a.cnsub ? '<span class="tag is-warning is-small is-light">字幕</span>' : ""}\n                                    </div>\n                                </a>\n                            </div>\n                            <div class="buttons column">\n                                <button class="button is-info is-small copy-to-clipboard" data-clipboard-text="magnet:?xt=urn:btih:${a.hash}" type="button">&nbsp;複製&nbsp;</button>\n                            </div>\n                            <div class="date column"><span class="time">${a.created_at}</span></div>\n                        </div>\n                    `;
                } else t = '<span class="no-data">暂无磁力信息</span>';
                $("#magnets-content").html(t);
            })).catch((e => {
                console.error(e);
                $("#magnets-content").html(`\n                <div class="movie-error">加载失败: ${e.message}</div>\n            `);
            }));
        }
        handleVideo(e) {
            (async e => {
                let t = `https://hohoj.tv/search?text=${e}`, n = await gmHttp.get(t), a = null;
                if (n.includes("找不到任何影片")) return a;
                const i = (new DOMParser).parseFromString(n, "text/html");
                $(i).find(".video-item a").toArray().forEach((t => {
                    if ($(t).find(".video-item-title").text().includes(e)) {
                        let e = $(t).attr("href").split("id=")[1];
                        a = "https://hohoj.tv/embed?id=" + e;
                    }
                }));
                return a;
            })(e).then((t => {
                const n = document.querySelector(".movie-poster-container"), a = document.querySelector(".movie-trailer");
                if (t) $(a).attr("src", t); else {
                    n.innerHTML = `\n                    <div class="movie-not-found">\n                        <i class="icon-warning"></i>\n                        <h3>未找到相关内容</h3>\n                        <p>hohoj.tv 中没有找到与当前番号相关的影片信息</p>\n                        <p style="margin:20px">请尝试以下网站</p>\n                        <p><a class="menu-btn" style="background:linear-gradient(to right, #d29494, rgb(254,98,142))" href="https://missav.ws/dm3/fc2-ppv-${e}" target="_blank">missav</a></p>\n                    </div>\n                `;
                    a.style.display = "none";
                }
            }));
        }
    }
    class FoldCategoryPlugin extends BasePlugin {
        async handle() {
            if (!window.isListPage) return;
            let e, t = $(".tabs ul");
            if (t.length > 0) {
                e = $("#tags");
                let n = $("#tags dl div.tag.is-info").map((function() {
                    return $(this).text().replaceAll("\n", "").replaceAll(" ", "");
                })).get().join(" ");
                if (!n) return;
                t.append('\n                <li class="is-active" id="foldCategoryBtn">\n                    <a class="menu-btn" style="background-color:#d23e60 !important;margin-left: 20px;border-bottom:none !important;border-radius:3px;">\n                        <span></span>\n                        <i style="margin-left: 10px"></i>\n                    </a>\n                </li>\n            ');
                $(".tabs").append(`<div style="padding-top:10px"><span>已选分类: ${n}</span></div>`);
            }
            let n = $("h2.section-title");
            if (n.length > 0) {
                n.append('\n                <div id="foldCategoryBtn">\n                    <a class="menu-btn" style="background-color:#d23e60 !important;margin-left: 20px;border-bottom:none !important;border-radius:3px;">\n                        <span></span>\n                        <i style="margin-left: 10px"></i>\n                    </a>\n                </div>\n            ');
                e = $("section > div > div.box");
            }
            if (!e) return;
            let a = $("#foldCategoryBtn"), i = "yes" === await storageManager.getItem(storageManager.fold_category_key), [r, o] = i ? [ "展开", "icon-angle-double-down" ] : [ "折叠", "icon-angle-double-up" ];
            a.find("span").text(r).end().find("i").attr("class", o);
            window.location.href.includes("noFold=1") || e[i ? "hide" : "show"]();
            a.on("click", (async t => {
                t.preventDefault();
                i = !i;
                await storageManager.setItem(storageManager.fold_category_key, i ? "yes" : "no");
                const [n, r] = i ? [ "展开", "icon-angle-double-down" ] : [ "折叠", "icon-angle-double-up" ];
                a.find("span").text(n).end().find("i").attr("class", r);
                e[i ? "hide" : "show"]();
            }));
        }
    }
    class ActressInfoPlugin extends BasePlugin {
        constructor() {
            super(...arguments);
            __publicField(this, "apiUrl", "https://ja.wikipedia.org/wiki/");
        }
        handle() {
            this.handleDetailPage().then();
            this.handleStarPage().then();
        }
        async initCss() {
            return "\n            <style>\n                .info-tag {\n                    background-color: #ecf5ff;\n                    display: inline-block;\n                    height: 32px;\n                    padding: 0 10px;\n                    line-height: 30px;\n                    font-size: 12px;\n                    color: #409eff;\n                    border: 1px solid #d9ecff;\n                    border-radius: 4px;\n                    box-sizing: border-box;\n                    white-space: nowrap;\n                }\n            </style>\n        ";
        }
        async handleDetailPage() {
            let e = $(".female").prev().map(((e, t) => $(t).text().trim())).get();
            if (!e.length) return;
            let t = null, n = "";
            for (let i = 0; i < e.length; i++) {
                let r = e[i];
                t = await storageManager.getItem(storageManager.actress_prefix_key + r);
                if (!t) try {
                    t = await this.searchInfo(r);
                    t && await storageManager.setItem(storageManager.actress_prefix_key + r, t, g);
                } catch (a) {
                    console.error("该名称查询失败,尝试其它名称");
                }
                let o = "";
                o = t ? `\n                    <div class="panel-block">\n                        <strong>${r}:</strong>\n                        <a href="${t.url}" style="margin-left: 5px" target="_blank">\n                            <span class="info-tag">${t.birthday} ${t.age}</span>\n                            <span class="info-tag">${t.height} ${t.weight}</span>\n                            <span class="info-tag">${t.threeSizeText} ${t.braSize}</span>\n                        </a>\n                    </div>\n                ` : `<div class="panel-block"><a href="${this.apiUrl + r}" target="_blank"><strong>${r}:</strong></a></div> `;
                n += o;
            }
            $('strong:contains("演員")').parent().after(n);
        }
        async handleStarPage() {
            let e = [], t = $(".actor-section-name");
            t.length && t.text().trim().split(",").forEach((t => {
                e.push(t.trim());
            }));
            let n = $(".section-meta:not(:contains('影片'))");
            n.length && n.text().trim().split(",").forEach((t => {
                e.push(t.trim());
            }));
            if (!e.length) return;
            let a = null;
            for (let o = 0; o < e.length; o++) {
                let t = e[o];
                a = await storageManager.getItem(storageManager.actress_prefix_key + t);
                if (a) break;
                try {
                    a = await this.searchInfo(t);
                } catch (r) {
                    console.error("该名称查询失败,尝试其它名称");
                }
                if (a) break;
            }
            a && e.forEach((e => {
                storageManager.setItem(storageManager.actress_prefix_key + e, a, g);
            }));
            let i = '<div style="font-size: 17px; font-weight: normal; margin-top: 5px;">无此相关演员信息</div>';
            a && (i = `\n                <a href="${a.url}" target="_blank">\n                    <div style="font-size: 17px; font-weight: normal; margin-top: 5px;">\n                        <div style="display: flex; margin-bottom: 10px;">\n                            <span style="width: 300px;">出生日期: ${a.birthday}</span>\n                            <span style="width: 200px;">年龄: ${a.age}</span>\n                            <span style="width: 200px;">身高: ${a.height}</span>\n                        </div>\n                        <div style="display: flex; margin-bottom: 10px;">\n                            <span style="width: 300px;">体重: ${a.weight}</span>\n                            <span style="width: 200px;">三围: ${a.threeSizeText}</span>\n                            <span style="width: 200px;">罩杯: ${a.braSize}</span>\n                        </div>\n                    </div>\n                </a>\n            `);
            t.parent().append(i);
        }
        async searchInfo(e) {
            "三上悠亞" === e && (e = "三上悠亜");
            let t = this.apiUrl + e;
            const n = await gmHttp.get(t), a = new DOMParser, i = $(a.parseFromString(n, "text/html"));
            let r = i.find('tr:has(a[title="誕生日"]) td').text().trim(), o = i.find("th:contains('現年齢')").parent().find("td").text().trim() ? parseInt(i.find("th:contains('現年齢')").parent().find("td").text().trim()) + "岁" : "", s = i.find('tr:has(a[title="身長"]) td').text().trim().split(" ")[0] + "cm", l = i.find('tr:has(a[title="体重"]) td').text().trim().split("/")[1].trim();
            "― kg" === l && (l = "");
            return {
                birthday: r,
                age: o,
                height: s,
                weight: l,
                threeSizeText: i.find('a[title="スリーサイズ"]').closest("tr").find("td").text().replace("cm", "").trim(),
                braSize: i.find('th:contains("ブラサイズ")').next("td").contents().first().text().trim(),
                url: t
            };
        }
    }
    class AliyunPanPlugin extends BasePlugin {
        handle() {
            $("body").append('<a class="a-success" id="refresh-token-btn" style="position:fixed; right: 0; top:50%;z-index:99999">获取refresh_token</a>');
            $("#refresh-token-btn").on("click", (e => {
                let t = localStorage.getItem("token");
                if (!t) {
                    alert("请先登录!");
                    return;
                }
                let n = JSON.parse(t).refresh_token;
                navigator.clipboard.writeText(n).then((() => {
                    alert("已复制到剪切板 如失败, 请手动复制: " + n);
                })).catch((e => {
                    console.error("Failed to copy refresh token: ", e);
                }));
            }));
        }
    }
    class HitShowPlugin extends BasePlugin {
        constructor() {
            super();
        }
        handle() {
            $('a[href*="rankings/playback"]').on("click", (e => {
                e.preventDefault();
                e.stopPropagation();
                window.location.href = "/?handlePlayback=1&period=daily";
            }));
            this.handlePlayback().then();
        }
        async handlePlayback() {
            if (!window.location.href.includes("handlePlayback=1")) return;
            let e = new URLSearchParams(window.location.search).get("period");
            this.toolBar(e);
            let t = $(".movie-list");
            t.html("");
            let n = loading();
            try {
                const n = await (async (e = "daily", t = "high_score") => {
                    let n = `${b}/v1/rankings/playback?period=${e}&filter_by=${t}`, a = {
                        jdSignature: await v()
                    };
                    return (await http.get(n, null, a)).data.movies;
                })(e);
                let a = this.markDataListHtml(n);
                t.html(a);
                window.refresh();
                this.loadScore(n);
            } finally {
                n.close();
            }
        }
        toolBar(e) {
            $(".pagination").remove();
            $(".main-tabs ul li").removeClass("is-active");
            $(".main-tabs ul li:first").addClass("is-active");
            let t = `\n            <div class="button-group" style="margin-top:18px">\n                <div class="buttons has-addons" id="conditionBox">\n                    <a style="padding:18px 18px !important;" class="button is-small ${"daily" === e ? "is-info" : ""}" href="/?handlePlayback=1&period=daily">日榜</a>\n                    <a style="padding:18px 18px !important;" class="button is-small ${"weekly" === e ? "is-info" : ""}" href="/?handlePlayback=1&period=weekly">周榜</a>\n                    <a style="padding:18px 18px !important;" class="button is-small ${"monthly" === e ? "is-info" : ""}" href="/?handlePlayback=1&period=monthly">月榜</a>\n                </div>\n            </div>\n        `;
            $(".toolbar").html(t);
        }
        getStarRating(e) {
            let t = "";
            const n = Math.floor(e);
            for (let a = 0; a < n; a++) t += '<i class="icon-star"></i>';
            for (let a = 0; a < 5 - n; a++) t += '<i class="icon-star gray"></i>';
            return t;
        }
        loadScore(e) {
            if (0 === e.length) return;
            (async () => {
                const t = [];
                for (const a of e) try {
                    const e = a.id;
                    if ($(`#${e}`).is(":hidden")) continue;
                    const t = await storageManager.getItem(storageManager.score_prefix_key + e);
                    if (t) {
                        this.appendScoreHtml(e, t);
                        continue;
                    }
                    for (;!document.hasFocus(); ) await new Promise((e => setTimeout(e, 500)));
                    const n = await x(e);
                    let i = n.score, r = n.watchedCount, o = `\n                        <span class="value">\n                            <span class="score-stars">${this.getStarRating(i)}</span> \n                            &nbsp; ${i}分,由${r}人評價\n                        </span>\n                    `;
                    this.appendScoreHtml(e, o);
                    await storageManager.setItem(storageManager.score_prefix_key + e, o, 6048e5);
                    await new Promise((e => setTimeout(e, 1e3)));
                } catch (n) {
                    t.push({
                        carNum: a.number,
                        error: n.message,
                        stack: n.stack
                    });
                    console.error(`🚨 解析评分数据失败 | 编号: ${a.number}\n`, `错误详情: ${n.message}\n`, n.stack ? `调用栈:\n${n.stack}` : "");
                }
                if (t.length > 0) {
                    show.error("解析评分数据失败, 个数:", t.length);
                    console.table(t);
                }
            })();
        }
        appendScoreHtml(e, t) {
            let n = $(`#score_${e}`);
            "" === n.html().trim() && n.slideUp(0, (function() {
                $(this).html(t).slideDown(500);
            }));
        }
        markDataListHtml(e) {
            let t = "";
            e.forEach((e => {
                t += `\n                <div class="item" id="${e.id}">\n                    <a href="/v/${e.id}" class="box" title="${e.origin_title}">\n                        <div class="cover ">\n                            <img loading="lazy" src="${e.cover_url.replace("https://tp-iu.cmastd.com/rhe951l4q", "https://c0.jdbstatic.com")}" alt="">\n                        </div>\n                        <div class="video-title"><strong>${e.number}</strong> ${e.origin_title}</div>\n                        <div class="score" id="score_${e.id}">\n                        </div>\n                        <div class="meta">\n                            ${e.release_date}\n                        </div>\n                        <div class="tags has-addons">\n                           ${e.has_cnsub ? '<span class="tag is-warning">含中字磁鏈</span>' : e.magnets_count > 0 ? '<span class="tag is-success">含磁鏈</span>' : '<span class="tag is-info">无磁鏈</span>'}\n                           ${e.new_magnets ? '<span class="tag is-info">今日新種</span>' : ""}\n                        </div>\n                    </a>\n                </div>\n            `;
            }));
            return t;
        }
    }
    class TOP250Plugin extends BasePlugin {
        constructor() {
            super();
            __publicField(this, "has_cnsub", "");
            __publicField(this, "movies", []);
        }
        handle() {
            $('.main-tabs ul li:contains("猜你喜歡")').html('<a href="/rankings/top"><span>Top250</span></a>');
            $('a[href*="rankings/top"]').on("click", (e => {
                e.preventDefault();
                e.stopPropagation();
                const t = $(e.target), n = (t.is("a") ? t : t.closest("a")).attr("href");
                let a = n.includes("?") ? n.split("?")[1] : n;
                const i = new URLSearchParams(a);
                this.checkLogin(e, i);
            }));
            this.handleTop().then();
        }
        async handleTop() {
            if (!window.location.href.includes("handleTop=1")) return;
            const e = new URLSearchParams(window.location.search);
            let t = e.get("type") || "all", n = e.get("type_value") || "";
            this.has_cnsub = e.get("has_cnsub") || "";
            let a = e.get("page") || 1;
            this.toolBar(t, n, a);
            let i = $(".movie-list");
            i.html("");
            let r = loading();
            try {
                const e = await (async (e = "all", t = "", n = 1, a = 40) => {
                    let i = `${b}/v1/movies/top?start_rank=1&type=${e}&type_value=${t}&ignore_watched=false&page=${n}&limit=${a}`, r = {
                        "user-agent": "Dart/3.5 (dart:io)",
                        "accept-language": "zh-TW",
                        host: "jdforrepam.com",
                        authorization: "Bearer " + await storageManager.getItem("appAuthorization"),
                        jdsignature: await v()
                    };
                    return await gmHttp.get(i, null, r);
                })(t, n, a, 50);
                let r = e.success, o = e.message, s = e.action;
                if (1 === r) {
                    let t = e.data.movies;
                    if (0 === t.length) {
                        show.error("无数据");
                        return;
                    }
                    this.movies = t;
                    const n = this.getBean("hitShowPlugin");
                    let a = n.markDataListHtml(t);
                    i.html(a);
                    window.refresh();
                    if ("1" === this.has_cnsub) {
                        $(".item:contains('含中字磁鏈')").show();
                        $(".item:contains('含磁鏈')").hide();
                    } else if ("0" === this.has_cnsub) {
                        $(".item:contains('含中字磁鏈')").hide();
                        $(".item:contains('含磁鏈')").show();
                    } else {
                        $(".item:contains('含中字磁鏈')").show();
                        $(".item:contains('含磁鏈')").show();
                    }
                    n.loadScore(t);
                } else {
                    console.error(e);
                    i.html(`<h3>${o}</h3>`);
                    show.error(o);
                }
                if ("JWTVerificationError" === s) {
                    await storageManager.removeItem("appAuthorization");
                    await this.checkLogin(null, new URLSearchParams(window.location.search));
                }
            } catch (o) {
                console.error("获取Top数据失败:", o);
                show.error(`获取Top数据失败: ${o ? o.message : o}`);
            } finally {
                r.close();
            }
        }
        toolBar(e, t, n) {
            $(".main-tabs ul li").removeClass("is-active");
            $(".main-tabs ul li:eq(1)").addClass("is-active");
            if ("5" === n.toString()) {
                $("#auto-page").remove();
                $(".pagination-next").remove();
            }
            $(".pagination-ellipsis").closest("li").remove();
            $(".pagination-list li a").each((function() {
                parseInt($(this).text()) > 5 && $(this).closest("li").remove();
            }));
            let a = "";
            for (let r = (new Date).getFullYear(); r >= 2008; r--) a += `\n                <a style="padding:18px 18px !important;" \n                   class="button is-small ${t === r.toString() ? "is-info" : ""}" \n                   href="/?handleTop=1&type=year&type_value=${r}&has_cnsub=${this.has_cnsub}">\n                  ${r}\n                </a>\n            `;
            let i = `\n            <div class="button-group">\n                <div class="buttons has-addons" id="conditionBox" style="margin-bottom: 0!important;">\n                    <a style="padding:18px 18px !important;" class="button is-small ${"all" === e ? "is-info" : ""}" href="/?handleTop=1&type=all&type_value=&has_cnsub=${this.has_cnsub}">全部</a>\n                    <a style="padding:18px 18px !important;" class="button is-small ${"0" === t ? "is-info" : ""}" href="/?handleTop=1&type=video_type&type_value=0&has_cnsub=${this.has_cnsub}">有码</a>\n                    <a style="padding:18px 18px !important;" class="button is-small ${"1" === t ? "is-info" : ""}" href="/?handleTop=1&type=video_type&type_value=1&has_cnsub=${this.has_cnsub}">无码</a>\n                    <a style="padding:18px 18px !important;" class="button is-small ${"2" === t ? "is-info" : ""}" href="/?handleTop=1&type=video_type&type_value=2&has_cnsub=${this.has_cnsub}">欧美</a>\n                    <a style="padding:18px 18px !important;" class="button is-small ${"3" === t ? "is-info" : ""}" href="/?handleTop=1&type=video_type&type_value=3&has_cnsub=${this.has_cnsub}">Fc2</a>\n                    \n                    <a style="padding:18px 18px !important;margin-left: 50px" class="button is-small ${"1" === this.has_cnsub ? "is-info" : ""}" data-cnsub-value="1">含中字磁鏈</a>\n                    <a style="padding:18px 18px !important;" class="button is-small ${"0" === this.has_cnsub ? "is-info" : ""}" data-cnsub-value="0">无字幕</a>\n                    <a style="padding:18px 18px !important;" class="button is-small" data-cnsub-value="">重置</a>\n                </div>\n                \n                <div class="buttons has-addons" id="conditionBox">\n                    ${a}\n                </div>\n            </div>\n        `;
            $(".toolbar").html(i);
            $("a[data-cnsub-value]").on("click", (e => {
                const t = $(e.currentTarget).data("cnsub-value");
                this.has_cnsub = t.toString();
                $("a[data-cnsub-value]").removeClass("is-info");
                $(e.currentTarget).addClass("is-info");
                $(".toolbar a.button").not("[data-cnsub-value]").each(((e, n) => {
                    const a = $(n), i = new URL(a.attr("href"), window.location.origin);
                    i.searchParams.set("has_cnsub", t);
                    a.attr("href", i.toString());
                }));
                const n = new URL(window.location.href);
                n.searchParams.set("has_cnsub", t);
                history.pushState({}, "", n.toString());
                if ("1" === this.has_cnsub) {
                    $(".item:contains('含中字磁鏈')").show();
                    $(".item:contains('含磁鏈')").hide();
                } else if ("0" === this.has_cnsub) {
                    $(".item:contains('含中字磁鏈')").hide();
                    $(".item:contains('含磁鏈')").show();
                } else {
                    $(".item:contains('含中字磁鏈')").show();
                    $(".item:contains('含磁鏈')").show();
                }
                this.getBean("hitShowPlugin").loadScore(this.movies);
            }));
        }
        async checkLogin(e, t) {
            if (!(await storageManager.getItem("appAuthorization"))) {
                show.error("未登录手机端接口, 无法查看");
                this.openLoginDialog();
                return;
            }
            let n = "all", a = "", i = t.get("t") || "";
            if (/^y\d+$/.test(i)) {
                n = "year";
                a = i.substring(1);
            } else if ("" !== i) {
                n = "video_type";
                a = i;
            }
            let r = `/?handleTop=1&type=${n}&type_value=${a}`;
            e && (e.ctrlKey || e.metaKey) ? window.open(r, "_blank") : window.location.href = r;
        }
        openLoginDialog() {
            layer.open({
                type: 1,
                title: "JavDB",
                closeBtn: 1,
                area: [ "360px", "auto" ],
                shadeClose: !1,
                content: '\n                <div style="padding: 30px; font-family: \'Helvetica Neue\', Arial, sans-serif;">\n                    <div style="margin-bottom: 25px;">\n                        <input type="text" id="username" name="username" \n                            style="width: 100%; padding: 12px 15px; border: 1px solid #e0e0e0; border-radius: 4px; \n                                   box-sizing: border-box; transition: all 0.3s; font-size: 14px;\n                                   background: #f9f9f9; color: #333;"\n                            placeholder="用户名 | 邮箱"\n                            onfocus="this.style.borderColor=\'#4a8bfc\'; this.style.background=\'#fff\'"\n                            onblur="this.style.borderColor=\'#e0e0e0\'; this.style.background=\'#f9f9f9\'">\n                    </div>\n                    \n                    <div style="margin-bottom: 15px;">\n                        <input type="password" id="password" name="password" \n                            style="width: 100%; padding: 12px 15px; border: 1px solid #e0e0e0; border-radius: 4px; \n                                   box-sizing: border-box; transition: all 0.3s; font-size: 14px;\n                                   background: #f9f9f9; color: #333;"\n                            placeholder="密码"\n                            onfocus="this.style.borderColor=\'#4a8bfc\'; this.style.background=\'#fff\'"\n                            onblur="this.style.borderColor=\'#e0e0e0\'; this.style.background=\'#f9f9f9\'">\n                    </div>\n                    \n                    <button id="loginBtn" \n                            style="width: 100%; padding: 12px; background: #4a8bfc; color: white; \n                                   border: none; border-radius: 4px; font-size: 15px; cursor: pointer;\n                                   transition: background 0.3s;"\n                            onmouseover="this.style.background=\'#3a7be0\'"\n                            onmouseout="this.style.background=\'#4a8bfc\'">\n                        登录\n                    </button>\n                </div>\n            ',
                success: (e, t) => {
                    $("#loginBtn").click((function() {
                        const e = $("#username").val(), n = $("#password").val();
                        if (!e || !n) {
                            show.error("请输入用户名和密码");
                            return;
                        }
                        let a = loading();
                        (async (e, t) => {
                            let n = `${b}//v1/sessions?username=${e}&password=${t}&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`, a = {
                                "user-agent": "Dart/3.5 (dart:io)",
                                "accept-language": "zh-TW",
                                "content-type": "multipart/form-data; boundary=--dio-boundary-2210433284",
                                jdsignature: await v()
                            };
                            return await gmHttp.post(n, null, a);
                        })(e, n).then((async e => {
                            let n = e.success;
                            if (0 === n) show.error(e.message); else {
                                if (1 !== n) {
                                    console.error("登录失败", e);
                                    throw new Error(e.message);
                                }
                                {
                                    let n = e.data.token;
                                    await storageManager.setItem("appAuthorization", n);
                                    await storageManager.setItem("appUser", e.data);
                                    show.ok("登录成功");
                                    layer.close(t);
                                    window.location.href = "/?handleTop=1&period=daily";
                                }
                            }
                        })).catch((e => {
                            console.error("登录异常:", e);
                            show.error(e.message);
                        })).finally((() => {
                            a.close();
                        }));
                    }));
                }
            });
        }
    }
    class NavBarPlugin extends BasePlugin {
        handle() {
            this.margeNav();
            this.hookSearch();
            if (window.location.href.includes("/search?q")) {
                let e = new URLSearchParams(window.location.search).get("q");
                $("#search-keyword").val(e);
            }
        }
        hookSearch() {
            $("#navbar-menu-hero").after('\n            <div class="navbar-menu">\n                <div class="navbar-start" style="display: flex; align-items: center; gap: 5px;">\n                    <select id="search-type" style="padding: 8px 12px; border: 1px solid #555; border-radius: 4px; background-color: #333; color: #eee; font-size: 14px; outline: none;">\n                        <option value="all">影片</option>\n                        <option value="actor">演員</option>\n                        <option value="series">系列</option>\n                        <option value="maker">片商</option>\n                        <option value="director">導演</option>\n                        <option value="code">番號</option>\n                        <option value="list">清單</option>\n                    </select>\n                    <input id="search-keyword" type="text" placeholder="輸入影片番號,演員名等關鍵字進行檢索" style="padding: 8px 12px; border: 1px solid #555; border-radius: 4px; flex-grow: 1; font-size: 14px; background-color: #333; color: #eee; outline: none;">\n                    <a href="/advanced_search?noFold=1" title="進階檢索" style="padding: 6px 12px; background-color: #444; border-radius: 4px; text-decoration: none; color: #ddd; font-size: 14px; border: 1px solid #555;"><span>...</span></a>\n                    <a id="search-img-btn" style="padding: 6px 16px; background-color: #444; color: #fff; border-radius: 4px; text-decoration: none; font-weight: 500; cursor: pointer; border: 1px solid #555;">识图</a>\n                    <a id="search-btn" style="padding: 6px 16px; background-color: #444; color: #fff; border-radius: 4px; text-decoration: none; font-weight: 500; cursor: pointer; border: 1px solid #555;">檢索</a>\n                </div>\n            </div>\n        ');
            $("#search-keyword").on("paste", (e => {
                setTimeout((() => {
                    $("#search-btn").click();
                }), 0);
            })).on("keypress", (e => {
                "Enter" === e.key && setTimeout((() => {
                    $("#search-btn").click();
                }), 0);
            }));
            $("#search-btn").on("click", (e => {
                let t = $("#search-keyword").val(), n = $("#search-type option:selected").val();
                "" !== t && (window.location.href.includes("/search?q") ? window.location.href = "/search?q=" + t + "&f=" + n : window.open("/search?q=" + t + "&f=" + n));
            }));
            $("#search-img-btn").on("click", (() => {
                this.getBean("SearchByImagePlugin").open();
            }));
        }
        margeNav() {
            $('a[href*="/feedbacks/new"]').remove();
            $('a[href*="theporndude.com"]').remove();
            $('a.navbar-link[href="/makers"]').parent().after('\n            <div class="navbar-item has-dropdown is-hoverable">\n                <a class="navbar-link">其它</a>\n                <div class="navbar-dropdown is-boxed">\n                  <a class="navbar-item" href="/feedbacks/new" target="_blank" >反饋</a>\n                  <a class="navbar-item" rel="nofollow noopener" target="_blank" href="https://theporndude.com/zh">ThePornDude</a>\n                </div>\n              </div>\n        ');
        }
    }
    class OtherSitePlugin extends BasePlugin {
        handle() {
            let e = this.getPageInfo().carNum, t = `\n            <div style="margin-top:20px;margin-left: -16px;">\n                <div style="display: flex;gap: 5px">\n                    <a id="javTrailersBtn" class="menu-btn" style="background:linear-gradient(to right, #d7ab91, rgb(255,76,76))"><span>JavTrailers</span></a>\n                    <a href="https://jable.tv/videos/${e}/" target="_blank" class="menu-btn" style="background:linear-gradient(to right, rgb(255,161,0), rgb(0,119,172))"><span>Jable</span></a>\n                    <a href="https://missav.ws/search/${e}" target="_blank" class="menu-btn" style="background:linear-gradient(to right, #d29494, rgb(254,98,142))"><span>MissAv</span></a>\n                    <a href="https://www.av.gl/vod/search.html?wd=${e}" target="_blank" class="menu-btn" style="color:#f40 !important;background:linear-gradient(to bottom, rgb(238,164,238), #fff)"><span>Avgle</span></a>\n                </div>\n            </div>\n        `;
            $(".column-video-cover").append(t);
            $("#javTrailersBtn").on("click", (t => utils.openPage(`https://javtrailers.com/video/${e.toLowerCase().replace("-", "00")}?handle=1`, e, !1, t)));
        }
    }
    class BusDetailPagePlugin extends BasePlugin {
        async initCss() {
            if (!window.isDetailPage) return "";
            $("h4:contains('論壇熱帖')").hide();
            $("h4:contains('同類影片')").hide();
            $("h4:contains('推薦')").hide();
            return window.location.href.includes("hideNav=1") ? "\n                .navbar-default {\n                    display: none !important;\n                }\n                body {\n                    padding-top:0px!important;\n                }\n            " : "";
        }
        async handle() {
            if (window.location.href.includes("/star/")) {
                const e = $(".avatar-box");
                if (e.length > 0) {
                    let t = e.parent();
                    t.css("position", "initial");
                    t.insertBefore(t.parent());
                }
            }
        }
    }
    class DetailPageButtonPlugin extends BasePlugin {
        constructor() {
            super();
            this.answerCount = 1;
        }
        handle() {
            this.bindHotkey();
            window.isDetailPage && this.createMenuBtn();
        }
        createMenuBtn() {
            const e = this.getPageInfo(), t = e.carNum, n = '\n            <div style="margin: 10px auto;">\n                <a id="filterBtn" class="menu-btn" style="background-color:#de3333">\n                    <span>屏蔽(a)</span>\n                </a>\n                <a id="favoriteBtn" class="menu-btn" style="background-color:#25b1dc">\n                    <span>收藏(s)</span>\n                </a>\n                <a id="hasDownBtn" class="menu-btn" style="background-color:#7bc73b">\n                    <span>加入已下载</span>\n                </a>\n                <a id="enable-magnets-filter" class="menu-btn" style="background-color:#c2bd4c">\n                    <span id="magnets-span">关闭磁力过滤</span>\n                </a>\n                \n\n                <a id="search-subtitle-btn" class="menu-btn fr-btn" style="background:linear-gradient(to bottom, #8d5656, rgb(196,159,91))">\n                    <span>字幕 (SubTitleCat)</span>\n                </a>\n                <a id="xunLeiSubtitleBtn" class="menu-btn fr-btn" style="background:linear-gradient(to left, #375f7c, #2196F3)">\n                    <span>字幕 (迅雷)</span>\n                </a>\n            </div>\n        ';
            s && $(".tabs").after(n);
            l && $("#mag-submit-show").before(n);
            $("#favoriteBtn").on("click", (() => this.favoriteOne()));
            $("#filterBtn").on("click", (e => this.filterOne(e)));
            $("#hasDownBtn").on("click", (async () => {
                await storageManager.saveCar(e.carNum, e.url, e.actress, p);
                window.refresh();
                show.ok("操作成功", {
                    duration: 100,
                    callback: () => {
                        utils.closePage();
                    }
                });
            }));
            $("#enable-magnets-filter").on("click", (e => {
                let t = $("#magnets-span");
                const n = this.getBean("HighlightMagnetPlugin");
                if ("关闭磁力过滤" === t.text()) {
                    n.showAll();
                    t.text("开启磁力过滤");
                } else {
                    n.handle();
                    t.text("关闭磁力过滤");
                }
            }));
            $("#search-subtitle-btn").on("click", (e => utils.openPage(`https://subtitlecat.com/index.php?search=${t}`, t, !1, e)));
            $("#xunLeiSubtitleBtn").on("click", (() => this.searchXunLeiSubtitle(t)));
            this.showStatus(t).then();
        }
        async showStatus(e) {
            let t = await storageManager.getCar(e);
            if (t) switch (t.status) {
              case d:
                $("#filterBtn").text("已屏蔽(a)");
                break;

              case c:
                $("#favoriteBtn").text("已收藏(s)");
                break;

              case p:
                $("#hasDownBtn").text("已加入已下载");
            }
        }
        async favoriteOne() {
            let e = this.getPageInfo();
            await storageManager.saveCar(e.carNum, e.url, e.actress, c);
            window.refresh();
            show.ok("操作成功", {
                duration: 100,
                callback: () => {
                    utils.closePage();
                }
            });
        }
        searchXunLeiSubtitle(e) {
            let t = loading();
            gmHttp.get(`https://api-shoulei-ssl.xunlei.com/oracle/subtitle?gcid=&cid=&name=${e}`).then((t => {
                let n = t.data;
                n && 0 !== n.length ? layer.open({
                    type: 1,
                    title: "迅雷字幕",
                    content: '<div id="table-container"></div>',
                    area: [ "50%", "70%" ],
                    success: t => {
                        new TableGenerator({
                            containerId: "table-container",
                            columns: [ {
                                key: "name",
                                title: "文件名"
                            }, {
                                key: "ext",
                                title: "类型"
                            }, {
                                key: "extra_name",
                                title: "来源"
                            } ],
                            data: n,
                            buttons: [ {
                                text: "下载",
                                class: "a-primary",
                                onClick: t => {
                                    gmHttp.get(t.url).then((n => {
                                        utils.download(n, e + "." + t.ext);
                                    }));
                                }
                            } ]
                        });
                    }
                }) : show.error("迅雷中找不到相关字幕!");
            })).finally((() => {
                t.close();
            }));
        }
        async filterOne(e, t) {
            e && e.preventDefault();
            let n = this.getPageInfo();
            if (t) {
                await storageManager.saveCar(n.carNum, n.url, n.actress, d);
                window.refresh();
                show.ok("操作成功", {
                    duration: 100,
                    callback: () => {
                        utils.closePage();
                    }
                });
            } else utils.q(e, `是否屏蔽${n.carNum}?`, (async () => {
                await storageManager.saveCar(n.carNum, n.url, n.actress, d);
                window.refresh();
                show.ok("操作成功", {
                    duration: 100,
                    callback: () => {
                        utils.closePage();
                    }
                });
            }));
        }
        speedVideo() {
            if ($("#preview-video").is(":visible")) {
                const e = document.getElementById("preview-video");
                if (e) {
                    e.muted = !1;
                    e.currentTime += 5;
                }
                return;
            }
            const e = $('iframe[id^="layui-layer-iframe"]');
            if (e.length > 0) {
                e[0].contentWindow.postMessage("speedVideo", "*");
                return;
            }
            let t = $(".preview-video-container");
            if (t.length > 0) {
                t[0].click();
                const e = document.getElementById("preview-video");
                if (e) {
                    e.currentTime += 5;
                    e.muted = !1;
                }
            } else $("#javTrailersBtn").click();
        }
        bindHotkey() {
            const e = {
                a: () => {
                    this.answerCount >= 2 ? this.filterOne(null, !0) : this.filterOne(null);
                    this.answerCount++;
                },
                s: () => this.favoriteOne(null),
                z: () => this.speedVideo()
            }, t = (e, t) => {
                w.registerHotkey(e, (() => {
                    window.isDetailPage ? t() : (e => {
                        const t = $(".layui-layer-content iframe");
                        if (0 === t.length) return !1;
                        t[0].contentWindow.postMessage(e, "*");
                    })(e);
                }));
            };
            window.isDetailPage && window.addEventListener("message", (t => {
                e[t.data] && e[t.data]();
            }));
            Object.entries(e).forEach((([e, n]) => {
                t(e, n);
            }));
        }
    }
    class HistoryPlugin extends BasePlugin {
        constructor() {
            super(...arguments);
            __publicField(this, "dataType", "all");
            __publicField(this, "tableObj", null);
        }
        handle() {
            s && $(".navbar-end").prepend('<div class="navbar-item has-dropdown is-hoverable">\n                    <a id="historyBtn" class="navbar-link nav-btn" style="color: #aade66 !important;padding-right:15px !important;">\n                        历史列表\n                    </a>\n                </div>');
            l && $("#navbar").append('\n                <ul class="nav navbar-nav navbar-right" style="margin-right: 10px">\n                    <li><a id="historyBtn" style="color: #86e114 !important;padding-right:15px !important;" role="button">历史列表</a></li>\n                </ul>\n           ');
            $("#historyBtn").on("click", (e => this.openHistory()));
        }
        openHistory() {
            layer.open({
                type: 1,
                title: "历史列表",
                content: '\n            <div style="margin: 10px">\n                <a class="menu-btn history-btn" data-action="all" style="background-color:#d3c8a5">所有</a>\n                <a class="menu-btn history-btn" data-action="filter" style="background-color:#ec4949">已屏蔽</a>\n                <a class="menu-btn history-btn" data-action="favorite" style="background-color:#50adb9;">已收藏</a>\n                <a class="menu-btn history-btn" data-action="hasDown" style="background-color:#8ebd6e;">已下载</a>\n            </div>\n            <div id="table-container"></div>\n        ',
                area: [ "60%", "80%" ],
                success: async e => {
                    const t = await this.getDataList();
                    this.loadTableData(t);
                    $(".layui-layer-content").on("click", ".history-btn", (async e => {
                        this.dataType = $(e.target).data("action");
                        this.reloadTable();
                    }));
                },
                end: async () => window.refresh()
            });
        }
        async handleClickDetail(e, t) {
            if (s) if (t.carNum.includes("FC2-")) {
                const e = t.url.split("/"), n = e[e.length - 1].split("#")[0];
                this.getBean("fc2Plugin").openFc2Page(n, t.carNum, t.url);
            } else utils.openPage(t.url, t.carNum, !1, e);
            if (l) {
                let n = t.url;
                if (n.includes("javdb")) if (t.carNum.includes("FC2-")) {
                    const e = n.split("/"), a = e[e.length - 1].split("#")[0];
                    let i = `${await storageManager.getSetting("javDbUrl", "https://javdb.com")}/users/collection_codes?movieId=${a}&carNum=${t.carNum}&url=${n}`;
                    window.open(i, "_blank");
                } else window.open(n, "_blank"); else utils.openPage(t.url, t.carNum, !1, e);
            }
        }
        async reloadTable() {
            const e = await this.getDataList();
            this.tableObj.update(e);
        }
        handleDelete(e, t) {
            utils.q(e, `是否移除${t.carNum}?`, (async () => {
                await storageManager.removeCar(t.carNum);
                this.getBean("listPagePlugin").showCarNumBox(t.carNum);
                this.reloadTable().then();
            }));
        }
        async getDataList() {
            let e = await storageManager.getCarList();
            this.allCount = e.length;
            this.filterCount = 0;
            this.favoriteCount = 0;
            this.hasDownCount = 0;
            e.forEach((e => {
                switch (e.status) {
                  case d:
                    this.filterCount++;
                    break;

                  case c:
                    this.favoriteCount++;
                    break;

                  case p:
                    this.hasDownCount++;
                }
            }));
            $('a[data-action="all"]').text(`所有 (${this.allCount})`);
            $('a[data-action="filter"]').text(`已屏蔽 (${this.filterCount})`);
            $('a[data-action="favorite"]').text(`已收藏 (${this.favoriteCount})`);
            $('a[data-action="hasDown"]').text(`已下载 (${this.hasDownCount})`);
            return "all" === this.dataType ? e : e.filter((e => e.status === this.dataType));
        }
        loadTableData(e) {
            this.tableObj = new TableGenerator({
                containerId: "table-container",
                columns: [ {
                    key: "carNum",
                    title: "番号"
                }, {
                    key: "actress",
                    title: "演员",
                    width: "250px"
                }, {
                    key: "createDate",
                    title: "操作日期",
                    width: "185px"
                }, {
                    key: "url",
                    title: "来源",
                    render: e => {
                        let t = e.url;
                        return t.includes("javdb") ? '<span style="color:#d34f9e">Javdb</span>' : t.includes("javbus") ? '<span style="color:#eaa813">JavBus</span>' : `<span style="color:#050505">${t}</span>`;
                    }
                }, {
                    key: "status",
                    title: "状态",
                    width: "250px",
                    render: e => {
                        let t, n = "";
                        switch (e.status) {
                          case "filter":
                            t = "#ec4949";
                            n = "已屏蔽";
                            break;

                          case "favorite":
                            t = "#50adb9";
                            n = "已收藏";
                            break;

                          case "hasDown":
                            t = "#8ebd6e";
                            n = "已下载";
                        }
                        return `<span style="color:${t}">${n}</span>`;
                    }
                } ],
                data: e,
                buttons: [ {
                    text: "移除",
                    class: "a-danger",
                    onClick: e => {
                        this.handleDelete(event, e);
                    }
                }, {
                    text: "详情页",
                    class: "a-info",
                    onClick: e => {
                        this.handleClickDetail(event, e);
                    }
                } ]
            });
        }
    }
    class ReviewPlugin extends BasePlugin {
        constructor() {
            super(...arguments);
            __publicField(this, "floorIndex", 1);
        }
        async handle() {
            if (window.isDetailPage) {
                if (s) {
                    const e = window.location.href.split("?")[0].split("/"), t = e[e.length - 1].split("#")[0];
                    await this.showReview(t);
                    await this.getBean("RelatedPlugin").showRelated();
                }
                if (l) {
                    let e = this.getPageInfo().carNum;
                    const t = await (async e => {
                        let t = `${b}/v2/search`, n = {
                            "user-agent": "Dart/3.5 (dart:io)",
                            "accept-language": "zh-TW",
                            host: "jdforrepam.com",
                            jdsignature: await v()
                        }, a = {
                            q: e,
                            page: 1,
                            type: "movie",
                            limit: 1,
                            movie_type: "all",
                            from_recent: "false",
                            movie_filter_by: "all",
                            movie_sort_by: "relevance"
                        };
                        return (await gmHttp.get(t, a, n)).data.movies;
                    })(e);
                    let n = null;
                    for (let a = 0; a < t.length; a++) {
                        let i = t[a];
                        if (i.number.toLowerCase() === e.toLowerCase()) {
                            n = i.id;
                            break;
                        }
                    }
                    if (!n) {
                        show.error("解析视频ID失败, 该视频可能在JavDb中不存在, 无法获取评论数据");
                        return;
                    }
                    this.showReview(n, $("#sample-waterfall")).then();
                }
            }
        }
        async showReview(e, t) {
            let n = $("#magnets-content");
            t && (n = t);
            n.append('<div id="reviewsLoading" style="margin-top:15px;background-color:#ffffff;padding:10px;margin-left: -10px;">获取评论中...</div>');
            let a = await storageManager.getSetting("reviewCount", 20), i = null;
            try {
                i = await y(e, 1, a);
            } catch (l) {
                console.error(l);
            }
            $("#reviewsLoading").remove();
            n.append('\n            <div style=" display: flex; align-items: center; margin: 16px 0; color: #666; font-size: 14px; ">\n                <span style=" flex: 1; height: 1px; background: linear-gradient(to right, transparent, #999, transparent); "></span>\n                <span style="padding: 0 10px;">评论区</span>\n                <a id="reviewsFold" style=" margin-left: 8px; color: #1890ff; text-decoration: none; display: flex; align-items: center; ">\n                    <span class="toggle-text">折叠</span>\n                    <span class="toggle-icon" style="margin-left: 4px;">▲</span>\n                </a>\n                <span style=" flex: 1; height: 1px; background: linear-gradient(to right, transparent, #999, transparent); "></span>\n            </div>\n        ');
            $("#reviewsFold").on("click", (() => {
                const e = $("#reviewsFold .toggle-text"), t = $("#reviewsFold .toggle-icon");
                if ("展开" === e.text()) {
                    e.text("折叠");
                    t.text("▲");
                    r.show();
                    o.show();
                } else {
                    e.text("展开");
                    t.text("▼");
                    r.hide();
                    o.hide();
                }
            }));
            n.append('<div id="reviewsContainer"></div>');
            n.append('<div id="reviewsFooter"></div>');
            const r = $("#reviewsContainer"), o = $("#reviewsFooter");
            if (!i) {
                r.append('<div style="margin-top:15px;background-color:#ffffff;padding:10px;margin-left: -10px;">获取评论失败</div>');
                return;
            }
            0 === i.length && r.append('<div style="margin-top:15px;background-color:#ffffff;padding:10px;margin-left: -10px;">无评论</div>');
            const s = await storageManager.getReviewFilterKeywordList();
            this.displayReviews(i, r, s);
            if (i.length === a) {
                o.html('\n                <button id="loadMoreReviews" style="width:100%; background-color: #e1f5fe; border:none; padding:10px; margin-top:10px; cursor:pointer; color:#0277bd; font-weight:bold; border-radius:4px;">\n                    加载更多评论\n                </button>\n                <div id="reviewsEnd" style="display:none; text-align:center; padding:10px; color:#666; margin-top:10px;">已加载全部评论</div>\n            ');
                let t = 1;
                $("#loadMoreReviews").click((async () => {
                    $("#loadMoreReviews").text("加载中...").prop("disabled", !0);
                    t++;
                    const n = await y(e, t, a);
                    this.displayReviews(n, r, s);
                    if (n.length < a) {
                        $("#loadMoreReviews").remove();
                        $("#reviewsEnd").show();
                    } else $("#loadMoreReviews").text("加载更多评论").prop("disabled", !1);
                }));
            } else i.length > 0 && o.html('<div style="text-align:center; padding:10px; color:#666; margin-top:10px;">已加载全部评论</div>');
        }
        displayReviews(e, t, n) {
            if (e.length) {
                e.forEach((e => {
                    let a = !1;
                    for (let t = 0; t < n.length; t++) if (e.content.indexOf(n[t]) > -1) {
                        a = !0;
                        break;
                    }
                    if (a) return;
                    let i = "";
                    for (let t = 0; t < e.score; t++) i += '<i class="icon-star"></i>';
                    let r = e.content.replace(/(https?:\/\/[^\s]+|magnet:\?[^\s"'\u4e00-\u9fa5,。?!()【】]+)/gi, (e => `<a href="${e}" class="a-primary" \n                        style="padding:0; word-break: break-all; white-space: pre-wrap;" target="_blank" rel="noopener noreferrer">${e}</a>\n\x3c!--                        <a class="a-success review-magnet" style="padding:0;margin-left:0">预览</a>--\x3e`)), o = `\n                <div class="item columns is-desktop" style="display:block;margin-top:6px;background-color:#ffffff;padding:10px;margin-left: -10px;word-break: break-word;position:relative;">\n                    <span style="position:absolute;top:5px;right:10px;color:#999;font-size:12px;">#${this.floorIndex++}楼</span>\n                    ${e.username} &nbsp;&nbsp; <span class="score-stars">${i}</span> \n                    <span class="time">${utils.formatDate(e.created_at)}</span> \n                    &nbsp;&nbsp; 点赞:${e.likes_count}\n                    <p class="review-content" style="margin-top: 5px;"> ${r} </p>\n                </div>\n            `;
                    t.append(o);
                }));
                utils.rightClick($(".review-content"), (e => {
                    const t = window.getSelection().toString();
                    if (t) {
                        e.preventDefault();
                        utils.q(e, `是否将 '${t}' 加入评论区关键词?`, (async () => {
                            await storageManager.saveReviewFilterKeyword(t);
                            show.ok("操作成功, 刷新页面后生效");
                        }));
                    }
                }));
            }
        }
    }
    class FilterTitleKeywordPlugin extends BasePlugin {
        handle() {
            if (!window.isDetailPage) return;
            let e, t;
            if (s) {
                e = $("h2");
                t = $(".male").prev();
            }
            l && (e = $("h3"));
            utils.rightClick(e, (e => {
                const t = window.getSelection().toString();
                if (t) {
                    e.preventDefault();
                    let n = {
                        clientX: e.clientX,
                        clientY: e.clientY + 80
                    };
                    utils.q(n, `是否屏蔽标题关键词 ${t}?`, (async () => {
                        await storageManager.saveTitleFilterKeyword(t);
                        window.refresh();
                        utils.closePage();
                    }));
                }
            }));
            t && t.length > 0 && utils.rightClick(t, (e => {
                e.preventDefault();
                let t = $(e.target).text().trim();
                utils.q(e, `是否屏蔽演员${t}?`, (async () => {
                    await storageManager.saveFilterActor(t);
                    window.refresh();
                    const e = this.getBean("detailPageButtonPlugin");
                    await e.filterOne(null, !0);
                }));
            }));
        }
    }
    class ListPageButtonPlugin extends BasePlugin {
        handle() {
            window.isListPage && this.createMenuBtn();
        }
        createMenuBtn() {
            if (s) {
                if (window.location.href.includes("/actors/")) {
                    $(".toolbar .buttons").append('\n                    <a class="menu-btn" id="waitCheckBtn" \n                       style="background-color:#56c938 !important;; margin-left: 40px;margin-bottom: 8px; border-bottom:none !important; border-radius:3px;">\n                      <span>打开待鉴定</span>\n                    </a>\n                    <a class="menu-btn" id="waitDownBtn" \n                       style="background-color:#2caac0 !important;; margin-left: 10px;margin-bottom: 8px; border-bottom:none !important; border-radius:3px;">\n                      <span>打开已收藏</span>\n                    </a>\n                ');
                    $(".toolbar .buttons").append(`\n                <a class="menu-btn" id="sort-toggle-btn" \n                   style="background-color:#8783ab !important; margin-left: 50px;margin-bottom: 8px; border-bottom:none !important; border-radius:3px;">当前排序方式: ${"rateCount" === localStorage.getItem("sortMethod") ? "评价人数" : "date" === localStorage.getItem("sortMethod") ? "时间" : "默认"}</a>\n                `);
                } else {
                    $(".tabs ul").append('\n                    <li class="is-active" id="waitCheckBtn">\n                        <a class="menu-btn" style="background-color:#56c938 !important;margin-left: 20px;border-bottom:none !important;border-radius:3px;">\n                            <span>打开待鉴定</span>\n                        </a>\n                    </li>\n                     <li class="is-active" id="waitDownBtn">\n                        <a class="menu-btn" style="background-color:#2caac0 !important;margin-left: 20px;border-bottom:none !important;border-radius:3px;">\n                            <span>打开已收藏</span>\n                        </a>\n                    </li>\n                ');
                    $(".tabs ul").after(`\n                  <div style="padding:10px">\n                    <a class="menu-btn" id="sort-toggle-btn" \n                       style="background-color:#8783ab !important; margin-left: 20px; border-bottom:none !important; border-radius:3px;">\n                      当前排序方式: ${"rateCount" === localStorage.getItem("sortMethod") ? "评价人数" : "date" === localStorage.getItem("sortMethod") ? "时间" : "默认"}\n                    </a>\n                  </div>\n                `);
                }
                this.sortItems();
            }
            if (l) {
                const e = '\n                <div style="margin-top: 10px">\n                    <a id="waitCheckBtn" class="menu-btn" style="background-color:#56c938 !important;margin-left: 14px;border-bottom:none !important;border-radius:3px;">\n                        <span>打开待鉴定</span>\n                    </a>\n                    <a id="waitDownBtn" class="menu-btn" style="background-color:#2caac0 !important;margin-left: 5px;border-bottom:none !important;border-radius:3px;">\n                        <span>打开已收藏</span>\n                    </a>\n                </div>\n            ';
                $(".masonry").parent().prepend(e);
            }
            $("#waitCheckBtn").on("click", (e => {
                this.openWaitCheck(e).then();
            }));
            $("#waitDownBtn").on("click", (e => {
                this.openFavorite(e).then();
            }));
            $("#sort-toggle-btn").on("click", (e => {
                const t = localStorage.getItem("sortMethod");
                let n;
                n = t && "default" !== t ? "rateCount" === t ? "date" : "default" : "rateCount";
                const a = {
                    default: "默认",
                    rateCount: "评价人数",
                    date: "时间"
                }[n];
                $(e.target).text(`当前排序方式: ${a}`);
                localStorage.setItem("sortMethod", n);
                this.sortItems();
            }));
        }
        sortItems() {
            const e = localStorage.getItem("sortMethod");
            if (!e) return;
            $(".movie-list .item").each((function(e) {
                $(this).attr("data-original-index") || $(this).attr("data-original-index", e);
            }));
            const t = $(".movie-list"), n = $(".item", t);
            if ("default" === e) n.sort((function(e, t) {
                return $(e).data("original-index") - $(t).data("original-index");
            })).appendTo(t); else {
                const a = n.get();
                a.sort((function(t, n) {
                    if ("rateCount" === e) {
                        const e = e => {
                            const t = $(e).find(".score .value").text().match(/由(\d+)人/);
                            return t ? parseFloat(t[1]) : 0;
                        };
                        return e(n) - e(t);
                    }
                    {
                        const e = e => {
                            const t = $(e).find(".meta").text().trim();
                            return new Date(t);
                        };
                        return e(n) - e(t);
                    }
                }));
                t.empty().append(a);
            }
        }
        async openWaitCheck() {
            let e;
            s && (e = o);
            l && (e = r);
            const t = await storageManager.getSetting("waitCheckCount", 5), n = [ "已收藏", "已屏蔽", "已下载" ];
            let a = 0;
            $(`${e.itemSelector}:visible`).each(((e, i) => {
                if (a >= t) return !1;
                const r = $(i);
                if (!n.some((e => r.find(`span:contains('${e}')`).length > 0))) {
                    const e = r.find("a");
                    if (e.length) {
                        let t = e.attr("href");
                        if (t) {
                            t += t.includes("?") ? "&autoPlay=1" : "?autoPlay=1";
                            window.open(t);
                            a++;
                        }
                    }
                }
            }));
            0 === a && show.info("没有需鉴定的视频");
        }
        async openFavorite() {
            let e = await storageManager.getSetting("waitCheckCount", 5);
            const t = (await storageManager.getCarList()).filter((e => e.status === c));
            for (let n = 0; n < e; n++) {
                if (n >= t.length) return;
                let e = t[n], a = e.carNum, i = e.url;
                if (a.includes("FC2-")) {
                    const t = e.url.split("/"), n = t[t.length - 1].split("#")[0];
                    let r = await storageManager.getSetting("javDbUrl", "https://javdb.com");
                    window.open(`${r}/users/collection_codes?movieId=${n}&carNum=${a}&url=${i}`);
                } else window.open(i);
            }
        }
    }
    class ListPagePlugin extends BasePlugin {
        async handle() {
            this.cleanRepeatId();
            this.replaceHdImg();
            await this.doFilter();
            this.bindClick().then();
            new BroadcastChannel("channel-refresh").addEventListener("message", (async e => {
                "refresh" === e.data.type && await this.doFilter();
            }));
            this.checkDom();
        }
        checkDom() {
            if (!window.isListPage) return;
            const e = this.getSelector(), t = document.querySelector(e.boxSelector), n = new MutationObserver((e => {
                utils.log("检查");
                n.disconnect();
                try {
                    this.replaceHdImg();
                    this.doFilter().then();
                    this.getBean("ListPageButtonPlugin").sortItems();
                } finally {
                    n.observe(t, a);
                }
            })), a = {
                childList: !0,
                subtree: !1
            };
            n.observe(t, a);
        }
        cleanRepeatId() {
            if (!l) return;
            $("#waterfall_h").removeAttr("id").attr("id", "no-page");
            const e = $('[id="waterfall"]');
            0 !== e.length && e.each((function() {
                const e = $(this);
                if (!e.hasClass("masonry")) {
                    e.children().insertAfter(e);
                    e.remove();
                }
            }));
        }
        async doFilter() {
            if (!window.isListPage) return;
            let e = $(this.getSelector().itemSelector).toArray();
            await this.filterMovieList(e);
            await this.getBean("autoPagePlugin").handlePaging();
        }
        async filterMovieList(e) {
            const t = await storageManager.getCarList(), n = await storageManager.getTitleFilterKeyword(), a = t.filter((e => e.status === d)).map((e => e.carNum)), i = t.filter((e => e.status === c)).map((e => e.carNum)), r = t.filter((e => e.status === p)).map((e => e.carNum));
            let o = await storageManager.getSetting("hideFilterItem", "yes"), g = window.location.href;
            (g.includes("search?q") || g.includes("/search/") || g.includes("/users/")) && (o = "no");
            e.forEach((e => {
                let t = $(e);
                const {carNum: c, aHref: d, title: p} = this.findCarNumAndHref(t), g = `${c}-hide`, h = `${c}-keywordHide`, u = `${c}-tag`;
                if ("no" === o && t.attr("data-hide") === g) {
                    t.show();
                    t.removeAttr("data-hide");
                }
                if (n.some((e => p.includes(e) || c.includes(e))) && t.attr("data-keyword-hide") !== h) {
                    t.hide();
                    t.attr("data-keyword-hide", h);
                    return;
                }
                if (a.includes(c) && "yes" === o && t.attr("data-hide") !== g) {
                    t.hide();
                    t.attr("data-hide", g);
                    return;
                }
                if (r.includes(c) && "yes" === o && t.attr("data-hide") !== g) {
                    t.hide();
                    t.attr("data-hide", g);
                    return;
                }
                let m = "", f = "";
                if (a.includes(c)) {
                    m = "已屏蔽";
                    f = "#d95427";
                } else if (i.includes(c)) {
                    m = "已收藏";
                    f = "#2caac0";
                } else if (r.includes(c)) {
                    m = "已下载";
                    f = "#58c433";
                }
                if (m && t.attr("data-tag") !== u) {
                    s && t.find(".tags").append(`\n                    <span class="tag is-success" \n                        style="margin-right: 5px; border-radius:10px; position:absolute; right: 0; top:5px;z-index:10;background-color: ${f} !important;">\n                        ${m}\n                    </span>`);
                    if (l) {
                        let e = `<a class="a-primary" style="margin-right: 5px; padding: 0 5px;color: #fff; border-radius:10px; position:absolute; right: 0; top:5px;z-index:10;background-color: ${f} !important;"><span>${m}</span></a>`;
                        t.find(".item-tag").append(e);
                    }
                    t.attr("data-tag", u);
                }
            }));
            $("#waitDownBtn span").text(`打开已收藏 (${i.length})`);
        }
        async bindClick() {
            let e = this.getSelector(), t = await storageManager.getSetting("dialogOpenDetail", "yes");
            $(e.boxSelector).on("click", ".item img", (e => {
                e.preventDefault();
                if ($(e.target).closest("div.meta-buttons").length) return;
                const n = $(e.target).closest(".item"), {carNum: a, aHref: i} = this.findCarNumAndHref(n);
                if (a.includes("FC2-")) {
                    let e = i.split("/").filter(Boolean).pop();
                    this.getBean("fc2Plugin").openFc2Page(e, a, i);
                } else "yes" === t ? utils.openPage(i, a, !1, e) : window.open(i);
            }));
            $(e.boxSelector).on("contextmenu", ".item img", (e => {
                e.preventDefault();
                const t = $(e.target).closest(".item"), {carNum: n, aHref: a} = this.findCarNumAndHref(t);
                utils.q(e, `是否屏蔽番号 ${n}?`, (async () => {
                    await storageManager.saveCar(n, a, "", d);
                    window.refresh();
                    show.ok("操作成功");
                }));
            }));
        }
        findCarNumAndHref(e) {
            let t, n, a = e.find("a").attr("href");
            if (s) {
                t = e.find(".video-title").find("strong").text();
                n = e.find(".video-title").text();
            }
            if (l) {
                t = a.split("/").filter(Boolean).pop();
                n = e.find("img").attr("title");
            }
            return {
                carNum: t,
                aHref: a,
                title: n
            };
        }
        showCarNumBox(e) {
            const t = $(".movie-list .item").toArray().find((t => $(t).find(".video-title strong").text() === e));
            if (t) {
                const n = $(t);
                if (n.attr("data-hide") === `${e}-hide`) {
                    n.show();
                    n.removeAttr("data-hide");
                }
            }
        }
        replaceHdImg(e) {
            e || (e = document.querySelectorAll(this.getSelector().coverImgSelector));
            s && e.forEach((e => {
                e.src = e.src.replace("thumbs", "covers");
            }));
            if (l) {
                const t = /\/(imgs|pics)\/(thumb|thumbs)\//, n = /(\.jpg|\.jpeg|\.png)$/i, a = e => {
                    if (e.src && t.test(e.src) && "true" !== e.dataset.hdReplaced) {
                        e.src = e.src.replace(t, "/$1/cover/").replace(n, "_b$1");
                        e.dataset.hdReplaced = "true";
                        e.loading = "lazy";
                    }
                };
                e.forEach((e => {
                    a(e);
                }));
            }
        }
    }
    class AutoPagePlugin extends BasePlugin {
        constructor() {
            super();
            this.paging = !1;
            this.selector = null;
            s && (this.selector = o);
            l && (this.selector = r);
        }
        async handle() {
            window.isListPage && !this.shouldDisablePaging() && this.bindPageClick().then();
        }
        async bindPageClick() {
            $(".pagination-link, .pagination-next, .pagination-previous, .pagination li a").on("click", (e => {
                e.preventDefault();
                e.stopPropagation();
                let t = $(e.target).attr("href");
                this.parsePage(t).then();
            }));
            0 === $("#auto-page").length && await this.insertPageBtn();
            $("#auto-page").on("click", (async e => {
                e.preventDefault();
                if ("yes" === await storageManager.getItem(storageManager.auto_page_key)) {
                    await storageManager.setItem(storageManager.auto_page_key, "no");
                    $("#auto-page").html("开启自动翻页");
                } else {
                    await storageManager.setItem(storageManager.auto_page_key, "yes");
                    $("#auto-page").html("关闭自动翻页");
                    await this.handlePaging();
                }
            }));
        }
        async insertPageBtn() {
            let e = "yes" === await storageManager.getItem(storageManager.auto_page_key) ? "关闭自动翻页" : "开启自动翻页";
            s && $(".pagination").prepend(`<a style="background-color:#fff; order: 2;padding: calc(.5em - 1px) .75em;" id='auto-page'>${e}</a>`);
            l && $(".pagination").append(`<li><a style="margin-left: 20px;cursor: pointer;" id='auto-page'>${e}</a></li>`);
        }
        async parsePage(e) {
            let t = loading();
            try {
                const t = await http.get(e), n = (new DOMParser).parseFromString(t, "text/html");
                let a = n.querySelectorAll(this.selector.requestDomItemSelector), i = n.querySelectorAll(".pagination");
                const r = this.getBean("listPagePlugin");
                await r.filterMovieList(a);
                let o = n.querySelectorAll(this.selector.coverImgSelector);
                r.replaceHdImg(o);
                let s = $(this.selector.boxSelector);
                s.fadeOut(300, (() => {
                    s.html(a).fadeIn(300, (async () => {}));
                }));
                await this.insertPageBtn();
                $(".pagination").replaceWith(i);
                window.history.pushState({}, "", e);
                if (l) {
                    const t = this.getPageNumberFromUrl(e);
                    document.title = document.title.replace(/第\d+頁/, "第" + t + "頁");
                }
                await utils.smoothScrollToTop();
                await this.bindPageClick();
                await this.handlePaging();
            } finally {
                t.close();
            }
        }
        getPageNumberFromUrl(e) {
            const t = e.match(/\/page\/(\d+)/);
            return t ? parseInt(t[1], 10) : null;
        }
        shouldDisablePaging() {
            return [ "search?q", "handlePlayback=1", "handleTop=1", "/want_watch_videos", "/watched_videos" ].some((e => window.location.href.includes(e)));
        }
        async handlePaging() {
            if (this.shouldDisablePaging()) return;
            if ($("#no-page").length) {
                $("#auto-page").remove();
                return;
            }
            if (0 === $(this.selector.boxSelector).length) return;
            if (!window.isListPage) return;
            if (this.paging) return;
            let e = !0;
            $(`${this.selector.itemSelector}:visible`).each(((t, n) => {
                0 === $(n).find("span:contains('已收藏')").length && 0 === $(n).find("span:contains('已屏蔽')").length && 0 === $(n).find("span:contains('已下载')").length && (e = !1);
            }));
            if (!e) return;
            if ("yes" !== await storageManager.getItem(storageManager.auto_page_key)) return;
            let t = null;
            s && (t = $(".pagination-next"));
            l && (t = $("#next"));
            if (t && 0 !== t.length) {
                this.paging = !0;
                show.info("下一页....", {
                    duration: 500,
                    callback: () => {
                        t[0].click();
                        this.paging = !1;
                    }
                });
            }
        }
    }
    class HighlightMagnetPlugin extends BasePlugin {
        handle() {
            this.handleDb();
            this.handleBus();
        }
        handleDb() {
            if (!s || !isDetailPage) return;
            let e = $("#magnets-content .name").toArray(), t = !1;
            e.forEach((e => {
                let n = $(e), a = n.text().toLowerCase();
                a.indexOf("4k") > -1 && n.css("color", "#f40");
                (a.indexOf("-c") > -1 || a.indexOf("-uc") > -1 || a.indexOf("4k") > -1) && (t = !0);
            }));
            t ? e.forEach((e => {
                let t = $(e), n = t.text().toLowerCase();
                n.indexOf("-c") > -1 || n.indexOf("-uc") > -1 || n.indexOf("4k") > -1 || t.parent().parent().parent().hide();
            })) : $("#enable-magnets-filter").addClass("do-hide");
        }
        handleBus() {
            l && isDetailPage && utils.loopDetector((() => $("#magnet-table td a").length > 0), (() => {
                let e = $("#magnet-table tr td:first-child a:first-child").toArray(), t = !1;
                e.forEach((e => {
                    let n = $(e), a = n.text().toLowerCase();
                    a.indexOf("4k") > -1 && n.css("color", "#f40");
                    (a.indexOf("-c") > -1 || a.indexOf("-uc") > -1 || a.indexOf("4k") > -1) && (t = !0);
                }));
                t ? e.forEach((e => {
                    let t = $(e), n = t.text().toLowerCase();
                    n.indexOf("-c") > -1 || n.indexOf("-uc") > -1 || n.indexOf("4k") > -1 || t.parent().parent().hide();
                })) : $("#enable-magnets-filter").addClass("do-hide");
            }));
        }
        showAll() {
            if (s) {
                $("#magnets-content .item").toArray().forEach((e => $(e).show()));
            }
            l && $("#magnet-table tr").toArray().forEach((e => $(e).show()));
        }
    }
    class AliyunApi {
        constructor(e) {
            this.baseApiUrl = "https://api.aliyundrive.com";
            this.refresh_token = e;
            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 e = this.baseApiUrl + "/v2/account/token", t = {
                refresh_token: this.refresh_token,
                grant_type: "refresh_token"
            };
            try {
                return "Bearer " + (await http.post(e, t)).access_token;
            } catch (n) {
                throw n.message.includes("is not valid") ? new Error("refresh_token无效, 请重新填写并保存") : n;
            }
        }
        async getUserInfo() {
            const e = await this.getHeaders();
            let t = this.baseApiUrl + "/v2/user/get";
            return await http.post(t, {}, e);
        }
        async deleteFile(e, t = null) {
            if (!e) throw new Error("未传入file_id");
            t || (t = await this.getDefaultDriveId());
            let n = {
                file_id: e,
                drive_id: t
            }, a = this.baseApiUrl + "/v2/recyclebin/trash";
            const i = await this.getHeaders();
            await gmHttp.post(a, n, i);
            return {};
        }
        async createFolder(e, t = null, n = "root") {
            t || (t = await this.getDefaultDriveId());
            let a = this.baseApiUrl + "/adrive/v2/file/createWithFolders", i = {
                name: e,
                type: "folder",
                parent_file_id: n,
                check_name_mode: "auto_rename",
                content_hash_name: "sha1",
                drive_id: t
            };
            const r = await this.getHeaders(), o = await gmHttp.post(a, i, r);
            return JSON.parse(o);
        }
        async getFileList(e = "root", t = null) {
            t || (t = await this.getDefaultDriveId());
            let n = this.baseApiUrl + "/adrive/v3/file/list";
            const a = {
                drive_id: t,
                parent_file_id: e,
                limit: 200,
                all: !1,
                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"
            }, i = await this.getHeaders();
            return (await gmHttp.post(n, a, i)).items;
        }
        async uploadFile(e, t, n, a = null) {
            let i = this.baseApiUrl + "/adrive/v2/file/createWithFolders";
            a || (a = await this.getDefaultDriveId());
            let r = {
                drive_id: a,
                part_info_list: [ {
                    part_number: 1
                } ],
                parent_file_id: e,
                name: t,
                type: "file",
                check_name_mode: "auto_rename"
            };
            const o = await this.getHeaders(), s = await gmHttp.post(i, r, o), l = s.upload_id, c = s.file_id, d = s.part_info_list[0].upload_url;
            console.log("创建完成: ", s);
            await this._doUpload(d, n);
            const p = await gmHttp.post("https://api.aliyundrive.com/v2/file/complete", r = {
                drive_id: "745851",
                file_id: c,
                upload_id: l
            }, o);
            console.log("标记完成:", p);
        }
        _doUpload(e, t) {
            return new Promise(((n, a) => {
                $.ajax({
                    type: "PUT",
                    url: e,
                    data: t,
                    contentType: " ",
                    processData: !1,
                    success: (e, t, i) => {
                        if (200 === i.status) {
                            console.log("上传成功:", e);
                            n({});
                        } else a(i);
                    },
                    error: e => {
                        console.error("上传失败", e.responseText);
                        a(e);
                    }
                });
            }));
        }
        async getDownloadUrl(e, t = null) {
            t || (t = await this.getDefaultDriveId());
            let n = this.baseApiUrl + "/v2/file/get_download_url";
            const a = await this.getHeaders();
            let i = {
                file_id: e,
                drive_id: t
            };
            return (await gmHttp.post(n, i, a)).url;
        }
        async _createBackupFolder(e) {
            const t = await this.getFileList();
            let n = null;
            for (let a = 0; a < t.length; a++) {
                let i = t[a];
                if (i.name === e) {
                    n = i;
                    break;
                }
            }
            if (!n) {
                console.log("不存在目录, 进行创建");
                n = await this.createFolder(e);
            }
            this.backupFolderId = n.file_id;
        }
        async backup(e, t, n) {
            if (this.backupFolderId) await this.uploadFile(this.backupFolderId, t, n); else {
                await this._createBackupFolder(e);
                await this.uploadFile(this.backupFolderId, t, n);
            }
        }
        async getBackupList(e) {
            let t = null;
            if (this.backupFolderId) t = await this.getFileList(this.backupFolderId); else {
                await this._createBackupFolder(e);
                t = await this.getFileList(this.backupFolderId);
            }
            const n = [];
            t.forEach((e => {
                n.push({
                    name: e.name,
                    fileId: e.file_id,
                    createTime: e.created_at,
                    size: e.size
                });
            }));
            return n;
        }
    }
    class WebDavApi {
        constructor(e, t, n) {
            this.davUrl = e.endsWith("/") ? e : e + "/";
            this.username = t;
            this.password = n;
            this.folderName = null;
        }
        _getAuthHeaders() {
            return {
                Authorization: `Basic ${btoa(`${this.username}:${this.password}`)}`,
                Depth: "1"
            };
        }
        _sendRequest(e, t, n = {}, a) {
            return new Promise(((i, r) => {
                const o = this.davUrl + t, s = {
                    ...this._getAuthHeaders(),
                    ...n
                };
                GM_xmlhttpRequest({
                    method: e,
                    url: o,
                    headers: s,
                    data: a,
                    onload: e => {
                        e.status >= 200 && e.status < 300 ? i(e) : r(new Error(`Request failed with status ${e.status}: ${e.statusText}`));
                    },
                    onerror: e => {
                        console.error("请求WebDav发生错误:", e);
                        r(new Error("请求WebDav失败, 请检查服务是否启动, 凭证是否正确"));
                    }
                });
            }));
        }
        async backup(e, t, n) {
            await this._sendRequest("MKCOL", e);
            const a = e + "/" + t;
            await this._sendRequest("PUT", a, {
                "Content-Type": "text/plain"
            }, n);
        }
        async getFileList(e) {
            var t, n;
            const a = (await this._sendRequest("PROPFIND", e, {
                "Content-Type": "application/xml"
            }, '\n                <?xml version="1.0"?>\n                <d:propfind xmlns:d="DAV:">\n                    <d:prop>\n                        <d:displayname />\n                        <d:getcontentlength />\n                        <d:creationdate />\n                        <d:iscollection />\n                    </d:prop>\n                </d:propfind>\n            ')).responseText, i = (new DOMParser).parseFromString(a, "text/xml").getElementsByTagNameNS("DAV:", "response"), r = [];
            for (let o = 0; o < i.length; o++) {
                if (0 === o) continue;
                if ("1" === i[o].getElementsByTagNameNS("DAV:", "iscollection")[0].textContent) continue;
                const e = i[o].getElementsByTagNameNS("DAV:", "displayname")[0].textContent, a = (null == (t = i[o].getElementsByTagNameNS("DAV:", "getcontentlength")[0]) ? void 0 : t.textContent) || "0", s = (null == (n = i[o].getElementsByTagNameNS("DAV:", "creationdate")[0]) ? void 0 : n.textContent) || "";
                r.push({
                    fileId: e,
                    name: e,
                    size: a,
                    createTime: s
                });
            }
            r.reverse();
            return r;
        }
        async deleteFile(e) {
            let t = this.folderName + "/" + encodeURI(e);
            await this._sendRequest("DELETE", t, {
                "Cache-Control": "no-cache"
            });
        }
        async getBackupList(e) {
            this.folderName = e;
            await this._sendRequest("MKCOL", e);
            return this.getFileList(e);
        }
        async getFileContent(e) {
            let t = this.folderName + "/" + e;
            return (await this._sendRequest("GET", t, {
                Accept: "application/octet-stream"
            })).responseText;
        }
    }
    class SettingPlugin extends BasePlugin {
        constructor() {
            super(...arguments);
            __privateAdd(this, a);
            __publicField(this, "folderName", "JSH-数据备份");
        }
        async initCss() {
            let e = await storageManager.getSetting("containerWidth", "100"), t = await storageManager.getSetting("containerColumns", 5), n = `\n            section .container{\n                max-width: 1000px !important;\n                min-width: ${e}%;\n            }\n            .movie-list{\n                grid-template-columns: repeat(${t}, minmax(0, 1fr));\n            }\n        `;
            l && (n = `\n                .container-fluid .row{\n                    max-width: 1000px !important;\n                    min-width: ${e}%;\n                    margin: auto auto;\n                }\n                \n                .masonry {\n                    grid-template-columns: repeat(${t}, minmax(0, 1fr));\n                }\n            `);
            return `\n            <style>\n                ${n}\n                .nav-btn::after {\n                    content:none !important;\n                }\n                \n                .setting-item {\n                    display: flex;\n                    align-items: center;\n                    justify-content: space-between;\n                    margin-bottom: 10px;\n                    padding: 10px;\n                    border: 1px solid #ddd;\n                    border-radius: 5px;\n                    background-color: #f9f9f9;\n                }\n                .setting-label {\n                    min-width: 250px;\n                    font-weight: bold;\n                    margin-right: 10px;\n                }\n                .form-content{\n                    max-width: 150px;\n                    min-width: 150px;\n                }\n                .form-content * {\n                    width: 100%;\n                    padding: 5px;\n                    margin-right: 10px;\n                    min-width: 150px;\n                    text-align: center;\n                }\n                .keyword-label {\n                    display: inline-flex;\n                    align-items: center;\n                    padding: 4px 8px;\n                    border-radius: 4px;\n                    color: white;\n                    font-size: 14px;\n                    position: relative;\n                    margin-left: 8px;\n                    margin-bottom: 2px;\n                }\n                \n                .keyword-remove {\n                    margin-left: 6px;\n                    cursor: pointer;\n                    font-size: 12px;\n                    line-height: 1;\n                }\n                \n                .keyword-input {\n                    padding: 6px 12px;\n                    border: 1px solid #ccc;\n                    border-radius: 4px;\n                    font-size: 14px;\n                    float:right;\n                }\n                \n                .add-tag-btn {\n                    padding: 6px 12px;\n                    background-color: #45d0b6;\n                    color: white;\n                    border: none;\n                    border-radius: 4px;\n                    cursor: pointer;\n                    font-size: 14px;\n                    margin-left: 8px;\n                    float:right;\n                }\n                \n                .add-tag-btn:hover {\n                    background-color: #3fceb7;\n                }\n                #saveBtn {\n                    padding: 8px 20px;\n                    background-color: #4CAF50;\n                    color: white;\n                    border: none;\n                    border-radius: 4px;\n                    cursor: pointer;\n                    font-size: 16px;\n                    margin-top: 10px;\n                }\n                #saveBtn:hover {\n                    background-color: #45a049;\n                }\n            </style\n        `;
        }
        handle() {
            s && $(".navbar-end").prepend('<div class="navbar-item has-dropdown is-hoverable">\n                    <a id="setting-btn" class="navbar-link nav-btn" style="color: #ff8400 !important;padding-right:15px !important;">\n                        设置\n                    </a>\n                </div>');
            l ? $("#navbar").append('\n                <ul class="nav navbar-nav navbar-right">\n                    <li><a id="setting-btn" style="color: #ff8400 !important;padding-right:15px !important;" role="button">设置</a></li>\n                </ul>\n           ') : $("#pt").append('<div class="z" style="float: right">\n                    <a id="setting-btn" class="a-primary" style="padding: 0px 16px;">\n                        设置\n                    </a>\n                </div>');
            $("#setting-btn").on("click", (() => {
                layer.open({
                    type: 1,
                    title: "设置",
                    content: '\n            <div style=" display: flex; flex-direction: column; height: 100%; ">\n                <div style="margin: 20px">\n                  <a id="importBtn" class="menu-btn" style="background-color:#d25a88"><span>导入数据</span></a>\n                  <a id="exportBtn" class="menu-btn" style="background-color:#85d0a3"><span>导出数据</span></a>\n                  <a id="syncDataBtn" class="menu-btn" style="background-color:#387ca9"><span>同步数据</span></a>\n                  <a id="getRefreshTokenBtn" class="menu-btn fr-btn" style="background-color:#c4a35e"><span>获取refresh_token</span></a>\n\n                </div>\n                <div style=" flex: 1; overflow-y: auto; margin: 0 20px; padding-bottom: 20px; ">\n                    <div class="setting-item">\n                        <span class="setting-label">阿里云盘备份</span>\n                        <div>\n                            <a id="backupBtn" class="menu-btn" style="background-color:#5d87c2"><span>备份数据</span></a>\n                            <a id="backupListBtn" class="menu-btn" style="background-color:#48c554"><span>查看备份</span></a>\n                        </div>\n                    </div>\n                    \n                    <div class="setting-item">\n                        <span class="setting-label">refresh_token:</span>\n                        <div class="form-content">\n                            <input id="refresh_token" >\n                        </div>\n                    </div>\n                    \n                    <hr style="border: 0; height: 2px; margin:20px 0;background-image: linear-gradient(to right, rgba(0,0,0,0), rgba(0,0,0,0.75), rgba(0,0,0,0));"/>\n                    \n                    <div class="setting-item">\n                        <span class="setting-label">WebDav备份</span>\n                        <div>\n                            <a id="webdavBackupBtn" class="menu-btn" style="background-color:#5d87c2"><span>备份数据</span></a>\n                            <a id="webdavBackupListBtn" class="menu-btn" style="background-color:#48c554"><span>查看备份</span></a>\n                        </div>\n                    </div>\n                    \n                    <div class="setting-item">\n                        <span class="setting-label">服务地址:</span>\n                        <div class="form-content">\n                            <input id="webDavUrl" >\n                        </div>\n                    </div>\n                    \n                    <div class="setting-item">\n                        <span class="setting-label">用户名:</span>\n                        <div class="form-content">\n                            <input id="webDavUsername" >\n                        </div>\n                    </div>\n                    \n                    <div class="setting-item">\n                        <span class="setting-label">密码:</span>\n                        <div class="form-content">\n                            <input id="webDavPassword" >\n                        </div>\n                    </div>\n                    \n                    <hr style="border: 0; height: 2px; margin:20px 0;background-image: linear-gradient(to right, rgba(0,0,0,0), rgba(0,0,0,0.75), rgba(0,0,0,0));"/>\n                    \n                    <div class="setting-item">\n                        <span class="setting-label">隐藏已屏蔽内容:</span>\n                        <div class="form-content">\n                            <select id="hideFilterItem">\n                                <option value="yes">是</option>\n                                <option value="no">否</option>\n                            </select>\n                        </div>\n                    </div>\n                    \n                    <div class="setting-item">\n                        <span class="setting-label">评论区条数:</span>\n                        <div class="form-content">\n                            <select id="reviewCount">\n                                <option value="10">10条</option>\n                                <option value="20">20条</option>\n                                <option value="30">30条</option>\n                                <option value="40">40条</option>\n                                <option value="50">50条</option>\n                            </select>\n                        </div>\n                    </div>\n                    \n                    <div class="setting-item">\n                        <span class="setting-label">页面列数:</span>\n                        <div class="form-content" style="position: relative;padding-top: 20px">\n                            <input type="range" id="containerColumns" min="3" max="10" step="1" style="padding:5px 0">\n                            <span id="showContainerColumns" style="position:absolute; top:-10px;"></span>\n                        </div>\n                    </div>\n                    \n                    <div class="setting-item">\n                        <span class="setting-label">页面宽度:</span>\n                        <div class="form-content" style="position: relative;padding-top: 20px">\n                            <input type="range" id="containerWidth" min="0" max="30" step="1" style="padding:5px 0">\n                            <span id="showContainerWidth" style="position:absolute; top:-10px;"></span>\n                        </div>\n                    </div>\n                    \n                    <div class="setting-item">\n                        <span class="setting-label">每次打开待鉴定待下载数量:</span>\n                        <div class="form-content">\n                            <input type="number" id="waitCheckCount" min="1" max="20" style="width: 100%;">\n                        </div>\n                    </div>\n                    \n                    <div class="setting-item">\n                        <span class="setting-label">详情页打开方式:</span>\n                        <div class="form-content">\n                            <select id="dialogOpenDetail">\n                                <option value="yes">弹窗</option>\n                                <option value="no">新窗口</option>\n                            </select>\n                        </div>\n                    </div>          \n                              \n                    <div class="setting-item">\n                        <span class="setting-label">JavDb地址(用于跟Bus同步数据):</span>\n                        <div class="form-content">\n                            <input id="javDbUrl" >\n                        </div>\n                    </div>\n                    \n                    <hr style="border: 0; height: 2px; margin:20px 0;background-image: linear-gradient(to right, rgba(0,0,0,0), rgba(0,0,0,0.75), rgba(0,0,0,0));"/>\n                    \n                    <div class="setting-item">\n                        <span class="setting-label">评论区屏蔽词:</span>\n                        <div id="reviewKeywordContainer" style="max-width: 50%;min-width: 50%;">\n                            <div class="tag-box">\n                            </div>\n                            <div style="margin-top: 10px;">\n                                <button class="add-tag-btn">添加</button>\n                                <input type="text" class="keyword-input" placeholder="添加屏蔽词">\n                            </div>\n                        </div>\n                    </div>\n                    \n                    <div class="setting-item">\n                        <span class="setting-label">视频列表屏蔽词:</span>\n                        <div id="filterKeywordContainer" style="max-width: 50%;min-width: 50%;">\n                            <div class="tag-box">\n                            </div>\n                            <div style="margin-top: 10px;">\n                                <button class="add-tag-btn">添加</button>\n                                <input type="text" class="keyword-input" placeholder="添加屏蔽词">\n                            </div>\n                        </div>\n                    </div>\n                    \n                    <div class="setting-item">\n                        <span class="setting-label">屏蔽男演员:</span>\n                        <div id="filterActorContainer" style="max-width: 50%;min-width: 50%;">\n                            <div class="tag-box">\n                            </div>\n                            <div style="margin-top: 10px;">\n                                <button class="add-tag-btn">添加</button>\n                                <input type="text" class="keyword-input" placeholder="添加屏蔽词">\n                            </div>\n                        </div>\n                    </div>\n                </div>\n                <div style=" flex-shrink: 0; padding: 15px 20px; text-align: right; border-top: 1px solid #eee; background: white; ">   \n                    <button id="saveBtn">保存设置</button>\n                </div>\n            </div>\n        ',
                    area: [ "50%", "80%" ],
                    scrollbar: !1,
                    success: (e, t) => {
                        $(e).find(".layui-layer-content").css("position", "relative");
                        this.loadForm();
                        this.bindClick();
                    }
                });
            }));
        }
        async loadForm() {
            let e = await storageManager.getSetting();
            $("#hideFilterItem").val(e.hideFilterItem || "yes");
            $("#dialogOpenDetail").val(e.dialogOpenDetail || "yes");
            $("#reviewCount").val(e.reviewCount || 20);
            $("#waitCheckCount").val(e.waitCheckCount || 5);
            $("#containerWidth").val((e.containerWidth || 100) - 70);
            $("#showContainerWidth").text(e.containerWidth + "%");
            $("#containerColumns").val(e.containerColumns || 4);
            $("#showContainerColumns").text(e.containerColumns || 4);
            $("#refresh_token").val(e.refresh_token || "");
            $("#javDbUrl").val(e.javDbUrl || "https://javdb.com");
            $("#webDavUrl").val(e.webDavUrl || "");
            $("#webDavUsername").val(e.webDavUsername || "");
            $("#webDavPassword").val(e.webDavPassword || "");
            let t = await storageManager.getReviewFilterKeywordList(), n = await storageManager.getTitleFilterKeyword(), a = await storageManager.getFilterActorList();
            t && t.forEach((e => {
                this.addLabelTag("#reviewKeywordContainer", e);
            }));
            n && n.forEach((e => {
                this.addLabelTag("#filterKeywordContainer", e);
            }));
            a && a.forEach((e => {
                this.addLabelTag("#filterActorContainer", e);
            }));
            [ "#reviewKeywordContainer", "#filterKeywordContainer", "#filterActorContainer" ].forEach((e => {
                $(`${e} .add-tag-btn`).on("click", (t => this.addKeyword(t, e)));
                $(`${e} .keyword-input`).on("keypress", (t => {
                    "Enter" === t.key && this.addKeyword(t, e);
                }));
            }));
        }
        bindClick() {
            $("#importBtn").on("click", (e => this.importData(e)));
            $("#exportBtn").on("click", (e => this.exportData(e)));
            $("#syncDataBtn").on("click", (e => this.syncData(e)));
            $("#backupBtn").on("click", (e => this.backupData(e)));
            $("#backupListBtn").on("click", (e => this.backupListBtn(e)));
            $("#webdavBackupBtn").on("click", (e => this.backupDataByWebDav(e)));
            $("#webdavBackupListBtn").on("click", (e => this.backupListBtnByWebDav(e)));
            $("#getRefreshTokenBtn").on("click", (e => layer.alert("即将跳转阿里云盘, 请登录后, 点击最右侧悬浮按钮获取refresh_token", {
                yes: function(e, t, n) {
                    window.open("https://www.aliyundrive.com/drive/home");
                    layer.close(e);
                }
            })));
            $("#containerWidth").on("input", (e => {
                const t = parseInt($(e.target).val()) + 70 + "%";
                $("#showContainerWidth").text(t);
                if (s) {
                    document.querySelector("section .container").style.minWidth = t;
                }
                if (l) {
                    document.querySelector(".container-fluid .row").style.minWidth = t;
                }
            }));
            $("#containerColumns").on("input", (e => {
                let t = $("#containerColumns").val();
                $("#showContainerColumns").text(t);
                if (s) {
                    document.querySelector(".movie-list").style.gridTemplateColumns = `repeat(${t}, minmax(0, 1fr))`;
                }
                if (l) {
                    document.querySelector(".masonry").style.gridTemplateColumns = `repeat(${t}, minmax(0, 1fr))`;
                }
            }));
            $("#saveBtn").on("click", (() => this.saveForm()));
        }
        async saveForm() {
            const e = $("#hideFilterItem").val(), t = $("#reviewCount").val(), n = $("#waitCheckCount").val(), a = parseInt($("#containerWidth").val()), i = parseInt($("#containerColumns").val()), r = $("#refresh_token").val();
            let o = await storageManager.getSetting();
            o.hideFilterItem = e;
            o.reviewCount = t;
            o.waitCheckCount = n;
            o.containerWidth = a + 70;
            o.containerColumns = i;
            o.refresh_token = r;
            o.webDavUrl = $("#webDavUrl").val();
            o.webDavUsername = $("#webDavUsername").val();
            o.webDavPassword = $("#webDavPassword").val();
            o.dialogOpenDetail = $("#dialogOpenDetail").val();
            o.javDbUrl = new URL($("#javDbUrl").val()).origin;
            await storageManager.saveSetting(o);
            let s = [];
            $("#reviewKeywordContainer .keyword-label").toArray().forEach((e => {
                let t = $(e).text().replace("×", "").replace(/[\r\n]+/g, " ").replace(/\s{2,}/g, " ").trim();
                s.push(t);
            }));
            await storageManager.saveReviewFilterKeyword(s);
            let l = [];
            $("#filterKeywordContainer .keyword-label").toArray().forEach((e => {
                let t = $(e).text().replace("×", "").replace(/[\r\n]+/g, " ").replace(/\s{2,}/g, " ").trim();
                l.push(t);
            }));
            await storageManager.saveTitleFilterKeyword(l);
            let c = [];
            $("#filterActorContainer .keyword-label").toArray().forEach((e => {
                let t = $(e).text().replace("×", "").replace(/[\r\n]+/g, " ").replace(/\s{2,}/g, " ").trim();
                c.push(t);
            }));
            await storageManager.saveFilterActor(c);
            show.ok("保存成功");
            window.refresh();
        }
        addLabelTag(e, t) {
            const n = $(`${e} .tag-box`), a = $(`\n            <div class="keyword-label" style="background-color: #c5b9a0">\n                ${t}\n                <span class="keyword-remove">×</span>\n            </div>\n        `);
            a.find(".keyword-remove").click((e => {
                $(e.target).parent().remove();
            }));
            n.append(a);
        }
        addKeyword(e, t) {
            let n = $(`${t} .keyword-input`);
            const a = n.val().trim();
            if (a) {
                this.addLabelTag(t, a);
                n.val("");
            }
        }
        importData() {
            try {
                const e = document.createElement("input");
                e.type = "file";
                e.accept = ".json";
                e.onchange = e => {
                    const t = e.target.files[0];
                    if (!t) return;
                    const n = new FileReader;
                    n.onload = e => {
                        try {
                            const t = e.target.result.toString(), n = JSON.parse(t);
                            layer.confirm("确定是否要覆盖导入?", {
                                icon: 3,
                                title: "确认覆盖",
                                btn: [ "确定", "取消" ]
                            }, (async function(e) {
                                await storageManager.importData(n);
                                show.ok("数据导入成功");
                                layer.close(e);
                                location.reload();
                            }));
                        } catch (t) {
                            console.error(t);
                            show.error("导入失败:文件内容不是有效的JSON格式 " + t);
                        }
                    };
                    n.onerror = () => {
                        show.error("读取文件时出错");
                    };
                    n.readAsText(t);
                };
                document.body.appendChild(e);
                e.click();
                setTimeout((() => document.body.removeChild(e)), 1e3);
            } catch (e) {
                console.error(e);
                show.error("导入数据时出错: " + e.message);
            }
        }
        async backupData(e) {
            const t = await storageManager.getSetting("refresh_token");
            if (!t) {
                show.error("请填写refresh_token并保存后, 再试此功能");
                return;
            }
            let n = utils.getNowStr("_", "_") + ".json", a = JSON.stringify(await storageManager.exportData());
            a = C(a);
            let i = loading();
            try {
                const e = new AliyunApi(t);
                await e.backup(this.folderName, n, a);
                show.ok("备份完成");
            } catch (r) {
                console.error(r);
                show.error(r.toString());
            } finally {
                i.close();
            }
        }
        async backupListBtn(e) {
            const t = await storageManager.getSetting("refresh_token");
            if (!t) {
                show.error("请填写refresh_token并保存后, 再试此功能");
                return;
            }
            let n = loading();
            try {
                const e = new AliyunApi(t), n = await e.getBackupList(this.folderName);
                this.openFileListDialog(n, e, "阿里云盘");
            } catch (a) {
                console.error(a);
                show.error(`发生错误: ${a ? a.message : a}`);
            } finally {
                n.close();
            }
        }
        async backupDataByWebDav(e) {
            const t = await storageManager.getSetting(), n = t.webDavUrl;
            if (!n) {
                show.error("请填写webDav服务地址并保存后, 再试此功能");
                return;
            }
            const a = t.webDavUsername;
            if (!a) {
                show.error("请填写webDav用户名并保存后, 再试此功能");
                return;
            }
            const i = t.webDavPassword;
            if (!i) {
                show.error("请填写webDav密码并保存后, 再试此功能");
                return;
            }
            let r = utils.getNowStr("_", "_") + ".json", o = JSON.stringify(await storageManager.exportData());
            o = C(o);
            let s = loading();
            try {
                const e = new WebDavApi(n, a, i);
                await e.backup(this.folderName, r, o);
                show.ok("备份完成");
            } catch (l) {
                console.error(l);
                show.error(l.toString());
            } finally {
                s.close();
            }
        }
        async backupListBtnByWebDav(e) {
            const t = await storageManager.getSetting(), n = t.webDavUrl;
            if (!n) {
                show.error("请填写webDav服务地址并保存后, 再试此功能");
                return;
            }
            const a = t.webDavUsername;
            if (!a) {
                show.error("请填写webDav用户名并保存后, 再试此功能");
                return;
            }
            const i = t.webDavPassword;
            if (!i) {
                show.error("请填写webDav密码并保存后, 再试此功能");
                return;
            }
            let r = loading();
            try {
                const e = new WebDavApi(n, a, i), t = await e.getBackupList(this.folderName);
                this.openFileListDialog(t, e, "WebDav");
            } catch (o) {
                console.error(o);
                show.error(`发生错误: ${o ? o.message : o}`);
            } finally {
                r.close();
            }
        }
        openFileListDialog(e, t, n) {
            layer.open({
                type: 1,
                title: n + "备份文件",
                content: '<div id="table-container"></div>',
                area: [ "40%", "70%" ],
                success: a => {
                    const i = new TableGenerator({
                        containerId: "table-container",
                        columns: [ {
                            key: "name",
                            title: "文件名"
                        }, {
                            key: "createTime",
                            title: "备份日期",
                            render: e => `${utils.getNowStr("-", ":", e.createTime)}`
                        }, {
                            key: "size",
                            title: "文件大小",
                            render: e => {
                                const t = [ "B", "KB", "MB", "GB", "TB", "PB" ];
                                let n = 0, a = e.size;
                                for (;a >= 1024 && n < t.length - 1; ) {
                                    a /= 1024;
                                    n++;
                                }
                                return `${a % 1 == 0 ? a.toFixed(0) : a.toFixed(2)} ${t[n]}`;
                            }
                        } ],
                        data: e,
                        buttons: [ {
                            text: "删除",
                            class: "a-danger",
                            onClick: async (e, a) => {
                                layer.confirm(`是否删除 ${a.name} ?`, {
                                    icon: 3,
                                    title: "提示",
                                    btn: [ "确定", "取消" ]
                                }, (async e => {
                                    layer.close(e);
                                    let r = loading();
                                    try {
                                        await t.deleteFile(a.fileId);
                                        let e = await t.getBackupList(this.folderName);
                                        i.update(e);
                                        "阿里云盘" === n ? layer.alert("已移至回收站, 请到阿里云盘回收站二次删除") : layer.alert("删除成功");
                                    } catch (o) {
                                        console.error(o);
                                        show.error(`发生错误: ${o ? o.message : o}`);
                                    } finally {
                                        r.close();
                                    }
                                }));
                            }
                        }, {
                            text: "下载",
                            class: "a-primary",
                            onClick: e => {
                                let a = loading();
                                try {
                                    "阿里云盘" === n ? t.getDownloadUrl(e.fileId).then((t => {
                                        gmHttp.get(t, null, {
                                            Referer: "https://www.aliyundrive.com/"
                                        }).then((t => {
                                            t = P(t);
                                            utils.download(t, e.name);
                                        }));
                                    })).catch((e => {
                                        console.error(e);
                                        show.error("下载失败: " + e);
                                    })) : t.getFileContent(e.fileId).then((t => {
                                        t = P(t);
                                        utils.download(t, e.name);
                                    }));
                                } catch (i) {
                                    console.error(i);
                                    show.error("下载失败: " + i);
                                } finally {
                                    a.close();
                                }
                            }
                        }, {
                            text: "导入",
                            class: "a-success",
                            onClick: e => {
                                layer.confirm(`是否将该云备份数据 ${e.name} 导入?`, {
                                    icon: 3,
                                    title: "提示",
                                    btn: [ "确定", "取消" ]
                                }, (async a => {
                                    layer.close(a);
                                    let i = loading();
                                    try {
                                        let a;
                                        if ("阿里云盘" === n) {
                                            const n = await t.getDownloadUrl(e.fileId);
                                            a = await gmHttp.get(n, null, {
                                                Referer: "https://www.aliyundrive.com/"
                                            });
                                        } else a = await t.getFileContent(e.fileId);
                                        a = P(a);
                                        const i = JSON.parse(a);
                                        await storageManager.importData(i);
                                        show.ok("导入成功!");
                                        window.location.reload();
                                    } catch (r) {
                                        console.error(r);
                                        show.error(r);
                                    } finally {
                                        i.close();
                                    }
                                }));
                            }
                        } ]
                    });
                }
            });
        }
        async exportData(e) {
            try {
                const e = JSON.stringify(await storageManager.exportData()), t = `${utils.getNowStr("_", "_")}.json`;
                utils.download(e, t);
                show.ok("数据导出成功");
            } catch (t) {
                console.error(t);
                show.error("导出数据时出错: " + t.message);
            }
        }
        async syncData(e) {
            let t = null, n = null;
            if (s) {
                t = "是否将JavBus的数据及配置同步到本站中? ";
                n = "https://www.javbus.com/temp?syncData=1";
            }
            if (l) {
                t = "是否将JavDB的数据及配置同步到本站中? ";
                n = await storageManager.getSetting("javDbUrl", "https://javdb.com") + "/feedbacks/new?syncData=1";
            }
            utils.q(e, t, (() => {
                const e = window.open(n);
                let t = new URL(n).origin;
                console.log("开始连接接受方:", t);
                let r, o = 0;
                if (!this.hasListenMsg) {
                    window.addEventListener("message", (n => {
                        if (n.origin === t) if ("ok" === n.data) {
                            clearInterval(r);
                            console.log("连接确认,开始同步数据");
                            e.postMessage("syncData", t);
                        } else {
                            const e = n.data;
                            console.log("收到数据", e);
                            __privateMethod(this, a, i).call(this, e);
                        }
                    }));
                    this.hasListenMsg = !0;
                }
                const s = () => {
                    if (o >= 8) {
                        clearInterval(r);
                        console.log("超过最大重试次数,停止尝试");
                        show.error("同步失败, 目标网站已中断, 请检查是否登录后再试!", {
                            close: !0,
                            duration: -1
                        });
                    } else {
                        console.log(`第 ${o + 1} 次ping...`);
                        e.postMessage("ping", t);
                        o++;
                    }
                };
                r = setInterval(s, 1e3);
                s();
            }));
        }
    }
    a = new WeakSet;
    i = async function(e) {
        try {
            const t = e.carList || [], n = e.filterActor || [], a = e.titleFilterKeyword || [], i = e.reviewFilterKeyword || [], r = e.setting || {}, o = await storageManager.getCarList() || [], s = await storageManager.getFilterActorList() || [], l = await storageManager.getTitleFilterKeyword() || [], c = await storageManager.getReviewFilterKeywordList() || [], d = await storageManager.getSetting() || {}, p = [ ...o ];
            t.forEach((e => {
                o.some((t => t.carNum === e.carNum)) || p.push(e);
            }));
            const g = [ ...new Set([ ...s, ...n ]) ], h = [ ...new Set([ ...l, ...a ]) ], u = [ ...new Set([ ...c, ...i ]) ], m = {
                ...d
            };
            Object.keys(r).forEach((e => {
                e in m && m[e] || (m[e] = r[e]);
            }));
            await storageManager.overrideCarList(p);
            await storageManager.saveFilterActor(g);
            await storageManager.saveTitleFilterKeyword(h);
            await storageManager.saveReviewFilterKeyword(u);
            await storageManager.saveSetting(m);
            show.ok("同步完成, 关闭提示后, 将重载数据", {
                close: !0,
                duration: -1,
                callback: () => {
                    window.location.reload();
                }
            });
        } catch (t) {
            console.error(t);
            show.error("同步数据时出错:", t);
        }
    };
    const _ = "x7k9p3";
    function C(e) {
        return (_ + e + _).split("").map((e => {
            const t = e.codePointAt(0);
            return String.fromCodePoint(t + 5);
        })).join("");
    }
    function P(e) {
        return e.split("").map((e => {
            const t = e.codePointAt(0);
            return String.fromCodePoint(t - 5);
        })).join("").slice(_.length, -_.length);
    }
    class SyncDataPlugin extends BasePlugin {
        async handle() {
            if (!window.location.href.includes("syncData=1")) return;
            l && $("h4").html("临时页面, 用于同步数据");
            let e = null;
            s && (e = "https://www.javbus.com");
            l && (e = await storageManager.getSetting("javDbUrl", "https://javdb.com"));
            console.log("等待发送方:", e);
            window.addEventListener("message", (async t => {
                if (t.origin === e) if ("ping" === t.data) {
                    console.log("收到 ping,发送确认");
                    t.source.postMessage("ok", t.origin);
                } else if ("syncData" === t.data) {
                    console.log("开始发送数据...");
                    const e = await storageManager.getCarList(), n = await storageManager.getFilterActorList(), a = await storageManager.getTitleFilterKeyword(), i = await storageManager.getReviewFilterKeywordList(), r = await storageManager.getSetting();
                    t.source.postMessage({
                        carList: e,
                        filterActor: n,
                        titleFilterKeyword: a,
                        reviewFilterKeyword: i,
                        setting: r
                    }, t.origin);
                    show.ok("数据已传输, 即将关闭页面...", {
                        callback: () => {
                            window.close();
                        }
                    });
                }
            }));
        }
    }
    class BusPreviewVideoPlugin extends BasePlugin {
        async initCss() {
            return "\n            .video-control-btn {\n                min-width:100px;\n                padding: 8px 16px;\n                background: rgba(0,0,0,0.7);\n                color: white;\n                border: none;\n                border-radius: 4px;\n                cursor: pointer;\n            }\n            .video-control-btn.active {\n                background-color: #1890ff; /* 选中按钮的背景色 */\n                color: white;             /* 选中按钮的文字颜色 */\n                font-weight: bold;        /* 加粗显示 */\n                border: 2px solid #096dd9; /* 边框样式 */\n            }\n        ";
        }
        handle() {
            if (!isDetailPage) return;
            const e = $("#sample-waterfall a:first").attr("href"), t = $(`\n            <a class="preview-video-container sample-box" style="cursor: pointer">\n                <div class="photo-frame" style="position:relative;">\n                    <img src="${e}" class="video-cover" alt="">\n                    <div class="play-icon" style="position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); \n                            color:white; font-size:40px; text-shadow:0 0 10px rgba(0,0,0,0.5);">\n                        ▶\n                    </div>\n                </div>\n            </a>`);
            $("#sample-waterfall").prepend(t);
            let n = $(".preview-video-container");
            n.on("click", (async t => {
                t.preventDefault();
                t.stopPropagation();
                if (!$("#preview-video").length) {
                    let t = await this.parseVideo(e);
                    console.log("解析播放地址:", t);
                    $("#magneturlpost").next().after(`<div><video id="preview-video" controls style="width: 100%;margin-top: 5px;"><source src="${t}" /></video></div>`);
                    this.handleVideo().then((() => {
                        const e = document.getElementById("preview-video");
                        if (e) {
                            const t = e.getBoundingClientRect();
                            window.scrollTo({
                                top: window.scrollY + t.top - 100,
                                behavior: "smooth"
                            });
                        }
                    }));
                }
            }));
            window.location.href.includes("autoPlay=1") && n[0].click();
        }
        async handleVideo() {
            const e = $("#preview-video"), t = e.find("source"), n = e.parent();
            if (!e.length || !t.length) return;
            const a = e[0];
            a.muted = !1;
            a.play();
            n.css("position", "relative");
            const i = t.attr("src"), r = [ "hhb", "hmb", "mhb", "mmb" ], o = r.find((e => i.includes(e))) || "mhb", s = [ {
                id: "video-mmb",
                text: "低画质",
                quality: "mmb"
            }, {
                id: "video-mhb",
                text: "中画质",
                quality: "mhb"
            }, {
                id: "video-hmb",
                text: "高画质",
                quality: "hmb"
            }, {
                id: "video-hhb",
                text: "超高清",
                quality: "hhb"
            } ];
            const l = `videoQualities_${this.getPageInfo().carNum}`;
            let c = JSON.parse(sessionStorage.getItem(l));
            if (!c) {
                c = (await Promise.all(s.map((async e => {
                    const t = i.replace(new RegExp(r.join("|"), "g"), e.quality);
                    try {
                        return (await fetch(t, {
                            method: "HEAD"
                        })).ok ? e : null;
                    } catch {
                        return null;
                    }
                })))).filter(Boolean);
                c.length && sessionStorage.setItem(l, JSON.stringify(c));
            }
            if (c.length <= 1) return;
            const d = c.map(((e, t) => `\n                <button class="video-control-btn${e.quality === o ? " active" : ""}" \n                        id="${e.id}" \n                        data-quality="${e.quality}"\n                        style="bottom: ${50 * t}px; right: -105px;">\n                    ${e.text}\n                </button>\n            `)).join("");
            n.append(d);
            const p = n.find(".video-control-btn");
            n.on("click", ".video-control-btn", (async e => {
                const n = $(e.currentTarget), o = n.data("quality");
                if (!n.hasClass("active")) try {
                    const e = i.replace(new RegExp(r.join("|"), "g"), o);
                    t.attr("src", e);
                    a.load();
                    a.muted = !1;
                    await a.play();
                    p.removeClass("active");
                    n.addClass("active");
                } catch (s) {
                    console.error("切换画质失败:", s);
                }
            }));
            p.last().trigger("click");
        }
        async parseVideo(e) {
            const t = `ok_url_${this.getPageInfo().carNum}`;
            let n = sessionStorage.getItem(t);
            if (n) return n;
            const a = e.match(/\/digital\/video\/([^\/]+)\//);
            if (!a || a.length < 2) {
                show.error("解析id错误" + e + ", 该视频没有对应的dmm视频");
                console.error("解析dmm视频id错误", e);
                setTimeout((() => {
                    $("#preview-video").remove();
                }), 1e3);
                return null;
            }
            const i = a[1], r = i.charAt(0).toLowerCase();
            let o = i.substring(0, 3);
            const s = async e => {
                try {
                    console.log("测试视频地址", e);
                    return (await fetch(e, {
                        method: "HEAD"
                    })).ok ? e : null;
                } catch {
                    return null;
                }
            };
            let l = i.replace("00", ""), c = [ `https://cc3001.dmm.co.jp/litevideo/freepv/${r}/${o}/${i}/${i}hhb.mp4`, `https://cc3001.dmm.co.jp/litevideo/freepv/${r}/${o}/${l}/${l}hhb.mp4`, `https://cc3001.dmm.co.jp/litevideo/freepv/${r}/${o}/${i}/${i}mhb.mp4`, `https://cc3001.dmm.co.jp/litevideo/freepv/${r}/${o}/${l}/${l}mhb.mp4` ], d = null;
            for (let p = 0; p < c.length; p++) {
                let e = await s(c[p]);
                if (e) {
                    console.log("测试成功,", e);
                    d = e;
                    break;
                }
            }
            if (!d) {
                show.error("解析dmm预览视频失败, 请联系作者, 提供番号信息");
                throw new Error("解析dmm预览视频失败, 请联系作者, 提供番号信息");
            }
            sessionStorage.setItem(t, d);
            return d;
        }
    }
    class SearchByImagePlugin extends BasePlugin {
        constructor() {
            super(...arguments);
            __publicField(this, "siteList", [ {
                name: "Google旧版",
                url: "https://www.google.com/searchbyimage?image_url={占位符}&client=firefox-b-d",
                ico: "https://www.google.com/favicon.ico"
            }, {
                name: "Google",
                url: "https://lens.google.com/uploadbyurl?url={占位符}",
                ico: "https://www.google.com/favicon.ico"
            }, {
                name: "Yandex",
                url: "https://yandex.ru/images/search?rpt=imageview&url={占位符}",
                ico: "https://yandex.ru/favicon.ico"
            } ]);
        }
        async initCss() {
            return "\n            <style>\n                #upload-area {\n                    border: 2px dashed #85af68;\n                    border-radius: 8px;\n                    padding: 40px;\n                    text-align: center;\n                    margin-bottom: 20px;\n                    transition: all 0.3s;\n                    background-color: #f9f9f9;\n                }\n                #upload-area:hover {\n                    border-color: #76b947;\n                    background-color: #f0f0f0;\n                }\n                /* 拖拽进入 */\n                #upload-area.highlight {\n                    border-color: #2196F3;\n                    background-color: #e3f2fd;\n                }\n                \n                \n                #select-image-btn {\n                    background-color: #4CAF50;\n                    color: white;\n                    border: none;\n                    padding: 10px 20px;\n                    border-radius: 4px;\n                    cursor: pointer;\n                    font-size: 16px;\n                    transition: background-color 0.3s;\n                }\n                #select-image-btn:hover {\n                    background-color: #45a049;\n                }\n                \n                \n                #handle-btn, #cancel-btn {\n                    padding: 8px 16px;\n                    border-radius: 4px;\n                    cursor: pointer;\n                    font-size: 14px;\n                    border: none;\n                    transition: opacity 0.3s;\n                }\n                #handle-btn {\n                    background-color: #2196F3;\n                    color: white;\n                }\n                #handle-btn:hover {\n                    opacity: 0.9;\n                }\n                #cancel-btn {\n                    background-color: #f44336;\n                    color: white;\n                }\n                #cancel-btn:hover {\n                    opacity: 0.9;\n                }\n                \n                .site-btns-container {\n                    display: flex;\n                    flex-wrap: wrap;\n                    gap: 10px;\n                    margin-top: 15px;\n                }\n                .site-btn {\n                    display: flex;\n                    align-items: center;\n                    padding: 8px 12px;\n                    background-color: #f5f5f5;\n                    border-radius: 4px;\n                    text-decoration: none;\n                    color: #333;\n                    transition: all 0.2s;\n                    font-size: 14px;\n                    border: 1px solid #ddd;\n                }\n                .site-btn:hover {\n                    background-color: #e0e0e0;\n                    transform: translateY(-2px);\n                    box-shadow: 0 2px 5px rgba(0,0,0,0.1);\n                }\n                .site-btn img {\n                    width: 16px;\n                    height: 16px;\n                    margin-right: 6px;\n                }\n                .site-btn span {\n                    white-space: nowrap;\n                }\n            </style>\n        ";
        }
        open() {
            layer.open({
                type: 1,
                title: "以图识图",
                content: '\n            <div style="padding: 20px">\n                <div id="upload-area">\n                    <div style="color: #555;margin-bottom: 15px;">\n                        <p>拖拽图片到此处 或 点击按钮选择图片</p>\n                        <p>也可以直接 Ctrl+V 粘贴图片或 图片URL</p>\n                    </div>\n                    <button id="select-image-btn">选择图片</button>\n                    <input type="file" style="display: none" id="image-file" accept="image/*">\n                </div>\n                \n                <div id="url-input-container" style="margin-top: 15px;display: none;">\n                    <input type="text" id="image-url" placeholder="粘贴图片URL地址..." style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box;">\n                </div>\n                \n                <div id="preview-area" style="margin-bottom: 20px; text-align: center; display: none;">\n                    <img id="preview-image" alt="" src="" style="max-width: 100%; max-height: 300px; border-radius: 4px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);">\n                    <div style="margin-top: 15px; display: flex; justify-content: center; gap: 10px;" id="action-btns">\n                        <button id="handle-btn">搜索图片</button>\n                        <button id="cancel-btn">取消</button>\n                    </div>\n                    \n                    <div id="search-results" style="display: none;">\n                        <p style="margin: 20px auto">请选择识图网站:<a id="openAll" style="cursor: pointer">全部打开</a></p>\n                        <div class="site-btns-container" id="site-btns-container"></div>\n                    </div>\n                </div>\n                \n            </div>\n        ',
                area: [ "40%", "80%" ],
                success: async e => {
                    this.initEventListeners();
                }
            });
        }
        initEventListeners() {
            const e = $("#upload-area"), t = $("#image-file"), n = $("#select-image-btn"), a = $("#preview-area"), i = $("#preview-image"), r = $("#action-btns"), o = $("#handle-btn"), s = $("#cancel-btn"), l = $("#url-input-container"), c = $("#image-url"), d = $("#search-results"), p = $("#site-btns-container");
            e.on("dragover", (t => {
                t.preventDefault();
                e.addClass("highlight");
            })).on("dragleave", (() => {
                e.removeClass("highlight");
            })).on("drop", (t => {
                t.preventDefault();
                e.removeClass("highlight");
                if (t.originalEvent.dataTransfer.files && t.originalEvent.dataTransfer.files[0]) {
                    this.handleImageFile(t.originalEvent.dataTransfer.files[0]);
                    this.resetSearchUI();
                }
            }));
            n.on("click", (() => {
                t.trigger("click");
            }));
            t.on("change", (e => {
                if (e.target.files && e.target.files[0]) {
                    this.handleImageFile(e.target.files[0]);
                    this.resetSearchUI();
                }
            }));
            $(document).on("paste", (async e => {
                const t = e.originalEvent.clipboardData.items;
                for (let a = 0; a < t.length; a++) if (-1 !== t[a].type.indexOf("image")) {
                    const e = t[a].getAsFile();
                    this.handleImageFile(e);
                    this.resetSearchUI();
                    return;
                }
                const n = e.originalEvent.clipboardData.getData("text");
                if (n && utils.isUrl(n)) {
                    l.show();
                    c.val(n);
                    i.attr("src", n);
                    a.show();
                    this.resetSearchUI();
                }
            }));
            o.on("click", (() => {
                const e = i.attr("src");
                e ? this.searchByImage(e).then((e => {
                    r.hide();
                    d.show();
                    p.empty();
                    this.siteList.forEach((t => {
                        const n = t.url.replace("{占位符}", encodeURIComponent(e));
                        p.append(`\n                        <a href="${n}" class="site-btn" target="_blank" title="${t.name}">\n                            <img src="${t.ico}" alt="${t.name}">\n                            <span>${t.name}</span>\n                        </a>\n                    `);
                    }));
                    p.show();
                })) : show.info("请粘贴或上传图片");
            }));
            s.on("click", (() => {
                a.hide();
                l.hide();
                t.val("");
                c.val("");
            }));
            c.on("change", (() => {
                if (utils.isUrl(c.val())) {
                    i.attr("src", c.val());
                    a.show();
                }
            }));
            $("#openAll").on("click", (() => {
                $(".site-btn").toArray().forEach((e => {
                    window.open($(e).attr("href"));
                }));
            }));
        }
        resetSearchUI() {
            $("#action-btns").show();
            $("#search-results").hide();
            $("#site-btns-container").hide().empty();
        }
        handleImageFile(e) {
            const t = document.getElementById("preview-image"), n = document.getElementById("preview-area"), a = document.getElementById("url-input-container");
            if (!e.type.match("image.*")) {
                show.info("请选择图片文件");
                return;
            }
            const i = new FileReader;
            i.onload = e => {
                t.src = e.target.result;
                n.style.display = "block";
                a.style.display = "none";
            };
            i.readAsDataURL(e);
        }
        async searchByImage(e) {
            let t = loading();
            try {
                let t = e;
                if (e.startsWith("data:")) {
                    show.info("开始上传图片...");
                    const n = await async function(e) {
                        var t;
                        const n = e.match(/^data:(.+);base64,(.+)$/);
                        if (!n || n.length < 3) throw new Error("无效的Base64图片数据");
                        const a = n[1], i = n[2], r = atob(i), o = new Array(r.length);
                        for (let g = 0; g < r.length; g++) o[g] = r.charCodeAt(g);
                        const s = new Uint8Array(o), l = new Blob([ s ], {
                            type: a
                        }), c = new FormData;
                        c.append("image", l);
                        const d = await fetch("https://api.imgur.com/3/image", {
                            method: "POST",
                            headers: {
                                Authorization: "Client-ID d70305e7c3ac5c6"
                            },
                            body: c
                        }), p = await d.json();
                        if (p.success && p.data && p.data.link) return p.data.link;
                        throw new Error((null == (t = p.data) ? void 0 : t.error) || "上传到Imgur失败");
                    }(e);
                    if (!n) {
                        show.error("上传到失败");
                        return;
                    }
                    t = n;
                }
                return t;
            } catch (n) {
                show.error(`搜索失败: ${n.message}`);
                console.error("搜索失败:", n);
            } finally {
                t.close();
            }
        }
    }
    class BusNavBarPlugin extends BasePlugin {
        handle() {
            $("#navbar > div > div > span").append('\n            <button class="btn btn-default" style="color: #0d9488" id="search-img-btn">识图</button>\n       ');
            $("#search-img-btn").on("click", (() => {
                this.getBean("SearchByImagePlugin").open();
            }));
        }
    }
    class RelatedPlugin extends BasePlugin {
        constructor() {
            super(...arguments);
            __publicField(this, "floorIndex", 1);
        }
        async showRelated() {
            let e = this.getPageInfo().movieId, t = $("#magnets-content");
            t.append('\n            <div style=" display: flex; align-items: center; margin: 16px 0; color: #666; font-size: 14px; ">\n                <span style=" flex: 1; height: 1px; background: linear-gradient(to right, transparent, #999, transparent); "></span>\n                <span style="padding: 0 10px;">相关清单</span>\n                <a id="relatedFold" style=" margin-left: 8px; color: #1890ff; text-decoration: none; display: flex; align-items: center; ">\n                    <span class="toggle-text">展开</span>\n                    <span class="toggle-icon" style="margin-left: 4px;">▼</span>\n                </a>\n                <span style=" flex: 1; height: 1px; background: linear-gradient(to right, transparent, #999, transparent); "></span>\n            </div>\n        ');
            let n = null;
            $("#relatedFold").on("click", (async () => {
                const t = $("#relatedFold .toggle-text"), r = $("#relatedFold .toggle-icon");
                if ("展开" === t.text()) {
                    t.text("折叠");
                    r.text("▲");
                    a.show();
                    i.show();
                    if (n) return;
                    try {
                        a.append('<div id="relate-load" style="margin-top:15px;background-color:#ffffff;padding:10px;margin-left: -10px;">正在查询中...</div>');
                        let t = 1, r = 20;
                        n = await k(e, t, r);
                        $("#relate-load").remove();
                        if (!n) {
                            a.append('<div style="margin-top:15px;background-color:#ffffff;padding:10px;margin-left: -10px;">获取清单失败</div>');
                            return;
                        }
                        0 === n.length && a.append('<div style="margin-top:15px;background-color:#ffffff;padding:10px;margin-left: -10px;">无清单</div>');
                        this.displayRelated(n, a);
                        if (n.length === r) {
                            i.html('\n                            <button id="loadMoreRelated" style="width:100%; background-color: #e1f5fe; border:none; padding:10px; margin-top:10px; cursor:pointer; color:#0277bd; font-weight:bold; border-radius:4px;">\n                                加载更多清单\n                            </button>\n                            <div id="reviewsEnd" style="display:none; text-align:center; padding:10px; color:#666; margin-top:10px;">已加载全部清单</div>\n                        ');
                            let t = 1;
                            $("#loadMoreRelated").click((async () => {
                                $("#loadMoreRelated").text("加载中...").prop("disabled", !0);
                                t++;
                                const n = await k(e, t, r);
                                this.displayRelated(n, a);
                                if (n.length < r) {
                                    $("#loadMoreRelated").remove();
                                    $("#reviewsEnd").show();
                                } else $("#loadMoreRelated").text("加载更多清单").prop("disabled", !1);
                            }));
                        } else n.length > 0 && i.html('<div style="text-align:center; padding:10px; color:#666; margin-top:10px;">已加载全部清单</div>');
                    } catch (o) {
                        console.error(o);
                        $("#relate-load").remove();
                        a.append('<div style="margin-top:15px;background-color:#ffffff;padding:10px;margin-left: -10px;">获取失败</div>');
                    }
                } else {
                    t.text("展开");
                    r.text("▼");
                    a.hide();
                    i.hide();
                }
            }));
            t.append('<div id="relatedContainer"></div>');
            t.append('<div id="relatedFooter"></div>');
            const a = $("#relatedContainer"), i = $("#relatedFooter");
        }
        displayRelated(e, t) {
            e.length && e.forEach((e => {
                let n = `\n                <div class="item columns is-desktop" style="display:block;margin-top:6px;background-color:#ffffff;padding:10px;margin-left: -10px;word-break: break-word;position:relative;">\n                   <span style="position:absolute;top:5px;right:10px;color:#999;font-size:12px;">#${this.floorIndex++}</span>\n                   <span style="position:absolute;bottom:5px;right:10px;color:#999;font-size:12px;">创建时间: ${e.createTime}</span>\n                   <p><a href="/lists/${e.relatedId}" target="_blank" style="color:#2e8abb">${e.name}</a></p>\n                   <p style="margin-top: 5px;">收藏次数: ${e.collectionCount} 被查看次数: ${e.viewCount}</p>\n                </div>\n            `;
                t.append(n);
            }));
        }
    }
    class WantAndWatchedVideosPlugin extends BasePlugin {
        constructor() {
            super(...arguments);
            __publicField(this, "type", null);
        }
        async handle() {
            if (window.location.href.includes("/want_watch_videos")) {
                $("h3").append('<a class="a-primary" id="wantWatchBtn" style="padding:10px;">导入至 JSH</a>');
                $("#wantWatchBtn").on("click", (e => {
                    this.type = c;
                    this.importWantWatchVideos(e, "是否将 想看的影片 导入到 JSH-收藏?");
                }));
            }
            if (window.location.href.includes("/watched_videos")) {
                $("h3").append('<a class="a-success" id="wantWatchBtn" style="padding:10px;">导入至 JSH</a>');
                $("#wantWatchBtn").on("click", (e => {
                    this.type = p;
                    this.importWantWatchVideos(e, "是否将 看过的影片 导入到 JSH-已下载?");
                }));
            }
        }
        importWantWatchVideos(e, t) {
            utils.q(null, `${t} <br/> <span style='color: #f40'>执行此功能前请记得备份数据</span>`, (async () => {
                let e = loading();
                try {
                    await this.parseMovieList();
                } catch (t) {
                    console.error(t);
                } finally {
                    e.close();
                }
            }));
        }
        async parseMovieList(e) {
            let t, n;
            if (e) {
                t = e.find(this.getSelector().itemSelector);
                n = e.find(".pagination-next").attr("href");
            } else {
                t = $(this.getSelector().itemSelector);
                n = $(".pagination-next").attr("href");
            }
            for (const i of t) {
                const e = $(i), t = e.find("a").attr("href"), n = e.find(".video-title strong").text().trim();
                if (t && n) try {
                    if (await storageManager.getCar(n)) {
                        show.info(`${n} 已存在, 跳过`);
                        continue;
                    }
                    await storageManager.saveCar(n, t, "", this.type);
                } catch (a) {
                    console.error(`保存失败 [${n}]:`, a);
                }
            }
            if (n) {
                show.info("发现下一页,正在解析:", n);
                await new Promise((e => setTimeout(e, 1e3)));
                $.ajax({
                    url: n,
                    method: "GET",
                    success: e => {
                        const t = new DOMParser, n = $(t.parseFromString(e, "text/html"));
                        this.parseMovieList(n);
                    },
                    error: function(e) {
                        console.error(e);
                        show.error("加载下一页失败:" + e.message);
                    }
                });
            } else {
                show.ok("导入结束!");
                window.refresh();
            }
        }
    }
    class CopyTitleOrDownImgPlugin extends BasePlugin {
        constructor() {
            super(...arguments);
            __publicField(this, "titleSvg", '<svg t="1747553289744" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7507" width="200" height="200"><path d="M959.8 150.8c0-2.3-1.9-4.2-4.2-4.2H253.3c-2.3 0-4.2 1.9-4.2 4.2v115.9c0 2.3 1.9 4.2 4.2 4.2h702.3c2.3 0 4.2-1.9 4.2-4.2V150.8z" fill="" p-id="7508"></path><path d="M126.4 208.8m-62.2 0a62.2 62.2 0 1 0 124.4 0 62.2 62.2 0 1 0-124.4 0Z" fill="" p-id="7509"></path><path d="M851.5 453.7c0-2.1-1.8-3.9-3.9-3.9H252.9c-2.1 0-3.9 1.7-3.9 3.9v116.6c0 2.1 1.7 3.9 3.9 3.9h594.7c2.1 0 3.9-1.7 3.9-3.9V453.7z" fill="" p-id="7510"></path><path d="M126.4 512m-62.2 0a62.2 62.2 0 1 0 124.4 0 62.2 62.2 0 1 0-124.4 0Z" fill="" p-id="7511"></path><path d="M851.5 756.9c0-2.1-1.8-3.9-3.9-3.9H252.9c-2.1 0-3.9 1.8-3.9 3.9v116.6c0 2.1 1.7 3.9 3.9 3.9h594.7c2.1 0 3.9-1.7 3.9-3.9V756.9z" fill="" p-id="7512"></path><path d="M126.4 815.2m-62.2 0a62.2 62.2 0 1 0 124.4 0 62.2 62.2 0 1 0-124.4 0Z" fill="" p-id="7513"></path></svg>');
            __publicField(this, "carNumSvg", '<svg t="1747552574854" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3539" width="200" height="200"><path d="M920.337035 447.804932c-6.067182-6.067182-10.918677-11.643178-16.985859-17.71036l48.536436-30.334889-42.469254-109.207238-121.340579 12.134365c-6.067182-6.067182-6.067182-12.134365-12.134365-18.201547-12.134365-12.134365-18.201547-24.267706-24.267706-30.334889-24.26873-36.402071-30.334889-42.469254-54.603619-42.469254H339.116511c-18.201547 0-24.267706 6.067182-54.603619 42.469254-6.067182 6.067182-12.134365 18.201547-24.267706 30.334889 0 0-6.067182 6.067182-12.134365 18.201547l-115.27442-12.134365-48.536436 109.207238 51.090608 24.378223c-6.067182 6.067182-30.334889 34.660404-30.334889 34.660405l-15.542998 22.280446-12.282744 17.018605c-6.067182 12.134365-5.064342 10.868535-5.064342 29.070082v224.480635c0 36.402071 18.201547 60.670801 54.603618 60.670801h115.273397c36.402071 0 54.603619-24.267706 54.603619-54.603619v-18.201547h424.693562v18.201547c0 30.334889 18.201547 54.603619 54.603618 54.603619h115.273397c36.402071 0 60.670801-24.267706 60.670801-60.670801V539.300786c0-42.469254 0.685615-46.662763-11.44875-64.863287-4.731768-6.744611-11.94403-16.196891-20.101827-26.632567z m-35.186383-78.381161l-30.334889 18.201547-12.134365-12.134365c-6.067182-8.899694-12.134365-12.134365-12.134365-18.201547l42.469254-6.067183 12.134365 18.201548z m-533.899776-97.072873h339.755054l78.871325 103.140055H272.378527l78.872349-103.140055zM175.305655 357.290429h36.402071c-6.067182 6.067182-6.067182 12.134365-12.134365 18.201547l-18.201547 6.067183-18.201547-12.134365 12.135388-12.134365z m667.375743 394.35765h-54.603619V678.843936H242.043638v72.804143H132.837424V527.167444c0-12.134365-0.041956-20.662599 1.216711-23.556508 1.258667-2.89391 9.955746-16.924461 21.193695-29.173437l35.722596-38.276768h639.576607l21.917172 20.938891c6.067182 6.067182 21.847587 21.366633 25.712615 28.732392 7.621585 9.996678 6.973832 10.999518 13.041014 23.133883v242.682182h-48.536436zM242.043638 533.234627h133.474944v60.670801H242.043638v-60.670801z m412.559197 0h133.474944v60.670801H654.602835v-60.670801z" p-id="3540"></path></svg>');
            __publicField(this, "downSvg", '<svg t="1747552626242" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4551" width="200" height="200"><path d="M641.6 660l-8.64-64 32-4.32a211.2 211.2 0 0 0-26.72-420.32 215.36 215.36 0 0 0-213.12 192 94.56 94.56 0 0 0 0 11.52v41.28h-64V384v-7.04a153.12 153.12 0 0 1 0-19.52A279.84 279.84 0 0 1 636.16 108H640A275.2 275.2 0 0 1 673.28 656z" fill="#333333" p-id="4552"></path><path d="M490.4 446.24l-7.52-39.84a182.4 182.4 0 0 1 107.52-162.88l29.12-13.28L646.08 288l-29.12 13.28a117.92 117.92 0 0 0-70.08 101.28l6.24 30.4zM392.96 652.32h-78.72A202.24 202.24 0 0 1 256 256l30.72-9.12 18.24 61.28-30.72 9.12a138.24 138.24 0 0 0 39.68 270.72h78.72zM479.2 512h64v320h-64z" fill="#333333" p-id="4553"></path><path d="M510.4 908l-156.32-147.68 43.84-46.4 112.48 106.08 112.8-106.08 43.84 46.56-156.64 147.52z" fill="#333333" p-id="4554"></path></svg>');
        }
        async initCss() {
            return `\n            .box .tags {\n                justify-content: space-between;\n            }\n            .tool-box span{\n                opacity:.3\n            }\n            \n            .tool-box span:hover{\n                opacity:1\n            }\n            ${l ? ".tool-box .icon{ height: 2rem; width: 2rem; }" : ""}\n        `;
        }
        handle() {
            if (window.isListPage) {
                this.addCopy();
                this.bindClick();
            }
        }
        addCopy() {
            $(this.getSelector().itemSelector).toArray().forEach((e => {
                let t = $(e);
                s && t.find(".tags").append(`\n                    <div class="tool-box">\n                        <span class="titleSvg"  title="复制标题" style="margin-right: 15px; color:#c5a45d;">${this.titleSvg}</span>\n                        <span class="carNumSvg" title="复制番号" style="margin-right: 15px; color:#9f2727;">${this.carNumSvg}</span>\n                        <span class="downSvg"   title="下载封面" style="margin-right: 15px; color:#2ca5c0;">${this.downSvg}</span>\n                    </div>\n                `);
                l && t.find(".photo-info").append(`\n                    <div class="tool-box">\n                        <span class="titleSvg"  title="复制标题" style="margin-right: 15px; color:#c5a45d;">${this.titleSvg}</span>\n                        <span class="carNumSvg" title="复制番号" style="margin-right: 15px; color:#9f2727;">${this.carNumSvg}</span>\n                        <span class="downSvg"   title="下载封面" style="margin-right: 15px; color:#2ca5c0;">${this.downSvg}</span>\n                    </div>                \n                `);
            }));
        }
        bindClick() {
            const e = this.getBean("ListPagePlugin");
            $(this.getSelector().boxSelector).on("click", ".titleSvg", (t => {
                t.preventDefault();
                t.stopPropagation();
                const n = $(t.target).closest(".item"), {carNum: a, aHref: i, title: r} = e.findCarNumAndHref(n);
                navigator.clipboard.writeText(r).then((() => {
                    show.info("标题已复制到剪切板, " + r);
                })).catch((e => {
                    console.error("复制失败: ", e);
                }));
            })).on("click", ".carNumSvg", (t => {
                t.preventDefault();
                t.stopPropagation();
                const n = $(t.target).closest(".item"), {carNum: a, aHref: i, title: r} = e.findCarNumAndHref(n);
                navigator.clipboard.writeText(a).then((() => {
                    show.info("番号已复制到剪切板, " + a);
                })).catch((e => {
                    console.error("复制失败: ", e);
                }));
            })).on("click", ".downSvg", (t => {
                t.preventDefault();
                t.stopPropagation();
                const n = $(t.target).closest(".item"), {carNum: a, aHref: i, title: r} = e.findCarNumAndHref(n);
                let o = n.find(".cover img");
                l && (o = n.find(".photo-frame img"));
                const s = o.attr("src");
                console.log(s);
                GM_download({
                    url: s,
                    name: r + ".jpg"
                });
            }));
        }
    }
    utils.importResource("https://cdn.jsdelivr.net/npm/[email protected]/layer.min.css");
    utils.importResource("https://cdn.jsdelivr.net/npm/[email protected]/src/toastify.min.css");
    window.onload = async function() {
        window.isDetailPage = function() {
            let e = window.location.href;
            return e.includes("javdb") ? e.includes("/v/") : !!e.includes("javbus") && $("#magnet-table").length > 0;
        }();
        window.isListPage = function() {
            let e = window.location.href;
            return e.includes("javdb") ? $(".movie-list").length > 0 : !!e.includes("javbus") && $(".masonry > div .item").length > 0;
        }();
        !function() {
            const e = new PluginManager;
            let t = window.location.hostname;
            if (t.includes("javdb")) {
                e.register(ListPagePlugin);
                e.register(AutoPagePlugin);
                e.register(Fc2Plugin);
                e.register(FoldCategoryPlugin);
                e.register(ListPageButtonPlugin);
                e.register(HistoryPlugin);
                e.register(SettingPlugin);
                e.register(NavBarPlugin);
                e.register(HitShowPlugin);
                e.register(TOP250Plugin);
                e.register(SyncDataPlugin);
                e.register(SearchByImagePlugin);
                e.register(CopyTitleOrDownImgPlugin);
                e.register(DetailPagePlugin);
                e.register(ReviewPlugin);
                e.register(RelatedPlugin);
                e.register(DetailPageButtonPlugin);
                e.register(HighlightMagnetPlugin);
                e.register(PreviewVideoPlugin);
                e.register(FilterTitleKeywordPlugin);
                e.register(ActressInfoPlugin);
                e.register(OtherSitePlugin);
                e.register(WantAndWatchedVideosPlugin);
            }
            if (t.includes("javbus")) {
                e.register(ListPagePlugin);
                e.register(ListPageButtonPlugin);
                e.register(SettingPlugin);
                e.register(HistoryPlugin);
                e.register(SyncDataPlugin);
                e.register(AutoPagePlugin);
                e.register(SearchByImagePlugin);
                e.register(BusNavBarPlugin);
                e.register(CopyTitleOrDownImgPlugin);
                e.register(BusDetailPagePlugin);
                e.register(DetailPageButtonPlugin);
                e.register(ReviewPlugin);
                e.register(FilterTitleKeywordPlugin);
                e.register(HighlightMagnetPlugin);
                e.register(BusPreviewVideoPlugin);
            }
            t.includes("javtrailers") && e.register(JavTrailersPlugin);
            t.includes("subtitlecat") && e.register(SubTitleCatPlugin);
            t.includes("aliyundrive") && e.register(AliyunPanPlugin);
            e.process().then();
        }();
    };
}();