[
  {
    "articleStyle": 1,
    "customOrder": -5,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\"User-Agent\": \"Mozilla/5.0 (Linux; U; Android 14; zh-cn; M2102K1AC Build/UKQ1.231207.002) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/109.0.5414.118 Mobile Safari/537.36 MQQBrowser/10.1.0\"}",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": ".thumbnail-group@li",
    "ruleContent": "<js>\np=result.match(/vod\\_data.*url\\\"\\:\\\"(.*?)\\\"\\,\\\"url/);\np=(p?p[1]:1).replace(/\\\\/g,'')||1; pi=java.getString('.breadcrumbs@span@text')||1;\n`<html>\n    <head>\n        <meta name=\"viewport\" content=\"width=device-width\">\n        <style>\n            body {\n                margin: 0;\n                font-family: Arial, sans-serif;\n                background: linear-gradient(135deg, #ece9e6, #ffffff);\n                display: flex;\n                flex-direction: column;\n                align-items: center;\n                justify-content: flex-start;\n                padding: 20px;\n            }\n            .container {\n                width: 100%;\n                max-width: 800px;\n                background: #fff;\n                border-radius: 10px;\n                box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n                overflow: hidden;\n                margin-bottom: 20px;\n            }\n            h3 {\n                margin: 0;\n                padding: 10px 20px;\n                font-size: 0.9em;\n                background: #333;\n                color: #fff;\n                border-radius: 10px 10px 0 0;\n            }\n            .video-container {\n                width: 100%;\n                background: #000;\n                position: relative;\n            }\n            video {\n                width: 100%;\n                height: auto;\n                display: block;\n            }\n            .info-container {\n                padding: 20px;\n            }\n            .info-container p {\n                margin: 10px 0;\n                color: #555;\n            }\n            .info-container p span {\n                font-weight: bold;\n                color: #000;\n            }\n        </style>\n    </head>\n    <body>\n        <div class=\"container\">\n        <h3>${pi}</h3>\n            <div class=\"video-container\">\n                <video controls autoplay name=\"media\" id=\"videoPlayer\">\n                    <source src=\"${p}\" type=\"video/mp4\">\n                </video>\n            </div>\n            <div class=\"info-container\">\n                \n            </div>\n        </div>\n\n        <script>\n            // 获取视频元素\n            const video = document.getElementById('videoPlayer');\n            let touchStartX = 0;\n            let touchStartY = 0;\n            let touchStartTime = 0;\n            let isLongPress = false;\n\n            // 滑动快进\n            video.addEventListener('touchstart', (e) => {\n                touchStartX = e.touches[0].clientX;\n                touchStartY = e.touches[0].clientY;\n                touchStartTime = Date.now();\n                isLongPress = false;\n            });\n\n            video.addEventListener('touchmove', (e) => {\n                const deltaX = e.touches[0].clientX - touchStartX;\n                const deltaY = e.touches[0].clientY - touchStartY;\n\n                // 如果是水平滑动，且未进入长按状态\n                if (Math.abs(deltaX) > Math.abs(deltaY) && !isLongPress) {\n                    const duration = video.duration;\n                    const seekTime = video.currentTime + (deltaX / 100); // 每滑动100px快进1秒\n                    video.currentTime = Math.min(Math.max(seekTime, 0), duration);\n                }\n            });\n\n            // 长按快进\n            video.addEventListener('touchend', (e) => {\n                const touchEndTime = Date.now();\n                const touchDuration = touchEndTime - touchStartTime;\n\n                // 如果长按时间超过500ms，进入长按快进状态\n                if (touchDuration > 500) {\n                    isLongPress = true;\n\n                    // 在长按状态下，根据滑动距离快进\n                    const deltaX = e.changedTouches[0].clientX - touchStartX;\n                    const duration = video.duration;\n                    const seekTime = video.currentTime + (deltaX / 100); // 每滑动100px快进1秒\n                    video.currentTime = Math.min(Math.max(seekTime, 0), duration);\n                } else {\n                    isLongPress = false;\n                }\n            });\n\n            // 防止默认行为（如页面滚动）\n            video.addEventListener('touchmove', (e) => {\n                e.preventDefault();\n            });\n        </script>\n    </body>\n</html>`;\n\n</js>",
    "ruleImage": "img@src",
    "ruleLink": "a@href\n<js>\nresult=result.replace('detail','play');\nif(!result.includes('/sid/1/nid/1.html')){\n\tresult=result.replace('.html','/sid/1/nid/1.html');\n\t}\nresult\n</js>",
    "ruleNextPage": "text.下一页@href",
    "rulePubDate": "p@text",
    "ruleTitle": "h5@text||img@alt",
    "singleUrl": false,
    "sortUrl": "搜索🔍::/index.php/vod/search/page/{{page}}/wd/{{source.getVariable()}}.html\n\n偷拍自拍::/index.php/vod/type/id/2/page/{{page}}.html\n国产精品::/index.php/vod/type/id/3/page/{{page}}.html\n伦理三级::/index.php/vod/type/id/4/page/{{page}}.html\n主播大秀::/index.php/vod/type/id/5/page/{{page}}.html\n网曝黑料::/index.php/vod/type/id/6/page/{{page}}.html\n热门头条::/index.php/vod/type/id/7/page/{{page}}.html\n抖音视频::/index.php/vod/type/id/8/page/{{page}}.html\n素人自拍::/index.php/vod/type/id/9/page/{{page}}.html\n\n刘玥::/index.php/vod/type/id/10/page/{{page}}.html\n过膝袜::/index.php/vod/type/id/11/page/{{page}}.html\n探花系列::/index.php/vod/type/id/12/page/{{page}}.html\n玩偶姐姐::/index.php/vod/type/id/13/page/{{page}}.html\ncosplay::/index.php/vod/type/id/14/page/{{page}}.html\n学生诱惑::/index.php/vod/type/id/15/page/{{page}}.html\n台湾粉红兔::/index.php/vod/type/id/16/page/{{page}}.html\n\n口交颜射::/index.php/vod/type/id/17/page/{{page}}.html\n女优明星::/index.php/vod/type/id/18/page/{{page}}.html\n翹臀美尻::/index.php/vod/type/id/19/page/{{page}}.html\n亚洲无码::/index.php/vod/type/id/20/page/{{page}}.html\n中文字幕::/index.php/vod/type/id/21/page/{{page}}.html\n熟女人妻::/index.php/vod/type/id/22/page/{{page}}.html\n亚洲有码::/index.php/vod/type/id/23/page/{{page}}.html\n强奸乱伦::/index.php/vod/type/id/24/page/{{page}}.html\n\n巨乳美乳::/index.php/vod/type/id/25/page/{{page}}.html\n制服丝袜::/index.php/vod/type/id/26/page/{{page}}.html\n少女萝莉::/index.php/vod/type/id/27/page/{{page}}.html\n卡通动漫::/index.php/vod/type/id/28/page/{{page}}.html\n东京热::/index.php/vod/type/id/29/page/{{page}}.html\n素人搭讪::/index.php/vod/type/id/31/page/{{page}}.html\n\n国产传媒::/index.php/vod/type/id/32/page/{{page}}.html\n麻豆传媒::/index.php/vod/type/id/33/page/{{page}}.html\n杏吧传媒::/index.php/vod/type/id/34/page/{{page}}.html\n兔子先生::/index.php/vod/type/id/35/page/{{page}}.html\n天美传媒::/index.php/vod/type/id/36/page/{{page}}.html\nSA国际传媒::/index.php/vod/type/id/37/page/{{page}}.html\n性视界::/index.php/vod/type/id/38/page/{{page}}.html\n扣扣传媒::/index.php/vod/type/id/39/page/{{page}}.html\n\n果冻传媒::/index.php/vod/type/id/40/page/{{page}}.html\n星空无限::/index.php/vod/type/id/41/page/{{page}}.html\n精东影业::/index.php/vod/type/id/42/page/{{page}}.html\n葫芦影业::/index.php/vod/type/id/43/page/{{page}}.html\n蜜桃传媒::/index.php/vod/type/id/44/page/{{page}}.html\n起点传媒::/index.php/vod/type/id/45/page/{{page}}.html\n皇家华人::/index.php/vod/type/id/46/page/{{page}}.html\nJVID::/index.php/vod/type/id/47/page/{{page}}.html\n\nSWAG::/index.php/vod/type/id/48/page/{{page}}.html\n水果派::/index.php/vod/type/id/49/page/{{page}}.html\n91传媒::/index.php/vod/type/id/50/page/{{page}}.html\n渡边传媒::/index.php/vod/type/id/51/page/{{page}}.html\n糖心传媒::/index.php/vod/type/id/52/page/{{page}}.html\n乐播传媒::/index.php/vod/type/id/53/page/{{page}}.html\n\n多人群交::/index.php/vod/type/id/54/page/{{page}}.html\nAl换脸::/index.php/vod/type/id/55/page/{{page}}.html\n重口色情::/index.php/vod/type/id/56/page/{{page}}.html\n同性专区::/index.php/vod/type/id/57/page/{{page}}.html\n淫妻绿帽::/index.php/vod/type/id/58/page/{{page}}.html\nTS人妖::/index.php/vod/type/id/59/page/{{page}}.html\nVR视角::/index.php/vod/type/id/60/page/{{page}}.html\n欺辱凌辱::/index.php/vod/type/id/61/page/{{page}}.html\n\n野外激情::/index.php/vod/type/id/62/page/{{page}}.html\nSM调教::/index.php/vod/type/id/63/page/{{page}}.html\n恐怖色情::/index.php/vod/type/id/64/page/{{page}}.html\n海外一区::/\n欧美精品::/index.php/vod/type/id/65/page/{{page}}.html\n韩国主播::/index.php/vod/type/id/66/page/{{page}}.html\n极品媚黑::/index.php/vod/type/id/67/page/{{page}}.html\n",
    "sourceComment": "大爱天尊20251010：修补分类索引与实际分类不匹配，替换源url为目前验证可用的网站\n大爱天尊20251006：修补搜索不能播放\n\n源变量里可以设置要搜索的内容，要搜什么直接填\n\n某些视频播放不了，可以在播放界面，点击右上角三个点，点击用浏览器打开，如果浏览器也播放不了，那就不是源的问题。（一般当天网站更新的视频可能看不了）\n\n部分图片不能显示，是因为网站抓来的视频本来就没图片\n\n源url里面的网站失效了，可以在下面的发布页里面找一个自己能访问的网址替换上去。\n发布页：https://wuxiants.github.io/",
    "sourceGroup": "sex",
    "sourceIcon": "https://images.icon-icons.com/1147/PNG/512/1486486316-arrow-film-movie-play-player-start-video_81236.png",
    "sourceName": "无限臀山失败",
    "sourceUrl": "https://wxts.wuxiants569.com/#大爱"
  },
  {
    "articleStyle": 0,
    "customOrder": -4,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "html",
    "ruleContent": "class.waterfall@html",
    "ruleLink": "html",
    "ruleTitle": "text",
    "singleUrl": false,
    "sourceGroup": "版本",
    "sourceIcon": "天",
    "sourceName": "图",
    "sourceUrl": "https://xn---50ppiccom-xr7r588tmbm.www-50ppic.com/?fuli.one"
  },
  {
    "articleStyle": 0,
    "coverDecodeJs": "java.createSymmetricCrypto(\"AES/CBC/NoPadding\",\"f5d965df75336270\",\"97b60394abc2fbe1\").decrypt(result)",
    "customOrder": -3,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\"User-Agent\":\"Mozilla/5.0 (Linux; U; Android 13; zh-Hans-CN; PFJM10 Build/TP1A.220905.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/135.0.4896.58 Quark/6.13.6.581 Mobile Safari/537.36\",\n\"Accept-Language\":\"zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7\"}",
    "lastUpdateTime": 1775586154133,
    "loadWithBaseUrl": true,
    "ruleArticles": "#body>.container>.row>div[role=\"main\"]>article:not(:has(meta[content=\"广告\"]))>a",
    "ruleContent": "<js>\nvar step1 = java.base64Decode('QGpzOg0KbGV0IHVybHMgPSBbXTsNCmxldCByZXN1bHRTdHIgPSBTdHJpbmcocmVzdWx0KTsNCg0KLy8g566A5YyW5o+Q5Y+WbTN1OA0KbGV0IGdldE0zdTggPSBmdW5jdGlvbigpIHsNCiAgICBsZXQgdXJsU2V0ID0gW107DQogICAgDQogICAgLy8gMS4g5LuOdmlkZW/moIfnrb7mj5Dlj5YNCiAgICBsZXQgdmlkZW9zID0gamF2YS5nZXRFbGVtZW50cygndmlkZW8nKTsNCiAgICBpZiAodmlkZW9zICYmIHZpZGVvcy5sZW5ndGggPiAwKSB7DQogICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdmlkZW9zLmxlbmd0aDsgaSsrKSB7DQogICAgICAgICAgICBsZXQgdiA9IHZpZGVvc1tpXTsNCiAgICAgICAgICAgIGxldCBzcmMgPSBTdHJpbmcodi5hdHRyKCdzcmMnKSk7DQogICAgICAgICAgICBpZiAoc3JjLmluZGV4T2YoJy5tM3U4JykgPiAtMSkgew0KICAgICAgICAgICAgICAgIGlmICh1cmxTZXQuaW5kZXhPZihzcmMpID09PSAtMSkgew0KICAgICAgICAgICAgICAgICAgICB1cmxTZXQucHVzaChzcmMpOw0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0NCiAgICAgICAgfQ0KICAgIH0NCiAgICANCiAgICAvLyAyLiDku45IVE1M5rqQ56CB5o+Q5Y+WDQogICAgbGV0IHJlZ2V4ID0gLyhodHRwcz86W14nIlxzXSo/XC5tM3U4W14nIlxzXSopL2c7DQogICAgbGV0IG1hdGNoOw0KICAgIHdoaWxlICgobWF0Y2ggPSByZWdleC5leGVjKHJlc3VsdFN0cikpICE9PSBudWxsKSB7DQogICAgICAgIGxldCB1cmwgPSBtYXRjaFsxXS5yZXBsYWNlKC9cXC9nLCAiIik7DQogICAgICAgIGlmICh1cmxTZXQuaW5kZXhPZih1cmwpID09PSAtMSkgew0KICAgICAgICAgICAgdXJsU2V0LnB1c2godXJsKTsNCiAgICAgICAgfQ0KICAgIH0NCiAgICANCiAgICByZXR1cm4gdXJsU2V0Ow0KfTsNCg0KLy8g5aSE55CG5YiG6ZuGDQppZiAoL+eCueaIkS8udGVzdChyZXN1bHQpICYmIC/mn6XnnIvor6bmg4UvLnRlc3QocmVzdWx0KSkgew0KICAgIGxldCBsaW5rcyA9IGphdmEuZ2V0RWxlbWVudHMoJ0BAI3Bvc3Q+YXJ0aWNsZT4ucG9zdC1jb250ZW50PnA+YScpOw0KICAgIGxldCB0ZW1wVXJscyA9IFtdOw0KICAgIA0KICAgIGlmIChsaW5rcyAmJiBsaW5rcy5sZW5ndGggPiAwKSB7DQogICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbGlua3MubGVuZ3RoIC0gMTsgaSsrKSB7DQogICAgICAgICAgICBsZXQgaHJlZiA9IFN0cmluZyhsaW5rc1tpXS5hdHRyKCdocmVmJykpOw0KICAgICAgICAgICAgbGV0IGRvYyA9IFN0cmluZyhqYXZhLmFqYXgoc291cmNlLmtleSArIGhyZWYpKTsNCiAgICAgICAgICAgIGxldCBtYXRjaGVzID0gZG9jLm1hdGNoKC8oaHR0cHM/OlteJyJcc10qP1wubTN1OFteJyJcc10qKS9nKTsNCiAgICAgICAgICAgIGlmIChtYXRjaGVzKSB7DQogICAgICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCBtYXRjaGVzLmxlbmd0aDsgaisrKSB7DQogICAgICAgICAgICAgICAgICAgIGxldCB1cmwgPSBtYXRjaGVzW2pdLnJlcGxhY2UoL1xcL2csICIiKTsNCiAgICAgICAgICAgICAgICAgICAgaWYgKHRlbXBVcmxzLmluZGV4T2YodXJsKSA9PT0gLTEpIHsNCiAgICAgICAgICAgICAgICAgICAgICAgIHRlbXBVcmxzLnB1c2godXJsKTsNCiAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0NCiAgICAgICAgfQ0KICAgIH0NCiAgICANCiAgICB1cmxzID0gdGVtcFVybHM7DQp9IGVsc2Ugew0KICAgIHVybHMgPSBnZXRNM3U4KCk7DQp9DQoNCi8vIOWOu+mHje+8iOWGjeasoeehruS/ne+8iQ0KbGV0IGZpbmFsVXJscyA9IFtdOw0KZm9yIChsZXQgaSA9IDA7IGkgPCB1cmxzLmxlbmd0aDsgaSsrKSB7DQogICAgbGV0IHVybCA9IHVybHNbaV07DQogICAgaWYgKHVybCAmJiB1cmwuaW5kZXhPZignLm0zdTgnKSA+IC0xICYmIGZpbmFsVXJscy5pbmRleE9mKHVybCkgPT09IC0xKSB7DQogICAgICAgIGZpbmFsVXJscy5wdXNoKHVybCk7DQogICAgfQ0KfQ0KdXJscyA9IGZpbmFsVXJsczsNCg0KLy8g566A5YyW5pKt5pS+5ZmoDQp2YXIgaHRtbCA9ICc8IURPQ1RZUEUgaHRtbD4nICsNCic8aHRtbD4nICsNCic8aGVhZD4nICsNCiAgICAnPG1ldGEgbmFtZT0idmlld3BvcnQiIGNvbnRlbnQ9IndpZHRoPWRldmljZS13aWR0aCI+JyArDQogICAgJzxzdHlsZT4nICsNCiAgICAgICAgJyogeyBib3gtc2l6aW5nOiBib3JkZXItYm94OyB9JyArDQogICAgICAgICdib2R5IHsgbWFyZ2luOiAwOyBwYWRkaW5nOiAyMHB4OyBiYWNrZ3JvdW5kOiAjZjBmMGYwOyBmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IH0nICsNCiAgICAgICAgJy5jb250YWluZXIgeyBtYXgtd2lkdGg6IDEwMDBweDsgbWFyZ2luOiAwIGF1dG87IGJhY2tncm91bmQ6IHdoaXRlOyBib3JkZXItcmFkaXVzOiAxMHB4OyBvdmVyZmxvdzogaGlkZGVuOyBib3gtc2hhZG93OiAwIDJweCAxMHB4IHJnYmEoMCwwLDAsMC4xKTsgfScgKw0KICAgICAgICAnLmhlYWRlciB7IGJhY2tncm91bmQ6IGxpbmVhci1ncmFkaWVudCgxMzVkZWcsICM2NjdlZWEgMCUsICM3NjRiYTIgMTAwJSk7IGNvbG9yOiB3aGl0ZTsgcGFkZGluZzogMTVweDsgdGV4dC1hbGlnbjogY2VudGVyOyBmb250LXNpemU6IDE2cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyB9JyArDQogICAgICAgICcudmlkZW8td3JhcHBlciB7IHBvc2l0aW9uOiByZWxhdGl2ZTsgd2lkdGg6IDEwMCU7IHBhZGRpbmctdG9wOiA1Ni4yNSU7IC8qIDE2Ojkg5a696auY5q+UICovIGJhY2tncm91bmQ6ICMwMDA7IH0nICsNCiAgICAgICAgJyN2aWRlbyB7IHBvc2l0aW9uOiBhYnNvbHV0ZTsgdG9wOiAwOyBsZWZ0OiAwOyB3aWR0aDogMTAwJTsgaGVpZ2h0OiAxMDAlOyBvYmplY3QtZml0OiBjb250YWluOyB9JyArDQogICAgICAgICcuY29udHJvbHMgeyBkaXNwbGF5OiBmbGV4OyBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47IGFsaWduLWl0ZW1zOiBjZW50ZXI7IHBhZGRpbmc6IDE1cHggMjBweDsgYmFja2dyb3VuZDogI2Y4ZjlmYTsgYm9yZGVyLXRvcDogMXB4IHNvbGlkICNlZWU7IH0nICsNCiAgICAgICAgJy5uYXYtZ3JvdXAgeyBkaXNwbGF5OiBmbGV4OyBnYXA6IDEwcHg7IH0nICsNCiAgICAgICAgJ2J1dHRvbiB7IHBhZGRpbmc6IDEwcHggMjBweDsgYmFja2dyb3VuZDogIzAwN2JmZjsgY29sb3I6IHdoaXRlOyBib3JkZXI6IG5vbmU7IGJvcmRlci1yYWRpdXM6IDVweDsgY3Vyc29yOiBwb2ludGVyOyBmb250LXNpemU6IDE0cHg7IHRyYW5zaXRpb246IGJhY2tncm91bmQgMC4zczsgfScgKw0KICAgICAgICAnYnV0dG9uOmhvdmVyIHsgYmFja2dyb3VuZDogIzAwNTZiMzsgfScgKw0KICAgICAgICAnYnV0dG9uOmRpc2FibGVkIHsgYmFja2dyb3VuZDogIzZjNzU3ZDsgY3Vyc29yOiBub3QtYWxsb3dlZDsgfScgKw0KICAgICAgICAnc2VsZWN0IHsgcGFkZGluZzogMTBweCAxNXB4OyBib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBib3JkZXItcmFkaXVzOiA1cHg7IGZvbnQtc2l6ZTogMTRweDsgYmFja2dyb3VuZDogd2hpdGU7IG1pbi13aWR0aDogMTIwcHg7IH0nICsNCiAgICAgICAgJy5pbmZvIHsgdGV4dC1hbGlnbjogY2VudGVyOyBwYWRkaW5nOiAxMHB4OyBiYWNrZ3JvdW5kOiAjZjVmNWY1OyBjb2xvcjogIzY2NjsgZm9udC1zaXplOiAxNHB4OyB9JyArDQogICAgICAgICcuZnVsbHNjcmVlbi1idG4geyBwYWRkaW5nOiAxMHB4OyBiYWNrZ3JvdW5kOiAjMjhhNzQ1OyB9JyArDQogICAgICAgICcuZnVsbHNjcmVlbi1idG46aG92ZXIgeyBiYWNrZ3JvdW5kOiAjMjE4ODM4OyB9JyArDQogICAgICAgICdAbWVkaWEgKG1heC13aWR0aDogNzY4cHgpIHsnICsNCiAgICAgICAgICAgICdib2R5IHsgcGFkZGluZzogMTBweDsgfScgKw0KICAgICAgICAgICAgJy5jb250YWluZXIgeyBib3JkZXItcmFkaXVzOiA1cHg7IH0nICsNCiAgICAgICAgICAgICcuY29udHJvbHMgeyBmbGV4LWRpcmVjdGlvbjogY29sdW1uOyBnYXA6IDEwcHg7IH0nICsNCiAgICAgICAgICAgICcubmF2LWdyb3VwIHsgd2lkdGg6IDEwMCU7IGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjsgfScgKw0KICAgICAgICAgICAgJ2J1dHRvbiwgc2VsZWN0IHsgd2lkdGg6IDEwMCU7IH0nICsNCiAgICAgICAgJ30nICsNCiAgICAnPC9zdHlsZT4nICsNCic8L2hlYWQ+JyArDQonPGJvZHk+JyArDQogICAgJzxkaXYgY2xhc3M9ImNvbnRhaW5lciI+JyArDQogICAgICAgICc8ZGl2IGNsYXNzPSJoZWFkZXIiPicgKw0KICAgICAgICAgICAgJzxzcGFuIGlkPSJjdXJyZW50Ij4xPC9zcGFuPiAvIDxzcGFuIGlkPSJ0b3RhbCI+JyArIHVybHMubGVuZ3RoICsgJzwvc3Bhbj4g6ZuGJyArDQogICAgICAgICc8L2Rpdj4nICsNCiAgICAgICAgJzxkaXYgY2xhc3M9InZpZGVvLXdyYXBwZXIiPicgKw0KICAgICAgICAgICAgJzx2aWRlbyBjb250cm9scyBhdXRvcGxheSBwbGF5c2lubGluZSBpZD0idmlkZW8iPicgKw0KICAgICAgICAgICAgICAgICc8c291cmNlIHNyYz0iJyArICh1cmxzWzBdIHx8ICcnKSArICciIHR5cGU9ImFwcGxpY2F0aW9uL3gtbXBlZ1VSTCI+JyArDQogICAgICAgICAgICAgICAgJ+aCqOeahOa1j+iniOWZqOS4jeaUr+aMgeinhumikeaSreaUvicgKw0KICAgICAgICAgICAgJzwvdmlkZW8+JyArDQogICAgICAgICc8L2Rpdj4nICsNCiAgICAgICAgJzxkaXYgY2xhc3M9ImNvbnRyb2xzIj4nICsNCiAgICAgICAgICAgICc8ZGl2IGNsYXNzPSJuYXYtZ3JvdXAiPicgKw0KICAgICAgICAgICAgICAgICc8YnV0dG9uIG9uY2xpY2s9ImNoYW5nZVZpZGVvKC0xKSIgaWQ9InByZXZCdG4iPuS4iuS4gOmbhjwvYnV0dG9uPicgKw0KICAgICAgICAgICAgICAgICc8c2VsZWN0IG9uY2hhbmdlPSJqdW1wVG9WaWRlbyh0aGlzLnZhbHVlKSIgaWQ9InZpZGVvU2VsZWN0Ij4nOw0KDQovLyDnlJ/miJDpgInpobkNCmZvciAobGV0IGkgPSAwOyBpIDwgdXJscy5sZW5ndGg7IGkrKykgew0KICAgIGh0bWwgKz0gJzxvcHRpb24gdmFsdWU9IicgKyBpICsgJyI+56ysICcgKyAoaSArIDEpICsgJyDpm4Y8L29wdGlvbj4nOw0KfQ0KDQpodG1sICs9ICc8L3NlbGVjdD4nICsNCiAgICAgICAgICAgICAgICAnPGJ1dHRvbiBvbmNsaWNrPSJjaGFuZ2VWaWRlbygxKSIgaWQ9Im5leHRCdG4iPuS4i+S4gOmbhjwvYnV0dG9uPicgKw0KICAgICAgICAgICAgJzwvZGl2PicgKw0KICAgICAgICAgICAgJzxidXR0b24gb25jbGljaz0idG9nZ2xlRnVsbHNjcmVlbigpIiBjbGFzcz0iZnVsbHNjcmVlbi1idG4iPuWFqOWxjzwvYnV0dG9uPicgKw0KICAgICAgICAnPC9kaXY+JyArDQogICAgICAgICc8ZGl2IGNsYXNzPSJpbmZvIj7mib7liLAgJyArIHVybHMubGVuZ3RoICsgJyDkuKrop4bpopHmupA8L2Rpdj4nICsNCiAgICAnPC9kaXY+JyArDQoNCiAgICAnPHNjcmlwdD4nICsNCiAgICAgICAgJ3ZhciB2aWRlb1VybHMgPSAnICsgSlNPTi5zdHJpbmdpZnkodXJscykgKyAnOycgKw0KICAgICAgICAndmFyIGN1cnJlbnRJbmRleCA9IDA7JyArDQogICAgICAgICd2YXIgdmlkZW8gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgidmlkZW8iKTsnICsNCiAgICAgICAgJ3ZhciB2aWRlb1NlbGVjdCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCJ2aWRlb1NlbGVjdCIpOycgKw0KICAgICAgICAndmFyIGN1cnJlbnRTcGFuID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoImN1cnJlbnQiKTsnICsNCiAgICAgICAgJ3ZhciB0b3RhbFNwYW4gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgidG90YWwiKTsnICsNCiAgICAgICAgJ3ZhciBwcmV2QnRuID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoInByZXZCdG4iKTsnICsNCiAgICAgICAgJ3ZhciBuZXh0QnRuID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoIm5leHRCdG4iKTsnICsNCiAgICAgICAgJycgKw0KICAgICAgICAnZnVuY3Rpb24gdXBkYXRlVUkoKSB7JyArDQogICAgICAgICAgICAnY3VycmVudFNwYW4udGV4dENvbnRlbnQgPSBjdXJyZW50SW5kZXggKyAxOycgKw0KICAgICAgICAgICAgJ3RvdGFsU3Bhbi50ZXh0Q29udGVudCA9IHZpZGVvVXJscy5sZW5ndGg7JyArDQogICAgICAgICAgICAndmlkZW9TZWxlY3QudmFsdWUgPSBjdXJyZW50SW5kZXg7JyArDQogICAgICAgICAgICAncHJldkJ0bi5kaXNhYmxlZCA9IGN1cnJlbnRJbmRleCA9PT0gMDsnICsNCiAgICAgICAgICAgICduZXh0QnRuLmRpc2FibGVkID0gY3VycmVudEluZGV4ID09PSB2aWRlb1VybHMubGVuZ3RoIC0gMTsnICsNCiAgICAgICAgICAgICd2aWRlby5zcmMgPSB2aWRlb1VybHNbY3VycmVudEluZGV4XTsnICsNCiAgICAgICAgICAgICd2aWRlby5sb2FkKCk7JyArDQogICAgICAgICd9JyArDQogICAgICAgICcnICsNCiAgICAgICAgJ2Z1bmN0aW9uIGNoYW5nZVZpZGVvKGRpcmVjdGlvbikgeycgKw0KICAgICAgICAgICAgJ3ZhciBuZXdJbmRleCA9IGN1cnJlbnRJbmRleCArIGRpcmVjdGlvbjsnICsNCiAgICAgICAgICAgICdpZiAobmV3SW5kZXggPj0gMCAmJiBuZXdJbmRleCA8IHZpZGVvVXJscy5sZW5ndGgpIHsnICsNCiAgICAgICAgICAgICAgICAnY3VycmVudEluZGV4ID0gbmV3SW5kZXg7JyArDQogICAgICAgICAgICAgICAgJ3VwZGF0ZVVJKCk7JyArDQogICAgICAgICAgICAnfScgKw0KICAgICAgICAnfScgKw0KICAgICAgICAnJyArDQogICAgICAgICdmdW5jdGlvbiBqdW1wVG9WaWRlbyhpbmRleCkgeycgKw0KICAgICAgICAgICAgJ2N1cnJlbnRJbmRleCA9IHBhcnNlSW50KGluZGV4KTsnICsNCiAgICAgICAgICAgICd1cGRhdGVVSSgpOycgKw0KICAgICAgICAnfScgKw0KICAgICAgICAnJyArDQogICAgICAgICdmdW5jdGlvbiB0b2dnbGVGdWxsc2NyZWVuKCkgeycgKw0KICAgICAgICAgICAgJ2lmICghZG9jdW1lbnQuZnVsbHNjcmVlbkVsZW1lbnQpIHsnICsNCiAgICAgICAgICAgICAgICAnaWYgKHZpZGVvLnJlcXVlc3RGdWxsc2NyZWVuKSB7JyArDQogICAgICAgICAgICAgICAgICAgICd2aWRlby5yZXF1ZXN0RnVsbHNjcmVlbigpOycgKw0KICAgICAgICAgICAgICAgICd9IGVsc2UgaWYgKHZpZGVvLndlYmtpdFJlcXVlc3RGdWxsc2NyZWVuKSB7JyArDQogICAgICAgICAgICAgICAgICAgICd2aWRlby53ZWJraXRSZXF1ZXN0RnVsbHNjcmVlbigpOycgKw0KICAgICAgICAgICAgICAgICd9IGVsc2UgaWYgKHZpZGVvLm1velJlcXVlc3RGdWxsU2NyZWVuKSB7JyArDQogICAgICAgICAgICAgICAgICAgICd2aWRlby5tb3pSZXF1ZXN0RnVsbFNjcmVlbigpOycgKw0KICAgICAgICAgICAgICAgICd9JyArDQogICAgICAgICAgICAnfSBlbHNlIHsnICsNCiAgICAgICAgICAgICAgICAnaWYgKGRvY3VtZW50LmV4aXRGdWxsc2NyZWVuKSB7JyArDQogICAgICAgICAgICAgICAgICAgICdkb2N1bWVudC5leGl0RnVsbHNjcmVlbigpOycgKw0KICAgICAgICAgICAgICAgICd9IGVsc2UgaWYgKGRvY3VtZW50LndlYmtpdEV4aXRGdWxsc2NyZWVuKSB7JyArDQogICAgICAgICAgICAgICAgICAgICdkb2N1bWVudC53ZWJraXRFeGl0RnVsbHNjcmVlbigpOycgKw0KICAgICAgICAgICAgICAgICd9IGVsc2UgaWYgKGRvY3VtZW50Lm1vekNhbmNlbEZ1bGxTY3JlZW4pIHsnICsNCiAgICAgICAgICAgICAgICAgICAgJ2RvY3VtZW50Lm1vekNhbmNlbEZ1bGxTY3JlZW4oKTsnICsNCiAgICAgICAgICAgICAgICAnfScgKw0KICAgICAgICAgICAgJ30nICsNCiAgICAgICAgJ30nICsNCiAgICAgICAgJycgKw0KICAgICAgICAnLy8g5Yid5aeL5YyWJyArDQogICAgICAgICd1cGRhdGVVSSgpOycgKw0KICAgICAgICAnJyArDQogICAgICAgICcvLyDplK7nm5jlv6vmjbfplK4nICsNCiAgICAgICAgJ2RvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoImtleWRvd24iLCBmdW5jdGlvbihlKSB7JyArDQogICAgICAgICAgICAnaWYgKGUua2V5ID09PSAiQXJyb3dMZWZ0IikgY2hhbmdlVmlkZW8oLTEpOycgKw0KICAgICAgICAgICAgJ2Vsc2UgaWYgKGUua2V5ID09PSAiQXJyb3dSaWdodCIpIGNoYW5nZVZpZGVvKDEpOycgKw0KICAgICAgICAgICAgJ2Vsc2UgaWYgKGUua2V5ID09PSAiZiIgfHwgZS5rZXkgPT09ICJGIikgdG9nZ2xlRnVsbHNjcmVlbigpOycgKw0KICAgICAgICAnfSk7JyArDQogICAgICAgICcnICsNCiAgICAgICAgJy8vIOinhumikemUmeivr+WkhOeQhicgKw0KICAgICAgICAndmlkZW8uYWRkRXZlbnRMaXN0ZW5lcigiZXJyb3IiLCBmdW5jdGlvbigpIHsnICsNCiAgICAgICAgICAgICdjb25zb2xlLmxvZygi6KeG6aKR5Yqg6L296ZSZ6K+v77yM5bCd6K+V5YiH5o2i5Yiw5LiL5LiA5LiqIik7JyArDQogICAgICAgICAgICAnaWYgKGN1cnJlbnRJbmRleCA8IHZpZGVvVXJscy5sZW5ndGggLSAxKSB7JyArDQogICAgICAgICAgICAgICAgJ2N1cnJlbnRJbmRleCsrOycgKw0KICAgICAgICAgICAgICAgICd1cGRhdGVVSSgpOycgKw0KICAgICAgICAgICAgJ30nICsNCiAgICAgICAgJ30pOycgKw0KICAgICc8L3NjcmlwdD4nICsNCic8L2JvZHk+JyArDQonPC9odG1sPic7DQoNCmh0bWw7');\nvar step2 = java.getString(step1);\nresult = step2\n</js>",
    "ruleImage": "@js:\nvar text = java.getString('script@html');\nvar match = text.match(/loadBannerDirect\\('([^']+)'/);\nvar img = match ? match[1] : '';\nimg;",
    "ruleLink": "href",
    "ruleNextPage": "page",
    "rulePubDate": "{{@@.wraps@text}}{{@@.post-card-info span@text##\\n}}",
    "ruleTitle": "h2@text",
    "singleUrl": false,
    "sortUrl": "搜索::/search/{{source.getVariable()}}/{{page}}/\n首页::/page/{{page}}/\n今日看料::/category/24hcg/{{page}}/\n热门吃瓜::/category/rgtj/{{page}}/\n每日热瓜::/category/mrrg/{{page}}/\n反差女神::/category/fcns/{{page}}/\n学院热瓜::/category/xyrg/{{page}}/\n网红吃瓜::/category/whhl/{{page}}/\n每日大赛::/category/mrds/{{page}}/\n海角乱伦::/category/llsq/{{page}}/\n黑料大事::/category/hlda/{{page}}/\n撸友看片::/category/lydt/{{page}}/\n黑料杂谈::/category/hlzt/{{page}}/\nav解说::/category/avjs/{{page}}/\n禁播动漫::/category/mrst/{{page}}/\n性爱技巧::/category/wyxs/{{page}}/\n爽文短剧::/category/swdj/{{page}}/\n明星吃瓜::/category/mxbg/{{page}}/\n官场秘闻::/category/gcmw/{{page}}/\n学生::/search/学生/{{page}}/\n全部①::/<,page/{{page}}/>\n全部②::/page/3/\n全部③::/page/5/\n偷情::/search/偷情/{{page}}/\n白虎::/search/白虎/{{page}}/\n反差::/search/反差/{{page}}/\n极品::/search/极品/{{page}}/\n萝莉::/search/萝莉/{{page}}/\n00后::/search/00后/{{page}}/\n女同::/search/女同/{{page}}/\n双马尾::/search/双马尾/{{page}}/\n学院::/search/学院/{{page}}/\n高三::/search/高三/{{page}}/\n高中::/search/高中/{{page}}/\n少女::/search/少女/{{page}}/\n情趣::/search/情趣/{{page}}/\n自拍::/search/自拍/{{page}}/\n大学::/search/大学/{{page}}/\n大一::/search/大一/{{page}}/\n学妹::/search/学妹/{{page}}/\n校花::/search/校花/{{page}}/\n调教::/search/调教/{{page}}/\n女神::/search/女神/{{page}}/\n少妇::/search/少妇/{{page}}/\n巨乳::/search/巨乳/{{page}}/\n孕妇::/search/孕妇/{{page}}/\n口::/search/口交/{{page}}/\n精::/search/精/{{page}}/",
    "sourceGroup": "版本",
    "sourceIcon": "https://i1.wp.com/i.postimg.cc/wjL5myHr/kpptube-cc-3e997cb42a6b0f37af6c6a40866ba202.gif",
    "sourceName": "2.2",
    "sourceUrl": "https://wiki.cvgdpnvq.xyz/",
    "style": "iframe{\n\theight:600px\n}\ntitle{\n\tdisplay:block\n}"
  },
  {
    "articleStyle": 0,
    "customOrder": -2,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 1775590497300,
    "loadWithBaseUrl": true,
    "ruleArticles": "article",
    "ruleContent": "class.dplayer@all<js>\nresult=result.match(/http.*m3u8/)[0]##\\</js>{{@@title@text##正在播放:|永久.*}}\n<video src=\"{{result}}\" width=\"100%\" height=\"auto\" controls></video>",
    "ruleImage": "@js:\"https://mgtv-bbqn.oss-cn-beijing.aliyuncs.com/1/2310310103284A29582395A850D3A0F5C26862354MzFE/SrRlbr0.gif\"",
    "ruleLink": "a.0@href",
    "ruleNextPage": "page",
    "rulePubDate": "class.post-card-info@text",
    "ruleTitle": "h2@text##热榜.*",
    "singleUrl": false,
    "sortUrl": "学生::/search/学生/{{page}}/\n全部①::/<,page/{{page}}/>\n全部②::/page/3/\n全部③::/page/5/\n搜索::/search/{{source.getVariable()}}/{{page}}/\n偷情::/search/偷情/{{page}}/\n白虎::/search/白虎/{{page}}/\n反差::/search/反差/{{page}}/\n极品::/search/极品/{{page}}/\n萝莉::/search/萝莉/{{page}}/\n00后::/search/00后/{{page}}/\n女同::/search/女同/{{page}}/\n双马尾::/search/双马尾/{{page}}/\n学院::/search/学院/{{page}}/\n高三::/search/高三/{{page}}/\n高中::/search/高中/{{page}}/\n少女::/search/少女/{{page}}/\n情趣::/search/情趣/{{page}}/\n自拍::/search/自拍/{{page}}/\n大学::/search/大学/{{page}}/\n大一::/search/大一/{{page}}/\n学妹::/search/学妹/{{page}}/\n校花::/search/校花/{{page}}/\n调教::/search/调教/{{page}}/\n女神::/search/女神/{{page}}/\n少妇::/search/少妇/{{page}}/\n巨乳::/search/巨乳/{{page}}/\n孕妇::/search/孕妇/{{page}}/\n口::/search/口交/{{page}}/\n精::/search/精/{{page}}/",
    "sourceComment": "//多个视频不会写\n发:https://heiliao.su",
    "sourceGroup": "美涩",
    "sourceIcon": "http://p6.itc.cn/images01/20201202/8d012ed623d647a78635557e7d235ab6.jpeg",
    "sourceName": "黑料不打洋🥝无法加载",
    "sourceUrl": "https://heiliao1076.pro/"
  },
  {
    "articleStyle": 0,
    "customOrder": -1,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "class.listing-videos@li",
    "ruleContent": "<js>\ntitle=java.getElements('title').text()\nresult=java.getElements('class.flowplayer').attr('data-item')\nresult=result.match(/src\":\"(.*)\",\"type\":/)[1]\nif(result){\n\tjava.toast('🔞视频链接获取成功！\\n加载稍慢，请耐心等待\\nby 银河中的咸鱼')\nresult=result.replace(/\\\\/g,'')\nresult = \"<video src=\\\"\" + result + \"\\\" width=\\\"100%\\\" height=\\\"auto\\\" controls=\\\"controls\\\" autoplay=\\\"autoplay\\\"></video>\";\r\nresult = \"<html><head><meta charset=\\\"utf-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no\\\" /><style>html,body{margin:0;padding:0;width:100%;}</style></head><body>\" + result + \"<h4>\"+title+\"</h4>\"+ \"</body></html>\"\n result\n}else{\n\tjava.toast('🔞视频链接获取失败❗️\\nby 银河中的咸鱼')\n}\n</js>",
    "ruleImage": "img@src",
    "ruleLink": "a.0@href##/$##\n<js>\nif(!result.match(/sub-eng/)){\n\tresult=result+\"-episode-1-sub-eng/\"\n}else{\n\tresult\n}\n</js>",
    "ruleNextPage": "page",
    "rulePubDate": "class.time-infos@text##^##时长：",
    "ruleTitle": "a@text",
    "singleUrl": false,
    "sortUrl": "搜索::https://www.xanimeporn.com/page/{{page}}/?s={{source.getVariable()}}\n播放量::https://www.xanimeporn.com/page/{{page}}/?filtre=views&cat=0\n评分::https://www.xanimeporn.com/page/{{page}}/?filtre=rate&cat=0\n最新::https://www.xanimeporn.com/page/{{page}}/?display=tube&filtre=date\n时长::https://www.xanimeporn.com/page/{{page}}/?display=tube&filtre=duree",
    "sourceGroup": "h",
    "sourceIcon": "https://img1.baidu.com/it/u=2189826692,2238731457&fm=253&fmt=auto?w=500&h=500",
    "sourceName": "XAnime失败",
    "sourceUrl": "https://www.xanimeporn.com/"
  },
  {
    "articleStyle": 3,
    "customOrder": 0,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 1775588940919,
    "loadWithBaseUrl": true,
    "ruleArticles": "[class=\"box\"]@a",
    "ruleContent": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<title>内容提取</title>\n<!-- v2025.05.10 -->\n\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<script src=\"https://code.jquery.com/jquery-3.6.0.min.js\"></script>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.3/viewer.min.css\" />\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.3/viewer.min.js\"></script>\n<style>\n    body { font-family: Arial, sans-serif; font-size: 16px; }\n    #title, #page, #loading-status { margin: 0 auto; font-size: 20px; text-align: center; }\n    #description, #urls, #video-url, #video-sources, #messages { width: 100%; max-width: 800px; margin: 1.5px auto; font-size: 14px; text-align: left; word-wrap: break-word; white-space: pre-wrap; }\n    #text, #text :not(img), #text img + * { text-indent: 2em; width: 100%; font-size: 16px; line-height: 1.5em; margin-top: 0; margin-bottom: 0; word-wrap: break-word; white-space: pre-wrap; }\n    img, #text img { width: 100%; height: auto; display: block; margin-bottom: 1.5px; }\n    .flex-container { display: flex; justify-content: center; align-items: center; gap: 10px; margin: 1.5px 0; font-size: 14px; }\n    button, select { flex: 1 1 31%; padding: 3px; border: 1px solid #ccc; border-radius: 5px; box-sizing: border-box; cursor: pointer; background-color: #f9f9f9; transition: background-color 0.3s ease; margin: 1.5px; min-width: 0; font-size: 14px; }\n    #url-select, #video-source-select { flex: 1 1 100%; margin-left: 0; margin-right: 0; text-align: center; }\n    #video-element { width: 100%; height: auto; }\n    textarea { width: 100%; height: auto; min-height: 100px; box-sizing: border-box; resize: vertical; }\n    .error, .warn { color: red; }\n</style>\n</head>\n<body>\n    <h3 id=\"title\">{{@@title@text||h1.0@text||h2.0@text||.title.0@text}}</h3>\n    <p id=\"description\">{{@@.info.0@html||.jianjie@html}}</p>\n    <p id=\"page\" style=\"display:none;\">共<span id=\"total-pages\">1</span>页</p>\n    <p id=\"loading-status\" style=\"display:none;\"></p>\n\n    <div class=\"flex-container\" id=\"loading-buttons\" style=\"display:none;\">\n        <button id=\"prev-page-btn\">上一页</button>\n        <button id=\"next-page-btn\">下一页</button>\n        <button id=\"auto-load-btn\">自&nbsp;&nbsp;动</button>\n    </div>\n    \n    <div class=\"flex-container\">\n        <select id=\"url-select\" style=\"display:none;\"></select>\n    </div>\n    \n    <div class=\"flex-container\">\n        <button id=\"toggle-urls-btn\">显/隐网址</button>\n        <button id=\"toggle-messages-btn\">显/隐信息</button>\n        <button id=\"toggle-debug-btn\">显/隐调试</button>\n    </div>\n    <div id=\"urls\"></div>\n    <div id=\"messages\"></div>\n    <div id=\"debug-info\"></div>\n    <div id=\"video-url\"></div>\n    <div id=\"video-container\" style=\"display: none;\">\n        <video id=\"video-element\" controls preload=\"auto\" width=\"640\" height=\"264\">\n            <source id=\"video-source\" src=\"\" type=\"\">您的浏览器不支持 video 标签。\n        </video>\n    </div>\n    <div class=\"flex-container\" id=\"video-source-container\" style=\"display: none;\">\n        <select id=\"video-source-select\" onchange=\"updateVideoSource()\"></select>\n    </div>\n    <div id=\"images\"></div>\n    <div id=\"text\"></div>\n\n    <script>\n        // 配置对象，包含各种选择器、延迟时间等配置项\n        const config = {    \n            videoSelector: 'body', // 视频选择器\n            imgSelector: '.gridlane-box-inside img,.photos figure img,.content p img', // 图片选择器\n            textSelector: '#content', // 文本选择器\n            debugSelector: '#content, .page, .pager, .content, script', // 调试信息选择器\n            swapImageAttributes: false, // 是否交换图片属性\n            delayTime: 1500, // 延迟提取时间\n            retryDelayTime: 1500, // 重试加载延迟时间\n            maxLoadAttempts: 3, // 最大加载次数\n            autoLoading: false, // true自动模式，false单页模式\n            debugOnce: 0, // 只在特定索引输出一次调试信息\n            totalPagesText: '{{@@.page.0@a.-2@textNodes}}', // 总页码\n            urlSuffixToRemove: /\\.html$/, // 移除url后缀\n            pageUrlText: '{urlPrefix}_{i}.html', // 拼接URL模板        \n            ListMode: true, // true网址列表模式，false网址拼接模式    \n            initialUrls: `{{@@#sort-item-5.0@a@href}}`, // 网址\n            initialUrlsName: `{{@@#sort-item-5.0@a@span@text}}`, // 网址名称\n            sourceurl: '', // 来源URL前缀\n        };\n\n        let videoSources = []; // 存储视频源数组\n        let loadAttempts = {}; // 记录每个URL的加载尝试次数\n        let urls = []; // 存储所有页面的URL\n        let imageBox;\n        let textBox;\n        let currentPageIndex = 0; // 当前页面索引\n        let canLoadNextPage = true; // 控制是否可以加载下一页\n        let autoLoadInProgress = false; // 自动加载状态\n\n        // 构建URL列表\n        function buildUrls(totalPages, baseUrl) {\n            let initialUrlsArray = config.initialUrls.trim().split('\\n').filter(url => url.trim() !== '');\n            let initialUrlsNameArray = config.initialUrlsName.trim().split('\\n').filter(name => name.trim() !== '');\n\n            if (config.ListMode && initialUrlsArray.length > 0) {\n                if (initialUrlsArray.length !== initialUrlsNameArray.length) {\n                    $('#messages').append(`<span class=\"warn\">警告：initialUrls 和 initialUrlsName 的长度不匹配。</span><br>`);\n                }\n\n                urls = initialUrlsArray.map(url => {\n                    if (config.sourceurl && url.startsWith('/') && !/^https?:\\/\\//i.test(url)) {\n                        return config.sourceurl.replace(/\\/$/, '') + url;\n                    } else {\n                        return url;\n                    }\n                });\n\n                urls.forEach((url, index) => {\n                    const name = initialUrlsNameArray[index] || `第 ${index + 1} 页`;\n                    $('#url-select').append(`<option value=\"${index}\">${name}</option>`);\n                    $('#urls').append(`<div>${name}: ${url}</div>`);\n                });\n            } else {\n                if (totalPages === 1) {\n                    urls.push(baseUrl);\n                } else {\n                    urls.push(baseUrl);\n                    for (let i = 2; i <= totalPages; i++) {\n                        urls.push(config.pageUrlText.replace('{urlPrefix}', baseUrl.replace(config.urlSuffixToRemove, '').replace(/\\/$/, '')).replace('{i}', i));\n                    }\n                }\n\n                urls.forEach((url, index) => {\n                    const name = `第 ${index + 1} 页`;\n                    $('#url-select').append(`<option value=\"${index}\">${name}</option>`);\n                    $('#urls').append(`<div>${name}: ${url}</div>`);\n                });\n            }\n\n            $('#total-pages').text(urls.length);\n            toggleNavigationButtons();\n            toggleTotalPagesDisplay();\n        }\n\n        // 规范化URL\n        function normalizeUrl(url) {\n            if (typeof url !== 'string' || !url.trim()) {\n                return '';\n            }\n            const match = url.match(/['\"](.*?)['\"]/);\n            if (match && match[1]) {\n                url = match[1];\n            }\n\n            function processUrl(str) {\n                str = str.trim();\n                str = str.replace(/\\\\u[\\dA-F]{4}/gi, match => String.fromCharCode(parseInt(match.replace(/\\\\u/g, ''), 16)));\n                str = decodeURIComponent(str);\n                str = str.replace(/^http:\\/([^/])/, 'http://$1');\n                str = str.replace(/^https:\\/([^/])/, 'https://$1');\n                return str;\n            }\n            return processUrl(url);\n        }\n\n        // 清空容器内容\n        function clearContainers() {\n            $('#messages').empty();\n            $('#images').empty();\n            $('#text').empty();\n        }\n\n        // 更新图像源\n        function updateImageSrc(elements, shouldSwap) {\n            elements.each(function () {\n                const $this = $(this);\n                const attrsToUpdate = {};\n                if (shouldSwap) {\n                    ['data-original', 'data-src', 'data-url'].forEach(attr => {\n                        if ($this.attr(attr)) {\n                            attrsToUpdate['src'] = $this.attr(attr);\n                        }\n                    });\n                }\n                $this.attr(attrsToUpdate);\n            });\n            return elements;\n        }\n\n        // 切换导航按钮显示状态\n        function toggleNavigationButtons() {\n            if ($('#url-select option').length > 1 && !config.autoLoading) {\n                $('#loading-buttons').show();\n                $('#url-select').show();\n            } else {\n                $('#loading-buttons').hide();\n                $('#url-select').hide();\n            }\n        }\n\n        // 显示加载状态\n        function showLoadingStatus(pageNumber) {\n            const selectedOption = $('#url-select option:selected').text();\n            $('#loading-status').text(`正在加载：${selectedOption}`).show();\n        }\n\n        // 隐藏加载状态\n        function hideLoadingStatus() {\n            $('#loading-status').hide();\n        }\n\n        // 加载指定索引的内容\n        function loadContent(index) {\n            if (index < 0 || index >= urls.length || !canLoadNextPage) return;\n            canLoadNextPage = false;\n            currentPageIndex = index;\n            $('#url-select').val(index);\n            $('#messages').append(`<div>当前地址: <span class=\"warn\">${urls[index]}</span></div>`);\n            if (autoLoadInProgress) {\n                showLoadingStatus(index + 1);\n            }\n            $.ajax({\n                url: urls[index],\n                type: 'GET',\n                success: function (data) {\n                    try {\n                    const $data = $(data);\n                    let updatedHtmlContent = data.replace(/(['\"])(\\/\\/)(?!\\/)/g, '$1https://')\n                        .replace(/src=\"upload/gi, 'src=\"/upload')\n                        .replace(/style=[\"'][^'\"]+[\"']/gi, '')\n                        .replace(/\\\\\\//g, '/');\n                    const parser = new DOMParser();\n                    const doc = parser.parseFromString(updatedHtmlContent, \"text/html\");\n\n                    if (config.debugOnce === index) {\n                        const debugElements = $(doc).find(config.debugSelector);\n                        if (debugElements.length > 0) {\n                            const debugContents = $('<pre>').html(debugElements.clone().wrapAll('<div/>').parent().html()).html();\n                            $('#debug-info').html(`<span class=\"warn\">调试信息: <textarea rows=\"10\" cols=\"80\">${debugContents}</textarea></span>`);\n                        } else {\n                            $('#debug-info').html(`<span class=\"warn\">调试信息: <textarea rows=\"10\" cols=\"80\">调试信息未提取到内容，请检查选择器！</textarea></span>`);\n                        }\n                    }\n                    // 方法1：提取视频\n                    const videoSources1 = [];\n                    const videoContents = $(doc).find(config.videoSelector);\n                    const videoTags = $(videoContents).find('video, source');\n                    videoTags.each(function() {\n                        const videosrc = $(this).attr('src') || \n                                     $(this).attr('data-src') || \n                                     $(this).attr('data-original') || '';\n                        \n                        if (videosrc) {\n                            videoSources1.push(videosrc);\n                        }\n                    });\n                    //反馈\n                    if (videoSources1.length > 0) {\n                        $('#messages').append(`<span>方法1，找到 ${videoSources1.length} 个视频。</span><br>`);\n                    }\n\n                    // 方法2：正则提取视频\n                    const regex = /['\"]https?[^'<>\"]+(m3u8|mp4|webm|ogg|flv|mp3|m4a|wav|ape|flac)([^'<>\"]+)?['\"]/gi;\n                    const matches = data.match(regex);\n                    const videoSources2 = [];\n\n                    if (matches) {\n                        const uniqueMatches = [...new Set(matches)];\n                    \n                        uniqueMatches.forEach(match => {\n                            const normalizedSrc = normalizeUrl(match.replace(/['\"]/g, ''));\n                            videoSources2.push(normalizedSrc);\n                        });\n                    }\n                    //反馈\n                    if (videoSources2.length > 0) {\n                        $('#messages').append(`<span>方法2，找到 ${videoSources2.length} 个视频。</span><br>`);\n                    }\n\n                    // 合并两种方法的结果\n                    videoSources = [...videoSources1, ...videoSources2];\n\n                    // 去重并标准化 URL\n                    const imageExtensions = /\\.(jpg|jpeg|png|gif|bmp|svg)$/i;\n\n                    videoSources = videoSources\n                                  .map(src => normalizeUrl(src.replace(/\\\\+/g, '')))\n                                  .filter(src => src) // 过滤空值\n                                  .filter(src => !imageExtensions.test(src)); // 移除图片地址\n                        \n                    videoSources = [...new Set(videoSources)];// 去重\n\n                    // 显示最终结果\n                    $('#messages').append(`<span>总共找到 ${videoSources.length} 个视频。</span><br>`);\n\n                    if (videoSources.length > 0) {\n                        $('#messages').append(`<span>成功提取到视频，找到 ${videoSources.length} 个视频。</span><br>`);\n                        videoSources.forEach((src, idx) => {\n                            $('#messages').append(`<div>视频地址:<span class=\"warn\"> ${src}</span><br></div>`);\n                            $('#video-source-select').append(`<option value=\"${idx}\">视频源 ${idx + 1}</option>`);\n                        });\n                    \n                        if (videoSources.length == 1) {\n                            $('#video-container').show();\n                            $('#video-url').show();\n                            $('#video-source-container').hide();\n                            updateVideoSource();\n                        } else if (videoSources.length > 1) {\n                            $('#video-container').show();\n                            $('#video-url').show();\n                            $('#video-source-container').show();\n                            updateVideoSource();\n                        } else {\n                            $('#video-container').hide();\n                            $('#video-url').hide();\n                            $('#video-source-container').hide();\n                        }\n                    } else {\n                        $('#messages').append(`<span class=\"warn\">未找到视频源。</span><br>`);\n                        $('#video-container').hide();\n                        $('#video-url').hide();\n                        $('#video-source-container').hide();\n                    }\n\n                    //提取图片\n                    const $imgContents = $(doc).find(config.imgSelector);\n                    const shouldSwap = config.swapImageAttributes;\n                    const newContents = updateImageSrc($imgContents.clone(), shouldSwap);\n                    $('#images').append(newContents).show();\n                    if (newContents.length > 0) {\n                        $('#messages').append(`<span>成功提取图片，共 ${newContents.length} 张。</span><br>`);\n                        newContents.each(function () {\n                            const imgSrc = $(this).attr('src') || $(this).attr('data-original') || $(this).attr('data-src') || $(this).attr('data-url');\n                            $('#messages').append(`<div>地址:<span class=\"warn\"> ${imgSrc}</span><br></div>`);\n                        });\n                    } else {\n                        $('#messages').append(`<span class=\"warn\">未提取到图片。</span><br>`);\n                    }\n\n                    //提取图片和文本\n                    const textContents = $(doc).find(config.textSelector).map(function () {\n                        const $currentContents = $(this);\n                        $currentContents.find('img + br, script, video, source, iframe').remove();\n                        $currentContents.html($currentContents.html().replace(/>\\s+/gi, '>').replace(/<\\/?br\\s*([^>]*)\\s*\\/?>/gi, '\\n').replace(/\\n+/g, '\\n'));\n                        return $currentContents.html();\n                    }).get().join('');\n                    if (textContents.trim()) {\n                        $('#text').append(`<span>${textContents}</span><br>`).show();\n                        $('#messages').append(`<span>成功提取图文。</span><br>`);\n                    } else {\n                        $('#messages').append(`<span class=\"warn\">未提取到图文。</span><br>`);\n                    }\n\n                    if (autoLoadInProgress && currentPageIndex < urls.length - 1) {\n                        setTimeout(() => { \n                            canLoadNextPage = true;\n                            loadContent(currentPageIndex + 1); \n                        }, config.delayTime);\n                    } else {\n                        canLoadNextPage = true;\n                        if (autoLoadInProgress) {\n                            hideLoadingStatus();\n                        }\n                    }\n                } catch (parseError) {\n                    $('#messages').append(`<span class=\"error\">解析页面内容时发生错误: ${parseError.message}</span><br>`);\n                    handleLoadFailure(urls, index);\n                } finally {\n                    if (imageBox) imageBox.viewer.update();\n                    if (textBox) textBox.viewer.update();\n                }\n            },\n            error: function (jqXHR, textStatus, errorThrown) {\n                let errorMessage = `内容加载失败: ${urls[index]}`;\n                switch (textStatus) {\n                    case 'timeout':\n                        errorMessage += ', 请求超时';\n                        break;\n                    case 'abort':\n                        errorMessage += ', 请求被取消';\n                        break;\n                    case 'parsererror':\n                        errorMessage += ', 解析响应出错';\n                        break;\n                    default:\n                        errorMessage += `, 状态码: ${jqXHR.status}, 错误信息: ${errorThrown}`;\n                        break;\n                }\n                $('#messages').append(`<span class=\"error\">${errorMessage}</span><br>`);\n                handleLoadFailure(urls, index);\n                }\n            });\n        }\n\n        // 处理加载失败的情况\n        function handleLoadFailure(urls, index) {\n            if (!loadAttempts[urls[index]]) {\n                loadAttempts[urls[index]] = 1;\n            } else {\n                loadAttempts[urls[index]]++;\n            }\n            if (loadAttempts[urls[index]] <= config.maxLoadAttempts) {\n                const retryMessage = `第${index + 1}页加载失败，正在进行第${loadAttempts[urls[index]]}次加载！`;\n                $('#messages').append(`<span class=\"error\">${retryMessage}</span><br>`);\n                setTimeout(() => { \n                    canLoadNextPage = true;\n                    loadContent(index); \n                }, config.retryDelayTime);\n            } else {\n                const finalErrorMessage = `第${index + 1}页加载失败，已达到最大尝试次数(${config.maxLoadAttempts})！`;\n                $('#messages').append(`<span class=\"error\">${finalErrorMessage}</span><br>`);\n                if (autoLoadInProgress && currentPageIndex < urls.length - 1) {\n                    setTimeout(() => { \n                        canLoadNextPage = true;\n                        loadContent(currentPageIndex + 1); \n                    }, config.delayTime);\n                } else {\n                    canLoadNextPage = true;\n                    if (autoLoadInProgress) {\n                        hideLoadingStatus();\n                    }\n                }\n            }\n        }\n\n        // 更新视频源\n        function updateVideoSource() {\n            const selectedIndex = parseInt(document.getElementById('video-source-select').value);\n            if (isNaN(selectedIndex) || !videoSources[selectedIndex]) {\n                $('#messages').append(`<span class=\"warn\">未找到有效的视频源。</span><br>`);\n                console.warn(\"Invalid or undefined video source:\", selectedIndex, videoSources);\n                return;\n            }\n\n            const selectedSource = videoSources[selectedIndex];\n            document.getElementById('video-url').textContent = `视频地址:\\n ${selectedSource}`;\n\n            const videoSourceElement = document.getElementById('video-source');\n            videoSourceElement.src = selectedSource;\n\n            const videoElement = document.getElementById('video-element');\n            videoElement.load();\n\n            $('#messages').append(`<span>更新视频源为: ${selectedSource}</span><br>`);\n            console.log(\"Updated video source to:\", selectedSource);\n        }\n\n        // 切换总页数显示状态\n        function toggleTotalPagesDisplay() {\n            if (urls.length > 1) {\n                $('#page').show();\n            } else {\n                $('#page').hide();\n            }\n        }\n\n        // 页面加载完成后执行的主要逻辑\n        $(document).ready(function () {\n            imageBox = document.getElementById('images');\n            textBox = document.getElementById('text');\n            if (imageBox && textBox) {\n                new Viewer(imageBox, { title: true, interval: 2000 });\n                new Viewer(textBox, { title: true, interval: 2000 });\n            }\n\n            const totalPagesText = config.totalPagesText;\n            const totalPages = parseInt(totalPagesText, 10) || 1;\n            const baseUrl = '{{baseUrl}}';\n\n            clearContainers();\n            $('#urls, #debug-info textarea, #video-url, #video-source-select').empty();\n            $('#urls, #messages, #debug-info, #video-url, #video-container, #video-source-container, #images, #text').hide();\n\n            buildUrls(totalPages, baseUrl);\n\n            const urlSelect = document.getElementById('url-select');\n            if (urlSelect.options.length > 0) {\n                urlSelect.value = '0'; \n\n                if (config.autoLoading) {\n                    autoLoadInProgress = true;\n                    for (let i = 0; i < urls.length; i++) {\n                        loadContent(i);\n                    }\n                } else {\n                    loadContent(0);\n                }\n            } else {\n                loadContent(0);\n            }\n\n            $('#url-select').change(function () {\n                clearContainers();\n                const selectedIndex = parseInt($(this).val());\n                loadContent(selectedIndex);\n            });\n            $('#prev-page-btn').click(function () {\n                clearContainers();\n                if (currentPageIndex > 0) {\n                    loadContent(currentPageIndex - 1);\n                }\n            });\n            $('#next-page-btn').click(function () {\n                clearContainers();\n                if (currentPageIndex < urls.length - 1) {\n                    loadContent(currentPageIndex + 1);\n                }\n            });\n            $('#auto-load-btn').click(function () {\n                autoLoadInProgress = true;\n                showLoadingStatus(1); \n                for (let i = currentPageIndex + 1; i < urls.length; i++) {\n                    loadContent(i);\n                }\n            });\n            $('#toggle-messages-btn').click(function () { $('#messages').toggle(); });\n            $('#toggle-urls-btn').click(function () { $('#urls').toggle(); });\n            $('#toggle-debug-btn').click(function () { $('#debug-info').toggle(); });\n        });\n    </script>\n</body>\n</html>",
    "ruleImage": "img@data-src",
    "ruleLink": "a.0@href",
    "ruleNextPage": "page",
    "rulePubDate": "em@text",
    "ruleTitle": "strong@text",
    "singleUrl": false,
    "sortUrl": "搜索🔍::/new/index.php?mod=search&kw={{source.getVariable()}}&page={{page}}\n最新::/new/index.php?page={{page}}\n国产自拍::/new/index.php?mod=forumdisplay&fid=10065&page={{page}}\n欧美极品::/new/index.php?mod=forumdisplay&fid=10066&page={{page}}\n日韩无码::/new/index.php?mod=forumdisplay&fid=10067&page={{page}}\n日韩有码::/new/index.php?mod=forumdisplay&fid=10068&page={{page}}\n中文字幕::/new/index.php?mod=forumdisplay&fid=10069&page={{page}}\n动漫精品::/new/index.php?mod=forumdisplay&fid=10070&page={{page}}\n极品萝莉::/new/index.php?mod=forumdisplay&fid=10071&page={{page}}\n强奸乱伦::/new/index.php?mod=forumdisplay&fid=10072&page={{page}}\n童颜巨乳::/new/index.php?mod=forumdisplay&fid=10073&page={{page}}\n三级自慰::/new/index.php?mod=forumdisplay&fid=10075&page={{page}}",
    "sourceComment": "xxrbs.com",
    "sourceGroup": "美涩",
    "sourceIcon": "https://xn--bwy.taojing62.buzz/upload/155042831.jpg",
    "sourceName": "日鲍社",
    "sourceUrl": "https://879.xxrbs.biz/"
  },
  {
    "articleStyle": 1,
    "customOrder": 0,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "div.video-item",
    "ruleContent": "<!DOCTYPE html>\n<html lang=\"zh-Hans\">\n<head>\n<title>{{@@h5.mt-3@text}}</title>\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no\">\n<meta name=\"referrer\" content=\"no-referrer\">\n<link href=\"https://cdn.bootcdn.net/ajax/libs/plyr/3.7.8/plyr.css\" rel=\"stylesheet\">\n</head>\n<body>\n<p></p>\n<div class=\"video-container\">\n  <video id=\"player\" playsinline controls preload=\"auto\" poster=\"https://qyyuapi.com/img/noposter.png\">\n  </video>\n</div>\n<details>\n  <summary>\n    <h3></h3>\n  </summary>\n  <img>\n</details>\n<div class=\"all-info\">\n<div>\n    <p>🕵 片名：{{@@h5.mt-3@text}}</p>\n    <p>👨‍🎤 主演：{{@@div.model-name.mt-1@text}}</p>\n</div>\n<div class=\"jiekou\" style=\"\">\n<p>🎬 集数： </p>\n<div id=\"selected-jiekou\" onclick=\"jiekouList()\"><button data-id=\"0\"><b>无尽视频<sup>1</sup></b></button></div><div id=\"jiekou-list\" style=\"display: none;\"></div></div>\n\n{{\nlet video_url= java.getString('iframe.player@src')\nlet content = java.get(source.sourceUrl + video_url,{}).body();\nlet ss = java.getString('#my-video@src', content);\n\nlet dom = `<div class=\"jishu\" style=\"display:block;\"><p>\n<button onclick=\"jishu(this)\" data-src=\"${ss}\"><b>01</b></button>\n</p></div>`;\ndom;\n}}\n\n\n</div>\n\n<script src=\"https://gcore.jsdelivr.net/npm/hls.js@canary\"></script>\n<script src=\"https://cdn.bootcdn.net/ajax/libs/plyr/3.7.8/plyr.min.js\"></script>\n\n<script>\n\nconst JKkey = \"{{java.md5Encode16(baseUrl.replace(/.*\\}([^\\}\\`]+)\\`/,'$1'))}}\";\nconst JDkey = \"{{java.md5Encode16(baseUrl.replace(/.*\\}([^\\}\\`]+)\\`/,'$1') + 'time')}}\";\nconst PTtime = {{/^\\d+$/.test('跳过片头：') ?'跳过片头：' : 0}};\nconst PWtime = {{/^\\d+$/.test('跳过片尾：') ? '跳过片尾：' : 0}};\nconst BSspeed = {{/^\\d+$/.test('长按倍速：') ? '长按倍速：' : 2}};\nconst ImageUrl = \"{{/^http/.test('背景图片：') ? '背景图片：' : ''}}\";\nconst Opacity1 = \"{{/0|1|^0\\.\\d+$/.test('图片透明度：') ? '图片透明度：' : ''}}\";\nconst Opacity2 = \"{{/0|1|^0\\.\\d+$/.test('按钮透明度：') ? '按钮透明度：' : ''}}\";\n\n// 获取视频URL并更新视频源\nasync function geturl() {\n    try {\n        let src = String($(\".jishu button.active\")[0].dataset.src);\n\n        // 获取页面信息\n        let fm = \"\";\n\n        // 获取视频源\n        let zyurl = [];\n        if (/mxcontent/.test(src)) {\n            zyurl.push({src:src,size:\"1\"});\n        } else {\n            zyurl.push({src:src,size:\"1\"});\n        }\n\n        // 更新详情封面\n        $(\"img\")[0].src = fm;\n\n        // 更新视频封面\n        $(\".video-container\")[0].style.background = `#000 url('${fm}') no-repeat center center / cover`;\n\n        // 返回视频源\n        let sources = zyurl;\n        return { sources: sources };\n    } catch (error) {\n        weblog(error, '错误:', true);\n        console.error(\"错误:\", error);\n        throw error;\n    }\n}\n\n// 点击集数按钮时调用的函数\nasync function jishu(item) {\n    var video = $('video')[0];\n    var wasPlaying = (video && !video.paused) || localStorage.getItem('fromEnded') === 'true';\n    if (localStorage.getItem('fromEnded') === 'true') {\n        localStorage.removeItem('fromEnded');\n    }\n    omit($('.jishu button.active'));\n    item.className = \"active\";\n    const { sources } = await geturl();\n    setTimeout(updatePadding, 100);\n    var index1 = $('#selected-jiekou button')[0].dataset.id;\n    var index2 = Array.from(item.parentNode.children).indexOf(item);\n    var Progress = {\n        index1: index1,\n        index2: index2\n    };\n    localStorage.setItem(JKkey, JSON.stringify(Progress));\n    localStorage.removeItem(JDkey);\n    initializePlayer(sources, JDkey, PTtime, PWtime, BSspeed, 1);\n    if (wasPlaying && video) {\n        const tryAutoPlay = () => {\n            if (video.readyState >= 3) {\n                video.play().catch(e => {\n                    console.log(\"自动播放被阻止:\", e);\n                    $('.plyr__control--overlaid').show();\n                });\n                video.removeEventListener('canplay', tryAutoPlay);\n            }\n        };\n        if (video.readyState >= 3) {\n            video.play().catch(e => console.log(\"立即播放失败:\", e));\n        } else {\n            video.addEventListener('canplay', tryAutoPlay);\n        }\n    }\n}\n\n// 页面加载时初始化播放器\n(async () => {\n    var m = 0,n = 0;\n    var Progress = localStorage.getItem(JKkey);\n    if (Progress) {\n        var history = JSON.parse(Progress);\n        m = history.index1;\n        n = history.index2;\n    }\n    if (m > 0) {\n        const buttonList = $('#jiekou-list')[0].querySelectorAll('button');\n        const targetButton = Array.from(buttonList).find(btn => btn.getAttribute('data-id') == m);\n        jiekou(targetButton);\n        const allButtons = $('.jishu')[m].querySelectorAll('button');\n        active(allButtons, n);\n    } else {\n        active($('.jishu button'), n);\n    }\n    const { sources } = await geturl();\n    setTimeout(updatePadding, 100);\n    localStorage.setItem('HistoryTAG', 1);\n    initializePlayer(sources, JDkey, PTtime, PWtime, BSspeed, 1);\n})();\n\n/*************jsku************/\n// 弹窗提示\nfunction weblog(message, title = '提示：', copy = false) {\n    // 0. 全屏状态处理（仅退出不恢复）\n    if (document.fullscreenElement) {\n        document.exitFullscreen().catch(err => {\n            console.warn('退出全屏失败:', err);\n        });\n        setTimeout(updatePadding, 100);\n    }\n\n    // 1. 保存页面原始状态\n    const previousOverflow = document.body.style.overflow;\n    const previousActiveElement = document.activeElement;\n    document.body.style.overflow = 'hidden';\n\n    // 2. 创建遮罩层\n    const overlay = document.createElement('div');\n    overlay.style.cssText = `\n        position: fixed;\n        top: 0;\n        left: 0;\n        width: 100%;\n        height: 100%;\n        background-color: rgba(0, 0, 0, 0.7);\n        z-index: 2147483647;\n        backdrop-filter: blur(3px);\n        opacity: 0;\n        transition: opacity 0.3s ease;\n        pointer-events: auto;\n    `;\n\n    // 3. 创建弹窗容器\n    const popup = document.createElement('div');\n    popup.className = 'popup';\n    popup.tabIndex = -1;\n\n    // 4. 创建标题\n    const titleElement = document.createElement('h3');\n    titleElement.textContent = title;\n    titleElement.className = 'titleElement';\n    popup.appendChild(titleElement);\n\n    // 5. 创建内容区域\n    const contentElement = document.createElement('div');\n    contentElement.textContent = message;\n    contentElement.className = 'contentElement';\n    popup.appendChild(contentElement);\n\n    // 6. 创建按钮容器\n    const buttonContainer = document.createElement('div');\n    buttonContainer.style.cssText = `\n        display: flex;\n        justify-content: flex-end;\n        gap: 12px;\n    `;\n\n    // 7. 根据copy参数决定是否显示复制按钮\n    if (copy) {\n        const copyButton = document.createElement('button');\n        copyButton.textContent = '复制文本';\n        copyButton.style.cssText = `\n            padding: 8px 18px;\n            cursor: pointer;\n            background-color: #4CAF50;\n            color: #eee;\n            border: none;\n            border-radius: 6px;\n            font-size: 14px;\n            font-weight: 500;\n            transition: all 0.2s;\n            height: 36px;\n            box-sizing: border-box;\n            line-height: 1;\n            display: inline-flex;\n            align-items: center;\n            justify-content: center;\n        `;\n\n        // 复制功能实现\n        copyButton.onclick = async () => {\n            const originalText = copyButton.textContent;\n\n            copyButton.disabled = true;\n            copyButton.style.opacity = '0.7';\n            copyButton.textContent = '复制中...';\n\n            try {\n                if (navigator.clipboard) {\n                    await navigator.clipboard.writeText(message);\n                } else {\n                    const textarea = document.createElement('textarea');\n                    textarea.value = message;\n                    textarea.style.position = 'fixed';\n                    document.body.appendChild(textarea);\n                    textarea.select();\n                    document.execCommand('copy');\n                    document.body.removeChild(textarea);\n                }\n\n                copyButton.textContent = '✓ 已复制';\n                copyButton.style.backgroundColor = '#2196F3';\n\n                setTimeout(() => {\n                    copyButton.textContent = originalText;\n                    copyButton.style.backgroundColor = '#4CAF50';\n                    copyButton.disabled = false;\n                    copyButton.style.opacity = '1';\n                }, 2000);\n            } catch (err) {\n                console.error('复制失败:', err);\n                copyButton.textContent = '复制失败';\n                setTimeout(() => {\n                    copyButton.textContent = originalText;\n                    copyButton.disabled = false;\n                    copyButton.style.opacity = '1';\n                }, 2000);\n            }\n        };\n\n        buttonContainer.appendChild(copyButton);\n    }\n\n    // 8. 创建关闭按钮\n    const closeButton = document.createElement('button');\n    closeButton.textContent = '关闭';\n    closeButton.style.cssText = `\n        padding: 8px 18px;\n        cursor: pointer;\n        background-color: #3493b6;\n        color: #eee;\n        border: none;\n        border-radius: 6px;\n        font-size: 14px;\n        font-weight: 500;\n        transition: all 0.2s;\n        height: 36px;\n        box-sizing: border-box;\n        line-height: 1;\n        display: inline-flex;\n        align-items: center;\n        justify-content: center;\n    `;\n    buttonContainer.appendChild(closeButton);\n    popup.appendChild(buttonContainer);\n\n    // 9. 关闭功能\n    const removePopup = () => {\n        popup.style.opacity = '0';\n        popup.style.transform = 'translate(-50%, -50%) scale(0.95)';\n        overlay.style.opacity = '0';\n        \n        setTimeout(() => {\n            // 移除元素\n            if (overlay.parentNode) overlay.parentNode.removeChild(overlay);\n            if (popup.parentNode) popup.parentNode.removeChild(popup);\n            \n            // 恢复页面状态\n            document.body.style.overflow = previousOverflow;\n            previousActiveElement?.focus();\n            document.removeEventListener('keydown', escHandler);\n        }, 300);\n    };\n\n    closeButton.onclick = removePopup;\n    overlay.onclick = removePopup;\n\n    // 10. 添加到页面\n    document.body.appendChild(overlay);\n    document.body.appendChild(popup);\n\n    // 触发动画\n    setTimeout(() => {\n        overlay.style.opacity = '1';\n        popup.style.opacity = '1';\n        popup.style.transform = 'translate(-50%, -50%) scale(1)';\n    }, 10);\n\n    // 11. ESC键关闭\n    const escHandler = (e) => {\n        if (e.key === 'Escape') {\n            removePopup();\n        }\n    };\n    document.addEventListener('keydown', escHandler);\n}\n\n// 选中标签\nfunction $(rule) {\n    return document.querySelectorAll(rule);\n}\n\n// 删除选中标签的class\nfunction omit(items) {\n    return Array.from(items, (item) => {\n        item.className = \"\";\n    });\n}\n\n// 选中标签的class增加active\nfunction active(items, index) {\n    items[index].className = \"active\";\n}\n\nlet isButtonListVisible = false;\n\n//切换候选列表显示\nfunction jiekouList() {\n    const selectedButton = $('#selected-jiekou > button')[0];\n    const buttonList = $('#jiekou-list')[0];\n    isButtonListVisible = !isButtonListVisible;\n    if (isButtonListVisible) {\n        if (buttonList.querySelectorAll('button').length > 0) {\n            selectedButton.style.borderRadius = '0';\n            buttonList.style.display = 'block';\n        }\n        selectedButton.style.opacity = '1';\n        // 添加全局点击事件监听\n        document.addEventListener('click', function globalClickListener(e) {\n            const clickedInsideButtonList = buttonList.contains(e.target);\n            const clickedSelectedButton = $('#selected-jiekou > button')[0].contains(e.target);\n            if (!clickedInsideButtonList && !clickedSelectedButton) {\n                selectedButton.style.borderRadius = '';\n                selectedButton.style.opacity = '';\n                buttonList.style.display = 'none';\n                isButtonListVisible = false;\n                document.removeEventListener('click', globalClickListener);\n            }\n        });\n    } else {\n        selectedButton.style.borderRadius = '';\n        selectedButton.style.opacity = '';\n        buttonList.style.display = 'none';\n    }\n}\n\n//切换列表接口\nfunction jiekou(clickedButton) {\n    const selectedContainer = $('#selected-jiekou')[0];\n    const selectedButton = selectedContainer.querySelector('button');\n    if (selectedButton) {\n        selectedButton.style.borderRadius = '';\n        selectedButton.style.opacity = '';\n    }\n    const buttonList = $('#jiekou-list')[0];\n    buttonList.appendChild(selectedContainer.querySelector('button'));\n    selectedContainer.appendChild(clickedButton);\n    isButtonListVisible = false;\n    buttonList.style.display = 'none';\n    const allButtons = buttonList.querySelectorAll('button');\n    allButtons.forEach(button => {\n        button.setAttribute('onclick', 'jiekou(this)');\n    });\n    const buttonsArray = Array.from(buttonList.querySelectorAll('button'));\n    buttonsArray.sort((a, b) => {\n        return parseInt(a.getAttribute('data-id')) - parseInt(b.getAttribute('data-id'));\n    });\n    buttonList.innerHTML = '';\n    buttonsArray.forEach(button => {\n        buttonList.appendChild(button);\n    });\n    JishuList(clickedButton);\n}\n\n// 切换集数列表显示\nfunction JishuList(clickedButton) {\n    const dataId = clickedButton.getAttribute('data-id');\n    const allJishuLists = $('.jishu');\n    allJishuLists.forEach(list => {\n        list.style.display = 'none';\n    });\n    allJishuLists[dataId].style.display = 'block';\n}\n\n// 保存原生的 fetch 函数\nconst originalFetch = window.fetch;\n\n// 重新定义全局的 fetch 函数\nwindow.fetch = async function(input, init = {}) {\n    const url = typeof input === 'string' ? input : input.url;\n    \n    // 准备请求选项\n    let requestOptions = {\n        method: init.method || 'GET',\n        headers: {\n            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',\n            'Accept-Encoding': 'gzip, deflate, br',\n            'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',\n            ...init.headers\n        },\n        cache: 'no-cache',\n        ...init\n    };\n\n    // 处理请求体\n    if (init.body) {\n        const body = init.body;\n        if (!requestOptions.headers['Content-Type']) {\n            requestOptions.headers['Content-Type'] = typeof body === 'object' \n                ? 'application/json'\n                : 'application/x-www-form-urlencoded';\n        }\n        \n        if (typeof body === 'object' && !(body instanceof FormData) && !(body instanceof URLSearchParams)) {\n            requestOptions.body = JSON.stringify(body);\n        } else if (typeof body === 'string') {\n            requestOptions.body = body.replace(/\\+/g, '%2B');\n        } else {\n            requestOptions.body = body;\n        }\n    }\n\n    // 如果没有请求体但存在 Content-Type 头，则删除它\n    if (!init.body && requestOptions.headers['Content-Type']) {\n        delete requestOptions.headers['Content-Type'];\n    }\n\n    // 使用降级策略\n    return await fetchWithFallback(input, init, url, requestOptions);\n};\n\n// 降级策略函数\nasync function fetchWithFallback(input, init, url, requestOptions) {\n    // 确定当前可用的方法级别\n    let methodLevel = 1; // 从最高级别开始尝试\n    \n    while (methodLevel <= 2) {\n        try {\n            switch (methodLevel) {\n                case 1: // 第一级：legado\n                    if (typeof window.run === 'function') {\n                        console.log('Using legado (level 1)');\n                        return await useWindowRun(url, requestOptions);\n                    }\n                    break;\n                    \n                case 2: // 第二级：原生 fetch\n                    console.log('Using fetch (level 2)');\n                    return await originalFetch(input, init);\n            }\n        } catch (error) {\n            console.warn(`Method level ${methodLevel} failed:`, error);\n            // 当前级别失败，尝试下一级别\n        }\n        \n        methodLevel++; // 尝试下一级别\n    }\n    \n    // 使用原生 fetch 作为最终保底\n    console.error('All method levels failed, using native fetch as final fallback');\n    return await originalFetch(input, init);\n}\n\n// 使用 legado 发送请求\nasync function useWindowRun(url, requestOptions) {\n    const origin = window.location.origin;\n    const rawText = await window.run(`\n        let response = java.connect('${/^http/.test(url) ? url : (origin + url)},${JSON.stringify(requestOptions)}');\n        response.code() + '#|#' + response.body();\n    `);\n    const raw = rawText.split(\"#|#\");\n    \n    // 判断状态码\n    let status = parseInt(raw[0]);\n    \n    // 状态码对应的文本\n    const statusTexts = {\n        100: 'Continue',\n        101: 'Switching Protocols',\n        102: 'Processing',\n        200: 'OK',\n        201: 'Created',\n        202: 'Accepted',\n        203: 'Non-Authoritative Information',\n        204: 'No Content',\n        205: 'Reset Content',\n        206: 'Partial Content',\n        207: 'Multi-Status',\n        208: 'Already Reported',\n        226: 'IM Used',\n        300: 'Multiple Choices',\n        301: 'Moved Permanently',\n        302: 'Found',\n        303: 'See Other',\n        304: 'Not Modified',\n        305: 'Use Proxy',\n        307: 'Temporary Redirect',\n        308: 'Permanent Redirect',\n        400: 'Bad Request',\n        401: 'Unauthorized',\n        402: 'Payment Required',\n        403: 'Forbidden',\n        404: 'Not Found',\n        405: 'Method Not Allowed',\n        406: 'Not Acceptable',\n        407: 'Proxy Authentication Required',\n        408: 'Request Timeout',\n        409: 'Conflict',\n        410: 'Gone',\n        411: 'Length Required',\n        412: 'Precondition Failed',\n        413: 'Payload Too Large',\n        414: 'URI Too Long',\n        415: 'Unsupported Media Type',\n        416: 'Range Not Satisfiable',\n        417: 'Expectation Failed',\n        418: 'I\\'m a teapot',\n        421: 'Misdirected Request',\n        422: 'Unprocessable Entity',\n        423: 'Locked',\n        424: 'Failed Dependency',\n        425: 'Too Early',\n        426: 'Upgrade Required',\n        428: 'Precondition Required',\n        429: 'Too Many Requests',\n        431: 'Request Header Fields Too Large',\n        451: 'Unavailable For Legal Reasons',\n        500: 'Internal Server Error',\n        501: 'Not Implemented',\n        502: 'Bad Gateway',\n        503: 'Service Unavailable',\n        504: 'Gateway Timeout',\n        505: 'HTTP Version Not Supported',\n        506: 'Variant Also Negotiates',\n        507: 'Insufficient Storage',\n        508: 'Loop Detected',\n        510: 'Not Extended',\n        511: 'Network Authentication Required'\n    };\n    \n    // 提取响应体\n    const responseBody = raw.length > 1 ? raw[1] : '';\n    \n    // 判断Content-Type\n    let contentType = 'text/plain;charset=utf-8';\n    \n    // 先检查URL扩展名\n    const urlLower = url.toLowerCase();\n    if (urlLower.includes('.ts') || urlLower.includes('.m3u8') || urlLower.includes('.mpeg')) {\n        contentType = 'video/mp2t';\n    } else if (urlLower.includes('.mp4') || urlLower.includes('.m4v')) {\n        contentType = 'video/mp4';\n    } else if (urlLower.includes('.webm')) {\n        contentType = 'video/webm';\n    } else if (urlLower.includes('.avi')) {\n        contentType = 'video/x-msvideo';\n    } else if (urlLower.includes('.mov')) {\n        contentType = 'video/quicktime';\n    } else if (urlLower.includes('.flv')) {\n        contentType = 'video/x-flv';\n    } else if (urlLower.includes('.mkv')) {\n        contentType = 'video/x-matroska';\n    } else if (urlLower.includes('.jpg') || urlLower.includes('.jpeg')) {\n        contentType = 'image/jpeg';\n    } else if (urlLower.includes('.png')) {\n        contentType = 'image/png';\n    } else if (urlLower.includes('.gif')) {\n        contentType = 'image/gif';\n    } else if (urlLower.includes('.svg')) {\n        contentType = 'image/svg+xml';\n    } else if (urlLower.includes('.webp')) {\n        contentType = 'image/webp';\n    } else if (urlLower.includes('.json')) {\n        contentType = 'application/json;charset=utf-8';\n    } else if (urlLower.includes('.xml')) {\n        contentType = 'application/xml;charset=utf-8';\n    } else if (urlLower.includes('.html') || urlLower.includes('.htm')) {\n        contentType = 'text/html;charset=utf-8';\n    } else if (urlLower.includes('.css')) {\n        contentType = 'text/css;charset=utf-8';\n    } else if (urlLower.includes('.js')) {\n        contentType = 'application/javascript;charset=utf-8';\n    } else if (urlLower.includes('.pdf')) {\n        contentType = 'application/pdf';\n    } else if (urlLower.includes('.zip')) {\n        contentType = 'application/zip';\n    } else if (urlLower.includes('.rar')) {\n        contentType = 'application/x-rar-compressed';\n    } else if (urlLower.includes('.7z')) {\n        contentType = 'application/x-7z-compressed';\n    } else if (urlLower.includes('.tar')) {\n        contentType = 'application/x-tar';\n    } else if (urlLower.includes('.gz')) {\n        contentType = 'application/gzip';\n    } else {\n        // 如果没有通过URL判断出来，尝试通过内容判断\n        if (responseBody && responseBody.length > 0) {\n            // 尝试判断是否为JSON\n            try {\n                // 检查是否以{或[开头\n                const trimmed = responseBody.trim();\n                if (trimmed.startsWith('{') || trimmed.startsWith('[')) {\n                    JSON.parse(responseBody);\n                    contentType = 'application/json;charset=utf-8';\n                }\n            } catch (e) {\n                // 不是JSON，继续检查\n            }\n            \n            // 检查是否为HTML\n            if (responseBody.includes('<!DOCTYPE') || \n                responseBody.includes('<html') || \n                responseBody.includes('<head>') || \n                responseBody.includes('<body>')) {\n                contentType = 'text/html;charset=utf-8';\n            }\n            \n            // 检查是否为CSS\n            else if (responseBody.includes('{') && responseBody.includes('}') && \n                    (responseBody.includes('color:') || \n                     responseBody.includes('font-size:') || \n                     responseBody.includes('background:'))) {\n                contentType = 'text/css;charset=utf-8';\n            }\n            \n            // 检查是否为JavaScript\n            else if (responseBody.includes('function') || \n                    responseBody.includes('var ') || \n                    responseBody.includes('const ') || \n                    responseBody.includes('let ') || \n                    responseBody.includes('console.log')) {\n                contentType = 'application/javascript;charset=utf-8';\n            }\n            \n            // 检查是否包含大量非ASCII字符或控制字符（可能是二进制数据）\n            else if (responseBody.length > 100) {\n                let binaryCount = 0;\n                for (let i = 0; i < Math.min(responseBody.length, 1000); i++) {\n                    const charCode = responseBody.charCodeAt(i);\n                    // 控制字符（除了常见的空白字符）或非ASCII字符\n                    if ((charCode < 32 && charCode !== 9 && charCode !== 10 && charCode !== 13) || charCode > 127) {\n                        binaryCount++;\n                    }\n                }\n                \n                // 如果超过5%的字符是二进制特征，认为是二进制数据\n                if (binaryCount > Math.min(responseBody.length, 1000) * 0.05) {\n                    contentType = 'application/octet-stream';\n                }\n            }\n        }\n    }\n    \n    // 创建并返回Response对象\n    return new Response(responseBody, {\n        status: status,\n        statusText: statusTexts[status] || 'Unknown Status',\n        headers: new Headers({\n            'Content-Type': contentType\n        })\n    });\n}\n\n// fetchRequest 函数\nasync function fetchRequest(url, headers, body = null) {\n    try {\n        const init = {\n            headers: headers\n        };\n        \n        if (body) {\n            init.method = 'POST';\n            init.body = body;\n        }\n\n        const response = await fetch(url, init);\n        \n        if (!response.ok) {\n            throw new Error(`HTTP error! Status: ${response.status}`);\n        }\n\n        const rawText = await response.text();\n\n        // 尝试解析 JSON\n        try {\n            const jsonData = JSON.parse(rawText);\n            return jsonData;\n        } catch (e) {\n            // 如果不是 JSON，返回原始文本\n            return rawText;\n        }\n    } catch (error) {\n        weblog(error, '请求失败:', true);\n        return null;\n    }\n}\n\n// 全局时间管理器\nconst TimeManager = {\n    currentVideoUrl: '',\n    headtime: 0,\n    endtime: 0,\n    listeners: [],\n\n    init(videoUrl) {\n        this.currentVideoUrl = videoUrl;\n        this._loadFromStorage();\n        this._setupListeners();\n    },\n\n    _loadFromStorage() {\n        const head = localStorage.getItem('head' + this.currentVideoUrl);\n        const end = localStorage.getItem('end' + this.currentVideoUrl);\n        this.headtime = head ? parseFloat(head) : 0;\n        this.endtime = end ? parseFloat(end) : 0;\n        this._notifyAll();\n    },\n\n    _setupListeners() {\n        window.addEventListener('storage', (e) => {\n            if (e.key === 'head' + this.currentVideoUrl) {\n                this.headtime = e.newValue ? parseFloat(e.newValue) : 0;\n                this._notify('head', this.headtime);\n            }\n            if (e.key === 'end' + this.currentVideoUrl) {\n                this.endtime = e.newValue ? parseFloat(e.newValue) : 0;\n                this._notify('end', this.endtime);\n            }\n        });\n    },\n\n    setHeadTime(time) {\n        this.headtime = time;\n        localStorage.setItem('head' + this.currentVideoUrl, time);\n        this._notify('head', time);\n    },\n\n    setEndTime(time) {\n        this.endtime = time;\n        localStorage.setItem('end' + this.currentVideoUrl, time);\n        this._notify('end', time);\n    },\n\n    clearMarks() {\n        localStorage.removeItem('head' + this.currentVideoUrl);\n        localStorage.removeItem('end' + this.currentVideoUrl);\n        this.headtime = 0;\n        this.endtime = 0;\n        this._notifyAll();\n    },\n\n    addListener(callback) {\n        this.listeners.push(callback);\n    },\n\n    _notify(type, value) {\n        this.listeners.forEach(cb => cb({ type, value }));\n    },\n\n    _notifyAll() {\n        this._notify('head', this.headtime);\n        this._notify('end', this.endtime);\n    }\n};\n\n// 初始设置\nlet player = null;\nlet timeManager = null;\nlet currentHls = null;\nlet isSwitching = false;\n\n// 初始化播放器\nfunction initializePlayer(sources, currentVideoUrl, defaultHeadtime, defaultEndtime, speed, autonext) {\n    const video = $('video')[0];\n    video.style.height = '56.25vw';\n    const qualityOptions = sources.map(source => parseInt(source.size));\n\n    // 修改图片和透明度\n    updateBackground(\n        typeof ImageUrl !== 'undefined' ? ImageUrl : undefined,\n        typeof Opacity1 !== 'undefined' ? Opacity1 : undefined, \n        typeof Opacity2 !== 'undefined' ? Opacity2 : undefined\n    );\n\n    // 初始化时间管理器\n    if (!timeManager || timeManager.currentVideoUrl !== currentVideoUrl) {\n        timeManager = Object.create(TimeManager);\n        timeManager.init(currentVideoUrl);\n        \n        // 设置默认值（如果localStorage中没有）\n        if (!localStorage.getItem('head' + currentVideoUrl) && defaultHeadtime) {\n            timeManager.setHeadTime(defaultHeadtime);\n        }\n        if (!localStorage.getItem('end' + currentVideoUrl) && defaultEndtime) {\n            timeManager.setEndTime(defaultEndtime);\n        }\n    }\n\n    // 如果播放器已存在，则只更新视频源\n    if (player) {\n        // 获取当前画质\n        let currentQuality = qualityOptions[0];\n        if (player.storage && player.storage.get) {\n            const savedQuality = player.storage.get('quality');\n            if (savedQuality && qualityOptions.includes(parseInt(savedQuality))) {\n                currentQuality = parseInt(savedQuality);\n            }\n        }\n        if (!currentQuality) {\n            currentQuality = Math.max(...qualityOptions);\n        }\n        \n        // 加载当前画质的视频源\n        const selectedSource = sources.find(source => source.size === currentQuality.toString()) || sources[0];\n        const savedProgress = localStorage.getItem(currentVideoUrl);\n        const progress = (savedProgress && savedProgress > timeManager.headtime) ? savedProgress : timeManager.headtime;\n        \n        // 更新画质配置\n        player.config.quality.options = qualityOptions;\n        player.config.quality.default = currentQuality;\n        player.config.quality.onChange = (newQuality) => {\n            changeVideoQuality(newQuality, sources);\n        };\n        \n        // 更新主菜单的画质显示\n        mainMenuQuality(currentQuality)\n        \n        // 更新画质菜单选项\n        updateQualityOptions(qualityOptions, currentQuality, sources);\n        \n        // 更新p标签显示当前源\n        $(\"body>p\")[0].innerHTML = `\n          <div style=\"display: flex; align-items: center; justify-content: space-between; width: 100%;\">\n            <a href=\"legadovideo://${encodeURIComponent(selectedSource.src)}\">\n              ${selectedSource.src}\n            </a>\n            <button \n              onclick=\"navigator.clipboard.writeText('${selectedSource.src.replace(/'/g, \"\\\\'\")}')\n                .then(() => weblog('链接已复制到剪贴板'))\n                .catch(() => weblog('复制链接失败'))\"\n            >\n              复制\n            </button>\n          </div>\n        `;\n        \n        setTimeout(() => (isSwitching = false), 2000);\n        \n        if (Hls.isSupported() && /m3u8|hls/.test(selectedSource.src)) {\n            initializeHlsPlayer(selectedSource.src, selectedSource.headersOrReferer, video, progress);\n        } else {\n            initializeRegularPlayer(selectedSource.src, selectedSource.headersOrReferer, video, progress);\n        }\n        \n        return player;\n    }\n\n    // 创建新的播放器实例\n    player = new Plyr(video, {\n        controls: [\n            'play-large',   // 大播放按钮\n            'rewind',       // 倒退\n            'play',         // 播放\n            'fast-forward', // 快进\n            'progress',     // 进度条\n            'current-time', // 当前时间\n            'duration',     // 总时长\n            'mute',         // 静音\n            'volume',       // 音量\n            'captions',     // 字幕\n            'settings',     // 设置\n            'pip',          // 画中画\n            'airplay',      // Airplay\n            'fullscreen'    // 全屏\n        ],\n        settings: ['quality', 'speed'],\n        quality: {\n            default: qualityOptions[0],\n            options: qualityOptions,\n            forced: true,\n            onChange: (newQuality) => {\n                changeVideoQuality(newQuality, sources);\n            }\n        },\n        fullscreen: {\n            enabled: true,\n            fallback: true,\n            iosNative: true,\n            container: null,\n        },\n        speed: {\n            selected: 1, // 设置默认播放倍数\n            options: [8,5,4,3,2.5, 2, 1.5, 1, 0.5, 0.25],\n        },\n        i18n: {\n            restart: '重新开始',\n            rewind: '倒退 {seektime} 秒',\n            play: '播放',\n            pause: '暂停',\n            fastForward: '快进 {seektime} 秒',\n            seek: '进度',\n            seekLabel: '{currentTime} / {duration}',\n            played: '播放',\n            buffered: '缓冲',\n            currentTime: '当前时间',\n            duration: '持续时间',\n            volume: '音量',\n            mute: '静音',\n            unmute: '取消静音',\n            enableCaptions: '启用字幕',\n            disableCaptions: '禁用字幕',\n            enterFullscreen: '进入全屏',\n            exitFullscreen: '退出全屏',\n            frameTitle: '播放器',\n            captions: '字幕',\n            settings: '设置',\n            speed: '速度',\n            normal: '正常',\n            quality: '画质',\n            qualityLabel: {\n                0: '自动',\n            },\n            pip: '画中画',\n            loop: '循环',\n            start: '开始',\n            end: '结束',\n            all: '全部',\n            reset: '重置',\n            disabled: '禁用',\n            advertisement: '广告'\n        },\n        keyboard: {\n            focused: true,\n            global: true,\n        },\n        tooltips: {\n            controls: true,\n            seek: true\n        },\n        captions: {\n            active: true,\n            update: true,\n            language: 'auto',\n        },\n    });\n\n    player.on('ready', () => {\n        video.style.visibility = 'visible';\n\n        // 添加显示集数\n        addEpisodeBarToPlayer();\n\n        // 添加跳过菜单项\n        addSkipMenuItems(currentVideoUrl, timeManager);\n\n        // 初始化播放器方向控制功能\n        initPlayerOrientationControl(player);\n\n        // 设置进度记录\n        progressRecording(currentVideoUrl, video);\n\n        // 设置自动下一集监听\n        autoNextListener(currentVideoUrl, autonext, video);\n\n        // 添加上下集按钮\n        addEpisodeButtons(currentVideoUrl, autonext);\n\n        // 设置手势控制\n        gestureControls(player, video, speed);\n\n        // 设置全屏和按钮显示处理\n        fullscreenControls(autonext, video);\n\n        // 初始化处理全屏状态\n        updateFullscreen(autonext, video);\n\n        // 播放开始自动改为黑色背景\n        player.on('play', () => {\n            $(\".video-container\")[0].style.background = '#000';\n        });\n\n        // 进度大于0时自动改为黑色背景\n        player.on('timeupdate', () => {\n            if (video.currentTime > 0) $(\".video-container\")[0].style.background = '#000';\n        });\n\n        // 获取保存的播放进度\n        const savedProgress = localStorage.getItem(currentVideoUrl);\n        const progress = (savedProgress && savedProgress > timeManager.headtime) ? parseFloat(savedProgress) : timeManager.headtime;\n        if (!isNaN(progress) && progress > 0) {\n            video.currentTime = progress;\n        }\n\n        // 调用切换画质函数加载默认画质\n        changeVideoQuality(qualityOptions[0], sources);\n    });\n\n    return player;\n}\n\n// 修改图片和透明度\nfunction updateBackground(imageUrl, opacity1, opacity2) {\n    if (!imageUrl || imageUrl === '') imageUrl = 'https://bg.qyyuapi.com/img/background.jpg';\n    if (!opacity1 || opacity1 === '') opacity1 = 0.2;\n    if (!opacity2 || opacity2 === '') opacity2 = 0.6;\n    document.body.style.setProperty('--bg-image', `url('${imageUrl}')`);\n    document.body.style.setProperty('--bg-opacity1', opacity1);\n    document.body.style.setProperty('--bg-opacity2', opacity2);\n}\n\n// 更新画质菜单选项\nfunction updateQualityOptions(qualityOptions, currentQuality, sources) {\n    if (!player || !player.elements || !player.elements.settings) return;\n    \n    try {\n        const settings = player.elements.settings;\n        const qualityPanel = settings.panels.quality;\n        if (!qualityPanel) return;\n        const menuContainer = qualityPanel.querySelector('[role=\"menu\"]');\n        if (!menuContainer) return;\n        menuContainer.innerHTML = '';\n        qualityOptions.forEach(quality => {\n            const isSelected = quality === currentQuality;\n            const button = createQualityButton(quality, isSelected, sources);\n            menuContainer.appendChild(button);\n        });\n    } catch (error) {\n        console.error('更新画质菜单选项失败:', error);\n    }\n}\n\n// 创建画质按钮\nfunction createQualityButton(quality, isSelected, sources) {\n    const button = document.createElement('button');\n    button.type = 'button';\n    button.className = 'plyr__control';\n    button.setAttribute('role', 'menuitemradio');\n    button.setAttribute('aria-checked', isSelected ? 'true' : 'false');\n    button.setAttribute('data-plyr', 'quality');\n    button.value = quality;\n    \n    // 根据画质生成对应的按钮\n    const badge = getQualityBadge(quality);\n    button.innerHTML = `\n        <span>${quality}p${badge ? `<span class=\"plyr__menu__value\"><span class=\"plyr__badge\">${badge}</span></span>` : '</span>'}\n    `;\n    \n    // 绑定点击事件\n    button.addEventListener('click', function(e) {\n        e.preventDefault();\n        e.stopPropagation();\n        \n        const quality = parseInt(this.value);\n        \n        // 1. 触发画质变更事件\n        if (player.quality) {\n            player.quality.current = quality;\n            if (player.quality.set) {\n                player.quality.set(quality);\n            }\n            player.emit('qualitychange', quality);\n        }\n        \n        // 2. 更新配置\n        player.config.quality.current = quality;\n        \n        // 3. 保存到Plyr存储\n        if (player.storage && player.storage.set) {\n            player.storage.set({ quality: quality });\n        }\n        \n        // 4. 更新画质菜单选中状态\n        qualitySelection(quality);\n        \n        // 5. 更新主菜单的画质显示\n        mainMenuQuality(quality);\n        \n        // 6. 调用画质切换函数\n        changeVideoQuality(quality, sources);\n        \n        // 7. 返回主菜单\n        backToMainMenu();\n    });\n    \n    // 设置初始选中状态\n    if (isSelected) {\n        button.classList.add('plyr__control--selected');\n        const checkSpan = button.querySelector('.plyr__control--checked');\n        if (checkSpan) {\n            checkSpan.style.display = 'block';\n            checkSpan.innerHTML = '✓';\n        }\n    }\n    \n    return button;\n}\n\n// 更新画质菜单选中状态\nfunction qualitySelection(selectedQuality) {\n    if (!player || !player.elements.settings) return;\n    \n    const settings = player.elements.settings;\n    const qualityPanel = settings.panels.quality;\n    if (!qualityPanel) return;\n    \n    const menuContainer = qualityPanel.querySelector('[role=\"menu\"]');\n    if (!menuContainer) return;\n    \n    const allButtons = menuContainer.querySelectorAll('[data-plyr=\"quality\"]');\n    allButtons.forEach(btn => {\n        const quality = parseInt(btn.value);\n        const isSelected = quality === selectedQuality;\n        \n        btn.setAttribute('aria-checked', isSelected ? 'true' : 'false');\n        \n        if (isSelected) {\n            btn.classList.add('plyr__control--selected');\n            const checkSpan = btn.querySelector('.plyr__control--checked');\n            if (checkSpan) {\n                checkSpan.style.display = 'block';\n                checkSpan.innerHTML = '✓';\n                checkSpan.style.color = 'var(--plyr-control-toggle-checked-background, #00b3ff)';\n            }\n        } else {\n            btn.classList.remove('plyr__control--selected');\n            const checkSpan = btn.querySelector('.plyr__control--checked');\n            if (checkSpan) {\n                checkSpan.style.display = 'none';\n            }\n        }\n    });\n}\n\n// 在home菜单中查找画质按钮\nfunction findQualityMenu(homeMenu) {\n    const allButtons = homeMenu.querySelectorAll('[data-plyr=\"settings\"]');\n    \n    for (let button of allButtons) {\n        const buttonText = button.textContent || button.innerText;\n        \n        if (buttonText.includes('画质')) {\n            return button;\n        }\n    }\n    \n    console.log('未找到包含关键词的按钮');\n    return null;\n}\n\n// 更新主菜单的画质显示\nfunction mainMenuQuality(quality) {\n    try {\n        // 查找设置弹出层容器\n        const menuContainer = document.querySelector('.plyr__menu__container');\n        if (!menuContainer) {\n            console.log('未找到菜单容器');\n            return;\n        }\n        \n        // 查找主菜单（包含\"-home\"的ID）\n        const homeMenu = menuContainer.querySelector('[id*=\"-home\"]');\n        if (!homeMenu) {\n            console.log('未找到主菜单');\n            return;\n        }\n        \n        // 在主菜单中查找画质按钮\n        const qualityButton = findQualityMenu(homeMenu);\n        if (!qualityButton) {\n            console.log('未找到画质按钮');\n            return;\n        }\n        \n        // 更新画质显示\n        const valueSpan = qualityButton.querySelector('.plyr__menu__value');\n        if (valueSpan) {\n            valueSpan.innerHTML = `${quality}p`;\n        } else {\n            console.log('未找到valueSpan');\n        }\n        \n    } catch (error) {\n        console.error('更新主菜单显示失败:', error);\n    }\n}\n\n// 返回主菜单\nfunction backToMainMenu() {\n    try {\n        // 查找设置弹出层容器\n        const menuContainer = document.querySelector('.plyr__menu__container');\n        if (!menuContainer) {\n            console.log('未找到菜单容器');\n            return;\n        }\n        \n        // 更改home菜单和quality菜单显示\n        const homeMenu = menuContainer.querySelector('[id*=\"-home\"]');\n        const qualityMenu = menuContainer.querySelector('[id*=\"-quality\"]');\n        \n        if (homeMenu && qualityMenu) {\n            homeMenu.removeAttribute('hidden');\n            qualityMenu.setAttribute('hidden', '');\n            \n            return;\n        }\n        \n        console.log('未找到需要的菜单');\n        \n    } catch (error) {\n        console.error('返回主菜单失败:', error);\n    }\n}\n\n// 根据画质返回对应的徽章文本\nfunction getQualityBadge(quality) {\n    if (quality >= 2160) return '4K';\n    if (quality >= 1440) return '2K';\n    if (quality >= 1080) return 'FHD';\n    if (quality >= 720) return 'HD';\n    if (quality >= 480) return 'SD';\n    if (quality >= 360) return 'LD';\n    if (quality >= 240) return 'ULD';\n    return '';\n}\n\n// 设置进度记录\nfunction progressRecording(currentVideoUrl, video) {\n    const progressInterval = setInterval(() => {\n        const currentTime = video.currentTime;\n        localStorage.setItem(currentVideoUrl, currentTime.toString());\n        localStorage.setItem('HistoryTIME', Date.now());\n    }, 5000);\n}\n\n// 设置自动下一集监听\nfunction autoNextListener(currentVideoUrl, autonext, video) {\n    player.on('timeupdate', () => {\n        if (!autonext || video.paused || timeManager.endtime === 0 || video.duration <= 0) return;\n        if ((video.duration - video.currentTime) < timeManager.endtime) {\n            const randomDelay = Math.floor(Math.random() * 200) + 100;\n            setTimeout(() => {\n                if (isSwitching) return;\n                switchToNextEpisode(currentVideoUrl, autonext);\n            }, randomDelay);\n        }\n    });\n\n    player.on('ended', () => {\n        if (isSwitching || !autonext || video.duration <= 0) return;\n        const randomDelay = Math.floor(Math.random() * 200) + 100;\n        setTimeout(() => {\n            if (isSwitching) return;\n            localStorage.setItem('fromEnded', 'true');\n            switchToNextEpisode(currentVideoUrl, autonext);\n        }, randomDelay);\n    });\n}\n\n// 添加上下集按钮\nfunction addEpisodeButtons(currentVideoUrl, autonext) {\n    if (autonext) {\n        const style = document.createElement('style');\n        style.textContent = `\n            .plyr__control--episode-prev,\n            .plyr__control--episode-next {\n                display: none;\n                margin: 1px;\n            }\n            .plyr__controls [data-plyr=\"rewind\"],\n            .plyr__controls [data-plyr=\"fast-forward\"] {\n                margin: 1px;\n            }\n        `;\n        document.head.appendChild(style);\n\n        const controlsContainer = document.querySelector('.plyr__controls');\n        if (controlsContainer) {\n            // 获取参考按钮\n            const rewindBtn = controlsContainer.querySelector('[data-plyr=\"rewind\"]');\n            const fastForwardBtn = controlsContainer.querySelector('[data-plyr=\"fast-forward\"]');\n\n            // 创建上一集按钮（放在后退前）\n            if (rewindBtn && !document.querySelector('.plyr__control--episode-prev')) {\n                const prevBtn = document.createElement('button');\n                prevBtn.className = 'plyr__control plyr__control--episode-prev';\n                prevBtn.innerHTML = `\n                    <svg aria-hidden=\"true\" focusable=\"false\" width=\"18\" height=\"18\">\n                        <use xlink:href=\"#plyr-prev-episode\"></use>\n                    </svg>\n                    <span class=\"plyr__tooltip\">上一集</span>\n                `;\n                prevBtn.onclick = (e) => {\n                    e.preventDefault();\n                    switchToPrevEpisode(currentVideoUrl, autonext);\n                };\n                rewindBtn.parentNode.insertBefore(prevBtn, rewindBtn);\n            }\n\n            // 创建下一集按钮（放在快进后）\n            if (fastForwardBtn && !document.querySelector('.plyr__control--episode-next')) {\n                const nextBtn = document.createElement('button');\n                nextBtn.className = 'plyr__control plyr__control--episode-next';\n                nextBtn.innerHTML = `\n                    <svg aria-hidden=\"true\" focusable=\"false\" width=\"18\" height=\"18\">\n                        <use xlink:href=\"#plyr-next-episode\"></use>\n                    </svg>\n                    <span class=\"plyr__tooltip\">下一集</span>\n                `;\n                nextBtn.onclick = (e) => {\n                    e.preventDefault();\n                    switchToNextEpisode(currentVideoUrl, autonext);\n                };\n                fastForwardBtn.parentNode.insertBefore(nextBtn, fastForwardBtn.nextSibling);\n            }\n        }\n    }\n}\n\n// 设置手势控制\nfunction gestureControls(player, video, speed) {\n    const gesture = {\n        startX: 0,\n        startY: 0,\n        startTime: 0,\n        isLongPress: false,\n        initialSpeed: 1,\n        isSeeking: false,\n        longPressTimer: null,\n        wasPlaying: false,\n        lastTime: 0,\n        initialBrightness: 1,\n        isBrightnessControl: false,\n        initialVolume: 1,\n        isVolumeControl: false,\n        gestureType: null,\n        threshold: 15\n    };\n\n    // 提示工具\n    const controlTooltip = document.createElement('div');\n    controlTooltip.className = 'plyr__center-tooltip';\n    controlTooltip.innerHTML = `\n        <span class=\"control-icon\" style=\"font-weight:bold\"></span>\n        <span class=\"control-value\"></span>\n    `;\n    document.querySelector('.plyr__video-wrapper').appendChild(controlTooltip);\n\n    // 获取系统亮度（如果支持）\n    const getSystemBrightness = () => {\n        return parseFloat(localStorage.getItem('systemBrightness')) || 1;\n    };\n\n    // 设置系统亮度（模拟实现）\n    const setSystemBrightness = (brightness) => {\n        localStorage.setItem('systemBrightness', brightness.toString());\n        \n        if ('screen' in window && 'brightness' in window.screen) {\n            try {\n                window.screen.brightness = brightness;\n            } catch (e) {\n                console.log('Screen Brightness API not supported');\n            }\n        }\n        \n        let brightnessOverlay = document.getElementById('brightness-overlay');\n        if (!brightnessOverlay) {\n            brightnessOverlay = document.createElement('div');\n            brightnessOverlay.id = 'brightness-overlay';\n            brightnessOverlay.style.cssText = `\n                position: fixed;\n                top: 0;\n                left: 0;\n                width: 100%;\n                height: 100%;\n                background: black;\n                pointer-events: none;\n                z-index: 2147483647;\n                opacity: 0;\n                transition: opacity 0.2s ease;\n            `;\n            document.body.appendChild(brightnessOverlay);\n            \n            document.addEventListener('fullscreenchange', updateBrightnessOverlay);\n            document.addEventListener('webkitfullscreenchange', updateBrightnessOverlay);\n        }\n        brightnessOverlay.style.opacity = (1 - brightness).toString();\n        \n        updateBrightnessOverlay();\n    };\n\n    // 更新亮度覆盖层位置\n    const updateBrightnessOverlay = () => {\n        const brightnessOverlay = document.getElementById('brightness-overlay');\n        if (!brightnessOverlay) return;\n        \n        const isFullscreen = document.fullscreenElement || \n                           document.webkitFullscreenElement ||\n                           document.mozFullScreenElement ||\n                           document.msFullscreenElement;\n        \n        if (isFullscreen) {\n            const fullscreenElement = document.fullscreenElement || \n                                    document.webkitFullscreenElement ||\n                                    document.mozFullScreenElement ||\n                                    document.msFullscreenElement;\n            \n            if (fullscreenElement) {\n                if (fullscreenElement !== document.body) {\n                    if (!fullscreenElement.contains(brightnessOverlay)) {\n                        fullscreenElement.appendChild(brightnessOverlay);\n                    }\n                    brightnessOverlay.style.position = 'absolute';\n                    brightnessOverlay.style.zIndex = '2147483647';\n                } else {\n                    if (document.body.contains(brightnessOverlay)) {\n                        document.body.appendChild(brightnessOverlay);\n                    }\n                    brightnessOverlay.style.position = 'fixed';\n                    brightnessOverlay.style.zIndex = '2147483647';\n                }\n            }\n        } else {\n            if (!document.body.contains(brightnessOverlay)) {\n                document.body.appendChild(brightnessOverlay);\n            }\n            brightnessOverlay.style.position = 'fixed';\n            brightnessOverlay.style.zIndex = '2147483647';\n        }\n    };\n\n    // 检查是否在全屏模式\n    const isFullscreen = () => {\n        return document.fullscreenElement || \n               document.webkitFullscreenElement ||\n               document.mozFullScreenElement ||\n               document.msFullscreenElement;\n    };\n\n    // 检查是否在控制区域（全屏时排除顶部10%）\n    const isInControlArea = (startX, startY) => {\n        // 只有在全屏模式下才排除顶部区域\n        if (isFullscreen()) {\n            const screenHeight = window.innerHeight;\n            // 全屏时顶部10%区域用于系统手势（如下拉通知栏）\n            if (startY < screenHeight * 0.1) {\n                return false;\n            }\n        }\n        \n        return true;\n    };\n\n    // 确定手势类型\n    const determineGestureType = (diffX, diffY, startX) => {\n        // 如果已经确定了手势类型，就保持原样\n        if (gesture.gestureType) {\n            return gesture.gestureType;\n        }\n        \n        const absDiffX = Math.abs(diffX);\n        const absDiffY = Math.abs(diffY);\n        \n        // 只有当移动距离超过阈值时才确定手势类型\n        if (absDiffX < gesture.threshold && absDiffY < gesture.threshold) {\n            return null;\n        }\n        \n        // 判断主要移动方向\n        if (absDiffX > absDiffY) {\n            // 主要横向移动 - 进度控制\n            return 'seek';\n        } else {\n            // 主要纵向移动 - 根据起始位置判断是亮度还是音量\n            const isLeftSide = startX < window.innerWidth / 2;\n            return isLeftSide ? 'brightness' : 'volume';\n        }\n    };\n\n    // 显示控制提示\n    const showControlTooltip = (icon, value = '') => {\n        controlTooltip.style.opacity = '1';\n        controlTooltip.querySelector('.control-icon').textContent = icon;\n        controlTooltip.querySelector('.control-value').textContent = value;\n    };\n\n    // 隐藏控制提示\n    const hideControlTooltip = () => {\n        controlTooltip.style.opacity = '0';\n    };\n\n    // 长按倍数播放\n    const onTouchStart = (e) => {\n        if (e.touches?.length > 1) return;\n\n        const clientX = e.clientX || e.touches[0].clientX;\n        const clientY = e.clientY || e.touches[0].clientY;\n        \n        // 检查是否在控制区域（全屏时排除顶部10%）\n        if (!isInControlArea(clientX, clientY)) return;\n\n        gesture.startX = clientX;\n        gesture.startY = clientY;\n        gesture.startTime = video.currentTime;\n        gesture.initialSpeed = player.speed;\n        gesture.isLongPress = false;\n        gesture.isSeeking = false;\n        gesture.wasPlaying = !video.paused;\n        gesture.lastTime = Date.now();\n        gesture.gestureType = null;\n        \n        gesture.initialBrightness = getSystemBrightness();\n        gesture.initialVolume = video.volume;\n        gesture.isBrightnessControl = false;\n        gesture.isVolumeControl = false;\n\n        gesture.longPressTimer = setTimeout(() => {\n            if (!gesture.isSeeking && !gesture.gestureType) {\n                gesture.isLongPress = true;\n                player.speed = speed;\n                \n                // 显示长按倍速提示\n                showControlTooltip('倍速', `${speed}×`);\n            }\n        }, 800);\n    };\n\n    // 滑动控制进度、亮度和音量\n    const onTouchMove = (e) => {\n        if (!gesture.startX || gesture.isLongPress) return;\n\n        const currentX = e.clientX || e.touches[0].clientX;\n        const currentY = e.clientY || e.touches[0].clientY;\n        const diffX = currentX - gesture.startX;\n        const diffY = currentY - gesture.startY;\n        \n        // 确定手势类型（如果尚未确定）\n        if (!gesture.gestureType) {\n            gesture.gestureType = determineGestureType(diffX, diffY, gesture.startX);\n            if (gesture.gestureType) {\n                clearTimeout(gesture.longPressTimer);\n            }\n        }\n        \n        // 根据确定的手势类型执行相应操作\n        switch (gesture.gestureType) {\n            case 'brightness':\n                handleBrightnessControl(diffY);\n                break;\n                \n            case 'volume':\n                handleVolumeControl(diffY);\n                break;\n                \n            case 'seek':\n                handleSeekControl(diffX);\n                break;\n                \n            default:\n                // 手势类型未确定，不执行任何操作\n                return;\n        }\n        \n        gesture.lastTime = Date.now();\n    };\n\n    // 处理亮度控制\n    const handleBrightnessControl = (diffY) => {\n        const brightnessChange = -diffY / window.innerHeight;\n        let newBrightness = Math.max(0.1, Math.min(1, gesture.initialBrightness + brightnessChange));\n        \n        setSystemBrightness(newBrightness);\n        \n        showControlTooltip('亮度', `${Math.round(newBrightness * 100)}%`);\n    };\n\n    // 处理音量控制\n    const handleVolumeControl = (diffY) => {\n        const volumeChange = -diffY / window.innerHeight;\n        let newVolume = Math.max(0, Math.min(1, gesture.initialVolume + volumeChange));\n        \n        video.volume = newVolume;\n        player.volume = newVolume;\n        \n        const iconText = newVolume === 0 ? '静音' : '音量';\n        showControlTooltip(iconText, `${Math.round(newVolume * 100)}%`);\n    };\n\n    // 处理进度控制\n    const handleSeekControl = (diffX) => {\n        if (!gesture.isSeeking) {\n            gesture.isSeeking = true;\n            gesture.wasPlaying = !video.paused;\n            if (gesture.wasPlaying) {\n                document.querySelector('.plyr__control--overlaid').classList.add('hidden');\n                video.pause();\n            }\n        }\n        \n        const seekAmount = Math.round((diffX / window.innerWidth) * 300);\n        const newTime = Math.max(0, Math.min(\n            gesture.startTime + seekAmount,\n            video.duration\n        ));\n        \n        if (Math.abs(video.currentTime - newTime) >= 1) {\n            $(\".video-container\")[0].style.background = '#000';\n            video.currentTime = newTime;\n        }\n        \n        if (newTime <= 0) {\n            showControlTooltip('已到开头');\n        } else if (newTime >= video.duration) {\n            showControlTooltip('已到结尾');\n        } else {\n            const directionText = seekAmount > 0 ? '前进' : '后退';\n            showControlTooltip(directionText, `${Math.abs(seekAmount)}秒`);\n        }\n    };\n\n    // 触摸结束\n    const onTouchEnd = () => {\n        clearTimeout(gesture.longPressTimer);\n        if (gesture.isLongPress) {\n            player.speed = gesture.initialSpeed;\n            // 立即隐藏提示\n            hideControlTooltip();\n        }\n        else if (gesture.wasPlaying && !gesture.isLongPress && gesture.isSeeking) {\n            video.play().catch(e => console.log(\"播放恢复失败:\", e));\n            setTimeout(() => {\n                document.querySelector('.plyr__control--overlaid').classList.remove('hidden');\n            }, 100);\n            // 延迟隐藏提示\n            setTimeout(hideControlTooltip, 500);\n        } else {\n            // 其他情况延迟隐藏提示\n            setTimeout(hideControlTooltip, 500);\n        }\n        \n        // 重置所有状态\n        gesture.startX = 0;\n        gesture.isSeeking = false;\n        gesture.isLongPress = false;\n        gesture.isBrightnessControl = false;\n        gesture.isVolumeControl = false;\n        gesture.gestureType = null;\n    };\n\n    // 事件监听\n    const playerContainer = document.querySelector('.plyr__video-wrapper');\n    playerContainer.addEventListener('touchstart', onTouchStart, { passive: true });\n    playerContainer.addEventListener('mousedown', onTouchStart);\n    playerContainer.addEventListener('touchmove', onTouchMove, { passive: false });\n    playerContainer.addEventListener('mousemove', onTouchMove);\n    playerContainer.addEventListener('touchend', onTouchEnd);\n    playerContainer.addEventListener('mouseup', onTouchEnd);\n    playerContainer.addEventListener('mouseleave', onTouchEnd);\n\n    setSystemBrightness(getSystemBrightness());\n\n    document.addEventListener('fullscreenchange', updateBrightnessOverlay);\n    document.addEventListener('webkitfullscreenchange', updateBrightnessOverlay);\n\n    // 注入CSS样式\n    const style = document.createElement('style');\n    style.textContent = `\n        .plyr__center-tooltip {\n            position: absolute;\n            top: calc(50% - 75px);\n            left: 50%;\n            transform: translate(-50%, -50%);\n            background-color: transparent;\n            color: white;\n            padding: 10px 20px;\n            border-radius: 5px;\n            z-index: 1000;\n            font-size: 18px;\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n            pointer-events: none;\n            opacity: 0;\n            transition: opacity 0.3s ease;\n            text-shadow: 0 0 5px rgba(0, 0, 0, 0.6), 0 0 10px rgba(0, 0, 0, 0.3);\n        }\n        .plyr__center-tooltip span { \n            font-weight: bold; \n            text-shadow: inherit; \n        }\n        .plyr__center-tooltip .control-value { \n            font-weight: normal; \n        }\n        \n        #brightness-overlay {\n            background: black;\n            pointer-events: none;\n            opacity: 0;\n            transition: opacity 0.2s ease;\n            z-index: 2147483647 !important;\n        }\n    `;\n    document.head.appendChild(style);\n}\n\n// 根据当前方向更新按钮可见状态\nfunction updateButtonVisibility(autonext) {\n    if (!document.fullscreenElement || !autonext) return;\n    \n    const isPortrait = window.innerHeight > window.innerWidth;\n    if (isPortrait) {\n        $('[data-plyr=\"rewind\"], [data-plyr=\"fast-forward\"]').forEach(btn => {\n            btn.style.display = 'none';\n        });\n    } else {\n        $('[data-plyr=\"rewind\"], [data-plyr=\"fast-forward\"]').forEach(btn => {\n            btn.style.display = 'flex';\n        });\n    }\n}\n\n// 处理全屏状态\nfunction updateFullscreen(autonext, video) {\n    if (!document.fullscreenElement) {\n        // 退出全屏时的处理\n        video.style.height = '56.25vw';\n        video.style.removeProperty('min-height');\n        $('.plyr__menu__container > div').forEach(menu => {\n            menu.style.maxHeight = '44vw';\n            menu.style.overflowY = 'auto';\n        });\n        if (autonext) {\n            $('.plyr__control--episode-prev, .plyr__control--episode-next').forEach(btn => {\n                btn.style.display = 'none';\n            });\n        }\n        $('[data-plyr=\"rewind\"], [data-plyr=\"fast-forward\"]').forEach(btn => {\n            btn.style.display = 'flex';\n        });\n        setTimeout(updatePadding, 100);\n    } else {\n        // 进入全屏时的处理\n        video.style.minHeight = '100%';\n        video.style.removeProperty('height');\n        $('.plyr__menu__container > div').forEach(menu => {\n            menu.style.maxHeight = '';\n            menu.style.overflowY = '';\n        });\n        if (autonext) {\n            $('.plyr__control--episode-prev, .plyr__control--episode-next').forEach(btn => {\n                btn.style.display = 'flex';\n            });\n            updateButtonVisibility(autonext); // 根据当前方向更新按钮\n        }\n        \n        // 强制重绘\n        setTimeout(() => {\n            const videoWrapper = document.querySelector('.plyr__video-wrapper');\n            if (videoWrapper) {\n                videoWrapper.style.display = 'flex';\n                videoWrapper.style.alignItems = 'center';\n                videoWrapper.style.justifyContent = 'center';\n                video.style.maxWidth = '100%';\n                video.style.maxHeight = '100%';\n                video.style.width = 'auto';\n                video.style.height = 'auto';\n            }\n        }, 100);\n        setTimeout(updatePadding, 100);\n    }\n}\n\n// 设置全屏和按钮显示处理\nfunction fullscreenControls(autonext, video) {\n    // 添加事件监听器\n    document.addEventListener('fullscreenchange', () => updateFullscreen(autonext, video));\n    window.addEventListener('resize', () => updateButtonVisibility(autonext));\n    window.addEventListener('orientationchange', () => {\n        setTimeout(() => updateButtonVisibility(autonext), 100);\n    });\n}\n\n// 锁定屏幕方向为横屏（实时跟随设备方向）\nfunction lockLandscapeOrientation() {\n    if (screen.orientation && screen.orientation.lock) {\n        // 移除之前的监听器\n        if (lockLandscapeOrientation.currentListener) {\n            window.removeEventListener('deviceorientation', lockLandscapeOrientation.currentListener);\n        }\n        \n        let lastDirection = null;\n        let hasSetInitial = false;\n        const DEAD_ZONE = 20; // 死区范围，避免轻微偏转就切换\n        \n        const handleOrientation = (event) => {\n            const gamma = event.gamma;\n            const beta = event.beta; // 前后倾斜角度\n            \n            // 在死区内不切换方向\n            if (Math.abs(gamma) < DEAD_ZONE) {\n                return;\n            }\n            \n            let newDirection;\n            \n            // 根据屏幕朝向调整方向判断\n            if (Math.abs(beta) > 90) {\n                // 屏幕朝下，需要反向判断\n                if (gamma > 0) {\n                    newDirection = 'landscape-primary'; // 屏幕朝下时，向右倾斜用右横屏\n                } else {\n                    newDirection = 'landscape-secondary'; // 屏幕朝下时，向左倾斜用左横屏\n                }\n            } else {\n                // 屏幕朝上，正常判断\n                if (gamma > 0) {\n                    newDirection = 'landscape-secondary'; // 设备向右，左横屏\n                } else {\n                    newDirection = 'landscape-primary'; // 设备向左，右横屏\n                }\n            }\n            \n            // 初始设置：立即根据第一个有效的gamma值设置方向\n            if (!hasSetInitial) {\n                hasSetInitial = true;\n                lastDirection = newDirection;\n                console.log('初始设置方向:', newDirection, 'gamma:', gamma, 'beta:', beta, '屏幕朝下:', Math.abs(beta) > 90);\n                screen.orientation.lock(newDirection).catch(error => {\n                    console.warn('初始方向锁定失败:', error);\n                });\n                return;\n            }\n            \n            // 后续切换：只有当方向确实改变时才锁定\n            if (newDirection !== lastDirection) {\n                lastDirection = newDirection;\n                console.log('切换横屏方向:', newDirection, 'gamma:', gamma, 'beta:', beta, '屏幕朝下:', Math.abs(beta) > 90);\n                screen.orientation.lock(newDirection).catch(error => {\n                    console.warn('横屏方向切换失败:', error);\n                });\n            }\n        };\n        \n        // 开始监听\n        window.addEventListener('deviceorientation', handleOrientation);\n        lockLandscapeOrientation.currentListener = handleOrientation;\n        \n        // 不设置默认方向，等待第一个设备方向事件\n        console.log('等待设备方向数据...');\n    }\n}\n\n// 锁定屏幕方向为竖屏\nfunction lockPortraitOrientation() {\n    if (screen.orientation && screen.orientation.lock) {\n        // 移除横屏的监听器（如果有）\n        if (lockLandscapeOrientation.currentListener) {\n            window.removeEventListener('deviceorientation', lockLandscapeOrientation.currentListener);\n            lockLandscapeOrientation.currentListener = null;\n        }\n        \n        console.log('锁定竖屏方向');\n        // 强制锁定竖屏，忽略当前设备方向\n        screen.orientation.lock('portrait').catch(error => {\n            console.warn('竖屏锁定失败:', error);\n        });\n    }\n}\n\n// 解锁屏幕方向\nfunction unlockOrientation() {\n    if (screen.orientation && screen.orientation.unlock) {\n        screen.orientation.unlock();\n    }\n    \n    // 移除设备方向监听\n    if (lockLandscapeOrientation.currentListener) {\n        window.removeEventListener('deviceorientation', lockLandscapeOrientation.currentListener);\n        lockLandscapeOrientation.currentListener = null;\n    }\n}\n\n// 检测视频方向\nfunction checkVideoOrientation(player) {\n    const video = player.media;\n    if (video.videoWidth && video.videoHeight) {\n        const aspectRatio = video.videoWidth / video.videoHeight;\n        return aspectRatio > 1; // 大于1为横屏，小于1为竖屏\n    }\n    return false;\n}\n\n// 初始化播放器方向控制\nfunction initPlayerOrientationControl(player) {\n    let isLandscapeVideo = false;\n    \n    // 视频元数据加载时检测视频方向\n    player.on('loadedmetadata', () => {\n        isLandscapeVideo = checkVideoOrientation(player);\n        console.log('视频方向:', isLandscapeVideo ? '横屏' : '竖屏');\n    });\n    \n    // 进入全屏时根据视频方向锁定屏幕\n    player.on('enterfullscreen', () => {\n        isLandscapeVideo = checkVideoOrientation(player);\n        console.log('进入全屏，视频方向:', isLandscapeVideo ? '横屏' : '竖屏');\n        \n        // 立即锁定方向，不等待\n        if (isLandscapeVideo) {\n            lockLandscapeOrientation();\n        } else {\n            lockPortraitOrientation();\n        }\n    });\n    \n    // 退出全屏时解锁方向\n    player.on('exitfullscreen', () => {\n        console.log('退出全屏，解锁方向');\n        unlockOrientation();\n    });\n}\n\n// 添加顶部集数显示（上移动画版）\nfunction addEpisodeBarToPlayer() {\n    // 添加顶部集数显示条\n    const episodeBar = document.createElement('div');\n    episodeBar.className = 'plyr__episode-bar';\n    episodeBar.style.transform = 'translateY(0)';\n    episodeBar.style.opacity = '1';\n    \n    // 创建标题元素\n    const titleElement = document.createElement('div');\n    titleElement.className = 'plyr__episode-title';\n    \n    // 初始化集数标题\n    const updateEpisodeTitle = () => {\n        const activeButton = document.querySelector('.jishu button.active');\n        if (activeButton) {\n            titleElement.textContent = activeButton.textContent.trim();\n        }\n    };\n    \n    // 初始设置标题\n    updateEpisodeTitle();\n    episodeBar.appendChild(titleElement);\n    document.querySelector('.plyr__video-wrapper').appendChild(episodeBar);\n\n    // 同步播放器控件状态（顶部条上移，底部条下移）\n    const syncWithControls = () => {\n        const controls = player.elements.controls;\n        const controlsStyle = window.getComputedStyle(controls);\n        \n        // 根据底部控制栏状态决定顶部条状态\n        if (controlsStyle.transform === 'none' || controlsStyle.opacity === '1') {\n            // 控制栏显示时：顶部条下滑进入\n            episodeBar.style.transform = 'translateY(0)';\n            episodeBar.style.opacity = '1';\n        } else {\n            // 控制栏隐藏时：顶部条上滑隐藏\n            episodeBar.style.transform = 'translateY(-100%)';\n            episodeBar.style.opacity = '0';\n        }\n    };\n\n    // 使用Plyr原生事件同步状态\n    player.on('controlsshown', () => {\n        episodeBar.style.transform = 'translateY(0)';\n        episodeBar.style.opacity = '1';\n    });\n    \n    player.on('controlshidden', () => {\n        episodeBar.style.transform = 'translateY(-100%)';\n        episodeBar.style.opacity = '0';\n    });\n\n    // 监听集数切换事件\n    const observeEpisodeChange = () => {\n        const activeButtonObserver = new MutationObserver(() => {\n            updateEpisodeTitle();\n            // 切换集数时短暂显示\n            //episodeBar.style.transform = 'translateY(0)';\n            //episodeBar.style.opacity = '1';\n            //setTimeout(syncWithControls, 500);\n        });\n\n        const buttons = document.querySelectorAll('.jishu button');\n        buttons.forEach(button => {\n            activeButtonObserver.observe(button, { attributes: true });\n        });\n    };\n\n    // 全屏适配\n    player.on('enterfullscreen exitfullscreen', () => {\n        if (player.fullscreen.active) {\n            episodeBar.style.height = '60px';\n            episodeBar.querySelector('.plyr__episode-title').style.fontSize = '18px';\n        } else {\n            episodeBar.style.height = '40px';\n            episodeBar.querySelector('.plyr__episode-title').style.fontSize = '14px';\n        }\n    });\n\n    // 初始同步\n    setTimeout(() => {\n        // 绑定与Plyr相同的鼠标事件\n        const container = player.elements.container;\n        \n        container.addEventListener('mousemove', () => {\n            episodeBar.style.transform = 'translateY(0)';\n            episodeBar.style.opacity = '1';\n        });\n        \n        container.addEventListener('mouseleave', syncWithControls);\n        \n        syncWithControls();\n        observeEpisodeChange();\n    }, 50);\n    \n    // 添加样式\n    const style = document.createElement('style');\n    style.textContent = `\n        .plyr__episode-bar {\n            position: absolute;\n            top: 0;\n            left: 0;\n            right: 0;\n            height: 40px;\n            background: linear-gradient(\n              to bottom, \n              rgba(0,0,0,0.8) 0%,\n              rgba(0,0,0,0.5) 30%,\n              rgba(0,0,0,0) 100%\n            );\n            color: white;\n            display: flex;\n            align-items: center;\n            padding-left: 15px;\n            z-index: 3;\n            transform: translateY(-100%);\n            opacity: 0;\n            transition: all 0.4s ease-in-out;\n            pointer-events: none;\n        }\n        .plyr__episode-title {\n            font-size: 14px;\n            text-shadow: 0 0 5px rgba(0,0,0,0.5);\n            white-space: nowrap;\n            overflow: hidden;\n            text-overflow: ellipsis;\n            width: 75%;\n            display: block;   \n        }\n        .plyr--fullscreen .plyr__episode-bar {\n            height: 60px;\n            padding-left: 20px;\n        }\n        .plyr--fullscreen .plyr__episode-title {\n            font-size: 18px;\n        }\n    `;\n    document.head.appendChild(style);\n}\n\n// 添加跳过菜单项\nfunction addSkipMenuItems(currentVideoUrl, timeManager) {\n    // 等待设置菜单加载完成\n    setTimeout(() => {\n        const settingsMenu = document.querySelector('.plyr__menu__container');\n        if (!settingsMenu) return;\n\n        // 创建跳过菜单项\n        const skipMenuItem = document.createElement('div');\n        skipMenuItem.className = 'plyr__skip-menu-item';\n        skipMenuItem.style.margin = '0 8px';\n        skipMenuItem.style.boxShadow = `\n            0 -1px 0 #ccc, \n            0 -2px 0 var(--plyr-menu-back-border-shadow-color, #fff)\n        `;\n        skipMenuItem.innerHTML = `\n            <span style=\"display: block; text-align: center; font-size: 15px; margin: 8px;\">标记片头/片尾</span>\n        `;\n        skipMenuItem.setAttribute('role', 'menuitem');\n\n        // 创建子菜单容器\n        const submenuContainer = document.createElement('div');\n        submenuContainer.className = 'plyr__skip-submenu';\n        submenuContainer.setAttribute('hidden', '');\n        submenuContainer.setAttribute('role', 'menu');\n        \n        // 创建返回项\n        const backItem = document.createElement('div');\n        backItem.style.margin = '4px 0';\n        backItem.style.boxShadow = `\n            0 1px 0 var(--plyr-menu-back-border-shadow-color, #fff), \n            0 2px 0 #ccc\n        `;\n        backItem.innerHTML = `\n            <span style=\"display: block; text-align: center; height: 32px; font-size: 15px; margin: 4px 10px;\">返回上级菜单</span>\n        `;\n        backItem.setAttribute('role', 'menuitem');\n\n        // 实时获取标记时间\n        const getMarkTimes = () => ({\n            head: localStorage.getItem('head' + currentVideoUrl),\n            end: localStorage.getItem('end' + currentVideoUrl)\n        });\n\n        // 创建子菜单项\n        const submenuItems = `\n            <div style=\"display: flex; align-items: center; justify-content: space-between; padding: 4px 8px; margin: 2px 4px;\">\n                <div style=\"display: flex; align-items: center;\">\n                    <div style=\"font-size: 14px;\" data-action=\"mark-start\" role=\"menuitem\">\n                        ${getMarkTimes().head ? '已设片头' : '标记片头'}\n                    </div>\n                    <div style=\"font-size: 14px; color: #999; margin-left: 10px;\" class=\"head-time-display\">\n                        ${getMarkTimes().head ? formatTime(getMarkTimes().head) : '无'}\n                    </div>\n                </div>\n            </div>\n            \n            <div style=\"display: flex; align-items: center; justify-content: space-between; padding: 4px 8px; margin: 2px 4px;\">\n                <div style=\"display: flex; align-items: center;\">\n                    <div style=\"font-size: 14px;\" data-action=\"mark-end\" role=\"menuitem\">\n                        ${getMarkTimes().end ? '已设片尾' : '标记片尾'}\n                    </div>\n                    <div style=\"font-size: 14px; color: #999; margin-left: 10px;\" class=\"end-time-display\">\n                        ${getMarkTimes().end ? formatTime(getMarkTimes().end) : '无'}\n                    </div>\n                </div>\n            </div>\n            \n            <div style=\"display: flex; justify-content: center; padding: 4px 8px; margin: 2px 0 0 0;\">\n                <div style=\"font-size: 14px;\" data-action=\"clear-marks\" role=\"menuitem\">\n                    清除全部标记\n                </div>\n            </div>\n        `;\n\n        submenuContainer.appendChild(backItem);\n        submenuContainer.insertAdjacentHTML('beforeend', submenuItems);\n\n        // 添加到DOM - 插入到菜单最后面\n        settingsMenu.appendChild(skipMenuItem);\n        settingsMenu.appendChild(submenuContainer);\n\n        // 存储原始菜单项\n        const originalMenuItems = Array.from(settingsMenu.children).filter(\n            child => !child.classList.contains('plyr__skip-menu-item') && \n                    !child.classList.contains('plyr__skip-submenu')\n        );\n\n        // 更新时间显示函数\n        function updateTimeDisplay() {\n            const { head, end } = getMarkTimes();\n            const headDisplay = submenuContainer.querySelector('.head-time-display');\n            const endDisplay = submenuContainer.querySelector('.end-time-display');\n            const markStartBtn = submenuContainer.querySelector('[data-action=\"mark-start\"]');\n            const markEndBtn = submenuContainer.querySelector('[data-action=\"mark-end\"]');\n            \n            if (headDisplay) {\n                headDisplay.textContent = head ? formatTime(head) : '无';\n                headDisplay.style.color = head ? '#4CAF50' : '#999';\n                markStartBtn.textContent = head ? '已设片头' : '标记片头';\n            }\n            \n            if (endDisplay) {\n                endDisplay.textContent = end ? formatTime(end) : '无';\n                endDisplay.style.color = end ? '#FF5722' : '#999';\n                markEndBtn.textContent = end ? '已设片尾' : '标记片尾';\n            }\n        }\n\n        // 添加事件监听\n        skipMenuItem.addEventListener('click', (e) => {\n            e.stopPropagation();\n            updateTimeDisplay();\n            originalMenuItems.forEach(item => item.style.display = 'none');\n            skipMenuItem.style.display = 'none';\n            submenuContainer.removeAttribute('hidden');\n        });\n\n        // 返回按钮点击事件\n        backItem.addEventListener('click', () => {\n            submenuContainer.setAttribute('hidden', '');\n            originalMenuItems.forEach(item => item.style.display = '');\n            skipMenuItem.style.display = '';\n        });\n\n        // 标记片头点击事件\n        submenuContainer.querySelector('[data-action=\"mark-start\"]').addEventListener('click', () => {\n            let headtime = getMarkTimes().head;\n            timeManager.setHeadTime(player.currentTime);\n            showTemporaryMessage(`已${headtime ? '重设' : '标记'}片头: ${formatTime(timeManager.headtime)}`);\n        });\n\n        // 标记片尾点击事件\n        submenuContainer.querySelector('[data-action=\"mark-end\"]').addEventListener('click', () => {\n            let endtime = getMarkTimes().end;\n            timeManager.setEndTime(player.duration - player.currentTime);\n            showTemporaryMessage(`已${endtime ? '重设' : '标记'}片尾: ${formatTime(timeManager.endtime)}`);\n        });\n\n        // 清除标记点击事件\n        submenuContainer.querySelector('[data-action=\"clear-marks\"]').addEventListener('click', () => {\n            timeManager.clearMarks();\n            showTemporaryMessage('已清除全部标记');\n        });\n\n        // 添加时间更新监听\n        timeManager.addListener(({ type }) => {\n            updateTimeDisplay();\n            \n            // 如果是清除操作，确保UI同步更新\n            if (type === 'clear') {\n                const markStartBtn = submenuContainer.querySelector('[data-action=\"mark-start\"]');\n                const markEndBtn = submenuContainer.querySelector('[data-action=\"mark-end\"]');\n                if (markStartBtn) markStartBtn.textContent = '标记片头';\n                if (markEndBtn) markEndBtn.textContent = '标记片尾';\n            }\n        });\n\n        // 显示临时消息\n        function showTemporaryMessage(message) {\n            const messageEl = document.createElement('div');\n            messageEl.className = 'plyr__skip-message';\n            messageEl.textContent = message;\n            document.querySelector('.plyr').appendChild(messageEl);\n            \n            setTimeout(() => {\n                messageEl.classList.add('fade-out');\n                setTimeout(() => messageEl.remove(), 300);\n            }, 2000);\n        }\n\n        // 添加样式\n        if (!document.querySelector('#plyrSkipMessageStyle')) {\n            const style = document.createElement('style');\n            style.id = 'plyrSkipMessageStyle';\n            style.textContent = `\n                .plyr__skip-message {\n                    position: fixed;\n                    top: 30px;\n                    left: 15px;\n                    transform: none;\n                    background-color: rgba(0, 0, 0, 0.5);\n                    color: white;\n                    padding: 10px 20px;\n                    border-radius: 4px;\n                    z-index: 1000;\n                    text-align: left;\n                    font-size: 14px;\n                    transition: opacity 0.3s ease;\n                }\n                .plyr__skip-message.fade-out {\n                    opacity: 0;\n                }\n                .plyr__skip-menu-item {\n                    cursor: pointer;\n                }\n                .plyr__skip-menu-item:hover {\n                    background-color: rgba(255,255,255,0.1);\n                }\n            `;\n            document.head.appendChild(style);\n        }\n\n        // 初始显示菜单项\n        skipMenuItem.style.display = '';\n\n        // 监听显示菜单项\n        function observeMainMenuState() {\n            const observer = new MutationObserver((mutations) => {\n                mutations.forEach((mutation) => {\n                    const homeMenu = document.querySelector('[id^=\"plyr-settings-\"][id$=\"-home\"]');\n                    const subMenu = document.querySelector('.plyr__skip-submenu');\n                    if (homeMenu && subMenu) {\n                        const homeIsHidden = homeMenu.hasAttribute('hidden');\n                        const subIsHidden = subMenu.hasAttribute('hidden');\n                        skipMenuItem.style.display = homeIsHidden || !subIsHidden ? 'none' : '';\n                    }\n                });\n            });\n\n            // 监听整个 document（因为菜单可能动态加载）\n            observer.observe(document.body, {\n                childList: true,    // 监听子元素增删\n                subtree: true,      // 监听所有后代元素\n                attributes: true,   // 监听属性变化\n                attributeFilter: ['hidden', 'id'] // 只监听 hidden 和 id 变化\n            });\n\n            // 初始检查\n            const initialHomeMenu = document.querySelector('[id^=\"plyr-settings-\"][id$=\"-home\"]');\n            const initialSubMenu = document.querySelector('.plyr__skip-submenu');\n            if (initialHomeMenu && initialSubMenu) {\n                const homeIsHidden = initialHomeMenu.hasAttribute('hidden');\n                const subIsHidden = initialSubMenu.hasAttribute('hidden');\n                skipMenuItem.style.display = homeIsHidden || !subIsHidden ? 'none' : '';\n            }\n        }\n\n        // 启动监听\n        observeMainMenuState();\n    }, 500);\n}\n\n// 格式化时间显示\nfunction formatTime(seconds) {\n    seconds = parseFloat(seconds);\n    const date = new Date(0);\n    date.setSeconds(seconds);\n    const timeString = date.toISOString().substr(11, 8);\n    return timeString.startsWith('00:') ? timeString.substr(3) : timeString;\n}\n\n// HLS播放-检测网络状况并自适应调整\nfunction getOptimalHlsConfig() {\n    const connection = navigator.connection || {};\n    const downlink = connection.downlink || 5;\n    \n    if (downlink > 10) {\n        return adaptiveConfigManager.getHighSpeedConfig();\n    } else if (downlink > 5) {\n        return adaptiveConfigManager.getMediumSpeedConfig();\n    } else {\n        return adaptiveConfigManager.getLowSpeedConfig();\n    }\n}\n\n// 自适应配置管理器\nconst adaptiveConfigManager = {\n    performanceMetrics: {\n        loadTimes: [],\n        bufferingEvents: 0,\n        averageLoadTime: 0,\n        lastUpdateTime: 0\n    },\n    \n    // 配置模板\n    configTemplates: {\n        highSpeed: {\n            // 缓冲区设置\n            maxBufferSize: 800 * 1024 * 1024,  // 800MB\n            maxBufferLength: 600,              // 10分钟缓冲区\n            maxMaxBufferLength: 1200,          // 20分钟最大缓冲区\n            backBufferLength: 300,             // 5分钟后缓冲区\n            \n            // 预加载优化\n            preloadTime: 90,                   // 预加载90秒\n            initialLiveManifestSize: 5,\n            \n            // 网络优化\n            maxLoadingDelay: 1,\n            maxSeekHole: 0.5,\n            maxFragLookUpTolerance: 0.05,\n            highBufferWatchdogPeriod: 0.5,\n            nudgeOffset: 0.02,\n            nudgeMaxRetry: 15,\n            maxStarvationDelay: 1\n        },\n        mediumSpeed: {\n            // 缓冲区设置\n            maxBufferSize: 600 * 1024 * 1024,  // 600MB\n            maxBufferLength: 450,              // 7.5分钟缓冲区\n            maxMaxBufferLength: 900,           // 15分钟最大缓冲区\n            backBufferLength: 240,             // 4分钟后缓冲区\n            \n            // 预加载优化\n            preloadTime: 75,                   // 预加载75秒\n            initialLiveManifestSize: 4,\n            \n            // 网络优化\n            maxLoadingDelay: 1.5,\n            maxSeekHole: 1,\n            maxFragLookUpTolerance: 0.08,\n            highBufferWatchdogPeriod: 1,\n            nudgeOffset: 0.03,\n            nudgeMaxRetry: 12,\n            maxStarvationDelay: 2\n        },\n        lowSpeed: {\n            // 缓冲区设置\n            maxBufferSize: 500 * 1024 * 1024,  // 500MB\n            maxBufferLength: 360,              // 6分钟缓冲区\n            maxMaxBufferLength: 720,           // 12分钟最大缓冲区\n            backBufferLength: 180,             // 3分钟后缓冲区\n            \n            // 预加载优化\n            preloadTime: 60,                   // 预加载60秒\n            initialLiveManifestSize: 3,\n            \n            // 网络优化\n            maxLoadingDelay: 2,\n            maxSeekHole: 1.5,\n            maxFragLookUpTolerance: 0.1,\n            highBufferWatchdogPeriod: 1.5,\n            nudgeOffset: 0.05,\n            nudgeMaxRetry: 15,\n            maxStarvationDelay: 3\n        }\n    },\n    \n    // 根据性能指标调整配置\n    adaptConfigBasedOnPerformance() {\n        const metrics = this.performanceMetrics;\n        \n        // 计算平均加载时间\n        if (metrics.loadTimes.length > 0) {\n            metrics.averageLoadTime = metrics.loadTimes.reduce((a, b) => a + b) / metrics.loadTimes.length;\n        }\n\n        // 基于性能指标选择配置\n        if (metrics.averageLoadTime < 2000 && metrics.bufferingEvents < 2) {\n            console.log('加载状况良好，使用高速配置');\n            return this.getHighSpeedConfig();\n        } else if (metrics.averageLoadTime < 5000 && metrics.bufferingEvents < 5) {\n            console.log('加载状况中等，使用平衡配置');\n            return this.getMediumSpeedConfig();\n        } else {\n            console.log('加载状况较差，使用保守配置');\n            return this.getLowSpeedConfig();\n        }\n    },\n    \n    getHighSpeedConfig() {\n        return { ...this.configTemplates.highSpeed };\n    },\n    \n    getMediumSpeedConfig() {\n        return { ...this.configTemplates.mediumSpeed };\n    },\n    \n    getLowSpeedConfig() {\n        return { ...this.configTemplates.lowSpeed };\n    },\n    \n    // 应用配置到HLS实例\n    applyConfigToHls(hlsInstance, config) {\n        Object.keys(config).forEach(key => {\n            if (hlsInstance.hasOwnProperty(key)) {\n                hlsInstance[key] = config[key];\n            }\n        });\n    },\n    \n    // 动态调整配置\n    adaptHlsConfig(hlsInstance) {\n        if (this.performanceMetrics.loadTimes.length >= 3) {\n            const newConfig = this.adaptConfigBasedOnPerformance();\n            this.applyConfigToHls(hlsInstance, newConfig);\n            console.log('已根据加载性能动态调整HLS配置');\n        }\n    },\n    \n    // 记录片段加载时间\n    recordFragmentLoadTime(duration) {\n        this.performanceMetrics.loadTimes.push(duration);\n        \n        // 只保留最近10个记录\n        if (this.performanceMetrics.loadTimes.length > 10) {\n            this.performanceMetrics.loadTimes.shift();\n        }\n    },\n    \n    // 记录缓冲事件\n    recordBufferingEvent() {\n        this.performanceMetrics.bufferingEvents++;\n    },\n    \n    // 重置性能指标\n    resetMetrics() {\n        this.performanceMetrics.loadTimes = [];\n        this.performanceMetrics.bufferingEvents = 0;\n        this.performanceMetrics.averageLoadTime = 0;\n    }\n};\n\n// HLS播放\nfunction initializeHlsPlayer(source, headersOrReferer = null, video, currentTime, callback) {\n    if (currentHls) {\n        currentHls.stopLoad();\n        currentHls.detachMedia();\n        currentHls.destroy();\n    }\n\n    // 处理参数兼容性\n    let headers = null;\n    if (headersOrReferer) {\n        if (typeof headersOrReferer === 'string') {\n            headers = { 'Referer': headersOrReferer };\n        } else {\n            headers = headersOrReferer;\n        }\n    }\n\n    // 广告拦截配置\n    const adBlockConfig = {\n        enabled: true, // 设为false来禁用广告拦截\n        // 广告片段识别关键词\n        adKeywords: ['/ad/', 'ad_', '_ad', 'commercial', 'midroll', 'preroll', 'postroll'],\n        // 处理方式：'skip'=跳过，'empty'=返回空数据\n        strategy: 'skip'\n    };\n\n    // 获取初始配置\n    const initialConfig = getOptimalHlsConfig();\n    \n    currentHls = new Hls({\n        ...initialConfig,\n        // 通用优化设置\n        enableWorker: true,\n        enableSoftwareAES: true,\n        stretchShortVideoTrack: true,\n        forceKeyFrameOnDiscontinuity: true,\n        optimizeAudioOnly: false,\n        lowLatencyMode: false,\n        \n        // 使用 xhrSetup\n        xhrSetup: function(xhr, url) {\n            const startTime = performance.now();\n            const connection = navigator.connection || {};\n            const downlink = connection.downlink || 5;\n            const timeout = downlink > 10 ? 90000 : downlink > 5 ? 60000 : 30000;\n            \n            // 设置超时\n            xhr.timeout = timeout;\n            \n            // 设置响应类型\n            xhr.responseType = 'arraybuffer';\n            \n            // 检查是否为广告片段\n            if (adBlockConfig.enabled && isAdSegment(url)) {\n                return handleAdRequest(xhr, url);\n            }\n            \n            // 添加自定义 headers\n            if (headers) {\n                Object.keys(headers).forEach(key => {\n                    xhr.setRequestHeader(key, headers[key]);\n                });\n            }\n            \n            // 监听加载完成事件\n            const originalSend = xhr.send;\n            xhr.send = function(body) {\n                this.addEventListener('loadend', function() {\n                    if (this.status >= 200 && this.status < 300) {\n                        const loadTime = performance.now() - startTime;\n                        adaptiveConfigManager.recordFragmentLoadTime(loadTime);\n                        \n                        // 如果加载时间过长，动态调整配置\n                        if (loadTime > 5000) {\n                            adaptiveConfigManager.adaptHlsConfig(currentHls);\n                        }\n                    }\n                });\n                originalSend.call(this, body);\n            };\n            \n            // 监听超时事件\n            xhr.addEventListener('timeout', function() {\n                console.warn('XHR request timed out after', timeout, 'ms');\n            });\n            \n            // 监听错误事件\n            xhr.addEventListener('error', function() {\n                console.error('XHR request failed');\n            });\n        }\n    });\n\n    // 广告检测函数\n    function isAdSegment(url) {\n        if (!adBlockConfig.enabled) return false;\n        \n        const lowerUrl = url.toLowerCase();\n        \n        // 检查URL是否包含广告关键词\n        for (const keyword of adBlockConfig.adKeywords) {\n            if (lowerUrl.includes(keyword.toLowerCase())) {\n                return true;\n            }\n        }\n        \n        return false;\n    }\n\n    // 处理广告请求\n    function handleAdRequest(xhr, url) {\n        console.log('拦截广告片段:', url.substring(0, 100));\n        \n        switch (adBlockConfig.strategy) {\n            case 'skip':\n                // 返回空数据，让HLS跳过这个片段\n                return createMockResponse(xhr);\n                \n            case 'empty':\n                // 返回一个小型的合法视频片段（避免解码错误）\n                return createEmptySegmentResponse(xhr);\n                \n            default:\n                return createMockResponse(xhr);\n        }\n    }\n\n    // 创建模拟响应（跳过广告）\n    function createMockResponse(xhr) {\n        // 设置XHR状态为已完成\n        Object.defineProperties(xhr, {\n            'readyState': { value: 4, writable: false },\n            'status': { value: 200, writable: false },\n            'response': { value: new ArrayBuffer(0), writable: false },\n            'responseText': { value: '', writable: false }\n        });\n        \n        // 异步触发事件\n        setTimeout(() => {\n            // 触发readyStateChange\n            if (xhr.onreadystatechange) {\n                xhr.onreadystatechange.call(xhr);\n            }\n            \n            // 触发load事件\n            if (xhr.onload) {\n                xhr.onload.call(xhr);\n            }\n            \n            // 触发原生事件\n            const events = ['readystatechange', 'load', 'loadend'];\n            events.forEach(eventName => {\n                try {\n                    xhr.dispatchEvent(new Event(eventName));\n                } catch (e) {\n                    // 忽略事件分发错误\n                }\n            });\n        }, 0);\n        \n        // 阻止实际网络请求\n        xhr.send = function() {\n            // 什么都不做，已经模拟了响应\n        };\n        \n        return true;\n    }\n\n    // 创建空片段响应（更稳定的方案）\n    function createEmptySegmentResponse(xhr) {\n        // 创建一个非常小的视频片段（避免解码器错误）\n        // 这是一个H.264 NAL unit的简单示例（空片段）\n        const emptySegment = new Uint8Array([\n            0x00, 0x00, 0x00, 0x01, // NALU start code\n            0x09, 0xF0,             // NALU type: Access Unit Delimiter\n            0x00, 0x00, 0x00, 0x01, // NALU start code\n            0x06, 0x05              // NALU type: SEI\n        ]);\n        \n        Object.defineProperties(xhr, {\n            'readyState': { value: 4, writable: false },\n            'status': { value: 200, writable: false },\n            'response': { value: emptySegment.buffer, writable: false }\n        });\n        \n        setTimeout(() => {\n            if (xhr.onload) xhr.onload.call(xhr);\n            try {\n                xhr.dispatchEvent(new Event('load'));\n            } catch (e) {\n                // 忽略错误\n            }\n        }, 10);\n        \n        xhr.send = function() {\n            // 阻止实际发送\n        };\n        \n        return true;\n    }\n\n    // 监听HLS事件来优化广告检测\n    currentHls.on(Hls.Events.FRAG_LOADING, (event, data) => {\n        const frag = data.frag;\n        // 可以在片段加载时进行额外检测\n        if (frag.duration < 10 && frag.duration > 0) {\n            // 短片段可能是广告，但这里只是记录不处理\n            frag._isPotentialAd = true;\n        }\n    });\n\n    currentHls.loadSource(source);\n    currentHls.attachMedia(video);\n\n    // 监听缓冲事件\n    currentHls.on(Hls.Events.ERROR, (event, data) => {\n        if (data.details === Hls.ErrorDetails.BUFFER_STALLED_ERROR) {\n            adaptiveConfigManager.recordBufferingEvent();\n            \n            // 如果有多次缓冲事件，立即调整配置\n            if (adaptiveConfigManager.performanceMetrics.bufferingEvents >= 3) {\n                adaptiveConfigManager.adaptHlsConfig(currentHls);\n            }\n        }\n        \n        // 处理广告拦截可能引起的错误\n        if (data.details === Hls.ErrorDetails.FRAG_LOAD_ERROR || \n            data.details === Hls.ErrorDetails.FRAG_LOAD_TIMEOUT) {\n            if (data.frag && isAdSegment(data.frag.url)) {\n                console.log('广告片段加载错误已忽略');\n                data.recovered = true;\n            }\n        }\n    });\n\n    currentHls.on(Hls.Events.MANIFEST_PARSED, () => {\n        if (currentTime > 0) {\n            video.currentTime = parseFloat(currentTime);\n            $(\".video-container\")[0].style.background = '#000';\n        }\n        if (callback) callback();\n    });\n\n    // 定期检查性能并调整配置（每30秒）\n    const performanceCheckInterval = setInterval(() => {\n        if (adaptiveConfigManager.performanceMetrics.loadTimes.length >= 5) {\n            adaptiveConfigManager.adaptHlsConfig(currentHls);\n        }\n    }, 30000);\n\n    // 清理interval当HLS实例被销毁时\n    currentHls.on(Hls.Events.DESTROYING, () => {\n        clearInterval(performanceCheckInterval);\n    });\n}\n\n// 可选：提供一个函数来启用/禁用广告拦截\nfunction setAdBlockEnabled(enabled) {\n    if (window.initializeHlsPlayer && window.initializeHlsPlayer.adBlockConfig) {\n        window.initializeHlsPlayer.adBlockConfig.enabled = enabled;\n    }\n}\n\n// 可选：添加广告关键词\nfunction addAdKeyword(keyword) {\n    if (window.initializeHlsPlayer && window.initializeHlsPlayer.adBlockConfig) {\n        if (!window.initializeHlsPlayer.adBlockConfig.adKeywords.includes(keyword)) {\n            window.initializeHlsPlayer.adBlockConfig.adKeywords.push(keyword);\n        }\n    }\n}\n\n// 普通播放\nfunction initializeRegularPlayer(source, headersOrReferer = null, video, currentTime, callback) {\n    video.src = '';\n    video.load();\n    video.preload = \"auto\";\n\n    // 处理参数兼容性\n    let headers = null;\n    if (headersOrReferer) {\n        if (typeof headersOrReferer === 'string') {\n            headers = { 'Referer': headersOrReferer };\n        } else {\n            headers = headersOrReferer;\n        }\n    }\n\n    if (headers) {\n        const xhr = new XMLHttpRequest();\n        xhr.open('HEAD', source, true);\n        \n        Object.keys(headers).forEach(key => {\n            xhr.setRequestHeader(key, headers[key]);\n        });\n        \n        xhr.withCredentials = true;\n        xhr.timeout = 10000;\n        \n        xhr.onload = function() {\n            const acceptRanges = xhr.getResponseHeader('Accept-Ranges');\n            const contentLength = xhr.getResponseHeader('Content-Length');\n            \n            console.log('服务器响应:', {\n                acceptRanges: acceptRanges,\n                contentLength: contentLength,\n                status: xhr.status\n            });\n            \n            if (acceptRanges === 'bytes' && contentLength) {\n                console.log('服务器支持range请求，使用MediaSource播放');\n                setVideoSourceWithHeaders();\n            } else {\n                console.log('服务器不支持range请求，直接加载');\n                directLoadVideo();\n            }\n        };\n        \n        xhr.onerror = function() {\n            console.error('HEAD请求失败');\n            directLoadVideo();\n        };\n        \n        xhr.ontimeout = function() {\n            console.warn('HEAD请求超时');\n            directLoadVideo();\n        };\n        \n        try {\n            xhr.send();\n        } catch (error) {\n            console.error('发送HEAD请求异常:', error);\n            directLoadVideo();\n        }\n    } else {\n        directLoadVideo();\n    }\n\n    function setVideoSourceWithHeaders() {\n        if ('MediaSource' in window && MediaSource.isTypeSupported('video/mp4')) {\n            console.log('使用MediaSource API');\n            const mediaSource = new MediaSource();\n            video.src = URL.createObjectURL(mediaSource);\n            \n            mediaSource.addEventListener('sourceopen', function() {\n                const mimeCodec = 'video/mp4; codecs=\"avc1.42E01E,mp4a.40.2\"';\n                const sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);\n                \n                const xhr = new XMLHttpRequest();\n                xhr.open('GET', source, true);\n                xhr.responseType = 'arraybuffer';\n                \n                Object.keys(headers).forEach(key => {\n                    xhr.setRequestHeader(key, headers[key]);\n                });\n                \n                xhr.onload = function() {\n                    if (xhr.status >= 200 && xhr.status < 300) {\n                        console.log('视频数据加载完成，大小:', (xhr.response.byteLength / 1024 / 1024).toFixed(2), 'MB');\n                        sourceBuffer.appendBuffer(xhr.response);\n                        sourceBuffer.addEventListener('updateend', function() {\n                            if (!sourceBuffer.updating) {\n                                mediaSource.endOfStream();\n                                handleVideoReady();\n                            }\n                        });\n                    } else {\n                        console.error('视频数据请求失败，状态码:', xhr.status);\n                        directLoadVideo();\n                    }\n                };\n                \n                xhr.onerror = function() {\n                    console.error('视频数据请求网络错误');\n                    directLoadVideo();\n                };\n                \n                xhr.send();\n            });\n        } else {\n            console.log('浏览器不支持MediaSource，直接设置src');\n            video.src = source;\n            video.addEventListener('loadedmetadata', function() {\n                handleVideoReady();\n            }, { once: true });\n            video.load();\n        }\n    }\n\n    function directLoadVideo() {\n        video.src = source;\n        video.load();\n        handleVideoReady();\n    }\n\n    function handleVideoReady() {\n        const onLoaded = () => {\n            if (currentTime > 0) {\n                video.currentTime = parseFloat(currentTime);\n                $(\".video-container\")[0].style.background = '#000';\n            }\n            if (callback) callback();\n        };\n\n        if (video.readyState >= 1) {\n            setTimeout(onLoaded, 0);\n        } else {\n            video.addEventListener('loadedmetadata', onLoaded, { once: true });\n        }\n    }\n}\n\n// 上一集函数\nfunction switchToPrevEpisode(currentVideoUrl, autonext) {\n    if (isSwitching || !autonext) return;\n\n    isSwitching = true;\n    localStorage.removeItem(currentVideoUrl);\n    const currentButton = $('.jishu button.active')[0];\n    const prevButton = currentButton?.previousElementSibling;\n\n    if (prevButton && prevButton.innerText !== \"\" && !localStorage.getItem(currentVideoUrl)) {\n        prevButton.click();\n    } else {\n        weblog('已经是第一集了！');\n    }\n}\n\n// 下一集函数\nfunction switchToNextEpisode(currentVideoUrl, autonext) {\n    if (isSwitching || !autonext) return;\n\n    isSwitching = true;\n    localStorage.removeItem(currentVideoUrl);\n    const currentButton = $('.jishu button.active')[0];\n    const nextButton = currentButton?.nextElementSibling;\n\n    if (nextButton && nextButton.innerText !== \"\") {\n        nextButton.click();\n    } else {\n        weblog('没有下一集了！');\n    }\n}\n\n// 切换视频质量的函数\nasync function changeVideoQuality(quality, sources) {\n    const video = $('video')[0];\n    const selectedSource = sources.find(source => source.size === quality.toString());\n    const currentTime = video.currentTime;\n    const wasPlaying = !video.paused;\n\n    if (wasPlaying) {\n        $(\".video-container\")[0].style.background = '#000';\n    }\n    $(\"body>p\")[0].innerHTML = `\n      <div style=\"display: flex; align-items: center; justify-content: space-between; width: 100%;\">\n        <a href=\"legadovideo://${encodeURIComponent(selectedSource.src)}\">\n          ${selectedSource.src}\n        </a>\n        <button \n          onclick=\"navigator.clipboard.writeText('${selectedSource.src.replace(/'/g, \"\\\\'\")}')\n            .then(() => weblog('链接已复制到剪贴板'))\n            .catch(() => weblog('复制链接失败'))\"\n        >\n          复制\n        </button>\n      </div>\n    `;\n\n    if (selectedSource) {\n        if (Hls.isSupported() && /m3u8|hls/.test(selectedSource.src)) {\n            initializeHlsPlayer(selectedSource.src, selectedSource.headersOrReferer, video, currentTime, () => {\n                if (wasPlaying) {\n                    video.play();\n                }\n            });\n        } else {\n            initializeRegularPlayer(selectedSource.src, selectedSource.headersOrReferer, video, currentTime, () => {\n                if (wasPlaying) {\n                    video.play();\n                }\n            });\n        }\n    }\n}\n\n// 页面信息高度调整\nfunction updatePadding() {\n    var videoheight = $(\"video\")[0].offsetHeight;\n    var h3height = $(\"h3\")[0].offsetHeight;\n    var selectedButton = $('#selected-jiekou > button')[0];\n    $(\"img\")[0].style.top = `calc(16px + ${videoheight}px + ${h3height}px)`;\n    $(\".all-info\")[0].style.paddingTop = `calc(20px + ${videoheight}px + ${h3height}px)`;\n    if ($('#selected-jiekou')[0] && $('#jiekou-list')[0]) {\n        $('#selected-jiekou')[0].style.top = `calc(16px + ${videoheight}px + ${h3height}px)`;\n        $('#jiekou-list')[0].style.top = `calc(15.9px + ${videoheight}px + ${h3height}px + ${selectedButton.offsetHeight}px)`;\n        $('#jiekou-list')[0].style.width = `${selectedButton.offsetWidth - 1.9}px`;\n    }\n}\nwindow.addEventListener('resize', updatePadding);\n\n// SVG图标JS动态注入\ndocument.write(`\n<svg xmlns=\"http://www.w3.org/2000/svg\" style=\"display:none\">\n  <symbol id=\"plyr-next-episode\" viewBox=\"0 0 18 18\">\n    <path d=\"M4 1v16l10-8z\" stroke-width=\"0.5\"/>\n    <rect x=\"14\" y=\"1\" width=\"4\" height=\"16\" rx=\"1\" stroke-width=\"0.5\"/>\n  </symbol>\n  <symbol id=\"plyr-prev-episode\" viewBox=\"0 0 18 18\">\n    <path d=\"M14 1v16L4 9z\" stroke-width=\"0.5\"/>\n    <rect x=\"0\" y=\"1\" width=\"4\" height=\"16\" rx=\"1\" stroke-width=\"0.5\"/>\n  </symbol>\n</svg>\n`);\n\ndocument.write(`\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" style=\"display: none;\">\n  <symbol id=\"plyr-airplay\" viewBox=\"0 0 18 18\">\n    <path d=\"M16 1H2a1 1 0 00-1 1v10a1 1 0 001 1h3v-2H3V3h12v8h-2v2h3a1 1 0 001-1V2a1 1 0 00-1-1z\"/>\n    <path d=\"M4 17h10l-5-6z\"/>\n  </symbol>\n  <symbol id=\"plyr-captions-off\" viewBox=\"0 0 18 18\">\n    <path d=\"M1 1c-.6 0-1 .4-1 1v11c0 .6.4 1 1 1h4.6l2.7 2.7c.2.2.4.3.7.3.3 0 .5-.1.7-.3l2.7-2.7H17c.6 0 1-.4 1-1V2c0-.6-.4-1-1-1H1zm4.52 10.15c1.99 0 3.01-1.32 3.28-2.41l-1.29-.39c-.19.66-.78 1.45-1.99 1.45-1.14 0-2.2-.83-2.2-2.34 0-1.61 1.12-2.37 2.18-2.37 1.23 0 1.78.75 1.95 1.43l1.3-.41C8.47 4.96 7.46 3.76 5.5 3.76c-1.9 0-3.61 1.44-3.61 3.7 0 2.26 1.65 3.69 3.63 3.69zm7.57 0c1.99 0 3.01-1.32 3.28-2.41l-1.29-.39c-.19.66-.78 1.45-1.99 1.45-1.14 0-2.2-.83-2.2-2.34 0-1.61 1.12-2.37 2.18-2.37 1.23 0 1.78.75 1.95 1.43l1.3-.41c-.28-1.15-1.29-2.35-3.25-2.35-1.9 0-3.61 1.44-3.61 3.7 0 2.26 1.65 3.69 3.63 3.69z\" fill-rule=\"evenodd\" fill-opacity=\".5\"/>\n  </symbol>\n  <symbol id=\"plyr-captions-on\" viewBox=\"0 0 18 18\">\n    <path d=\"M1 1c-.6 0-1 .4-1 1v11c0 .6.4 1 1 1h4.6l2.7 2.7c.2.2.4.3.7.3.3 0 .5-.1.7-.3l2.7-2.7H17c.6 0 1-.4 1-1V2c0-.6-.4-1-1-1H1zm4.52 10.15c1.99 0 3.01-1.32 3.28-2.41l-1.29-.39c-.19.66-.78 1.45-1.99 1.45-1.14 0-2.2-.83-2.2-2.34 0-1.61 1.12-2.37 2.18-2.37 1.23 0 1.78.75 1.95 1.43l1.3-.41C8.47 4.96 7.46 3.76 5.5 3.76c-1.9 0-3.61 1.44-3.61 3.7 0 2.26 1.65 3.69 3.63 3.69zm7.57 0c1.99 0 3.01-1.32 3.28-2.41l-1.29-.39c-.19.66-.78 1.45-1.99 1.45-1.14 0-2.2-.83-2.2-2.34 0-1.61 1.12-2.37 2.18-2.37 1.23 0 1.78.75 1.95 1.43l1.3-.41c-.28-1.15-1.29-2.35-3.25-2.35-1.9 0-3.61 1.44-3.61 3.7 0 2.26 1.65 3.69 3.63 3.69z\" fill-rule=\"evenodd\"/>\n  </symbol>\n  <symbol id=\"plyr-download\" viewBox=\"0 0 18 18\">\n    <path d=\"M9 13c.3 0 .5-.1.7-.3L15.4 7 14 5.6l-4 4V1H8v8.6l-4-4L2.6 7l5.7 5.7c.2.2.4.3.7.3zm-7 2h14v2H2z\"/>\n  </symbol>\n  <symbol id=\"plyr-enter-fullscreen\" viewBox=\"0 0 18 18\">\n    <path d=\"M10 3h3.6l-4 4L11 8.4l4-4V8h2V1h-7zM7 9.6l-4 4V10H1v7h7v-2H4.4l4-4z\"/>\n  </symbol>\n  <symbol id=\"plyr-exit-fullscreen\" viewBox=\"0 0 18 18\">\n    <path d=\"M1 12h3.6l-4 4L2 17.4l4-4V17h2v-7H1zM16 .6l-4 4V1h-2v7h7V6h-3.6l4-4z\"/>\n  </symbol>\n  <symbol id=\"plyr-fast-forward\" viewBox=\"0 0 18 18\">\n    <path d=\"M7.875 7.171L0 1v16l7.875-6.171V17L18 9 7.875 1z\"/>\n  </symbol>\n  <symbol id=\"plyr-logo-vimeo\" viewBox=\"0 0 18 18\">\n    <path d=\"M17 5.3c-.1 1.6-1.2 3.7-3.3 6.4-2.2 2.8-4 4.2-5.5 4.2-.9 0-1.7-.9-2.4-2.6C5 10.9 4.4 6 3 6c-.1 0-.5.3-1.2.8l-.8-1c.8-.7 3.5-3.4 4.7-3.5 1.2-.1 2 .7 2.3 2.5.3 2 .8 6.1 1.8 6.1.9 0 2.5-3.4 2.6-4 .1-.9-.3-1.9-2.3-1.1.8-2.6 2.3-3.8 4.5-3.8 1.7.1 2.5 1.2 2.4 3.3z\"/>\n  </symbol>\n  <symbol id=\"plyr-logo-youtube\" viewBox=\"0 0 18 18\">\n    <path d=\"M16.8 5.8c-.2-1.3-.8-2.2-2.2-2.4C12.4 3 9 3 9 3s-3.4 0-5.6.4C2 3.6 1.3 4.5 1.2 5.8 1 7.1 1 9 1 9s0 1.9.2 3.2c.2 1.3.8 2.2 2.2 2.4C5.6 15 9 15 9 15s3.4 0 5.6-.4c1.4-.3 2-1.1 2.2-2.4.2-1.3.2-3.2.2-3.2s0-1.9-.2-3.2zM7 12V6l5 3-5 3z\"/>\n  </symbol>\n  <symbol id=\"plyr-muted\" viewBox=\"0 0 18 18\">\n    <path d=\"M12.4 12.5l2.1-2.1 2.1 2.1 1.4-1.4L15.9 9 18 6.9l-1.4-1.4-2.1 2.1-2.1-2.1L11 6.9 13.1 9 11 11.1zM3.786 6.008H.714C.286 6.008 0 6.31 0 6.76v4.512c0 .452.286.752.714.752h3.072l4.071 3.858c.5.3 1.143 0 1.143-.602V2.752c0-.601-.643-.977-1.143-.601L3.786 6.008z\"/>\n  </symbol>\n  <symbol id=\"plyr-pause\" viewBox=\"0 0 18 18\">\n    <path d=\"M6 1H3c-.6 0-1 .4-1 1v14c0 .6.4 1 1 1h3c.6 0 1-.4 1-1V2c0-.6-.4-1-1-1zm6 0c-.6 0-1 .4-1 1v14c0 .6.4 1 1 1h3c.6 0 1-.4 1-1V2c0-.6-.4-1-1-1h-3z\"/>\n  </symbol>\n  <symbol id=\"plyr-pip\" viewBox=\"0 0 18 18\">\n    <path d=\"M13.293 3.293L7.022 9.564l1.414 1.414 6.271-6.271L17 7V1h-6z\"/>\n    <path d=\"M13 15H3V5h5V3H2a1 1 0 00-1 1v12a1 1 0 001 1h12a1 1 0 001-1v-6h-2v5z\"/>\n  </symbol>\n  <symbol id=\"plyr-play\" viewBox=\"0 0 18 18\">\n    <path d=\"M15.562 8.1L3.87.225c-.818-.562-1.87 0-1.87.9v15.75c0 .9 1.052 1.462 1.87.9L15.563 9.9c.584-.45.584-1.35 0-1.8z\"/>\n  </symbol>\n  <symbol id=\"plyr-restart\" viewBox=\"0 0 18 18\">\n    <path d=\"M9.7 1.2l.7 6.4 2.1-2.1c1.9 1.9 1.9 5.1 0 7-.9 1-2.2 1.5-3.5 1.5-1.3 0-2.6-.5-3.5-1.5-1.9-1.9-1.9-5.1 0-7 .6-.6 1.4-1.1 2.3-1.3l-.6-1.9C6 2.6 4.9 3.2 4 4.1 1.3 6.8 1.3 11.2 4 14c1.3 1.3 3.1 2 4.9 2 1.9 0 3.6-.7 4.9-2 2.7-2.7 2.7-7.1 0-9.9L16 1.9l-6.3-.7z\"/>\n  </symbol>\n  <symbol id=\"plyr-rewind\" viewBox=\"0 0 18 18\">\n    <path d=\"M10.125 1L0 9l10.125 8v-6.171L18 17V1l-7.875 6.171z\"/>\n  </symbol>\n  <symbol id=\"plyr-settings\" viewBox=\"0 0 18 18\">\n    <path d=\"M16.135 7.784a2 2 0 01-1.23-2.969c.322-.536.225-.998-.094-1.316l-.31-.31c-.318-.318-.78-.415-1.316-.094a2 2 0 01-2.969-1.23C10.065 1.258 9.669 1 9.219 1h-.438c-.45 0-.845.258-.997.865a2 2 0 01-2.969 1.23c-.536-.322-.999-.225-1.317.093l-.31.31c-.318.318-.415.781-.093 1.317a2 2 0 01-1.23 2.969C1.26 7.935 1 8.33 1 8.781v.438c0 .45.258.845.865.997a2 2 0 011.23 2.969c-.322.536-.225.998.094 1.316l.31.31c.319.319.782.415 1.316.094a2 2 0 012.969 1.23c.151.607.547.865.997.865h.438c.45 0 .845-.258.997-.865a2 2 0 012.969-1.23c.535.321.997.225 1.316-.094l.31-.31c.318-.318.415-.781.094-1.316a2 2 0 011.23-2.969c.607-.151.865-.547.865-.997v-.438c0-.451-.26-.846-.865-.997zM9 12a3 3 0 110-6 3 3 0 010 6z\"/>\n  </symbol>\n  <symbol id=\"plyr-volume\" viewBox=\"0 0 18 18\">\n    <path d=\"M15.6 3.3c-.4-.4-1-.4-1.4 0-.4.4-.4 1 0 1.4C15.4 5.9 16 7.4 16 9c0 1.6-.6 3.1-1.8 4.3-.4.4-.4 1 0 1.4.2.2.5.3.7.3.3 0 .5-.1.7-.3C17.1 13.2 18 11.2 18 9s-.9-4.2-2.4-5.7z\"/>\n    <path d=\"M11.282 5.282a.909.909 0 000 1.316c.735.735.995 1.458.995 2.402 0 .936-.425 1.917-.995 2.487a.909.909 0 000 1.316c.145.145.636.262 1.018.156a.725.725 0 00.298-.156C13.773 11.733 14.13 10.16 14.13 9c0-.17-.002-.34-.011-.51-.053-.992-.319-2.005-1.522-3.208a.909.909 0 00-1.316 0zm-7.496.726H.714C.286 6.008 0 6.31 0 6.76v4.512c0 .452.286.752.714.752h3.072l4.071 3.858c.5.3 1.143 0 1.143-.602V2.752c0-.601-.643-.977-1.143-.601L3.786 6.008z\"/>\n  </symbol>\n</svg>\n`);\n\n// localStorage数据\nconst allStorage = {};\nfor (let i = 0; i < localStorage.length; i++) {\n    const key = localStorage.key(i);\n    try {\n        allStorage[key] = JSON.parse(localStorage.getItem(key));\n    } catch (e) {\n        allStorage[key] = localStorage.getItem(key);\n    }\n}\n//weblog(JSON.stringify(allStorage), 'localStorage 数据：', true);\n</script>\n</body>\n</html>\n<js>\nresult\n.replace(/：\\s*/g,'：')\n.replace(/\\{\\{.*播放源\\)/g,'')\n.replace(/<p>(?!.*集数)(.*：)<\\/p>/gm, '<p style=\"display:none;\">$1</p>');\n</js>",
    "ruleImage": "img.img-placeholder@src",
    "ruleLink": "a@href",
    "ruleNextPage": "page",
    "ruleTitle": "div.video-item-title@text",
    "singleUrl": false,
    "sortUrl": "搜索::/search?text={{(source.getVariable()==''||source.getVariable()==null)?'丝袜':source.getVariable()}}&p={{page}}\n乱伦::/main_ctg?id=8&p={{page}}\n強姦凌辱::/main_ctg?id=2&p={{page}}\n内射受孕::/main_ctg?id=12&p={{page}}\n巨乳美乳::/main_ctg?id=9&p={{page}}\n出軌::/main_ctg?id=7&p={{page}}\n角色劇情::/main_ctg?id=6&p={{page}}\n絲襪美腿::/main_ctg?id=1&p={{page}}\n制服誘惑::/main_ctg?id=4&p={{page}}\n巨乳美乳::/main_ctg?id=9&p={{page}}\n巨乳美乳::/main_ctg?id=9&p={{page}}\n美腿::/ctg?id=129&p={{page}}\n人妻::/ctg?id=18&p={{page}}\n母親::/ctg?id=88&p={{page}}\n痴女::/ctg?id=65&p={{page}}\n女教师::/ctg?id=69&p={{page}}",
    "sourceIcon": "https://hohoj.tv/resources/img/logo.png",
    "sourceName": "HOHOJ",
    "sourceUrl": "https://hohoj.tv/",
    "style": "* {\n    z-index: 0;\n    margin: 0;\n    padding: 0;\n}\n\nbody {\n    margin: auto;\n    background: #bbb;\n    width: 100%;\n}\n\nbody::before {\n    content: '';\n    position: fixed;\n    top: calc(56.25vw + 15px);\n    left: 0;\n    width: 100%;\n    height: calc(100% - (56.25vw + 15px));\n    background-image: var(--bg-image);\n    background-size: cover;\n    background-position: center;\n    opacity: var(--bg-opacity1);\n    z-index: -1;\n    pointer-events: none;\n}\n\nbody>p:first-of-type {\n    width: 100%;\n    position: fixed;\n    top: 0px;\n    text-indent: 0px;\n    height: 16px;\n    font-size: 0.7rem;\n    border-radius: 0px 0px 0px 0px;\n    background: #000;\n    z-index: 200;\n    display: flex;\n    align-items: center;\n}\n\nbody>p:first-of-type a {\n    color: #888;\n    text-decoration: none;\n    white-space: nowrap;\n    overflow-x: auto;\n    overflow-y: hidden;\n    display: block;\n    flex: 1;\n    min-width: 0;\n}\n\nbody>p:first-of-type button {\n    width: 30px;\n    height: 16px;\n    font-size: 0.6rem;\n    white-space: nowrap;\n    background: #333;\n    border: 0;\n    color: #888;\n    cursor: pointer;\n    flex-shrink: 0;\n    position: relative;\n    z-index: 201;\n}\n\nvideo {\n    visibility: hidden;\n}\n\n.video-container {\n    position: fixed;\n    top: 15px;\n    width: 100%;\n    height: 56.25vw;\n    z-index: 200;\n}\n\n#player {\n    position: relative;\n    width: 100%;\n}\n\n:root {\n    color-scheme: only light;\n    --plyr-color-main: #00aaff;/* 播放器主要颜色 */\n    --plyr-control-color: #fff;/* 播放器控件图标颜色 */\n    --plyr-control-background: transparent;/* 播放器控件背景颜色 */\n    --plyr-video-background: transparent;/* 视频背景颜色 */\n    --plyr-range-fill-background: #0099ee;/* 进度条已填充部分的颜色 */\n    --plyr-range-thumb-background: #fff;/* 进度条滑块的颜色 */\n}\n\n.plyr {\n    height: 100% !important;\n    width: 100% !important;\n    object-fit: cover;\n}\n\n.plyr__video-wrapper * {\n    touch-action: none !important;\n}\n\n.plyr__video-wrapper video {\n    touch-action: none !important;\n}\n\n.plyr__controls {\n    touch-action: none !important;\n}\n\n.plyr__control--overlaid {\n    background: transparent;\n    border: 0;\n    border-radius: 100%;\n    color: #fff;\n    left: calc(50% - 25px);\n    top: calc(50% - 45px);\n    transform: none;\n    width: 60px;\n    height: 48px;\n    padding: 0;\n    z-index: 2;\n}\n\n.plyr__control--overlaid svg {\n    width: 50px;\n    height: 50px;\n    left: calc(50% - 25px);\n    top: calc(50% - 10px);\n    transform: none;\n    fill: #fff;/* 大播放器控件图标颜色 */\n    filter: \n        drop-shadow(0 0 20px rgba(0, 0, 0, 0.3))\n        drop-shadow(0 0 30px rgba(0, 0, 0, 0.1));\n}\n\n.plyr__control--overlaid.hidden {\n    display: none !important;\n    opacity: 0 !important;\n    pointer-events: none !important;\n}\n\n.plyr--video .plyr__control.plyr__tab-focus,.plyr--video .plyr__control:hover,.plyr--video .plyr__control[aria-expanded=true] {\n    background: transparent;/* 播放器控件悬停/点击背景颜色 */\n    color: #00aaff;/* 播放器控件悬停/点击图标颜色 */\n}\n\n.plyr__controls .plyr__controls__item {\n    margin-left: auto;\n    margin: calc(var(--plyr-control-spacing,10px)/4);\n}\n\n.plyr__time--duration {\n    display: inline-block !important;\n}\n\n.plyr__time+.plyr__time:before {\n    margin-right: 8px !important;\n}\n\n@media (max-width: 640px) {\n    .plyr__captions {\n        margin-bottom:-8px\n    }\n\n    .plyr__progress__container {\n        margin-right: 5px\n    }\n\n    .plyr__time {\n        position: absolute;\n        bottom: 29px;\n    }\n\n    .plyr__time--current {\n        left: 106px\n    }\n\n    .plyr__time+.plyr__time:before {\n        content: \"\"!important\n    }\n\n    .plyr__time--duration {\n        right: 110px;\n    }\n\n    .plyr__volume {\n        width: auto;\n        max-width: 32px!important;\n        min-width: 32px!important\n    }\n\n    input[id^=plyr-volume-] {\n        display: none!important;\n    }\n\n    .plyr--airplay-supported [data-plyr=airplay],.plyr--captions-enabled [data-plyr=captions],.plyr--pip-supported [data-plyr=pip] {\n        display: none!important;\n    }\n}\n\ndetails {\n    width: 100%;\n    height: auto;\n    margin: auto;\n}\n\ndetails>img {\n    position: fixed;\n    width: 100%;\n    max-height: 90vw;\n    object-fit: contain;\n    background: #000;\n    border-bottom: 0.5px solid #333;\n    top: calc(56.25vw + 16px + 1.5em);\n    z-index: 50;\n}\n\ndetails[open]>summary {\n    background: #bbb;/* 标题背景颜色 */\n}\n\nsummary {\n    position: fixed;\n    background: rgba(221, 221, 221, var(--bg-opacity2));/* 标题背景颜色和透明度 */\n    backdrop-filter: blur(5px);\n    -webkit-backdrop-filter: blur(5px);\n    color: #111;/* 标题文字颜色 */\n    box-shadow: 0 0.5px 3px #555;/* 标题阴影颜色 */\n    list-style: none;\n    width: 100%;\n    padding-top: calc(56.25vw + 16px);\n    outline: none;\n    line-height: 1.5;\n    text-align: left;\n    word-wrap: break-word;\n    z-index: 100;\n}\n\nsummary>h3 {\n    width: 95%;\n    margin: auto;\n}\n\nsummary::-webkit-details-marker {\n    display: none;\n}\n\n.all-info {\n    position: relative;\n    color: #333;/* 详情信息文字颜色 */\n    margin: auto;\n    width: 100%;\n    height: auto;\n    padding-top: calc(56.25vw + 24px + 1.5em);\n}\n\n.all-info>div {\n    width: 100%;\n    margin: auto;\n}\n\n.all-info>p {\n    text-indent: 0px;\n}\n\n.all-info>div>p {\n    width: 90%;\n    margin: 5px 5%;\n    outline: none;\n    text-align: left;\n    word-wrap: break-word;\n}\n\n.jiekou {\n    display: flex;\n}\n\n#selected-jiekou {\n    display: flex;\n    position: fixed;\n    justify-content: flex-end;\n    top: calc(56.25vw + 19.9px + 1.5em);\n    width: 150px;\n    right: 5px;\n}\n\n#selected-jiekou button {\n    width: 125px;\n    height: 28px;\n    padding: 2px;\n    background: rgba(204, 204, 204, var(--bg-opacity2));/* 已选接口背景颜色 */\n    backdrop-filter: blur(5px);\n    -webkit-backdrop-filter: blur(5px);\n    overscroll-behavior-y: none;\n    -webkit-overflow-scrolling: auto;\n    color: #4a89a9;\n    border: 1px solid #666;\n    border-radius: 0 0 3px 3px;\n    opacity: 0.5;\n}\n\n#jiekou-list {\n    display: none;\n    position: fixed;\n    overflow-y: auto;\n    max-height: 200px;\n    top: 0;\n    right: 5px;\n    background: rgba(204, 204, 204, var(--bg-opacity2));/* 接口列表背景颜色 */\n    backdrop-filter: blur(5px);\n    -webkit-backdrop-filter: blur(5px);\n    border: 1px solid #888;\n    border-top: none;\n    border-radius: 0 0 3px 3px;\n    z-index: 100;\n    margin: auto;\n}\n\n#jiekou-list button {\n    display: block;\n    width: 100%;\n    height: 28px;\n    margin: auto;\n    padding: 2px;\n    background: rgba(187, 187, 187, 0.1);/* 待选接口按钮背景颜色 */\n    color: #333;/* 待选接口按钮文字颜色 */\n    border: 1px solid #888;\n    border-top: none;\n    border-left: none;\n    border-right: none;\n    border-radius: 0px;\n    cursor: pointer;\n}\n\n#jiekou-list button:last-of-type {\n    border-bottom: none;\n    border-radius: 0 0 3px 3px;\n}\n\nsup {\n    font-size: 0.4em;\n    vertical-align: top;\n    position: relative;\n    top: -0.6em;\n}\n\n.jishu button:hover {\n    background: rgba(204, 204, 204, var(--bg-opacity2));/* 按钮悬停背景颜色 */\n    border: 1px solid #4a89a9;/* 按钮悬停边框颜色 */\n}\n\n.jishu button {\n    width: 30%;\n    margin: 1.25%;\n    padding: 5px;\n    outline: none;\n    border-radius: 8px;\n    border: 1px solid #666;\n    background: rgba(204, 204, 204, var(--bg-opacity2));/* 集数按钮背景颜色 */\n    color: #333;/* 集数按钮文字颜色 */\n    font-size: 0.7rem;\n    white-space: nowrap;\n    overflow: hidden;\n    text-overflow: ellipsis;\n}\n\n.jishu button.active {\n    background: rgba(204, 204, 204, var(--bg-opacity2));/* 已选集数按钮背景颜色 */\n    color: #4a89a9;\n    border: 1px solid #4a89a9;\n    position: sticky;\n    left: 0;\n    right: 0;\n}\n\n.popup {\n    position: fixed;\n    top: 50%;\n    left: 50%;\n    transform: translate(-50%, -50%) scale(0.95);\n    background-color: #ccc;\n    padding: 20px;\n    border-radius: 8px;\n    box-shadow: 0 4px 24px rgba(0, 0, 0, 0.3);\n    z-index: 2147483647;\n    width: 80%;\n    max-height: 80vh;\n    overflow: auto;\n    font-family: system-ui, -apple-system, sans-serif;\n    opacity: 0;\n    transition: all 0.3s ease;\n    pointer-events: auto;\n}\n\n.titleElement {\n    margin: 0 0 16px 0;\n    color: #333;\n    font-size: 18px;\n    font-weight: 600;\n}\n\n.contentElement {\n    white-space: pre-wrap;\n    word-wrap: break-word;\n    overflow-wrap: break-word;\n    max-height: calc(80vh - 150px);\n    overflow-y: auto;\n    padding: 16px;\n    background-color: #bbb;\n    color: #000;\n    border-radius: 6px;\n    margin-bottom: 20px;\n    font-size: 14px;\n    line-height: 1.6;\n    border: 1px solid #999;\n}"
  },
  {
    "articleStyle": 3,
    "customOrder": 1,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 1774110092242,
    "loadWithBaseUrl": true,
    "ruleArticles": ".item-box",
    "ruleContent": "<js>\n// 提取m3u8链接\nvar m3u8Match = result.match(/\"([^\"]*?index\\.m3u8[^\"]*)\"/i) \n             || result.match(/'([^']*?index\\.m3u8[^']*)'/i);\n\nvar p = '';\nif (m3u8Match) {\n    var u = m3u8Match[1]\n        .replace(/\\\\\\//g, '/')      // \\/ → /\n        .replace(/\\\\\\\\/g, '\\\\')      // \\\\ → \\\n        .trim();\n    \n    // 补全协议\n    if (u.startsWith('//')) {\n        u = 'https:' + u;\n    } else if (!u.startsWith('http')) {\n        // 需要基础URL，这里假设当前页面URL在result中或需要传入\n        u = 'https://' + u;  // 简化处理，或根据实际需求调整\n    }\n    p = u;\n}\n\n// 标题：从 span.tx-flex-sh > a 的 title 属性获取\nvar t = java.getString('.tags-box.0@a.0 @text') || '未知标题';\n\n// 标签：从 meta[name=\"description\"] 的 content 获取  \nvar b = java.getString('.mb5.1 @text') || '';\nvar updateIndex = b.indexOf('更新时间');\nif (updateIndex !== -1) {\nvar d = b.substring(updateIndex);  // 保留\"更新时间\"及之后的内容\n}\n\n`<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>${t}</title>\n<style>\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,sans-serif;background:#f0f9ff;padding:10px}\n.v-box{max-width:800px;margin:0 auto;background:white;border-radius:12px;box-shadow:0 5px 15px rgba(0,0,0,0.1);overflow:hidden}\n.header{padding:12px;border-bottom:1px solid #eee;display:flex;flex-wrap:wrap;justify-content:space-between}\n.title{font-size:18px;font-weight:600;margin-bottom:8px;width:100%}\n.tags{color:#5f6368;font-size:14px;flex:1;min-width:60%;word-break:break-all}\n.time{color:#5f6368;font-size:14px;text-align:right;flex-basis:35%}\n.v-wrap{position:relative;padding-top:56.25%;background:#000}\n.video{position:absolute;top:0;left:0;width:100%;height:100%}\n.footer{padding:8px;text-align:center;color:#5f6368;font-size:13px}\n.info-box{padding:15px;font-size:14px;line-height:1.6}\n.info-box p{margin:8px 0}\n.hint{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background:rgba(0,0,0,0.7);color:#fff;padding:12px 20px;border-radius:20px;font-size:1.1rem;z-index:10;display:none}\n.controls{position:absolute;top:0;left:0;width:100%;height:4px;background:rgba(255,255,255,0.3);z-index:5;transition:opacity 0.3s}\n.progress{height:100%;background:#4a9eff;width:0}\n</style>\n</head>\n<body>\n<div class=\"v-box\">\n<div class=\"header\">\n<div class=\"title\">${t}</div>\n<div class=\"tags\">${d}</div>\n<div class=\"time\" id=\"timeDisplay\">00:00/00:00</div></div>\n<div class=\"v-wrap\">\n<div class=\"controls\"><div class=\"progress\" id=\"progressBar\"></div></div>\n<div class=\"hint\" id=\"hint\">快进中 &gt;&gt;</div>\n<video class=\"video\" id=\"v\" controls playsinline>\n<source src=\"${p}\" type=\"application/x-mpegURL\">您的浏览器不支持HTML5视频\n</video>\n</div>\n<div class=\"footer\">滑动调整进度 | 长按2倍速</div>\n</div>\n<script>\nvar v = document.getElementById('v');\nvar tDisplay = document.getElementById('timeDisplay');\nvar pBar = document.getElementById('progressBar');\nvar hint = document.getElementById('hint');\nvar startX = 0, startTime = 0;\nvar longPressTimer;\nvar sensitivity = 0.1;\nvar longPressTime = 500;\nvar hintDuration = 2000;\nfunction updateTime() {\nif (!v.duration) return;\nvar m1 = Math.floor(v.currentTime / 60);\nvar s1 = Math.floor(v.currentTime % 60);\nvar m2 = Math.floor(v.duration / 60);\nvar s2 = Math.floor(v.duration % 60);\ntDisplay.textContent = m1 + ':' + (s1 < 10 ? '0' : '') + s1 + '/' + m2 + ':' + (s2 < 10 ? '0' : '') + s2;\npBar.style.width = (v.currentTime / v.duration) * 100 + '%';}\nv.addEventListener('timeupdate', updateTime);\nv.addEventListener('loadedmetadata', updateTime);\nv.addEventListener('touchstart', function(e) {\nstartX = e.touches[0].clientX;\nstartTime = Date.now();\nif (longPressTimer) clearTimeout(longPressTimer);\nhint.style.display = 'none';\nlongPressTimer = setTimeout(function() {\nv.playbackRate = 2.0;\nhint.style.display = 'block';\nsetTimeout(function() { hint.style.display = 'none'; }, hintDuration);}, longPressTime);});\nv.addEventListener('touchmove', function(e) {\ne.preventDefault();\nclearTimeout(longPressTimer);\nvar diffX = e.touches[0].clientX - startX;\nvar change = diffX * sensitivity * v.duration / 100;\nv.currentTime = Math.max(0, Math.min(v.currentTime + change, v.duration));\nstartX = e.touches[0].clientX;updateTime();});\nv.addEventListener('touchend', function() {\nv.playbackRate = 1.0;\nclearTimeout(longPressTimer);});\n</script>\n</body>\n</html>`\n</js>\n",
    "ruleImage": "img@src",
    "ruleLink": "a@href<js> resutl='https://l5--25w3xh.wumatantoupai1.com'+result</js><js>\nresult=result.replace('oddetail', '');\n</js>\n",
    "ruleNextPage": ".laypage_next@href",
    "ruleTitle": "a@title",
    "shouldOverrideUrlLoading": "ture",
    "singleUrl": false,
    "sortUrl": "搜索::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key={{source.getVariable()}}\n国产传媒::https://l5--25w3xh.wumatantoupai1.com/t/2/\n网红头条::https://l5--25w3xh.wumatantoupai1.com/t/241/\n国产视频::https://l5--25w3xh.wumatantoupai1.com/t/163/\n探花系列::https://l5--25w3xh.wumatantoupai1.com/t/239/\n网暴黑料::https://l5--25w3xh.wumatantoupai1.com/t/232/\n自拍::https://l5--25w3xh.wumatantoupai1.com/s/wd/%E5%9B%BD%E4%BA%A7%E8%87%AA%E6%8B%8D\nIPX::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=IPX\nJUL::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=JUL\nABW::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=ABW\nJUQ::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=JUQ\nSONE::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=SONE\nMIRD::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=MIRD\nIPZZ::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=IPZZ\nOFJE::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=OFJE\nMIDV::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=MIDV\nCAWD::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=CAWD\nSONE::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=SONE\nMIAB::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=MIAB\nMIMK::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=MIMK\nSSIS::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=SSIS\nPRED::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=PRED\nDASS::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=DASS\nSTARS::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=STARS\nFSDSS::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=FSDSS\nSTART::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=START\nmiru::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=miru\n爆菊::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=爆菊\n求饶::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=求饶\n短裙::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=短裙\n浴场::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=浴场\n迷晕::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=迷晕\n嫖妓::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=嫖妓\n正妹::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=正妹\n紧身::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=紧身\n老婆::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=老婆\n中出::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=中出\n女模::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=女模\n按摩::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=按摩\n阴道::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=阴道\n开档::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=开档\n拍摄::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=拍摄\n海滩::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=海滩\n奴隶::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=奴隶\n惩罚::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=惩罚\n精液::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=精液\n嫂子::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=嫂子\n上位::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=上位\n秘书::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=秘书\n上班::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=上班\n强迫::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=强迫\n甜蜜::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=甜蜜\n温柔::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=温柔\n暴力::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=暴力\n撕烂::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=撕烂\n女星::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=女星\n卖淫::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=卖淫\n夜班::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=夜班\n尾随::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=尾随\n色狼::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=色狼\n痴汉::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=痴汉\n偶遇::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=偶遇\n巨乳::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=巨乳\n调教::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=调教\n萝莉::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=萝莉\n自慰::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=自慰\n妈妈::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=妈妈\n母子::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=母子\n石川澪::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=石川澪\n皆月光::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=皆月光\n大槻響::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=大槻響\n櫻空桃::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=櫻空桃\n波多野結衣::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=波多野結衣\n桃乃木香奈::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=桃乃木香奈\n七瀨愛麗絲::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=七瀨愛麗絲\n吉根柚莉愛::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=吉根柚莉愛\n柏木こなつ::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=柏木こなつ\n天馬ゆい::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=天馬ゆい\n夢乃あいか::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=夢乃あいか\n未步なな::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=未步なな\n倉本すみれ::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=倉本すみれ\n望月つぼみ::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=望月つぼみ\n新井リマ::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=新井リマ\n浅野こころ::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=浅野こころ\n東雲みれい::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=東雲みれい\n松本一香::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=松本一香\n木下日葵::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=木下日葵\n瀬户环奈::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=瀬户环奈\n河北彩花::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=河北彩花\n沙月惠奈::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=沙月惠奈\n美園和花::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=美園和花\n沙月芽衣::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=沙月芽衣\n藤森里穗::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=藤森里穗\n石原希望::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=石原希望\n月乃露娜::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=月乃露娜\n小宵虎南::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=小宵虎南\n七澤米亞::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=七澤米亞\n小野六花::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=小野六花\n彌生美月::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=彌生美月\n山岸逢花::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=山岸逢花\n三上悠亞::https://l5--25w3xh.wumatantoupai1.com/addons/s/wd/link.php?key=三上悠亞",
    "sourceComment": "┍   　  　书源作者：闻君三月　　  　┒\n├───┬────────────┤\n│！免责│本书源只提供代码进行技术│\n│！声明│交流，请于２４小时后删除│\n└────────────────┘",
    "sourceGroup": "版本",
    "sourceIcon": "https://bike-egg-cup.img12345.com/ico/heiseicon.png",
    "sourceName": "8.4",
    "sourceUrl": "https://l5--25w3xh.wumatantoupai1.com/show/2/ "
  },
  {
    "articleStyle": 0,
    "customOrder": 2,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "版本",
    "sourceIcon": "糖心",
    "sourceName": "8.0",
    "sourceUrl": "https://www.q6md.com/"
  },
  {
    "articleStyle": 1,
    "customOrder": 3,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "class.inner_layer@ul@li@a",
    "ruleContent": "text.普通下载@href\n<js>\nresult+=\".m3u8\";\r\nresult = \"<video src=\\\"\" + result + \"\\\" width=\\\"100%\\\" height=\\\"240px\\\" controls=\\\"controls\\\" ></video>\";\r\nresult = \"<html><head><meta charset=\\\"utf-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no\\\" /><style>html,body{margin:0;padding:0;width:100%;}</style></head><body>\" + result + \"</body></html>\"\n</js>",
    "ruleImage": "img@data-original||img@src",
    "ruleLink": "href##$##,\\{\\\"webView\\\": true\\}",
    "ruleNextPage": "page",
    "rulePubDate": "class.timeobxobx@text",
    "ruleTitle": "p.-1@text",
    "singleUrl": false,
    "sortUrl": "亚洲精品::/Html/110/{{page - 1 == 0 ? \"\":\"index-\"+page+\".html\"}},{\"webView\": true}\nS级女优::/Html/100/{{page - 1 == 0 ? \"\":\"index-\"+page+\".html\"}},{\"webView\": true}\n成人动漫::/Html/101/{{page - 1 == 0 ? \"\":\"index-\"+page+\".html\"}},{\"webView\": true}\n欧美巨龙::/Html/62/{{page - 1 == 0 ? \"\": \"index-\"+page+\".html\"}},{\"webView\": true}\n熟女人妻::/Html/111/{{page - 1 == 0 ? \"\": \"index-\"+page+\".html\"}},{\"webView\": true}\n美颜巨乳::/Html/112/{{page - 1 == 0 ? \"\": \"index-\"+page+\".html\"}},{\"webView\": true}\n颜射吃精::/Html/113/{{page - 1 == 0 ? \"\": \"index-\"+page+\".html\"}},{\"webView\": true}\n丝袜制服::/Html/114/{{page - 1 == 0 ? \"\": \"index-\"+page+\".html\"}},{\"webView\": true}\n自拍隐摄::/Html/89/{{page - 1 == 0 ? \"\": \"index-\"+page+\".html\"}},{\"webView\": true}\n换妻游戏::/Html/90/{{page - 1 == 0 ? \"\": \"index-\"+page+\".html\"}},{\"webView\": true}\n网红主播::/Html/91/{{page - 1 == 0 ? \"\": \"index-\"+page+\".html\"}},{\"webView\": true}\n经典三级::/Html/109/{{page - 1 == 0 ? \"\": \"index-\"+page+\".html\"}},{\"webView\": true}",
    "sourceComment": "发布页https://guochandizhi6.com/\n永久地址https://992kp.com/",
    "sourceGroup": "版本",
    "sourceIcon": "https://i.postimg.cc/j5ZxW6v7/1657950527553.png",
    "sourceName": "7.2",
    "sourceUrl": "https://992.992kp340.work:8443/index.html"
  },
  {
    "articleStyle": 0,
    "customOrder": 5,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "版本",
    "sourceIcon": "",
    "sourceName": "6.6",
    "sourceUrl": "https://6661.vaf3.com/web/index.html?jkzz=1"
  },
  {
    "articleStyle": 3,
    "customOrder": 7,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 1775588705888,
    "loadWithBaseUrl": true,
    "ruleArticles": ".item",
    "ruleContent": "id.kt_player@all&&script@all",
    "ruleImage": "img@data-original",
    "ruleLink": "a@href",
    "ruleNextPage": "page",
    "rulePubDate": ".time@span",
    "ruleTitle": "img@alt",
    "singleUrl": false,
    "sortUrl": "搜索::https://www.85xo.com/search/{{v=source.getVariable()}}/\n亚洲人::/tags/ya-zhou-ren/\n马来::/tags/ma-lai/\n日本::/tags/ri-ben/\n后入::/tags/hou-ru/\n大奶::/tags/da-nai/\n高潮::/tags/gao-chao/\n做爱::/tags/zuo-ai/\n马来西亚::/tags/ma-lai-zi-ya/\n妹妹::/tags/mei-mei/\n兔牙::/tags/tu-ya/\n妹::/tags/mei/\n巨乳::/tags/ju-ru/\n自慰::/tags/zi-wei/\n情侣::/tags/qing-lv/\n骚::/tags/sao/\n男友::/tags/nan-you/\n淫叫::/tags/yin-jiao/\n抓奶::/tags/zhua-nai/\n新加坡::/tags/xin-jia-po/\n内衣::/tags/nei-yi/\n肉棒::/tags/rou-bang/\n床上::/tags/chuang-shang/\n嫩逼::/tags/nei-bi/\n日本人::/tags/ri-ben-ren/\n鲍鱼::/tags/bao-yu/\n口::/tags/kou/\n少女::/tags/shao-nv/\n美女::/tags/mei-nv/\n台灣::/tags/tai-wan/\n可爱::/tags/ke-ai/\n偷拍::/tags/tou-pai/\n掰逼::/tags/bai-bi/\n喷水::/tags/pen-shui/\n脱衣::/tags/tuo-yi/\n屁眼::/tags/pi-yan/\n口交::/tags/kou-jiao/\n高中::/tags/gao-zhong/\n妹子::/tags/mei-zi/\n中國::/tags/zhong-guo/\n母狗::/tags/mu-gao/\n全裸::/tags/quan-luo/\n美臀::/tags/mei-tun/\n贫乳::/tags/pin-ru/\n逼::/tags/bi/\n内裤::/tags/nei-ku/\n爱::/tags/ai/\n自拍::/tags/zi-pai/\n学生::/tags/xue-sheng/\n呻吟::/tags/shen-yin/\n韓國::/tags/han-guo/\n泰國::/tags/tai-guo/\n越南::/tags/yue-nan/\n近拍::/tags/jin-pai/\n香港::/tags/xiang-gang/\n新馬::/tags/xin-ma/\n街拍::/tags/jie-pai/",
    "sourceComment": "https://www.85po.com",
    "sourceGroup": "版本",
    "sourceIcon": "https://85tube.com/favicon.ico",
    "sourceName": "6.4",
    "sourceUrl": "https://www.85xo.com/",
    "style": "{background-color:black;margin:0;padding:0;width:100%;}"
  },
  {
    "articleStyle": 0,
    "customOrder": 8,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceComment": "视频",
    "sourceGroup": "版本",
    "sourceIcon": "https://img.fy6b.com/2024/06/13/7ca5da52f9cc0.jpg",
    "sourceName": "6.3",
    "sourceUrl": "https://2.hlg6440d.cc/"
  },
  {
    "articleStyle": 1,
    "customOrder": 8,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": ".appel-max@ul@li!0:1:2:3:4:5",
    "ruleContent": "<js>\np=result.match(/url\\\"\\:\\\"(.*?)\\\"\\,\\\"url/)[1].replace(/\\\\/g,'')\nvar p\n`<html>\n    <head>\n        <meta name=\"viewport\" content=\"width=device-width\">\n        <style>\n            body {\n                margin: 0;\n                font-family: Arial, sans-serif;\n                background: linear-gradient(135deg, #ece9e6, #ffffff);\n                display: flex;\n                flex-direction: column;\n                align-items: center;\n                justify-content: flex-start;\n                padding: 20px;\n            }\n           .container {\n                width: 100%;\n                max-width: 800px;\n                background: #fff;\n                border-radius: 10px;\n                box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n                overflow: hidden;\n                margin-bottom: 20px;\n            }\n            h3 {\n                margin: 0;\n                padding: 10px 20px;\n                font-size: 0.9em;\n                background: #333;\n                color: #fff;\n                border-radius: 10px 10px 0 0;\n            }\n           .video-container {\n                width: 100%;\n                background: #000;\n                position: relative;\n            }\n            video {\n                width: 100%;\n                height: auto;\n                display: block;\n            }\n           .info-container {\n                padding: 20px;\n            }\n           .info-container p {\n                margin: 10px 0;\n                color: #555;\n            }\n           .info-container p span {\n                font-weight: bold;\n                color: #000;\n            }\n        </style>\n    </head>\n    <body>\n        <div class=\"container\">\n            <div class=\"video-container\">\n                <video controls autoplay name=\"media\">\n                    <source src=\"${p}\" type=\"video/mp4\">\n                </video>\n            </div>\n            <div class=\"info-container\">\n                \n            </div>\n        </div>\n    </body>\n</html>`;\n\n</js>",
    "ruleImage": "img@data-original##.*gif",
    "ruleLink": "a.-1@href##/voddetail/(\\d+).html##https://cdnaaapi.yiniuyingshi6.com:2053/vodplay/$1-1-1.html",
    "ruleNextPage": "text.下一页@href",
    "rulePubDate": "{{@span.video-grade@text}}  {{@p@text}}",
    "ruleTitle": "h5@a@text",
    "singleUrl": false,
    "sortUrl": "制服丝袜::https://cdnaaapi.yiniuyingshi6.com:2053/vodtype/20.html\n群交淫乱::https://cdnaaapi.yiniuyingshi6.com:2053/vodtype/21.html\n无码专区::https://cdnaaapi.yiniuyingshi6.com:2053/vodtype/22.html\n偷拍自拍::https://cdnaaapi.yiniuyingshi6.com:2053/vodtype/23.html\n卡通动画::https://cdnaaapi.yiniuyingshi6.com:2053/vodtype/24.html\n中文字幕:https://cdnaaapi.yiniuyingshi6.com:2053/vodtype/25.html\n欧美性爱::https://cdnaaapi.yiniuyingshi6.com:2053/vodtype/26.html\n巨乳美乳::https://cdnaaapi.yiniuyingshi6.com:2053/vodtype/27.html\n国产裸聊::https://cdnaaapi.yiniuyingshi6.com:2053/vodtype/28.html\n国产自拍::https://cdnaaapi.yiniuyingshi6.com:2053/vodtype/29.html\n国产盗摄::https://cdnaaapi.yiniuyingshi6.com:2053/vodtype/30.html\n伦理三级::https://cdnaaapi.yiniuyingshi6.com:2053/vodtype/31.html\n女同性恋::https://cdnaaapi.yiniuyingshi6.com:2053/vodtype/32.html\n少女萝莉::https://cdnaaapi.yiniuyingshi6.com:2053/vodtype/33.html",
    "sourceComment": "需要频道换源\n地址发布页\nhttp://www.henniu69.xyz/",
    "sourceGroup": "678",
    "sourceIcon": "https://i.postimg.cc/xTLWq1dp/IMG-20220930-223954.jpg",
    "sourceName": "©h牛影视",
    "sourceUrl": "https://cdnaaapi.yiniuyingshi6.com:2053"
  },
  {
    "articleStyle": 0,
    "customOrder": 9,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "版本",
    "sourceIcon": "天",
    "sourceName": "4.8",
    "sourceUrl": "https://www.xn--vctr31ecwaz4k.com/"
  },
  {
    "articleStyle": 1,
    "coverDecodeJs": "/\\/(new|xiao|upload)\\//.test(src)?java.createSymmetricCrypto(\"AES/CBC/Pkcs7Padding\", \"f5d965df75336270\",\"97b60394abc2fbe1\").decrypt(result):result",
    "customOrder": 10,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\n\t\"User-Agent\": \"Mozilla/5.0 (Linux; Android 9) Mobile Safari/537.36\",\"referer\": \"{{baseUrl}}\"\n\t}",
    "lastUpdateTime": 1775591767759,
    "loadWithBaseUrl": true,
    "ruleArticles": "class.video-item",
    "ruleContent": "class.dplayer@all<js>\nresult=result.match(/http.*0/)[0]##\\</js>{{@@title@text}}\n<video src=\"{{result}}\" width=\"100%\" height=\"auto\" controls></video>",
    "ruleImage": "@js:\nurl=String(result).match(/.*loadImg\\(this,'(.*)'.*/)[1];\nresult=url",
    "ruleLink": "a@href",
    "ruleNextPage": "page",
    "rulePubDate": "class.date-xxx@text",
    "ruleTitle": "class.title@text",
    "singleUrl": false,
    "sortUrl": "首页::/page/{{page}}/\n最新黑料::/hlcg/page/{{page}}/\n今日热瓜::/jrrs/page/{{page}}/\n热门黑料::/jqrm/page/{{page}}/\n经典黑料::/lsdg/page/{{page}}/\n日榜黑料::/mrrb/page/{{page}}/\n周榜黑料::/zbjx/page/{{page}}/\n月榜黑料::/ybrg/page/{{page}}/\n原创社区::/ycsq/page/{{page}}/\n反差专区::/fczq/page/{{page}}/\n校园黑料::/xycg/page/{{page}}/\n网红黑料::/whhl/page/{{page}}/\n影视短剧::/ysdj/page/{{page}}/\n每日大赛::/mrds/page/{{page}}/\n明星丑闻::/mxcw/page/{{page}}/\n深夜综艺::/syzy/page/{{page}}/\n推特社区::/ttsq/page/{{page}}/\n独家曝料::/djbl/page/{{page}}/\n桃图杂志::/ttzz/page/{{page}}/\n黑料课堂::/hlkt/page/{{page}}/\n有求必应::/yqby/page/{{page}}/\n黑料爆改::/hlbg/page/{{page}}/\n官场曝料::/gchl/page/{{page}}/\n全球奇闻::/qqqw/page/{{page}}/\n抖音::/tag/2/{{page}}.html\n快手::/tag/3/{{page}}.html\n推特::/tag/7/{{page}}.html\n模特::/tag/36/{{page}}.html\n学生::/tag/10/{{page}}.html\n御姐::/tag/40/{{page}}.html\n少妇::/tag/405/{{page}}.html\n人妻::/tag/22/{{page}}.html\n自拍::/tag/332/{{page}}.html\n偷拍::/tag/27/{{page}}.html\n自慰::/tag/313/{{page}}.html\n后入::/tag/922/{{page}}.html\n母狗::/tag/140/{{page}}.html\n露脸::/tag/781/{{page}}.html\n露出::/tag/17/{{page}}.html\n直播::/tag/28/{{page}}.html\n约炮::/tag/163/{{page}}.html\n出轨::/tag/505/{{page}}.html\n偷情::/tag/18/{{page}}.html\n制服::/tag/50/{{page}}.html\n肥臀::/tag/35/{{page}}.html\n巨乳::/tag/34/{{page}}.html\n高颜值::/tag/275/{{page}}.html",
    "sourceComment": "感谢社区大佬的解密\n源社区：@Mengteen \n二传二创或者是其它问题请联系我。\n我邮箱:[xxxmgqxxx@vip.qq.com]\n我QQ:99737563(备注来意)\n2025.7.6 修复分类以及更新\n地址发布页：https://hlbg3.com/\n黑料最新入口\nhttps://hlbg8.com\n牢记永久域名\nhttps://www.heiliao88.com/\nhttps://155.fun或https://18hlw.com",
    "sourceGroup": "版本",
    "sourceIcon": "https://img4.tuwandata.com/v2/thumb/jpg/NWFkMywxMTI1LDAsOSwzLDEsLTEsTk9ORSwsLDkw/u/res.tuwan.com/zipgoods/20190508/3b6408c569f8eb687a8dd6eb3578bdb9.jpg",
    "sourceName": "6.2",
    "sourceUrl": "https://qbfeh.rcrfesyj.cc/"
  },
  {
    "articleStyle": 0,
    "customOrder": 11,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceComment": "视频",
    "sourceGroup": "版本",
    "sourceIcon": "https://img.fy6b.com/2024/06/13/7ca5da52f9cc0.jpg",
    "sourceName": "6.1",
    "sourceUrl": "https://www.xhsiy38.cc:2024/"
  },
  {
    "articleStyle": 0,
    "contentBlacklist": "",
    "contentWhitelist": "",
    "customOrder": 11,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\n\"User-Agent\": \"Mozilla/5.0 (Linux; U; Android 8.1.0; zh-CN; MI 8 Lite Build/OPM1.171019.019) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/78.0.3904.108 UCBrowser/13.2.0.1100 Mobile Safari/537.36\"\n}",
    "injectJs": "",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "class.module-item",
    "ruleContent": "<div class=\"play_video\">\n{{@@title@text}}{{@@class.player-wrapper@all}}",
    "ruleImage": "img@data-cover",
    "ruleLink": "a.0@href",
    "ruleNextPage": "page",
    "rulePubDate": "class.module-item-caption@text",
    "ruleTitle": "img@alt",
    "singleUrl": false,
    "sortUrl": "最新::https://cn1.91short.com/\n推荐::/short/recommend_home_list/\n美女正妹::/short/label_related_list/Ug_pu_kskqY%3D\n91大神::/short/label_related_list/otDa4t6lDDQ%3D\n门事件::/short/label_related_list/3QW8lOdBcls%3D\n大神::/search?wd=大神\n变量搜索::/search?wd={{java.encodeURI(source.getVariable())}}\n学生::/search?wd=学生\n91::/search?wd=91\n偷情::/search?wd=偷情\n推特::/search?wd=推特\n少女::/search?wd=少女\n贫乳::/search?wd=贫乳\n口交::/search?wd=口交\n妹妹::/search?wd=妹妹\n美女::/search?wd=美女\n\n美臀巨臀::/short/label_related_list/azG9-jZfzG0%3D?title=%E7%BE%8E%E8%87%80%E5%B7%A8%E8%87%80\n后入::/search?wd=后入\n国产高清::/short/home_category_list/hd\n排行::/short/ranking_list\n国产AV::/short/label_related_list/1Bd0Zzp8D_E%3D\n大象传媒::/short/label_related_list/F16wCJ3LmWY%3D\n情趣综艺::/short/label_related_list/-0S1LwkskU4%3D\n推荐2::/film/home_recommend_list\n专题::/film/home_subject_list\n女优::/film/home_actor_list\n无码::/film/home_category_list/coded\n中字::/film/home_category_list/chinese_subtitle\n动漫::/film/home_list/jOSxa-4E27U%3D\n经典三级::/film/home_list/uZg0vDL8P8A%3D\n欧美性爱::/film/home_list/LblejiEnM6s%3D\nAV解说::/film/home_list/vJq_GzRiesQ%3D",
    "sourceComment": "翻页和封面不会\n\n永久域名 https://cn1.91short.com",
    "sourceGroup": "678",
    "sourceIcon": "https://cn1.91short.com/public/statics/logo.png",
    "sourceName": "91视频",
    "sourceUrl": "https://cn1.91short.com/",
    "style": "iframe{\n\theight:auto\n}\ntitle{\n\tdisplay:block\n}"
  },
  {
    "articleStyle": 0,
    "customOrder": 12,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 1775590466136,
    "loadWithBaseUrl": true,
    "ruleArticles": "article",
    "ruleContent": "class.dplayer@all<js>\nresult=result.match(/http.*0/)[0]##\\</js>{{@@title@text##成人黑料.*}}\n<video src=\"{{result}}\" width=\"100%\" height=\"auto\" controls></video>",
    "ruleImage": "@js:\"https://mgtv-bbqn.oss-cn-beijing.aliyuncs.com/1/2310310103284A29582395A850D3A0F5C26862354MzFE/SrRlbr0.gif\"",
    "ruleLink": "a@href",
    "ruleNextPage": "page",
    "rulePubDate": "span.1@text",
    "ruleTitle": "class.post-card-title@text",
    "singleUrl": false,
    "sortUrl": "搜索::/search/{{source.getVariable()}}/{{page}}/\n今日吃瓜::/category/wpcz/{{page}}/\n热门大瓜::/category/rdsj/{{page}}/\n学生校园::/category/xsxy/{{page}}/\n网红黑料::/category/whhl/{{page}}/\n看片娱乐::/category/ysyl/{{page}}/\n乱伦道德::/category/lldd/{{page}}/\n人人吃瓜::/category/rrcg/{{page}}/\n海外吃瓜::/category/hwcg/{{page}}/\n骚男骚女::/category/snsn/{{page}}/",
    "sourceComment": "https://51cgg32.com",
    "sourceGroup": "版本",
    "sourceIcon": "http://p6.itc.cn/images01/20201202/8d012ed623d647a78635557e7d235ab6.jpeg",
    "sourceName": "5.9",
    "sourceUrl": "https://car.fuuanuxl.cc/"
  },
  {
    "articleStyle": 0,
    "customOrder": 13,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "class.pb@tag.div",
    "ruleDescription": "",
    "ruleImage": "class.focus@tag.span@tag.img@src",
    "ruleNextPage": "class.pagination pagination-multi@class.next-page@tag.a@href",
    "rulePubDate": "class.text-muted time.0@text##发布于:",
    "ruleTitle": "class.excerpt excerpt-one.0@tag.header@tag.a@text",
    "singleUrl": true,
    "sourceGroup": "版本",
    "sourceIcon": "https://www.xx3004.vip/wp-content/themes/xiu/images/wap-logo.png",
    "sourceName": "4.4",
    "sourceUrl": "https://www.san421.com/meinv"
  },
  {
    "articleStyle": 0,
    "customOrder": 14,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceComment": "",
    "sourceGroup": "版本",
    "sourceIcon": "https://m.acgnfl.com/24/07/content_33/525867/087.webp",
    "sourceName": "4.2推荐",
    "sourceUrl": "https://xrhf.taimei-t140.vip/"
  },
  {
    "articleStyle": 0,
    "customOrder": 14,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "纯欲",
    "sourceIcon": "",
    "sourceName": "樱之空动漫",
    "sourceUrl": "https://www.skrcc.cc/"
  },
  {
    "articleStyle": 3,
    "customOrder": 15,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\n\t\"User-Agent\": \"Mozilla/5.0 (Linux; Android 9) Mobile Safari/537.36\",\"referer\": \"{{baseUrl}}\"\n\t}",
    "jsLib": "let search = \"https://dns.jingluo.love/2025/68a878e00d302.jpg\";",
    "lastUpdateTime": 1775586135304,
    "loadWithBaseUrl": true,
    "ruleArticles": ".pornkvideos",
    "ruleContent": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<title>内容提取</title>\n<!-- v2025.05.10 -->\n\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<script src=\"https://code.jquery.com/jquery-3.6.0.min.js\"></script>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.3/viewer.min.css\" />\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.3/viewer.min.js\"></script>\n<style>\n    body { font-family: Arial, sans-serif; font-size: 16px; }\n    #title, #page, #loading-status { margin: 0 auto; font-size: 20px; text-align: center; }\n    #description, #urls, #video-url, #video-sources, #messages { width: 100%; max-width: 800px; margin: 1.5px auto; font-size: 14px; text-align: left; word-wrap: break-word; white-space: pre-wrap; }\n    #text, #text :not(img), #text img + * { text-indent: 2em; width: 100%; font-size: 16px; line-height: 1.5em; margin-top: 0; margin-bottom: 0; word-wrap: break-word; white-space: pre-wrap; }\n    img, #text img { width: 100%; height: auto; display: block; margin-bottom: 1.5px; }\n    .flex-container { display: flex; justify-content: center; align-items: center; gap: 10px; margin: 1.5px 0; font-size: 14px; }\n    button, select { flex: 1 1 31%; padding: 3px; border: 1px solid #ccc; border-radius: 5px; box-sizing: border-box; cursor: pointer; background-color: #f9f9f9; transition: background-color 0.3s ease; margin: 1.5px; min-width: 0; font-size: 14px; }\n    #url-select, #video-source-select { flex: 1 1 100%; margin-left: 0; margin-right: 0; text-align: center; }\n    #video-element { width: 100%; height: auto; }\n    textarea { width: 100%; height: auto; min-height: 100px; box-sizing: border-box; resize: vertical; }\n    .error, .warn { color: red; }\n</style>\n</head>\n<body>\n    <h3 id=\"title\">{{@@title@text||h1.0@text||h2.0@text||.title.0@text}}</h3>\n    <p id=\"description\">{{@@.info.0@html||.jianjie@html}}</p>\n    <p id=\"page\" style=\"display:none;\">共<span id=\"total-pages\">1</span>页</p>\n    <p id=\"loading-status\" style=\"display:none;\"></p>\n\n    <div class=\"flex-container\" id=\"loading-buttons\" style=\"display:none;\">\n        <button id=\"prev-page-btn\">上一页</button>\n        <button id=\"next-page-btn\">下一页</button>\n        <button id=\"auto-load-btn\">自&nbsp;&nbsp;动</button>\n    </div>\n    \n    <div class=\"flex-container\">\n        <select id=\"url-select\" style=\"display:none;\"></select>\n    </div>\n    \n    <div class=\"flex-container\">\n        <button id=\"toggle-urls-btn\">显/隐网址</button>\n        <button id=\"toggle-messages-btn\">显/隐信息</button>\n        <button id=\"toggle-debug-btn\">显/隐调试</button>\n    </div>\n    <div id=\"urls\"></div>\n    <div id=\"messages\"></div>\n    <div id=\"debug-info\"></div>\n    <div id=\"video-url\"></div>\n    <div id=\"video-container\" style=\"display: none;\">\n        <video id=\"video-element\" controls preload=\"auto\" width=\"640\" height=\"264\">\n            <source id=\"video-source\" src=\"\" type=\"\">您的浏览器不支持 video 标签。\n        </video>\n    </div>\n    <div class=\"flex-container\" id=\"video-source-container\" style=\"display: none;\">\n        <select id=\"video-source-select\" onchange=\"updateVideoSource()\"></select>\n    </div>\n    <div id=\"images\"></div>\n    <div id=\"text\"></div>\n\n    <script>\n        // 配置对象，包含各种选择器、延迟时间等配置项\n        const config = {    \n            videoSelector: 'body', // 视频选择器\n            imgSelector: '.gridlane-box-inside img,.photos figure img,.content p img', // 图片选择器\n            textSelector: '#content', // 文本选择器\n            debugSelector: '#content, .page, .pager, .content, script', // 调试信息选择器\n            swapImageAttributes: false, // 是否交换图片属性\n            delayTime: 1500, // 延迟提取时间\n            retryDelayTime: 1500, // 重试加载延迟时间\n            maxLoadAttempts: 3, // 最大加载次数\n            autoLoading: false, // true自动模式，false单页模式\n            debugOnce: 0, // 只在特定索引输出一次调试信息\n            totalPagesText: '{{@@.page.0@a.-2@textNodes}}', // 总页码\n            urlSuffixToRemove: /\\.html$/, // 移除url后缀\n            pageUrlText: '{urlPrefix}_{i}.html', // 拼接URL模板        \n            ListMode: true, // true网址列表模式，false网址拼接模式    \n            initialUrls: `{{@@#sort-item-5.0@a@href}}`, // 网址\n            initialUrlsName: `{{@@#sort-item-5.0@a@span@text}}`, // 网址名称\n            sourceurl: '', // 来源URL前缀\n        };\n\n        let videoSources = []; // 存储视频源数组\n        let loadAttempts = {}; // 记录每个URL的加载尝试次数\n        let urls = []; // 存储所有页面的URL\n        let imageBox;\n        let textBox;\n        let currentPageIndex = 0; // 当前页面索引\n        let canLoadNextPage = true; // 控制是否可以加载下一页\n        let autoLoadInProgress = false; // 自动加载状态\n\n        // 构建URL列表\n        function buildUrls(totalPages, baseUrl) {\n            let initialUrlsArray = config.initialUrls.trim().split('\\n').filter(url => url.trim() !== '');\n            let initialUrlsNameArray = config.initialUrlsName.trim().split('\\n').filter(name => name.trim() !== '');\n\n            if (config.ListMode && initialUrlsArray.length > 0) {\n                if (initialUrlsArray.length !== initialUrlsNameArray.length) {\n                    $('#messages').append(`<span class=\"warn\">警告：initialUrls 和 initialUrlsName 的长度不匹配。</span><br>`);\n                }\n\n                urls = initialUrlsArray.map(url => {\n                    if (config.sourceurl && url.startsWith('/') && !/^https?:\\/\\//i.test(url)) {\n                        return config.sourceurl.replace(/\\/$/, '') + url;\n                    } else {\n                        return url;\n                    }\n                });\n\n                urls.forEach((url, index) => {\n                    const name = initialUrlsNameArray[index] || `第 ${index + 1} 页`;\n                    $('#url-select').append(`<option value=\"${index}\">${name}</option>`);\n                    $('#urls').append(`<div>${name}: ${url}</div>`);\n                });\n            } else {\n                if (totalPages === 1) {\n                    urls.push(baseUrl);\n                } else {\n                    urls.push(baseUrl);\n                    for (let i = 2; i <= totalPages; i++) {\n                        urls.push(config.pageUrlText.replace('{urlPrefix}', baseUrl.replace(config.urlSuffixToRemove, '').replace(/\\/$/, '')).replace('{i}', i));\n                    }\n                }\n\n                urls.forEach((url, index) => {\n                    const name = `第 ${index + 1} 页`;\n                    $('#url-select').append(`<option value=\"${index}\">${name}</option>`);\n                    $('#urls').append(`<div>${name}: ${url}</div>`);\n                });\n            }\n\n            $('#total-pages').text(urls.length);\n            toggleNavigationButtons();\n            toggleTotalPagesDisplay();\n        }\n\n        // 规范化URL\n        function normalizeUrl(url) {\n            if (typeof url !== 'string' || !url.trim()) {\n                return '';\n            }\n            const match = url.match(/['\"](.*?)['\"]/);\n            if (match && match[1]) {\n                url = match[1];\n            }\n\n            function processUrl(str) {\n                str = str.trim();\n                str = str.replace(/\\\\u[\\dA-F]{4}/gi, match => String.fromCharCode(parseInt(match.replace(/\\\\u/g, ''), 16)));\n                str = decodeURIComponent(str);\n                str = str.replace(/^http:\\/([^/])/, 'http://$1');\n                str = str.replace(/^https:\\/([^/])/, 'https://$1');\n                return str;\n            }\n            return processUrl(url);\n        }\n\n        // 清空容器内容\n        function clearContainers() {\n            $('#messages').empty();\n            $('#images').empty();\n            $('#text').empty();\n        }\n\n        // 更新图像源\n        function updateImageSrc(elements, shouldSwap) {\n            elements.each(function () {\n                const $this = $(this);\n                const attrsToUpdate = {};\n                if (shouldSwap) {\n                    ['data-original', 'data-src', 'data-url'].forEach(attr => {\n                        if ($this.attr(attr)) {\n                            attrsToUpdate['src'] = $this.attr(attr);\n                        }\n                    });\n                }\n                $this.attr(attrsToUpdate);\n            });\n            return elements;\n        }\n\n        // 切换导航按钮显示状态\n        function toggleNavigationButtons() {\n            if ($('#url-select option').length > 1 && !config.autoLoading) {\n                $('#loading-buttons').show();\n                $('#url-select').show();\n            } else {\n                $('#loading-buttons').hide();\n                $('#url-select').hide();\n            }\n        }\n\n        // 显示加载状态\n        function showLoadingStatus(pageNumber) {\n            const selectedOption = $('#url-select option:selected').text();\n            $('#loading-status').text(`正在加载：${selectedOption}`).show();\n        }\n\n        // 隐藏加载状态\n        function hideLoadingStatus() {\n            $('#loading-status').hide();\n        }\n\n        // 加载指定索引的内容\n        function loadContent(index) {\n            if (index < 0 || index >= urls.length || !canLoadNextPage) return;\n            canLoadNextPage = false;\n            currentPageIndex = index;\n            $('#url-select').val(index);\n            $('#messages').append(`<div>当前地址: <span class=\"warn\">${urls[index]}</span></div>`);\n            if (autoLoadInProgress) {\n                showLoadingStatus(index + 1);\n            }\n            $.ajax({\n                url: urls[index],\n                type: 'GET',\n                success: function (data) {\n                    try {\n                    const $data = $(data);\n                    let updatedHtmlContent = data.replace(/(['\"])(\\/\\/)(?!\\/)/g, '$1https://')\n                        .replace(/src=\"upload/gi, 'src=\"/upload')\n                        .replace(/style=[\"'][^'\"]+[\"']/gi, '')\n                        .replace(/\\\\\\//g, '/');\n                    const parser = new DOMParser();\n                    const doc = parser.parseFromString(updatedHtmlContent, \"text/html\");\n\n                    if (config.debugOnce === index) {\n                        const debugElements = $(doc).find(config.debugSelector);\n                        if (debugElements.length > 0) {\n                            const debugContents = $('<pre>').html(debugElements.clone().wrapAll('<div/>').parent().html()).html();\n                            $('#debug-info').html(`<span class=\"warn\">调试信息: <textarea rows=\"10\" cols=\"80\">${debugContents}</textarea></span>`);\n                        } else {\n                            $('#debug-info').html(`<span class=\"warn\">调试信息: <textarea rows=\"10\" cols=\"80\">调试信息未提取到内容，请检查选择器！</textarea></span>`);\n                        }\n                    }\n                    // 方法1：提取视频\n                    const videoSources1 = [];\n                    const videoContents = $(doc).find(config.videoSelector);\n                    const videoTags = $(videoContents).find('video, source');\n                    videoTags.each(function() {\n                        const videosrc = $(this).attr('src') || \n                                     $(this).attr('data-src') || \n                                     $(this).attr('data-original') || '';\n                        \n                        if (videosrc) {\n                            videoSources1.push(videosrc);\n                        }\n                    });\n                    //反馈\n                    if (videoSources1.length > 0) {\n                        $('#messages').append(`<span>方法1，找到 ${videoSources1.length} 个视频。</span><br>`);\n                    }\n\n                    // 方法2：正则提取视频\n                    const regex = /['\"]https?[^'<>\"]+(m3u8|mp4|webm|ogg|flv|mp3|m4a|wav|ape|flac)([^'<>\"]+)?['\"]/gi;\n                    const matches = data.match(regex);\n                    const videoSources2 = [];\n\n                    if (matches) {\n                        const uniqueMatches = [...new Set(matches)];\n                    \n                        uniqueMatches.forEach(match => {\n                            const normalizedSrc = normalizeUrl(match.replace(/['\"]/g, ''));\n                            videoSources2.push(normalizedSrc);\n                        });\n                    }\n                    //反馈\n                    if (videoSources2.length > 0) {\n                        $('#messages').append(`<span>方法2，找到 ${videoSources2.length} 个视频。</span><br>`);\n                    }\n\n                    // 合并两种方法的结果\n                    videoSources = [...videoSources1, ...videoSources2];\n\n                    // 去重并标准化 URL\n                    const imageExtensions = /\\.(jpg|jpeg|png|gif|bmp|svg)$/i;\n\n                    videoSources = videoSources\n                                  .map(src => normalizeUrl(src.replace(/\\\\+/g, '')))\n                                  .filter(src => src) // 过滤空值\n                                  .filter(src => !imageExtensions.test(src)); // 移除图片地址\n                        \n                    videoSources = [...new Set(videoSources)];// 去重\n\n                    // 显示最终结果\n                    $('#messages').append(`<span>总共找到 ${videoSources.length} 个视频。</span><br>`);\n\n                    if (videoSources.length > 0) {\n                        $('#messages').append(`<span>成功提取到视频，找到 ${videoSources.length} 个视频。</span><br>`);\n                        videoSources.forEach((src, idx) => {\n                            $('#messages').append(`<div>视频地址:<span class=\"warn\"> ${src}</span><br></div>`);\n                            $('#video-source-select').append(`<option value=\"${idx}\">视频源 ${idx + 1}</option>`);\n                        });\n                    \n                        if (videoSources.length == 1) {\n                            $('#video-container').show();\n                            $('#video-url').show();\n                            $('#video-source-container').hide();\n                            updateVideoSource();\n                        } else if (videoSources.length > 1) {\n                            $('#video-container').show();\n                            $('#video-url').show();\n                            $('#video-source-container').show();\n                            updateVideoSource();\n                        } else {\n                            $('#video-container').hide();\n                            $('#video-url').hide();\n                            $('#video-source-container').hide();\n                        }\n                    } else {\n                        $('#messages').append(`<span class=\"warn\">未找到视频源。</span><br>`);\n                        $('#video-container').hide();\n                        $('#video-url').hide();\n                        $('#video-source-container').hide();\n                    }\n\n                    //提取图片\n                    const $imgContents = $(doc).find(config.imgSelector);\n                    const shouldSwap = config.swapImageAttributes;\n                    const newContents = updateImageSrc($imgContents.clone(), shouldSwap);\n                    $('#images').append(newContents).show();\n                    if (newContents.length > 0) {\n                        $('#messages').append(`<span>成功提取图片，共 ${newContents.length} 张。</span><br>`);\n                        newContents.each(function () {\n                            const imgSrc = $(this).attr('src') || $(this).attr('data-original') || $(this).attr('data-src') || $(this).attr('data-url');\n                            $('#messages').append(`<div>地址:<span class=\"warn\"> ${imgSrc}</span><br></div>`);\n                        });\n                    } else {\n                        $('#messages').append(`<span class=\"warn\">未提取到图片。</span><br>`);\n                    }\n\n                    //提取图片和文本\n                    const textContents = $(doc).find(config.textSelector).map(function () {\n                        const $currentContents = $(this);\n                        $currentContents.find('img + br, script, video, source, iframe').remove();\n                        $currentContents.html($currentContents.html().replace(/>\\s+/gi, '>').replace(/<\\/?br\\s*([^>]*)\\s*\\/?>/gi, '\\n').replace(/\\n+/g, '\\n'));\n                        return $currentContents.html();\n                    }).get().join('');\n                    if (textContents.trim()) {\n                        $('#text').append(`<span>${textContents}</span><br>`).show();\n                        $('#messages').append(`<span>成功提取图文。</span><br>`);\n                    } else {\n                        $('#messages').append(`<span class=\"warn\">未提取到图文。</span><br>`);\n                    }\n\n                    if (autoLoadInProgress && currentPageIndex < urls.length - 1) {\n                        setTimeout(() => { \n                            canLoadNextPage = true;\n                            loadContent(currentPageIndex + 1); \n                        }, config.delayTime);\n                    } else {\n                        canLoadNextPage = true;\n                        if (autoLoadInProgress) {\n                            hideLoadingStatus();\n                        }\n                    }\n                } catch (parseError) {\n                    $('#messages').append(`<span class=\"error\">解析页面内容时发生错误: ${parseError.message}</span><br>`);\n                    handleLoadFailure(urls, index);\n                } finally {\n                    if (imageBox) imageBox.viewer.update();\n                    if (textBox) textBox.viewer.update();\n                }\n            },\n            error: function (jqXHR, textStatus, errorThrown) {\n                let errorMessage = `内容加载失败: ${urls[index]}`;\n                switch (textStatus) {\n                    case 'timeout':\n                        errorMessage += ', 请求超时';\n                        break;\n                    case 'abort':\n                        errorMessage += ', 请求被取消';\n                        break;\n                    case 'parsererror':\n                        errorMessage += ', 解析响应出错';\n                        break;\n                    default:\n                        errorMessage += `, 状态码: ${jqXHR.status}, 错误信息: ${errorThrown}`;\n                        break;\n                }\n                $('#messages').append(`<span class=\"error\">${errorMessage}</span><br>`);\n                handleLoadFailure(urls, index);\n                }\n            });\n        }\n\n        // 处理加载失败的情况\n        function handleLoadFailure(urls, index) {\n            if (!loadAttempts[urls[index]]) {\n                loadAttempts[urls[index]] = 1;\n            } else {\n                loadAttempts[urls[index]]++;\n            }\n            if (loadAttempts[urls[index]] <= config.maxLoadAttempts) {\n                const retryMessage = `第${index + 1}页加载失败，正在进行第${loadAttempts[urls[index]]}次加载！`;\n                $('#messages').append(`<span class=\"error\">${retryMessage}</span><br>`);\n                setTimeout(() => { \n                    canLoadNextPage = true;\n                    loadContent(index); \n                }, config.retryDelayTime);\n            } else {\n                const finalErrorMessage = `第${index + 1}页加载失败，已达到最大尝试次数(${config.maxLoadAttempts})！`;\n                $('#messages').append(`<span class=\"error\">${finalErrorMessage}</span><br>`);\n                if (autoLoadInProgress && currentPageIndex < urls.length - 1) {\n                    setTimeout(() => { \n                        canLoadNextPage = true;\n                        loadContent(currentPageIndex + 1); \n                    }, config.delayTime);\n                } else {\n                    canLoadNextPage = true;\n                    if (autoLoadInProgress) {\n                        hideLoadingStatus();\n                    }\n                }\n            }\n        }\n\n        // 更新视频源\n        function updateVideoSource() {\n            const selectedIndex = parseInt(document.getElementById('video-source-select').value);\n            if (isNaN(selectedIndex) || !videoSources[selectedIndex]) {\n                $('#messages').append(`<span class=\"warn\">未找到有效的视频源。</span><br>`);\n                console.warn(\"Invalid or undefined video source:\", selectedIndex, videoSources);\n                return;\n            }\n\n            const selectedSource = videoSources[selectedIndex];\n            document.getElementById('video-url').textContent = `视频地址:\\n ${selectedSource}`;\n\n            const videoSourceElement = document.getElementById('video-source');\n            videoSourceElement.src = selectedSource;\n\n            const videoElement = document.getElementById('video-element');\n            videoElement.load();\n\n            $('#messages').append(`<span>更新视频源为: ${selectedSource}</span><br>`);\n            console.log(\"Updated video source to:\", selectedSource);\n        }\n\n        // 切换总页数显示状态\n        function toggleTotalPagesDisplay() {\n            if (urls.length > 1) {\n                $('#page').show();\n            } else {\n                $('#page').hide();\n            }\n        }\n\n        // 页面加载完成后执行的主要逻辑\n        $(document).ready(function () {\n            imageBox = document.getElementById('images');\n            textBox = document.getElementById('text');\n            if (imageBox && textBox) {\n                new Viewer(imageBox, { title: true, interval: 2000 });\n                new Viewer(textBox, { title: true, interval: 2000 });\n            }\n\n            const totalPagesText = config.totalPagesText;\n            const totalPages = parseInt(totalPagesText, 10) || 1;\n            const baseUrl = '{{baseUrl}}';\n\n            clearContainers();\n            $('#urls, #debug-info textarea, #video-url, #video-source-select').empty();\n            $('#urls, #messages, #debug-info, #video-url, #video-container, #video-source-container, #images, #text').hide();\n\n            buildUrls(totalPages, baseUrl);\n\n            const urlSelect = document.getElementById('url-select');\n            if (urlSelect.options.length > 0) {\n                urlSelect.value = '0'; \n\n                if (config.autoLoading) {\n                    autoLoadInProgress = true;\n                    for (let i = 0; i < urls.length; i++) {\n                        loadContent(i);\n                    }\n                } else {\n                    loadContent(0);\n                }\n            } else {\n                loadContent(0);\n            }\n\n            $('#url-select').change(function () {\n                clearContainers();\n                const selectedIndex = parseInt($(this).val());\n                loadContent(selectedIndex);\n            });\n            $('#prev-page-btn').click(function () {\n                clearContainers();\n                if (currentPageIndex > 0) {\n                    loadContent(currentPageIndex - 1);\n                }\n            });\n            $('#next-page-btn').click(function () {\n                clearContainers();\n                if (currentPageIndex < urls.length - 1) {\n                    loadContent(currentPageIndex + 1);\n                }\n            });\n            $('#auto-load-btn').click(function () {\n                autoLoadInProgress = true;\n                showLoadingStatus(1); \n                for (let i = currentPageIndex + 1; i < urls.length; i++) {\n                    loadContent(i);\n                }\n            });\n            $('#toggle-messages-btn').click(function () { $('#messages').toggle(); });\n            $('#toggle-urls-btn').click(function () { $('#urls').toggle(); });\n            $('#toggle-debug-btn').click(function () { $('#debug-info').toggle(); });\n        });\n    </script>\n</body>\n</html>",
    "ruleImage": "img@data-src",
    "ruleLink": "/vodplay/{{@a.0@href##voddetail/(.*).html##$1##}}-1-1.html",
    "ruleNextPage": "text.下页@href",
    "rulePubDate": ".vlength@text",
    "ruleTitle": "a@text",
    "singleUrl": false,
    "sortUrl": "国产色情::/vodtype/12.html\n日本无码::/vodtype/20.html\n自拍偷拍::/vodtype/21.html\n人妻熟女::/vodtype/22.html\n黑人洋屌::/vodtype/23.html\n欧美精品::/vodtype/24.html\n岛国女优::/vodtype/25.html\n萝莉少女::/vodtype/26.html\n国产精品::/vodtype/55.html\n国产直播::/vodtype/56.html\n动漫禁漫::/vodtype/57.html\n黑料吃瓜::/vodtype/58.html\n欧美大屌::/vodtype/60.html\n探花约炮::/vodtype/61.html\n华语精品::/vodtype/63.html\n乱伦精品::/vodtype/64.html\n学生合集::/vodtype/65.html\n卡通动漫::/vodtype/69.html\n乱伦中出::/vodtype/70.html\n传媒原创::/vodtype/71.html\n口爆颜射::/vodtype/72.html\n岛国群交::/vodtype/73.html\n日本有码::/vodtype/74.html\n中文字幕::/vodtype/75.html\n吃瓜爆料::/vodtype/76.html\n角色扮演::/vodtype/77.html\n淫娃自慰::/vodtype/78.html\n日本有码::/vodtype/80.html\n主播网红::/vodtype/81.html\n韩国直播::/vodtype/84.html\n公开漏出::/vodtype/85.html\n日本无码::/vodtype/86.html\n重口调教::/vodtype/88.html\n户外打野::/vodtype/89.html",
    "sourceComment": "shewo1.cc",
    "sourceGroup": "版本",
    "sourceIcon": "https://baf7baf7.shewo11.cc/template/shewo/images/logo.png",
    "sourceName": "2.6",
    "sourceUrl": "https://baf7baf7.shewo11.cc/"
  },
  {
    "articleStyle": 0,
    "customOrder": 16,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\n\t\"User-Agent\": \"Mozilla/5.0 (Linux; Android 9) Mobile Safari/537.36\",\"referer\": \"{{baseUrl}}\"\n\t}",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": ".picstyle ul li||.threadlist ul li",
    "ruleContent": ".bz_message_table@all&&link@all&&script@all",
    "ruleImage": "img@src",
    "ruleLink": "a@href",
    "ruleNextPage": "text.下一页@href",
    "rulePubDate": "span!0@text##\\s##😁",
    "ruleTitle": "span.0@text",
    "singleUrl": false,
    "sortUrl": "网友自拍::https://qp.tangse95.one/forum.php?mod=forumdisplay&fid=6&mobile=2\n有声小说::https://qp.tangse95.one/forum.php?mod=forumdisplay&fid=45&mobile=2\n国产自拍::https://qp.tangse95.one/forum.php?mod=forumdisplay&fid=18&mobile=2\n校园春色::https://qp.tangse95.one/forum.php?mod=forumdisplay&fid=14&mobile=2\n搜索::https://qp.tangse95.one/search.php?mod=forum&searchid=243&orderby=lastpost&ascdesc=desc&searchsubmit=yes&kw={{(source.getVariable()==''||source.getVariable()==null)?source.setVariable('妹妹'):\"\"}}{{source.getVariable()}}&mobile=2",
    "sourceComment": "https://96tang.club",
    "sourceGroup": "版本",
    "sourceIcon": "天",
    "sourceName": "4.1",
    "sourceUrl": "https://qp.tangse95.one"
  },
  {
    "articleStyle": 0,
    "contentBlacklist": "https://pc.stgowan.com/,\nhttps://dmku.mhtjx.top/,\nhttps://dmku.m3u8.pw/,\nhttps://dm.bbj.icu/,\nhttps://www.superplayer.top/index.php/index/dm",
    "coverDecodeJs": "function toByteArray(input) {\n  var out = new Packages.java.io.ByteArrayOutputStream();\n  var buffer = java.strToBytes('\\0'.repeat(4096));\n  var bytesRead;\n  while ((bytesRead = input.read(buffer)) != -1) {\n    out.write(buffer, 0, bytesRead);\n  }\n  return out.toByteArray();\n}\n\n(function() {\n  // 1. 读取原始字节内容\n  var textBytes = toByteArray(result);\n  // 2. 如果是GIF文件，直接返回原始字节\n  if (src.endsWith('.gif')) {\n    return textBytes;\n  }\n  try {\n    // 3. 将字节转换为字符串（用于解析数据URI）\n    var dataUri = java.bytesToStr(textBytes, \"UTF-8\");\n    // 4. 判断是完整的数据URI还是纯Base64数据\n    var base64Prefix = \"base64,\";\n    var base64Index = dataUri.indexOf(base64Prefix);\n    if (base64Index === -1) {\n      // 如果没有找到base64前缀，检查是否需要截取第一个/及之后的内容\n      var firstSlashIndex = dataUri.indexOf('/');\n      if (firstSlashIndex !== -1) {\n        // 如果找到第一个/，截取/及之后的内容\n        dataUri = dataUri.substring(firstSlashIndex);\n      }\n      // 对整个内容进行Base64解码\n      return java.base64DecodeToByteArray(dataUri);\n    } else {\n      // 如果是标准data URI，提取base64编码部分解码\n      var base64Data = dataUri.substring(base64Index + base64Prefix.length);\n      return java.base64DecodeToByteArray(base64Data);\n    }\n  } catch (e) {\n    // 解码失败时返回原始字节\n    return textBytes;\n  }\n})();",
    "customOrder": 17,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\n\t\"User-Agent\":\"Mozilla/5.0 (Linux; U; Android 10; zh-cn; MI CC 11)  AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4896.127 Mobile Safari/537.36 XiaoMi/MiuiBrowser/18.1.8 swan-mibrowser\",\n\t\"referer\": \"{{baseUrl}}\"\n}",
    "injectJs": "function setupCustomPlayer(video) {\n  // 手势滑动快进\n  let isDragging = false;\n  let startX = 0;\n  let startTime = 0;\n  \n  // 长按加速相关变量\n  let longPressTimer = null;\n  const LONG_PRESS_DELAY = 300;\n  const NORMAL_SPEED = 1.25;\n  const FAST_SPEED = 3;\n  let wasPaused = false;\n\n  // 触摸事件处理\n  function handleTouchStart(e) {\n    startX = e.touches[0].clientX;\n    startTime = video.currentTime;\n    wasPaused = video.paused;\n    \n    longPressTimer = setTimeout(() => {\n      video.playbackRate = FAST_SPEED;\n      if (wasPaused) video.play();\n    }, LONG_PRESS_DELAY);\n  }\n\n  function handleTouchMove(e) {\n    if (longPressTimer) {\n      clearTimeout(longPressTimer);\n      longPressTimer = null;\n    }\n    \n    const dx = e.touches[0].clientX - startX;\n    if (Math.abs(dx) > 10) {\n      if (!isDragging) {\n        video.pause();\n        isDragging = true;\n      }\n      const change = (dx / video.clientWidth) * video.duration;\n      video.currentTime = Math.max(0, Math.min(startTime + change, video.duration));\n    }\n  }\n\n  function handleTouchEnd() {\n    if (longPressTimer) {\n      clearTimeout(longPressTimer);\n      longPressTimer = null;\n    }\n    \n    if (isDragging) {\n      video.playbackRate = NORMAL_SPEED;\n      video.play();\n      isDragging = false;\n    } else if (video.playbackRate === FAST_SPEED) {\n      video.playbackRate = NORMAL_SPEED;\n      if (wasPaused) video.pause();\n    }\n  }\n\n  // 添加触摸事件监听\n  video.addEventListener('touchstart', handleTouchStart);\n  video.addEventListener('touchmove', handleTouchMove);\n  video.addEventListener('touchend', handleTouchEnd);\n  \n  // 初始播放速度\n  video.playbackRate = NORMAL_SPEED;\n\n  // 创建按钮的通用函数\n  function createButton(text, onClick, position, width = '20px') {\n    const button = document.createElement('button');\n    button.textContent = text;\n    button.style.position = 'absolute';\n    button.style[position.horizontal] = '0';\n    button.style.top = '50%';\n    button.style.transform = 'translateY(-50%)';\n    button.style.zIndex = '999';\n    button.style.padding = '1px';\n    button.style.background = 'rgba(51, 51, 51, 0)';\n    button.style.color = '#fff';\n    button.style.border = 'none';\n    button.style.cursor = 'pointer';\n    button.style.width = width;\n    button.style.height = '30px';\n    button.addEventListener('click', onClick);\n    video.parentNode.appendChild(button);\n    return button;\n  }\n\n  // 旋转按钮（右侧）\n  createButton('⟳', () => {\n    const currentRotation = parseInt(video.getAttribute('data-rotation') || '0');\n    const newRotation = (currentRotation + 90) % 360;\n    video.setAttribute('data-rotation', newRotation);\n    \n    // 保留当前的缩放比例\n    const currentTransform = video.style.transform || '';\n    let currentScale = 1;\n    const scaleMatch = currentTransform.match(/scale\\(([^)]+)\\)/);\n    if (scaleMatch) currentScale = parseFloat(scaleMatch[1]);\n    \n    video.style.transform = `rotate(${newRotation}deg) scale(${currentScale})`;\n  }, { horizontal: 'right' });\n\n  // 缩放按钮（左侧）\n  let zoomCount = 0;\n  createButton('+', () => {\n    const currentRotation = parseInt(video.getAttribute('data-rotation') || '0');\n    \n    // 获取当前缩放比例\n    const currentTransform = video.style.transform || '';\n    let currentScale = 1;\n    const scaleMatch = currentTransform.match(/scale\\(([^)]+)\\)/);\n    if (scaleMatch) currentScale = parseFloat(scaleMatch[1]);\n    \n    if (zoomCount < 4) {\n      const newScale = currentScale * 1.25;\n      video.style.transform = `rotate(${currentRotation}deg) scale(${newScale})`;\n      zoomCount++;\n    } else {\n      video.style.transform = `rotate(${currentRotation}deg) scale(1)`;\n      zoomCount = 0;\n    }\n  }, { horizontal: 'left' });\n\n  // 快速跳转按钮（底部中央）\n  const buttonContainer = document.createElement('div');\n  buttonContainer.style.position = 'absolute';\n  buttonContainer.style.bottom = '0';\n  buttonContainer.style.left = '50%';\n  buttonContainer.style.transform = 'translateX(-50%)';\n  buttonContainer.style.display = 'flex';\n  buttonContainer.style.gap = '10px';\n  buttonContainer.style.zIndex = '999';\n  \n  // 按钮配置\n  const seekButtons = [\n    { text: '-5分', time: -300 },\n    { text: '-1分', time: -60 },\n    { text: '+1分', time: 60 },\n    { text: '+5分', time: 300 }\n  ];\n\n  seekButtons.forEach(({ text, time }) => {\n    const button = document.createElement('button');\n    button.textContent = text;\n    button.style.padding = '1px';\n    button.style.background = 'rgba(51, 51, 51, 0)';\n    button.style.color = '#fff';\n    button.style.border = 'none';\n    button.style.cursor = 'pointer';\n    button.style.width = '60px';\n    button.style.height = '30px';\n    button.addEventListener('click', () => {\n      video.currentTime = Math.max(0, Math.min(video.currentTime + time, video.duration));\n    });\n    buttonContainer.appendChild(button);\n  });\n\n  video.parentNode.appendChild(buttonContainer);\n}\n\n// 修改初始化逻辑，增加重试机制\nfunction initPlayerWithRetry() {\n  const maxRetries = 10;\n  const retryInterval = 500;\n  let retries = 0;\n  const tryInit = () => {\n    const video = document.getElementById('video');\n    if (video) {\n      setupCustomPlayer(video);\n    } else if (retries < maxRetries) {\n      retries++;\n      setTimeout(tryInit, retryInterval);\n    }\n  };\n  tryInit();\n}\n// 使用重试机制初始化播放器\ninitPlayerWithRetry();",
    "lastUpdateTime": 1775584959581,
    "loadWithBaseUrl": true,
    "ruleArticles": "$.rescont.data",
    "ruleContent": "<html><head><meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no\" />\n<meta name=\"referrer\" content=\"never\"/>\n  <style>html, body {text-align: center;margin: 0; padding: 0;width: 100%;overflow: hidden;} </style>\n  <script src=\"https://unpkg.com/hls.js@1.4.3/dist/hls.min.js\"></script>\n</head><body>\n  <div class=\"container\">\n    <div class=\"title\">{{$.rescont.title}}</div>\n    <video id=\"video\" width=\"100%\" height=\"91%\" poster=\"\" controls autoplay muted loop></video>\n  </div>\n<script>\nconst v=document.getElementById('video'),s=[\n  \"{{$.rescont.videopath}}\",\n  \"\"];\nlet c=0;\nfunction setupCustomControls(e){/* 自定义功能实现 */}\nfunction playNext(){\n  c>=s.length&&(c=0); // 循环重置计数器\n  const u=s[c++];\n  // 检测Hls对象是否存在\n  if (typeof Hls !== 'undefined' && Hls.isSupported()) {\n    const h = new Hls({\n      enableSoftwareAES: true,          // 强制软件解密\n      forceKeyFrameOnDiscontinuity: true // 关键帧恢复\n    });\n    h.loadSource(u);\n    h.attachMedia(v);\n    h.on(Hls.Events.MANIFEST_PARSED,()=>v.play().then(()=>setupCustomControls(v)).catch(console.log));\n    h.on(Hls.Events.ERROR,(_,d)=>d.fatal&&playNext())\n  } else { // Hls加载失败或浏览器原生支持HLS\n    if (v.canPlayType('application/vnd.apple.mpegurl')) {\n      v.src = u;\n      v.onloadedmetadata = () => v.play().then(() => setupCustomControls(v));\n      v.onerror = playNext;\n    } else {\n      // 如果都不支持，尝试直接播放（可能支持MP4等格式）\n      v.src = u;\n      v.onerror = playNext;\n      v.play().then(() => setupCustomControls(v)).catch(playNext);\n    }\n  }\n}playNext();\n</script>\n</body></html>",
    "ruleImage": "{{$.coverbase64.url}}",
    "ruleLink": "/api/videoplay/{{$.id}}?uuid=1",
    "ruleNextPage": "$.rescont.next_page_url",
    "rulePubDate": "📆{{$.updated_at## .*}}  ⏱️{{$.playtimes}}",
    "ruleTitle": "$.title##.*屎.*|.*Ts.*|.*TS.*|.*ts.*|.*伪娘.*|.*人妖.*|.*男同.*|.*mbrba.*|.*水果派.*|.*解说.*|.*mmraa.*|.*ss-.*|.*fway.*|.*rebd.*|.*mbdd.*|.*双性.*|.*妈妈.*|.*儿子.*|.*爸爸.*|.*女儿.*|.*母子.*|.*父女.*|.*熟女.*|.*眼射.*|.*直男.*|.*CD.*|.*肥女.*|.*黄金.*|.*骚0.*|.*gv.*|.*父子.*|.*飞机.*|.*撸.*|.*厕.*|.*老阿姨.*|.*乱伦.*|.*[电影].*",
    "singleUrl": false,
    "sortUrl": "\n随机::/api/videosort/0?page={{ Math.ceil(Math.random()*1600) }}\n最新::/api/videosort/0?page={{page}}\n🔎搜索::/api/videosort/0?serach={{v=source.getVariable();if(/^\\s*$/.test(v)||v==null)source.setVariable('强奸');source.getVariable()}}&page={{page}}\n国产自拍::/api/videosort/28?page={{page}}\nH动漫::/api/videosort/32?page={{page}}\n3D动画::/api/videosort/65?page={{page}}\n国产AV::/api/videosort/68?page={{page}}\n高清无码::/api/videosort/30?page={{page}}\n凌辱侵犯::/api/videosort/60?page={{page}}\n性虐调教::/api/videosort/64?page={{page}}\n长腿丝袜::/api/videosort/43?page={{page}}\n制服诱惑::/api/videosort/33?page={{page}}\nAV素人::/api/videosort/39?page={{page}}\nAV剧情::/api/videosort/49?page={{page}}\n绿帽人妻::/api/videosort/58?page={{page}}\n痴女淫娃::/api/videosort/61?page={{page}}\n美乳巨乳::/api/videosort/38?page={{page}}\n草莓推荐::/api/videosort/52?page={{page}}\ntaipei1001::/api/videosort/69?page={{page}}\n259LUXU::/api/videosort/50?page={{page}}\n明星淫梦::/api/videosort/56?page={{page}}\n电车痴汉::/api/videosort/59?page={{page}}\n絕色佳人::/api/videosort/44?page={{page}}\n网红嫩模::/api/videosort/37?page={{page}}\n口交自慰::/api/videosort/63?page={{page}}\n精油汗汁::/api/videosort/62?page={{page}}\n角色扮演::/api/videosort/27?page={{page}}\n魔镜系列::/api/videosort/54?page={{page}}\n重咸口味::/api/videosort/48?page={{page}}\n三级电影:/api/videosort/46?page={{page}}\n家庭乱伦::/api/videosort/57?page={{page}}\nAV欧美::/api/videosort/36?page={{page}}\n恐怖情色::/api/videosort/51?page={{page}}\n酒店偷拍::/api/videosort/67?page={{page}}",
    "sourceGroup": "版本",
    "sourceIcon": "https://i1.wp.com/i.postimg.cc/wjL5myHr/kpptube-cc-3e997cb42a6b0f37af6c6a40866ba202.gif",
    "sourceName": "3.7",
    "sourceUrl": "https://api.cmapiaba.xyz/",
    "style": ".container {\n    position: relative; /* 相对定位，用于包含视频 */\n    height: 100%; /* 容器高度与视频原始高度相同 */\n    overflow: hidden; /* 隐藏超出容器的部分 */\n}\n.title {\n    position: absolute; /* 绝对定位，相对于容器 */\n    top: 0; \n    width: 100%;\n    overflow: hidden; \n    text-overflow: ellipsis;\n    display: -webkit-box;\n    -webkit-box-orient: vertical; \n    -webkit-line-clamp: 2;\n    z-index: 1; /* 确保标题在视频之上 */\n    background: #000; /* 纯黑色背景 */ \n    padding: 0 0 3px 0;\n}\nvideo {\n    position: absolute; /* 绝对定位，相对于容器 */ \n    top: -65px; /* 上移80px */\n    left: 0; \n    width: 100%; \n    height: calc(96% + 65px);  /* 调整高度以适应内容 */\n    object-fit: contain; /* 确保视频内容不被裁剪 */\n    z-index: 0; /* 确保视频在标题之下 */\n    controls=\"controls\" autoplay muted; \n} \n"
  },
  {
    "articleStyle": 0,
    "customOrder": 18,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "版本",
    "sourceIcon": "天",
    "sourceName": "3.4",
    "sourceUrl": "https://www.bec9693b2cfd.com/shipin/list-%E4%BA%9A%E6%B4%B2%E6%97%A0%E7%A0%81-1.html"
  },
  {
    "articleStyle": 0,
    "contentBlacklist": "",
    "contentWhitelist": "",
    "customOrder": 19,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\n\"User-Agent\": \"Mozilla/5.0 (Linux; U; Android 8.1.0; zh-CN; MI 8 Lite Build/OPM1.171019.019) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/78.0.3904.108 UCBrowser/13.2.0.1100 Mobile Safari/537.36\"\n}",
    "injectJs": "",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "class.module-item",
    "ruleContent": "<div class=\"play_video\">\n{{@@title@text}}{{@@class.player-wrapper@all}}",
    "ruleImage": "img@data-cover",
    "ruleLink": "a.0@href",
    "ruleNextPage": "page",
    "rulePubDate": "class.module-item-caption@text",
    "ruleTitle": "img@alt",
    "singleUrl": false,
    "sortUrl": "最新::https://cn1.91short.com/\n推荐::/short/recommend_home_list/\n美女正妹::/short/label_related_list/Ug_pu_kskqY%3D\n91大神::/short/label_related_list/otDa4t6lDDQ%3D\n门事件::/short/label_related_list/3QW8lOdBcls%3D\n大神::/search?wd=大神\n变量搜索::/search?wd={{java.encodeURI(source.getVariable())}}\n学生::/search?wd=学生\n91::/search?wd=91\n偷情::/search?wd=偷情\n推特::/search?wd=推特\n少女::/search?wd=少女\n贫乳::/search?wd=贫乳\n口交::/search?wd=口交\n妹妹::/search?wd=妹妹\n美女::/search?wd=美女\n\n美臀巨臀::/short/label_related_list/azG9-jZfzG0%3D?title=%E7%BE%8E%E8%87%80%E5%B7%A8%E8%87%80\n后入::/search?wd=后入\n国产高清::/short/home_category_list/hd\n排行::/short/ranking_list\n国产AV::/short/label_related_list/1Bd0Zzp8D_E%3D\n大象传媒::/short/label_related_list/F16wCJ3LmWY%3D\n情趣综艺::/short/label_related_list/-0S1LwkskU4%3D\n推荐2::/film/home_recommend_list\n专题::/film/home_subject_list\n女优::/film/home_actor_list\n无码::/film/home_category_list/coded\n中字::/film/home_category_list/chinese_subtitle\n动漫::/film/home_list/jOSxa-4E27U%3D\n经典三级::/film/home_list/uZg0vDL8P8A%3D\n欧美性爱::/film/home_list/LblejiEnM6s%3D\nAV解说::/film/home_list/vJq_GzRiesQ%3D",
    "sourceComment": "翻页和封面不会\n\n永久域名 https://cn1.91short.com",
    "sourceGroup": "版本",
    "sourceIcon": "天",
    "sourceName": "1.6",
    "sourceUrl": "https://cn1.91short.com",
    "style": "iframe{\n\theight:auto\n}\ntitle{\n\tdisplay:block\n}"
  },
  {
    "articleStyle": 0,
    "customOrder": 20,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\"User-Agent\":\"Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Mobile Safari/537.36 Reader\"}",
    "jsLib": "function sleep(time) {\n    let endTime = new Date().getTime() + time\n    while(true){\n        if (new Date().getTime() > endTime){\n            return;\n        }\n    }\n}\n\nfunction sleepToast(text, second) {\n    let {java} = this\n    java.log(text)\n    java.longToast(text)\n    if (second === undefined) {second = 0.01}\n    sleep(1000*second)\n}\n\nlet bookSourceCommentText = `Pixiv 小说\n\n书源版本：无法获取\n使用说明：📌阅读版本 3.25.0527 及之后版本可用\n可用功能：✅搜索✅发现✅添加网址✅订阅源\n搜索小说：✅单篇✅系列✅标签✅作者\n发现小说：✅关注✅追更✅推荐✅发现\n发现小说：✅收藏✅书签✅首页✅排行\n添加网址：✅Pixiv小说链接✅Pixiv系列链接\n订阅用法：点击订阅源打开小说/系列小说，【刷新】，点击【加入书架】按钮，添加到书架\n\n书源发布：https://t.me/PixivSource\n项目地址：https://github.com/DowneyRem/PixivSource\n使用教程：https://downeyrem.github.io/PixivSource/Pixiv\n\n规则订阅：import 订阅源\nhttps://cdn.jsdelivr.net/gh/DowneyRem/PixivSource@main/import.json\nhttps://raw.githubusercontent.com/DowneyRem/PixivSource/main/import.json\n\n⚙️ 书源设置：\n设置1️⃣：打开小说 - 菜单 - 登录 - 点击下方按钮\n设置2️⃣：编辑书源 - 基本 - 变量说明 - 修改并保存\n\n🚫 屏蔽作者(本地)：\n设置方法1️⃣：打开小说 - 菜单 - 登录 - 🚫 屏蔽作者\n`.trim()\n\nfunction updateSource() {\n    const {java, source} = this\n    let onlineSource, comment\n    java.longToast(\"🆙 更新书源\\n\\nJsdelivr CDN 更新有延迟\\nGithub 更新需代理\")\n    try {\n        let updateUrl = \"https://cdn.jsdelivr.net/gh/DowneyRem/PixivSource@main/pixiv.json\"\n        onlineSource = JSON.parse(java.get(updateUrl,{'User-Agent': 'Mozilla/5.0 (Linux; Android 14)','X-Requested-With': 'XMLHttpRequest'}).body())[0]  // 第1个书源\n        comment = onlineSource.bookSourceComment.split(\"\\n\")\n    } catch (e) {\n        try {\n            let updateUrl = \"https://raw.githubusercontent.com/DowneyRem/PixivSource/main/pixiv.json\"\n            onlineSource = JSON.parse(java.get(updateUrl,{'User-Agent': 'Mozilla/5.0 (Linux; Android 14)','X-Requested-With': 'XMLHttpRequest'}).body())[0]  // 第1个书源\n            comment = onlineSource.bookSourceComment.split(\"\\n\")\n        } catch (e) {\n            onlineSource = {lastUpdateTime: new Date().getTime(), bookSourceComment: bookSourceCommentText}\n            comment = onlineSource.bookSourceComment.split(\"\\n\")\n        }\n    }\n\n    let htm = `data:text/html; charset=utf-8,\n<html>\n<head>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>更新 Pixiv 书源</title>\n    <style> \n    table { text-align: center; margin: 0 auto; } .ann { display: flex; justify-content: center; align-items: center; height: 5vh; } \n    button { background-color: rgb(76, 175, 80); color: white; border: none; border-radius: 4px; height: 6vh; width: 30vw; overflow: hidden; } \n    button span { cursor: pointer; display: inline-block; position: relative; transition: 0.4s; } \n    button span:after { content: '>'; position: absolute; opacity: 0; top: 0; right: 30px; transition: 0.2s; } \n    button:active span { padding-right: 20px; } \n    button:active span:after { opacity: 1; right: -40px; }\n    </style>\n</head>\n\n<body>\n    <table border=\"1\" cellspacing=\"0\">\n        <th colspan=\"2\"> Pixiv 书源 \n        <a href=\"https://downeyrem.github.io/PixivSource/Pixiv\">🔰 使用指南</a>\n        || <a href=\"https://downeyrem.github.io/PixivSource/Sponsor\">❤️ 赞助开发</a>\n        </th>\n        <tr>\n            <td>☁️ 远程版本：${onlineSource.bookSourceComment.split(\"\\n\")[2].replace(\"书源版本：\", \"\")}</td>\n            <td>📆 更新：${java.timeFormat(onlineSource.lastUpdateTime)}</td>\n        </tr>\n        <tr><td colspan=\"2\" style=\"text-align: left;\">${comment.slice(3, 10).join(\"<br>\")}</td></tr>\n        <tr><td colspan=\"2\" style=\"text-align: left;\">${comment.slice(comment.length-20, comment.length).join(\"<br>\")}</td></tr>\n    </table>\n    \n    <table border=\"0\" cellspacing=\"20\">\n        <th colspan=\"2\"> 更新 Pixiv 书源 </th>\n        <tr><td><div class=\"ann\">\n            <a href=\"legado://import/importonline?src=https://cdn.jsdelivr.net/gh/DowneyRem/PixivSource@main/pixiv.json\">\n            <button><span>更新书源<br>(Jsdelivr CDN)</span></button>\n            </a></div></td>\n            \n            <td><div class=\"ann\">\n            <a href=\"legado://import/importonline?src=https://cdn.jsdelivr.net/gh/DowneyRem/PixivSource@main/btsrk.json\">\n            <button><span>更新订阅<br>(Jsdelivr CDN)</span></button>\n            </a></div></td>\n        </tr>\n        \n        <tr><td><div class=\"ann\">\n            <a href=\"legado://import/importonline?src=https://raw.githubusercontent.com/DowneyRem/PixivSource/main/pixiv.json\">\n            <button><span>书源链接<br>(GitHub)</span></button>\n            </a></div></td>\n            \n            <td><div class=\"ann\">\n            <a href=\"legado://import/importonline?src=https://raw.githubusercontent.com/DowneyRem/PixivSource/main/btsrk.json\">\n            <button><span>订阅链接<br>(GitHub)</span></button>\n            </a></div></td>\n        </tr>\n        \n        <tr><td><div class=\"ann\">\n            <a href=\"legado://import/importonline?src=https://codeberg.org/DowneyRem/PixivSource/raw/branch/main/pixiv.json\">\n            <button><span>备用书源链接<br>(Codeberg)</span></button>\n            </a></div></td>\n            \n            <td><div class=\"ann\">\n            <a href=\"legado://import/importonline?src=https://codeberg.org/DowneyRem/PixivSource/raw/branch/main/btsrk.json\">\n            <button><span>备用订阅链接<br>(Codeberg)</span></button>\n            </a></div></td>\n        </tr>\n    </table>\n</body>\n</html>`;\n    java.startBrowser(htm,'更新书源');\n    return []\n}",
    "lastUpdateTime": 1763913600251,
    "loadWithBaseUrl": true,
    "loginUi": "[\n    {\n        \"name\": \"🆙 更新书源\",\n        \"type\": \"button\",\n        \"action\": \"updateSource()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": -1\n        }\n    },\n    {\n        \"name\": \"\\uD83D\\uDD30 使用指南\",\n        \"type\": \"button\",\n        \"action\": \"startGithubReadme()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": -1\n        }\n    },\n    {\n        \"name\": \"\\uD83D\\uDC1E 反馈问题\",\n        \"type\": \"button\",\n        \"action\": \"startGithubIssue()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": -1\n        }\n    },\n    {\n        \"name\": \"⭐️ 收藏项目\",\n        \"type\": \"button\",\n        \"action\": \"startGithubLogin()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": -1\n        }\n    },\n    {\n        \"name\": \"\\uD83C\\uDD7F️ 书源频道\",\n        \"type\": \"button\",\n        \"action\": \"startTelegram()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": -1\n        }\n    },\n    {\n        \"name\": \"❤\\uFE0F 赞助开发\",\n        \"type\": \"button\",\n        \"action\": \"startGithubSponsor()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": -1\n        }\n    }\n]",
    "loginUrl": "function getWebViewUA() {\n    let userAgent = String(java.getWebViewUA())\n    if (userAgent.includes(\"Windows NT 10.0; Win64; x64\")) {\n        userAgent = \"Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Mobile Safari/537.36\"\n    }\n    return String(userAgent)\n}\n\nfunction login() {}\n\nfunction startBrowser(url, title) {\n    let msg = \"\", headers = `{\"headers\": {\"User-Agent\":\"${getWebViewUA()}\"}}`\n    if (url.includes(\"https://github.com\")) {\n        if (url.includes(\"issues\")) msg += \"🐞 反馈问题\"\n        else if (url.includes(\"doc\")) msg += \"🔰 使用指南\"\n        else msg += \"⭐️ 收藏项目\"\n        msg += \"\\n\\n即将打开 Github\\n请确认已开启代理/梯子/VPN等\"\n    } else if (url.includes(\"https://t.me\")) {\n        if (url.includes(\"FurryReading\")) msg += \"🐺 兽人阅读频道\"\n        else if (url.includes(\"joinchat\")) msg += \"🐞 反馈群组\"\n        msg += \"\\n\\n即将打开 Telegram\\n请确认已开启代理/梯子/VPN等\"\n    }\n    sleepToast(msg)\n    java.startBrowser(`${url}, ${headers}`, title)\n}\n\nfunction startGithub() {\n    startBrowser(\"https://github.com/DowneyRem/PixivSource\", \"书源介绍\")\n}\nfunction startGithubLogin() {\n    startBrowser(\"https://github.com/login?return_to=https://github.com/DowneyRem/PixivSource\", \"收藏项目\")\n}\nfunction startGithubIssue() {\n    startBrowser(\"https://github.com/DowneyRem/PixivSource/issues\", \"反馈问题\")\n}\nfunction startGithubReadme() {\n    startBrowser(\"https://downeyrem.github.io/PixivSource/Pixiv\", \"使用指南\")\n}\nfunction startGithubSponsor() {\n    startBrowser(\"https://downeyrem.github.io/PixivSource/Sponsor\", \"使用指南\")\n}\nfunction startTelegram() {\n    startBrowser(\"https://t.me/PixivSource\", \"Pixiv 书源频道\")\n}",
    "singleUrl": true,
    "sourceComment": "Pixiv 书源项目\n\n可用功能：✅导入书源✅更新书源\n\n书源发布：\nPixiv 书源频道 https://t.me/PixivSource\n兽人阅读频道 https://t.me/FurryReading\n\n项目地址：\nhttps://github.com/DowneyRem/PixivSource\nhttps://github.com/eigeen/PixivSourceProject\n\n规则订阅：Import 订阅源\nhttps://cdn.jsdelivr.net/gh/DowneyRem/PixivSource@main/import.json\nhttps://raw.githubusercontent.com/DowneyRem/PixivSource/main/import.json",
    "sourceGroup": "🐲 Furry",
    "sourceIcon": "https://cdn.jsdelivr.net/gh/DowneyRem/PixivSource@main/doc/pic/BookSourcePixiv.png",
    "sourceName": "Pixiv 书源 发布页",
    "sourceUrl": "https://downeyrem.github.io/PixivSource"
  },
  {
    "articleStyle": 2,
    "customOrder": 21,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\n  \"User-Agent\": \"Mozilla/5.0 (Linux; Android 10; TAS-AN00 Build/HUAWEITAS-AN00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/114.0.5735.61 Mobile Safari/537.36 Super 4.6.5\",\n  \"Referer\": \"https://www.yinghua228.com/\",\n  \"Cookie\": \"ad_dismiss=1\"\n}",
    "injectJs": "let sources = [];\nlet currentSourceIndex = 0;\nlet currentEpisodeIndex = 0;\nlet dp = null;\nlet currentVideoUrl = '';\nlet autoPlayNext = true;\nlet currentVodId = '';\nlet currentVideoDuration = 0;\nlet progressTimer = null; // 全局定时器，精准控制\n\n// ======== 源变量的存取操作 =========\nfunction getSourceVar() {\n    if (typeof source !== 'undefined' && source) {\n        return String(source.getVariable()) || '';\n    }\n    return '';\n}\nfunction setSourceVar(value) {\n    if (typeof source !== 'undefined' && source) {\n        source.putVariable(value);\n    }\n}\n\n// == 播放记录管理（多剧集 + 断点续播）==\nconst PROGRESS_SAVE_INTERVAL = 3000; // 每3秒保存一次进度\nconst PROGRESS_MIN_SAVE = 2; // 最小保存进度，2秒就存，避免短播放不记录\nconst PROGRESS_THRESHOLD = 0.95;\n\nfunction getAllRecords() {\n    const varStr = getSourceVar();\n    if (!varStr) return {};\n    try { return JSON.parse(varStr); } catch (e) { return {}; }\n}\nfunction getRecord(vodId) {\n    const all = getAllRecords();\n    return all[vodId] || null;\n}\nfunction saveRecord(vodId, record) {\n    const all = getAllRecords();\n    all[vodId] = record;\n    setSourceVar(JSON.stringify(all));\n}\nfunction removeRecord(vodId) {\n    const all = getAllRecords();\n    delete all[vodId];\n    setSourceVar(JSON.stringify(all));\n}\nfunction cleanOldRecords() {\n    const all = getAllRecords();\n    const entries = Object.entries(all);\n    if (entries.length > 50) {\n        entries.sort((a,b) => (b[1].timestamp||0)-(a[1].timestamp||0));\n        const keep = entries.slice(0,50);\n        setSourceVar(JSON.stringify(Object.fromEntries(keep)));\n    }\n}\n\n// ========== 核心工具函数（精准存/清进度）==========\nfunction stopProgressTimer() {\n    if (progressTimer) {\n        clearInterval(progressTimer);\n        progressTimer = null;\n    }\n}\n\n// 保存**当前播放集**的进度\nfunction saveCurrentProgressImmediately() {\n    if (!currentVodId || !dp || !sources[currentSourceIndex] || !sources[currentSourceIndex].episodes[currentEpisodeIndex]) {\n        return;\n    }\n    const current = dp.video.currentTime || 0;\n    const duration = dp.video.duration || 0;\n    // 小于最小保存进度/视频过短，不保存\n    if (current < PROGRESS_MIN_SAVE || duration < 5) return;\n    \n    // 只保存**当前集**的进度，强制用全局当前的集数/线路，杜绝串值\n    const record = {\n        sourceIndex: currentSourceIndex,\n        episodeIndex: currentEpisodeIndex,\n        episodeName: sources[currentSourceIndex].episodes[currentEpisodeIndex].name,\n        progress: (current/duration) > PROGRESS_THRESHOLD ? 0 : current,\n        duration: duration,\n        timestamp: Date.now() // 时间戳，确保最新记录\n    };\n    saveRecord(currentVodId, record);\n}\nfunction extractVodIdFromSourceContainer() {\n    const html = $('#source-container').html() || '';\n    const match = html.match(/\"id\":\"(\\d+)\"/) || html.match(/\\/id\\/(\\d+)/);\n    return match ? match[1] : '';\n}\n// 【核心修复】重进时**严格校验记录的集数+时间戳**，只加载对应集的最新进度\nfunction playFromRecordOrFirstEpisode() {\n    if (!currentVodId) { \n        playEpisode(0,0, false, 0); \n        return; \n    }\n    const record = getRecord(currentVodId);\n    // 严格校验：记录存在+对应集数有效，才恢复进度\n    if (record && sources[record.sourceIndex] && sources[record.sourceIndex].episodes[record.episodeIndex]) {\n        currentSourceIndex = record.sourceIndex;\n        currentEpisodeIndex = record.episodeIndex;\n        $('.tab-btn').removeClass('active').eq(record.sourceIndex).addClass('active');\n        initPlaylist();\n        // 只恢复**该记录对应集**的进度，精准匹配\n        playEpisode(record.sourceIndex, record.episodeIndex, false, record.progress);\n        showError(`已恢复历史播放：${record.episodeName} ${formatTime(record.progress)}`);\n    } else {\n        playEpisode(0,0, false, 0);\n    }\n}\n\n// ========== 页面初始化 ==========\n$(document).ready(function() {\n    sources = parseSourcesFromHTML();\n    currentVodId = extractVodIdFromSourceContainer();\n    if (sources.length === 0) {\n        $('#playlistContainer').html('<div class=\"error-msg show\">未找到播放列表数据</div>');\n        return;\n    }\n    initTabs();\n    initPlaylist();\n    playFromRecordOrFirstEpisode();\n});\n\n// ========== 线路/播放列表初始化（切集即时存进度）==========\nfunction initTabs() {\n    const $tabs = $('#sourceTabs'); $tabs.empty();\n    sources.forEach((src, index) => {\n        const $btn = $('<button>').addClass('tab-btn').text(src.name).toggleClass('active', index===0);\n        $btn.on('click', function() {\n            // 切线路：强制存当前进度+清定时器，新线路从头播\n            stopProgressTimer();\n            saveCurrentProgressImmediately();\n            $('.tab-btn').removeClass('active'); $(this).addClass('active');\n            currentSourceIndex = index; currentEpisodeIndex = 0;\n            initPlaylist();\n            playEpisode(currentSourceIndex, currentEpisodeIndex, true, 0);\n        });\n        $tabs.append($btn);\n    });\n    addAutoPlayToggle();\n}\nfunction addAutoPlayToggle() {\n    const $toggle = $('<button>').addClass('tab-btn').css({marginLeft:'auto',background:autoPlayNext?'#ff6b6b':'#666',fontSize:'12px'})\n        .text(autoPlayNext?'连播: 开':'连播: 关').on('click', function() {\n            autoPlayNext = !autoPlayNext;\n            $(this).text(autoPlayNext?'连播: 开':'连播: 关').css('background',autoPlayNext?'#ff6b6b':'#666');\n            showError(autoPlayNext?'已开启自动连播':'已关闭自动连播');\n            updateAutoPlayStatus();\n        });\n    $('#sourceTabs').append($toggle);\n}\nfunction updateAutoPlayStatus() {\n    $('#autoPlayStatus').text(autoPlayNext?'自动连播开启':'自动连播关闭').css('color',autoPlayNext?'#4ecdc4':'#888');\n}\n// 【核心修复】播放列表进度条**严格匹配记录的集数**，绝不显示错集进度\nfunction initPlaylist() {\n    const $container = $('#playlistContainer'); const $errorMsg = $('#errorMsg').detach();\n    $container.empty().append($errorMsg);\n    const currentSource = sources[currentSourceIndex];\n    const record = currentVodId ? getRecord(currentVodId) : null; // 只取当前视频的记录\n    \n    let recordTip = '';\n    // 记录提示只显示**当前视频最后播放集**的进度\n    if (record && (record.sourceIndex!==currentSourceIndex || record.episodeIndex!==currentEpisodeIndex)) {\n        const progressText = record.progress>0 ? ` (${formatTime(record.progress)})` : '';\n        recordTip = `<span style=\"color:#ff6b6b;margin-left:8px;cursor:pointer;\" onclick=\"resumeFromRecord()\">▶ 上次看到${record.episodeName}${progressText}</span>`;\n    }\n    $container.append(`\n        <div class=\"now-playing\">\n            <span class=\"label\">当前线路:</span><span class=\"source-name\">${currentSource.name}</span>\n            <span style=\"margin:0 5px;\">|</span><span class=\"label\">选中:</span><span id=\"currentEpiText\">${currentSource.episodes[currentEpisodeIndex]?.name||''}</span>\n            <span style=\"margin:0 5px;\">|</span><span id=\"autoPlayStatus\" style=\"color:${autoPlayNext?'#4ecdc4':'#888'};font-size:12px;\">${autoPlayNext?'自动连播开启':'自动连播关闭'}</span>\n            ${recordTip}\n        </div>\n    `);\n    $container.append(`<div class=\"playlist-title\"><span>播放列表</span><span class=\"episode-count\">共 ${currentSource.episodes.length} 集</span></div>`);\n    const $grid = $('<div>').addClass('episode-grid');\n    \n    currentSource.episodes.forEach((ep, idx) => {\n        const $btn = $('<button>').addClass('episode-btn').text(ep.name).toggleClass('playing', idx===currentEpisodeIndex);\n        // 【关键】只有**当前记录的集数**，才显示进度条，其他集绝不显示\n        if (record && record.sourceIndex === currentSourceIndex && record.episodeIndex === idx) {\n            $btn.css('border', '2px solid #ff6b6b');\n            if (record.progress > 0 && record.duration > 0) {\n                const percent = Math.min((record.progress / record.duration) * 100, 100);\n                const isFinished = percent > 95;\n                $btn.css('position', 'relative');\n                $btn.append(`\n                    <div style=\"\n                        position: absolute;\n                        bottom: 0;\n                        left: 0;\n                        height: 3px;\n                        background: ${isFinished ? '#4ecdc4' : '#ff6b6b'};\n                        width: ${isFinished ? 100 : percent}%;\n                    \"></div>\n                    <span style=\"\n                        position: absolute;\n                        top: 2px;\n                        right: 2px;\n                        font-size: 9px;\n                        color: ${isFinished ? '#4ecdc4' : '#ff6b6b'};\n                        background: rgba(0,0,0,0.7);\n                        padding: 1px 3px;\n                        border-radius: 3px;\n                    \">${isFinished ? '已看完' : formatTime(record.progress)}</span>\n                `);\n            } else {\n                $btn.append('<span style=\"position:absolute;top:2px;right:2px;font-size:10px;color:#ff6b6b;\">上次</span>');\n            }\n        }\n        $btn.on('click', function() {\n            // 切集：即时存当前进度+清定时器，新集强制0秒从头播\n            stopProgressTimer();\n            saveCurrentProgressImmediately();\n            currentEpisodeIndex = idx;\n            initPlaylist();\n            playEpisode(currentSourceIndex, currentEpisodeIndex, true, 0);\n        });\n        $grid.append($btn);\n    });\n    $container.append($grid);\n}\n\n// ========== 手动恢复历史记录（精准匹配集数）==========\nfunction resumeFromRecord() {\n    const record = getRecord(currentVodId);\n    if (!record) return;\n    if (sources[record.sourceIndex] && sources[record.sourceIndex].episodes[record.episodeIndex]) {\n        // 恢复前先保存当前播放的进度，避免丢失\n        stopProgressTimer();\n        saveCurrentProgressImmediately();\n        currentSourceIndex = record.sourceIndex; currentEpisodeIndex = record.episodeIndex;\n        $('.tab-btn').removeClass('active').eq(record.sourceIndex).addClass('active');\n        initPlaylist();\n        // 只恢复该记录对应集的进度\n        playEpisode(currentSourceIndex, currentEpisodeIndex, false, record.progress);\n        const progressText = record.progress>0 ? ` (${formatTime(record.progress)})` : '';\n        showError(`已恢复至: ${record.episodeName}${progressText}`);\n    }\n}\n// 时间格式化\nfunction formatTime(seconds) {\n    if (!seconds || seconds<0) return '00:00';\n    const h = Math.floor(seconds/3600); const m = Math.floor((seconds%3600)/60); const s = Math.floor(seconds%60);\n    return h>0 ? `${h}:${m.toString().padStart(2,'0')}:${s.toString().padStart(2,'0')}` : `${m.toString().padStart(2,'0')}:${s.toString().padStart(2,'0')}`;\n}\n\n// ========== 播放核心函数（切集0秒，重进精准加载对应进度）==========\nfunction playEpisode(sourceIdx, episodeIdx, showTip=false, resumeProgress=0) {\n    // 播放新集前，强制保存上一集进度，杜绝进度丢失/串集\n    stopProgressTimer();\n    saveCurrentProgressImmediately();\n    \n    // 强制更新全局当前集数，确保后续保存进度精准\n    currentSourceIndex = sourceIdx; \n    currentEpisodeIndex = episodeIdx;\n    \n    const src = sources[sourceIdx]; \n    const episode = src.episodes[episodeIdx];\n    if (!episode) return; // 集数无效，直接返回\n    \n    $('#currentEpiText').text(episode.name);\n    $('.episode-btn').removeClass('playing').eq(episodeIdx).addClass('playing');\n    showLoading(true); hideError(); hideUrlTip();\n    showError('正在解析播放地址，请稍候...');\n\n    $.ajax({\n        url: episode.url, type:'GET', dataType:'html', timeout:15000,\n        success: function(html) {\n            showLoading(false); hideError();\n            if (!currentVodId) currentVodId = extractVodId(html);\n            // 只使用外部传入的进度，切集传0则0，恢复记录传多少则多少，绝不自动读其他进度\n            let startProgress = resumeProgress;\n            parseAndPlay(html, showTip, startProgress);\n        },\n        error: function(xhr, status, error) {\n            showLoading(false);\n            showError(status==='timeout'?'请求超时，请尝试切换线路或刷新页面':xhr.status===404?'播放页面不存在，请尝试其他线路':'获取播放地址失败，请尝试切换线路');\n        }\n    });\n}\nfunction extractVodId(html) {\n    if (currentVodId) return currentVodId;\n    const match = html.match(/\"id\":\"(\\d+)\"/); if (match) return match[1];\n    const urlMatch = html.match(/\\/id\\/(\\d+)/); if (urlMatch) return urlMatch[1];\n    return '';\n}\nfunction parseAndPlay(html, showTip=false, startProgress=0) {\n    try {\n        const match = html.match(/var\\s+player_aaaa\\s*=\\s*(\\{.+?\\})[\\s;]*</);\n        if (!match) { showError('未找到播放器数据，该线路可能暂不可用'); return; }\n        let jsonStr = match[1].replace(/\\\\/g,\"\").trim();\n        let playerData; try { playerData = JSON.parse(jsonStr); } catch(e) { showError('数据解析失败，请尝试切换其他线路'); return; }\n        if (!currentVodId && playerData.id) currentVodId = String(playerData.id);\n        const videoUrl = playerData.url; if (!videoUrl) { showError('未找到视频链接，该线路可能暂不可用'); return; }\n        currentVideoUrl = videoUrl;\n        if (showTip) showUrlTip(videoUrl, '#playlistContainer');\n        isDirectVideo(videoUrl) ? playWithDPlayer(videoUrl, playerData, startProgress) : playWithIframe(videoUrl);\n    } catch(e) { showError('解析异常，请尝试切换线路：' + e.message.substring(0,50)); }\n}\nfunction isDirectVideo(url) {\n    const lowerUrl = url.toLowerCase();\n    return ['.mp4','.m3u8','.flv'].some(ext => lowerUrl.includes(ext));\n}\n\n// ========== DPlayer播放（精准按传入进度播放，实时存当前进度）==========\nfunction playWithDPlayer(url, playerData, startProgress=0) {\n    // 销毁旧播放器，杜绝旧播放器的进度干扰\n    if (dp) { \n        dp.destroy(); \n        dp = null; \n    }\n    $('#iframe-container').hide(); $('#dplayer').show(); hideUrlTip();\n    const isM3U8 = url.toLowerCase().includes('.m3u8');\n    dp = new DPlayer({\n        container: document.getElementById('dplayer'),\n        video: { url: url, type: isM3U8?'hls':'auto', pic: playerData.pic||'' },\n        autoplay: true, theme: '#ff6b6b', lang: 'zh-cn', hotkey: true, preload: 'auto', volume: 0.8,\n        playbackSpeed: [0.5,0.75,1,1.25,1.5,2]\n    });\n    let hasSeeked = false;\n\n    // 视频元数据加载完成后，精准跳转到传入的进度（只跳当前集的）\n    dp.on('loadedmetadata', function() {\n        currentVideoDuration = dp.video.duration || 0;\n        if (startProgress > 0 && currentVideoDuration > 0) {\n            const safeProgress = Math.min(startProgress, currentVideoDuration-2);\n            if (safeProgress > 0) { \n                dp.seek(safeProgress); \n                hasSeeked = true; \n                showError(`已从 ${formatTime(safeProgress)} 继续播放`); \n            }\n        }\n    });\n    // 播放时启动定时器，实时保存**当前集**进度\n    dp.on('play', function() {\n        stopProgressTimer();\n        progressTimer = setInterval(() => { saveCurrentProgressImmediately(); }, PROGRESS_SAVE_INTERVAL);\n    });\n    // 暂停时即时保存进度，避免退出丢失\n    dp.on('pause', function() {\n        stopProgressTimer();\n        saveCurrentProgressImmediately();\n    });\n    // 进度更新时，只校正**当前集**的恢复进度，绝不串集\n    dp.on('timeupdate', function() {\n        if (!hasSeeked && startProgress > 0 && dp.video.currentTime < 3) {\n            dp.seek(startProgress);\n            hasSeeked = true;\n        }\n    });\n    // 全屏/退出全屏适配\n    dp.on('fullscreen', function() {\n        if (screen.orientation && screen.orientation.lock) {\n            screen.orientation.lock('landscape').catch(()=>{screen.orientation.lock('any').catch(()=>{});});\n        }\n    });\n    dp.on('fullscreen_cancel', function() {\n        if (screen.orientation && screen.orientation.unlock) screen.orientation.unlock().catch(()=>{});\n    });\n    // M3U8视频适配\n    if (isM3U8 && Hls.isSupported()) {\n        dp.video.type = 'customHls';\n        dp.video.customType = {\n            customHls: function(video) { const hls = new Hls(); hls.loadSource(video.src); hls.attachMedia(video); }\n        };\n    }\n    // 播放错误提示\n    setTimeout(() => {\n        dp.on('error', function() { showError('视频播放失败，请尝试切换线路或剧集'); });\n    }, 10000);\n    // 视频播放完毕\n    dp.on('ended', function() {\n        stopProgressTimer();\n        saveCurrentProgressImmediately();\n        if (autoPlayNext) playNextEpisode();\n        else showError('本集已结束，自动连播已关闭');\n    });\n    // 页面关闭/刷新时，强制保存当前进度，这是关键！\n    window.addEventListener('beforeunload', function() {\n        stopProgressTimer();\n        saveCurrentProgressImmediately();\n    });\n    // 点击播放器显示视频地址\n    $('#dplayer').off('click').on('click', function(e) {\n        if ($(e.target).closest('.dplayer-controller, .dplayer-mask, #video-url-tip').length) return;\n        showUrlTip(url, '#dplayer');\n    });\n}\n\n// ========== 自动连播下一集（强制0秒从头播）==========\nfunction playNextEpisode() {\n    const currentSource = sources[currentSourceIndex];\n    const nextIndex = currentEpisodeIndex+1;\n    if (nextIndex < currentSource.episodes.length) {\n        showError(`即将播放下一集: ${currentSource.episodes[nextIndex].name}`);\n        // 自动连播也强制0秒，从头播放下一集\n        setTimeout(() => { playEpisode(currentSourceIndex, nextIndex, false, 0); }, 1500);\n    } else {\n        showError('本线路已播放完毕');\n        $('#autoPlayStatus').text('本线路完结').css('color','#ff6b6b');\n        cleanOldRecords();\n    }\n}\n\n// ========== 外部播放器iframe播放 ==========\nfunction playWithIframe(url) {\n    if (dp) { dp.destroy(); dp = null; }\n    $('#dplayer').hide(); const $container = $('#iframe-container'); $container.empty().show();\n    const $loading = $(`<div class=\"loading show\" style=\"position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);\"><div class=\"spinner\"></div><div>加载外部播放器...</div></div>`);\n    $container.append($loading);\n    const $iframe = $('<iframe>').attr('src','https://jx.quanmingjiexi.com/?url='+url).attr('allowfullscreen','true').attr('frameborder','0').css({width:'100%',height:'100%',opacity:'0'}).on('load',function(){$loading.remove();$(this).css('opacity','1');});\n    setTimeout(() => { $loading.remove(); $iframe.css('opacity','1'); }, 5000);\n    $container.append($iframe);\n}\n\n// ========== 基础工具函数 ==========\nfunction showLoading(show) { $('#player-loading').toggleClass('show', show); }\nfunction showError(msg) { $('#errorMsg').text(msg).addClass('show'); setTimeout(()=>$('#errorMsg').removeClass('show'),3000); }\nfunction hideError() { $('#errorMsg').removeClass('show'); }\n// 全屏变化适配\ndocument.addEventListener('fullscreenchange', () => {\n    if (document.fullscreenElement) {\n        if (screen.orientation && screen.orientation.lock) screen.orientation.lock('landscape').catch(()=>{screen.orientation.lock('any').catch(()=>{});});\n    } else {\n        if (screen.orientation && screen.orientation.unlock) screen.orientation.unlock().catch(()=>{});\n    }\n});\n// 屏幕旋转适配播放器大小\nwindow.addEventListener('orientationchange', () => { setTimeout(()=>dp&&dp.resize(),300); });\n// 显示视频地址提示\nfunction showUrlTip(url, container) {\n    hideUrlTip(); if (window.urlTipTimeout) clearTimeout(window.urlTipTimeout);\n    const $tip = $(`<div id=\"video-url-tip\" style=\"position:absolute;top:0;left:0;background:rgba(0,0,0,0.6);color:#fff;padding:8px 12px;font-size:12px;z-index:1000;max-width:100%;word-break:break-all;\"><div style=\"user-select:text;line-height:1.5;\">${url}</div></div>`);\n    $(container||'body').append($tip);\n    window.urlTipTimeout = setTimeout(()=>{hideUrlTip();},3000);\n}\nfunction hideUrlTip() { $('#video-url-tip').remove(); if (window.urlTipTimeout) clearTimeout(window.urlTipTimeout); window.urlTipTimeout=null; }\n// 详情展开/收起\nfunction toggleDetail() {\n    const content = document.getElementById('detailContent');\n    const btn = document.querySelector('#info .toggle-btn');\n    content.classList.toggle('show');\n    btn.classList.toggle('active');\n    btn.innerHTML = content.classList.contains('show') ? '收起详情 <span style=\"color:inherit\">▲</span>' : '查看详情 <span style=\"color:#ff6b6b\">▼</span>';\n}\n// 解析播放源和剧集\nfunction parseSourcesFromHTML() {\n    const sources = [];\n    $('.stui-pannel-box').each(function() {\n        const $box = $(this);\n        const sourceName = $box.find('.title').text().trim();\n        const episodes = [];\n        $box.find('.stui-content__playlist li a').each(function() {\n            const $a = $(this);\n            episodes.push({name:$a.text().trim(), url:$a.attr('href')});\n        });\n        if (episodes.length>0) sources.push({name:sourceName, episodes:episodes});\n    });\n    return sources;\n}\n",
    "lastUpdateTime": 1773791081203,
    "loadWithBaseUrl": true,
    "ruleArticles": ".stui-vodlist li||.stui-vodlist__media li",
    "ruleContent": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\">\n    <title>{{@@title@text}}</title>\n    <link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/dplayer@1.25.0/dist/DPlayer.min.css\">\n</head>\n<body>\n    <div id=\"dplayer\">\n        <div class=\"loading\" id=\"player-loading\">\n            <div class=\"spinner\"></div>\n            <div>加载中...</div>\n        </div>\n    </div>\n    \n    <div id=\"iframe-container\">\n        <div class=\"loading\" id=\"iframe-loading\">\n            <div class=\"spinner\"></div>\n            <div>加载外部播放器...</div>\n        </div>\n    </div>\n\n    <div id=\"info\">\n    <button class=\"toggle-btn\" onclick=\"toggleDetail()\">查看详情</button>\n    \n    <div class=\"detail-content\" id=\"detailContent\">\n        <div class=\"detail-inner\">\n            <div class=\"stui-content__detail\">\n{{@@.stui-content__detail > *:not(.play-btn)@html}}\n            </div>\n        </div>\n    </div>\n</div>\n    \n    <div class=\"source-tabs\" id=\"sourceTabs\"></div>\n\n    <div class=\"playlist-container\" id=\"playlistContainer\">\n        <div class=\"error-msg\" id=\"errorMsg\"></div>\n    </div>\n\n    <!-- 原始播放列表数据 -->\n    <div id=\"source-container\">\n        {{@@.stui-pannel > .playlist@all}}\n    </div>\n\n    <script src=\"https://pss.bdstatic.com/static/superman/js/lib/jquery-1-edb203c114.10.2.js\"></script>\n    <script src=\"https://cdn.jsdelivr.net/npm/hls.js@1.5.17/dist/hls.min.js\"></script>\n    <script src=\"https://cdn.jsdelivr.net/npm/dplayer@1.25.0/dist/DPlayer.min.js\"></script>\n\n</body>\n</html>",
    "ruleImage": "a[0]@data-original",
    "ruleLink": ".title a@href",
    "ruleNextPage": "text.下一页@href",
    "rulePubDate": "p@textNodes",
    "ruleTitle": ".title a@text",
    "singleUrl": false,
    "sortUrl": "日本动漫::/index.php/vod/type/id/20.html\n国产动漫::/index.php/vod/type/id/21.html\n欧美动漫::/index.php/vod/type/id/22.html\n动漫电影::/index.php/vod/type/id/23.html\n其他动漫::/index.php/vod/type/id/24.html",
    "sourceComment": "原作者：cute-pan\n\n添加搜索 (原生阅读不支持)\n美化UI（顶部播放器，中间显示详情，下方多线路播放列表）\n添加 自动播放下一集\n\n新增 播放记录，断点续播",
    "sourceGroup": "视频",
    "sourceIcon": "https://tse2.mm.bing.net/th/id/OIP.0w67-qvgh_VqOurfrC377AHaEK?dpr=3.5&pid=ImgDetMain&o=7&rm=3",
    "sourceName": "樱花动漫",
    "sourceUrl": "https://www.yinghua228.com",
    "style": "        * {\n            margin: 0;\n            padding: 0;\n            box-sizing: border-box;\n        }\n\n        body {\n            background: #0d0d0d;\n            font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n            color: #fff;\n            overflow-x: hidden;\n            -webkit-tap-highlight-color: transparent;\n        }\n\n        #dplayer {\n            width: 100%;\n            height: 56.25vw;\n            max-height: 70vh;\n            background: #000;\n            position: relative;\n            z-index: 10;\n        }\n\n        .source-tabs {\n            display: flex;\n            overflow-x: auto;\n            background: #1a1a1a;\n            padding: 10px 5px;\n            position: sticky;\n            top: 0;\n            z-index: 20;\n            border-bottom: 1px solid #333;\n            scrollbar-width: none;\n            -ms-overflow-style: none;\n        }\n\n        .source-tabs::-webkit-scrollbar {\n            display: none;\n        }\n\n        .tab-btn {\n            flex-shrink: 0;\n            padding: 8px 16px;\n            margin: 0 5px;\n            background: #2a2a2a;\n            border: 1px solid #444;\n            border-radius: 20px;\n            color: #aaa;\n            font-size: 14px;\n            cursor: pointer;\n            transition: all 0.3s ease;\n            white-space: nowrap;\n            outline: none;\n        }\n\n        .tab-btn.active {\n            background: #ff6b6b;\n            border-color: #ff6b6b;\n            color: #fff;\n            box-shadow: 0 2px 8px rgba(255, 107, 107, 0.4);\n        }\n      .tab-btn:active {\n            transform: scale(0.95);\n        }\n\n        .playlist-container {\n            padding: 15px;\n            background: #0d0d0d;\n            min-height: calc(100vh - 56.25vw - 60px);\n        }\n\n        .playlist-title {\n            font-size: 16px;\n            color: #fff;\n            margin-bottom: 15px;\n            padding-left: 10px;\n            border-left: 3px solid #ff6b6b;\n            display: flex;\n            align-items: center;\n            justify-content: space-between;\n        }\n\n        .episode-count {\n            font-size: 12px;\n            color: #888;\n            font-weight: normal;\n        }\n\n        .episode-grid {\n            display: grid;\n            grid-template-columns: repeat(4, 1fr);\n            gap: 10px;\n        }\n\n        @media (min-width: 480px) {\n            .episode-grid {\n                grid-template-columns: repeat(5, 1fr);\n            }\n        }\n\n        @media (min-width: 600px) {\n            .episode-grid {\n                grid-template-columns: repeat(6, 1fr);\n            }\n        }\n\n        .episode-btn {\n            background: #1f1f1f;\n            border: 1px solid #333;\n            border-radius: 8px;\n            padding: 12px 5px;\n            color: #ccc;\n            font-size: 14px;\n            cursor: pointer;\n            transition: all 0.2s;\n            text-align: center;\n            outline: none;\n            position: relative;\n            overflow: hidden;\n        }\n\n        .episode-btn::before {\n            content: '';\n            position: absolute;\n            top: 0;\n            left: -100%;\n            width: 100%;\n            height: 100%;\n            background: linear-gradient(90deg, transparent, rgba(255,255,255,0.1), transparent);\n            transition: left 0.5s;\n        }\n\n        .episode-btn:active::before {\n            left: 100%;\n        }\n\n        .episode-btn.playing {\n            background: #4ecdc4;\n            border-color: #4ecdc4;\n            color: #fff;\n            animation: pulse 2s infinite;\n        }\n\n        @keyframes pulse {\n            0%, 100% { box-shadow: 0 0 0 0 rgba(78, 205, 196, 0.4); }\n            50% { box-shadow: 0 0 0 8px rgba(78, 205, 196, 0); }\n        }\n\n        .episode-btn:active {\n            transform: scale(0.95);\n        }\n\n        #iframe-container {\n            width: 100%;\n            height: 56.25vw;\n            max-height: 70vh;\n            background: #000;\n            display: none;\n            position: relative;\n        }\n\n        #iframe-container iframe {\n            width: 100%;\n            height: 100%;\n            border: none;\n        }\n\n        .loading {\n            position: absolute;\n            top: 50%;\n            left: 50%;\n            transform: translate(-50%, -50%);\n            color: #ff6b6b;\n            font-size: 14px;\n            display: none;\n        }\n\n        .loading.show {\n            display: block;\n        }\n\n        .spinner {\n            width: 40px;\n            height: 40px;\n            border: 3px solid #333;\n            border-top-color: #ff6b6b;\n            border-radius: 50%;\n            animation: spin 1s linear infinite;\n            margin: 0 auto 10px;\n        }\n\n        @keyframes spin {\n            to { transform: rotate(360deg); }\n        }\n\n        .error-msg {\n            background: rgba(255, 107, 107, 0.1);\n            border: 1px solid #ff6b6b;\n            color: #ff6b6b;\n            padding: 10px;\n            border-radius: 8px;\n            margin: 10px 0;\n            font-size: 13px;\n            display: none;\n            text-align: center;\n        }\n\n        .error-msg.show {\n            display: block;\n        }\n\n        .now-playing {\n            background: linear-gradient(135deg, #1a1a1a 0%, #2a2a2a 100%);\n            padding: 12px 15px;\n            margin: -15px -15px 15px -15px;\n            border-bottom: 1px solid #333;\n            font-size: 14px;\n            color: #aaa;\n            display: flex;\n            align-items: center;\n            gap: 8px;\n        }\n\n        .now-playing .label {\n            color: #ff6b6b;\n            font-weight: bold;\n        }\n\n        .now-playing .source-name {\n            color: #4ecdc4;\n        }\n\n        .back-btn {\n            position: fixed;\n            top: 10px;\n            left: 10px;\n            z-index: 100;\n            background: rgba(0,0,0,0.6);\n            border: none;\n            color: #fff;\n            width: 36px;\n            height: 36px;\n            border-radius: 50%;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            font-size: 18px;\n            cursor: pointer;\n            backdrop-filter: blur(10px);\n        }\n\n        #source-container {\n            display: none;\n        }\n\n/* ========== 详情区域样式（完全隔离，不会冲突）========== */\n#info {\n    background: #1a1a1a;\n    margin: 10px 15px;\n    border-radius: 12px;\n    overflow: hidden;\n    border: 1px solid #333;\n}\n\n#info .toggle-btn {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    gap: 8px;\n    width: 100%;\n    padding: 12px 20px;\n    background: #252525;\n    color: #fff;\n    border: none;\n    cursor: pointer;\n    font-size: 14px;\n    font-weight: 500;\n    transition: all 0.3s ease;\n}\n\n#info .toggle-btn:hover {\n    background: #2f2f2f;\n}\n\n#info .toggle-btn::after {\n    content: '▼';\n    font-size: 10px;\n    color: #ff6b6b;\n    transition: transform 0.3s ease;\n}\n\n#info .toggle-btn.active::after {\n    transform: rotate(180deg);\n}\n\n#info .toggle-btn.active {\n    background: #ff6b6b;\n    color: #fff;\n}\n\n#info .toggle-btn.active::after {\n    color: #fff;\n}\n\n#info .detail-content {\n    max-height: 0;\n    overflow: hidden;\n    transition: max-height 0.4s ease, opacity 0.3s ease;\n    opacity: 0;\n    background: #1a1a1a;\n}\n\n#info .detail-content.show {\n    max-height: 800px;\n    opacity: 1;\n}\n\n/* 详情内部样式 - 全部加前缀避免冲突 */\n#info .detail-inner {\n    padding: 15px;\n}\n\n#info .detail-title {\n    font-size: 18px;\n    color: #fff;\n    margin-bottom: 12px;\n    display: flex;\n    align-items: center;\n    gap: 8px;\n    flex-wrap: wrap;\n    line-height: 1.4;\n}\n\n#info .detail-score {\n    background: #ff6b6b;\n    color: white;\n    padding: 2px 8px;\n    border-radius: 12px;\n    font-size: 12px;\n    font-weight: bold;\n    flex-shrink: 0;\n}\n\n#info .detail-row {\n    margin-bottom: 10px;\n    font-size: 13px;\n    line-height: 1.7;\n    color: #ccc;\n}\n\n#info .detail-label {\n    color: #888;\n    margin-right: 5px;\n}\n\n#info .detail-row a {\n    color: #4a9eff;\n    text-decoration: none;\n    margin-right: 6px;\n    transition: color 0.2s;\n}\n\n#info .detail-row a:hover {\n    color: #6ab3ff;\n    text-decoration: underline;\n}\n\n#info .detail-split {\n    display: inline-block;\n    width: 1px;\n    height: 10px;\n    background: #444;\n    margin: 0 8px;\n    vertical-align: middle;\n}\n\n#info .detail-desc {\n    background: #252525;\n    padding: 12px;\n    border-radius: 8px;\n    margin-top: 12px;\n    border-left: 3px solid #ff6b6b;\n    font-size: 13px;\n    line-height: 1.8;\n    color: #bbb;\n}\n\n#info .detail-desc-label {\n    display: block;\n    color: #ff6b6b;\n    margin-bottom: 6px;\n    font-weight: 500;\n}\n\n/* 隐藏元素 */\n#info .hidden-xs {\n    display: inline;\n}\n\n@media (max-width: 480px) {\n    #info .hidden-xs {\n        display: none !important;\n    }\n    \n    #info {\n        margin: 8px;\n    }\n    \n    #info .detail-inner {\n        padding: 12px;\n    }\n}\n\n/* 详情区域a标签样式 - 灰色不刺眼 */\n#info a {\n    color: #888 !important;\n    text-decoration: none !important;\n    pointer-events: none; /* 阻止点击 */\n    cursor: default;\n    margin-right: 6px;\n}\n\n#info a:hover {\n    color: #888 !important;\n    text-decoration: none !important;\n}\n"
  },
  {
    "articleStyle": 0,
    "customOrder": 22,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "@js:\nJSON.stringify({\n  'User-Agent': \"Mozilla/5.0 (Linux; Android 15; V2304A Build/AP3A.240905.015.A2; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/132.0.6834.163 Mobile Safari/537.36\" ,\n   'referer': \"https://ttkit.cn\"})",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "$.data[*]",
    "ruleImage": "$.cover",
    "ruleLink": "$.url",
    "rulePubDate": "$.hot",
    "ruleTitle": "$.title",
    "singleUrl": false,
    "sortUrl": "知乎::https://ttkit.cn/daily-hot/api/zhihu?cache=true\n百度::https://ttkit.cn/daily-hot/api/baidu?cache=true&type=realtime\n头条::https://ttkit.cn/daily-hot/api/toutiao?cache=true\n哔哩哔哩::https://ttkit.cn/daily-hot/api/bilibili?cache=true&type=0\n抖音::https://ttkit.cn/daily-hot/api/douyin?cache=true\n快手::https://ttkit.cn/daily-hot/api/kuaishou?cache=true\n虎扑::https://ttkit.cn/daily-hot/api/hupu?cache=true&type=1\n微信读书飙升榜::https://ttkit.cn/daily-hot/api/weread?cache=true&type=rising\n微信读书热搜榜::https://ttkit.cn/daily-hot/api/weread?cache=true&type=hot_search\n微信读书新书榜::https://ttkit.cn/daily-hot/api/weread?cache=true&type=newbook\n微信读书小说榜::https://ttkit.cn/daily-hot/api/weread?cache=true&type=general_novel_rising\n微信读书总榜::https://ttkit.cn/daily-hot/api/weread?cache=true&type=all\n极客公园::https://ttkit.cn/daily-hot/api/geekpark?cache=true\n果壳::https://ttkit.cn/daily-hot/api/guokr?cache=true\n网易新闻::https://ttkit.cn/daily-hot/api/netease-news?cache=true\n新浪新闻总排行::https://ttkit.cn/daily-hot/api/sina-news?cache=true&type=1\n新浪新闻视频榜::https://ttkit.cn/daily-hot/api/sina-news?cache=true&type=2\n新浪新闻图片榜::https://ttkit.cn/daily-hot/api/sina-news?cache=true&type=3\n新浪国内新闻::https://ttkit.cn/daily-hot/api/sina-news?cache=true&type=4\n新浪国际新闻::https://ttkit.cn/daily-hot/api/sina-news?cache=true&type=5\n新浪社会新闻::https://ttkit.cn/daily-hot/api/sina-news?cache=true&type=6\n新浪体育新闻::https://ttkit.cn/daily-hot/api/sina-news?cache=true&type=7\n新浪财经新闻::https://ttkit.cn/daily-hot/api/sina-news?cache=true&type=8\n新浪娱乐新闻::https://ttkit.cn/daily-hot/api/sina-news?cache=true&type=9\n新浪科技新闻::https://ttkit.cn/daily-hot/api/sina-news?cache=true&type=10\n新浪军事新闻::https://ttkit.cn/daily-hot/api/sina-news?cache=true&type=11\n36氪人气榜::https://ttkit.cn/daily-hot/api/36kr?cache=true&type=hot\n36氪视频榜::https://ttkit.cn/daily-hot/api/36kr?cache=true&type=video\n36氪热议榜::https://ttkit.cn/daily-hot/api/36kr?cache=true&type=comment\n36氪收藏榜::https://ttkit.cn/daily-hot/api/36kr?cache=true&type=collect\nIT之家::https://ttkit.cn/daily-hot/api/ithome?cache=true\n澎湃新闻::https://ttkit.cn/daily-hot/api/thepaper?cache=true\n腾讯新闻::https://ttkit.cn/daily-hot/api/qq-news?cache=true\n财联社::https://ttkit.cn/daily-hot/api/cls?cache=true\n金十数据::https://ttkit.cn/daily-hot/api/jin10?cache=true\n华尔街见闻::https://ttkit.cn/daily-hot/api/wallstreet?cache=true\n第一财经::https://ttkit.cn/daily-hot/api/yicai?cache=true\n财新网::https://ttkit.cn/daily-hot/api/caixin?cache=true\n微博::https://ttkit.cn/daily-hot/api/weibo?cache=true\n豆瓣小组::https://ttkit.cn/daily-hot/api/douban-group?cache=true\n百度贴吧::https://ttkit.cn/daily-hot/api/tieba?cache=true\n豆瓣电影::https://ttkit.cn/daily-hot/api/douban-movie?cache=true",
    "sourceGroup": "1",
    "sourceIcon": "https://ttkit.cn/favicon.ico",
    "sourceName": "每日热点",
    "sourceUrl": "https://ttkit.cn/daily-hot"
  },
  {
    "articleStyle": 0,
    "customOrder": 23,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "1",
    "sourceIcon": "",
    "sourceName": "源仓库(官方纯净)",
    "sourceUrl": "http://yckceo.vip"
  },
  {
    "articleStyle": 1,
    "customOrder": 24,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 1762712251432,
    "loadWithBaseUrl": true,
    "ruleArticles": "$.itemList",
    "ruleDescription": "<html>\n<head>\n    <title>开眼</title>\n    <style>\n        :root {\n            --text-color: #333;\n            --bg-color: #f9f9f9;\n            --title-color: #222;\n            --link-color: #0066cc;\n            --original-link-color: #888;\n            --download-bg: #f0f0f0;\n            --download-hover-bg: #e6e6e6;\n            --video-shadow: 0 4px 12px rgba(0,0,0,0.15);\n        }\n\n        @media (prefers-color-scheme: dark) {\n            :root {\n                --text-color: #e0e0e0;\n                --bg-color: #121212;\n                --title-color: #ffffff;\n                --link-color: #4dabf7;\n                --original-link-color: #aaaaaa;\n                --download-bg: #2d2d2d;\n                --download-hover-bg: #3d3d3d;\n                --video-shadow: 0 4px 12px rgba(0,0,0,0.3);\n            }\n        }\n\n        body {\n            font-family: 'Helvetica Neue', Arial, sans-serif;\n            max-width: 800px;\n            margin: 0 auto;\n            padding: 20px;\n            background-color: var(--bg-color);\n            color: var(--text-color);\n            line-height: 1.6;\n            transition: background-color 0.3s, color 0.3s;\n        }\n\n        .title {\n            font-size: 26px;\n            font-weight: bold;\n            margin: 30px 0 25px 0;\n            color: var(--title-color);\n            text-align: center;\n        }\n\n        video {\n            width: 100%;\n            border-radius: 6px;\n            margin: 0 auto 25px auto;\n            box-shadow: var(--video-shadow);\n            display: block;\n            background-color: #000;\n        }\n\n        .text {\n            font-size: 16px;\n            margin: 0 auto 30px auto;\n            color: var(--text-color);\n            max-width: 700px;\n            text-align: justify;\n        }\n\n        .download-section {\n            margin: 30px 0;\n            text-align: center;\n        }\n\n        .download-label {\n            font-size: 16px;\n            color: var(--text-color);\n            margin-bottom: 10px;\n        }\n\n        .down {\n            display: inline-block;\n            background-color: var(--download-bg);\n            padding: 10px 15px;\n            border-radius: 6px;\n            word-break: break-all;\n            color: var(--link-color);\n            text-decoration: none;\n            font-size: 14px;\n            max-width: 100%;\n            box-sizing: border-box;\n            transition: background-color 0.3s;\n        }\n\n        .down:hover {\n            background-color: var(--download-hover-bg);\n            text-decoration: underline;\n        }\n\n        .original-link {\n            text-align: right;\n            margin: 0 0 20px 0;\n        }\n\n        .original-link a {\n            color: var(--original-link-color);\n            text-decoration: none;\n            font-size: 14px;\n            transition: color 0.2s;\n        }\n\n        .original-link a:hover {\n            color: var(--link-color);\n            text-decoration: underline;\n        }\n    </style>\n</head>\n<body>\n    <div class=\"original-link\">\n        <a href=\"{{$.data.content.data.webUrl.raw||$.data.webUrl.raw}}\">原文地址</a>\n    </div>\n    \n    <p class=\"title\"><strong>{{$.data.content.data.title||$.data.title}}</strong></p>\n    \n    <video src=\"{{$.data.content.data.playUrl||$.data.playUrl}}\" width=100% height=\"auto\" controls=\"controls\" poster=\"{{$.data.content.data.cover.feed||$.data.feed}}\"></video>\n    \n    <p class=\"text\">{{$.data.content.data.description||$.data.description}}</p>\n    \n    <div class=\"download-section\">\n        <div class=\"download-label\">下载地址：</div>\n        <a class='down'>{{$.data.content.data.playUrl||$.data.playUrl}}</a>\n    </div>\n</body>\n</html>\n",
    "ruleImage": "$.data.content.data.cover.feed",
    "ruleLink": "$.data.text||$.data.content.data.webUrl.raw||$.data.web.raw",
    "ruleNextPage": "{{$.nextPageUrl}}&udid=187de68fafce4bcf8d6cca9e147574226a2e711e&vc=570&vn=6.0&size=1080X2255&deviceModel=JKM-AL00b&first_channel=eyepetizer_zhihuiyun_market&last_channel=eyepetizer_zhihuiyun_market&system_version_code=28",
    "rulePubDate": "$.data.header.description",
    "ruleTitle": "$.data.text||$.data.content.data.title||$.data.title",
    "singleUrl": false,
    "sortUrl": "日报::http://baobab.kaiyanapp.com/api/v5/index/tab/feed?udid=187de68fafce4bcf8d6cca9e147574226a2e711e&vc=570&vn=6.0&size=1080X2255&deviceModel=JKM-AL00b&first_channel=eyepetizer_zhihuiyun_market&last_channel=eyepetizer_zhihuiyun_market&system_version_code=28&&广告::http://baobab.kaiyanapp.com/api/v1/tag/videos?id=16&udid=187de68fafce4bcf8d6cca9e147574226a2e711e&vc=570&vn=6.0&size=1080X2255&deviceModel=JKM-AL00b&first_channel=eyepetizer_zhihuiyun_market&last_channel=eyepetizer_zhihuiyun_market&system_version_code=28&&剧情::http://baobab.kaiyanapp.com/api/v1/tag/videos?id=12&udid=187de68fafce4bcf8d6cca9e147574226a2e711e&vc=570&vn=6.0&size=1080X2255&deviceModel=JKM-AL00b&first_channel=eyepetizer_zhihuiyun_market&last_channel=eyepetizer_zhihuiyun_market&system_version_code=28&&运动::http://baobab.kaiyanapp.com/api/v1/tag/videos?id=1022&udid=187de68fafce4bcf8d6cca9e147574226a2e711e&vc=570&vn=6.0&size=1080X2255&deviceModel=JKM-AL00b&first_channel=eyepetizer_zhihuiyun_market&last_channel=eyepetizer_zhihuiyun_market&system_version_code=28&&创意::http://baobab.kaiyanapp.com/api/v1/tag/videos?id=2&udid=187de68fafce4bcf8d6cca9e147574226a2e711e&vc=570&vn=6.0&size=1080X2255&deviceModel=JKM-AL00b&first_channel=eyepetizer_zhihuiyun_market&last_channel=eyepetizer_zhihuiyun_market&system_version_code=28&&旅行::http://baobab.kaiyanapp.com/api/v1/tag/videos?id=1019&udid=187de68fafce4bcf8d6cca9e147574226a2e711e&vc=570&vn=6.0&size=1080X2255&deviceModel=JKM-AL00b&first_channel=eyepetizer_zhihuiyun_market&last_channel=eyepetizer_zhihuiyun_market&system_version_code=28&&记录::http://baobab.kaiyanapp.com/api/v1/tag/videos?id=24&udid=187de68fafce4bcf8d6cca9e147574226a2e711e&vc=570&vn=6.0&size=1080X2255&deviceModel=JKM-AL00b&first_channel=eyepetizer_zhihuiyun_market&last_channel=eyepetizer_zhihuiyun_market&system_version_code=28&&音乐::http://baobab.kaiyanapp.com/api/v1/tag/videos?id=1018&udid=187de68fafce4bcf8d6cca9e147574226a2e711e&vc=570&vn=6.0&size=1080X2255&deviceModel=JKM-AL00b&first_channel=eyepetizer_zhihuiyun_market&last_channel=eyepetizer_zhihuiyun_market&system_version_code=28&&影视::http://baobab.kaiyanapp.com/api/v1/tag/videos?id=1025&udid=187de68fafce4bcf8d6cca9e147574226a2e711e&vc=570&vn=6.0&size=1080X2255&deviceModel=JKM-AL00b&first_channel=eyepetizer_zhihuiyun_market&last_channel=eyepetizer_zhihuiyun_market&system_version_code=28&&科技::http://baobab.kaiyanapp.com/api/v1/tag/videos?id=1024&udid=187de68fafce4bcf8d6cca9e147574226a2e711e&vc=570&vn=6.0&size=1080X2255&deviceModel=JKM-AL00b&first_channel=eyepetizer_zhihuiyun_market&last_channel=eyepetizer_zhihuiyun_market&system_version_code=28&&开胃::http://baobab.kaiyanapp.com/api/v1/tag/videos?id=1020&udid=187de68fafce4bcf8d6cca9e147574226a2e711e&vc=570&vn=6.0&size=1080X2255&deviceModel=JKM-AL00b&first_channel=eyepetizer_zhihuiyun_market&last_channel=eyepetizer_zhihuiyun_market&system_version_code=28&&游戏::http://baobab.kaiyanapp.com/api/v1/tag/videos?id=30&udid=187de68fafce4bcf8d6cca9e147574226a2e711e&vc=570&vn=6.0&size=1080X2255&deviceModel=JKM-AL00b&first_channel=eyepetizer_zhihuiyun_market&last_channel=eyepetizer_zhihuiyun_market&system_version_code=28&&搞笑::http://baobab.kaiyanapp.com/api/v1/tag/videos?id=140&udid=187de68fafce4bcf8d6cca9e147574226a2e711e&vc=570&vn=6.0&size=1080X2255&deviceModel=JKM-AL00b&first_channel=eyepetizer_zhihuiyun_market&last_channel=eyepetizer_zhihuiyun_market&system_version_code=28&&时尚::http://baobab.kaiyanapp.com/api/v1/tag/videos?id=26&udid=187de68fafce4bcf8d6cca9e147574226a2e711e&vc=570&vn=6.0&size=1080X2255&deviceModel=JKM-AL00b&first_channel=eyepetizer_zhihuiyun_market&last_channel=eyepetizer_zhihuiyun_market&system_version_code=28&&综艺::http://baobab.kaiyanapp.com/api/v1/tag/videos?id=28&udid=187de68fafce4bcf8d6cca9e147574226a2e711e&vc=570&vn=6.0&size=1080X2255&deviceModel=JKM-AL00b&first_channel=eyepetizer_zhihuiyun_market&last_channel=eyepetizer_zhihuiyun_market&system_version_code=28&&生活::http://baobab.kaiyanapp.com/api/v1/tag/videos?id=666&udid=187de68fafce4bcf8d6cca9e147574226a2e711e&vc=570&vn=6.0&size=1080X2255&deviceModel=JKM-AL00b&first_channel=eyepetizer_zhihuiyun_market&last_channel=eyepetizer_zhihuiyun_market&system_version_code=28",
    "sourceGroup": "影视",
    "sourceIcon": "http://android-artworks.25pp.com/fs08/2024/11/14/0/110_43dbbf6566db7dc0860ea99af8391a83_con.png",
    "sourceName": "🎞\n开眼",
    "sourceUrl": "http://baobab.kaiyanapp.com",
    "style": ".text{color:#f0f0f0;text-indent: 2em}\nbody{background-color:#8e8e8e}\n.title{text-align:center;color:#ffffff}\n.down{font-size:10px}"
  },
  {
    "articleStyle": 0,
    "concurrentRate": "",
    "customOrder": 26,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36\"}",
    "injectJs": "const href = window.location.href\nif (/^https:\\/\\/www.yousuu.com/.test(href)) {\n  const list = [\n      {\n        name: \"夸克搜索\",\n        url: \"https://quark.sm.cn/s?q=\",\n      },\n      {\n        name: \"搜狗搜索\",\n        url: \"https://wap.sogou.com/web/searchList.jsp?keyword=\",\n      },\n      {\n        name: \"头条搜索\",\n        url: \"https://so.toutiao.com/search/?keyword=\",\n      },\n      {\n        name: \"360搜索\",\n        url: \"https://m.so.com/s?q=\",\n      },\n      {\n        name: \"必应搜索\",\n        url: \"https://cn.bing.com/search?q=\",\n      },\n      {\n        name: \"百度搜索\",\n        url: \"https://www.baidu.com/s?wd=\",\n      },\n    ],\n    autoBtn = document.createElement(\"div\"),\n    widthIsMax = window.innerWidth > window.innerHeight\n  let size,\n    unit = 1500\n\n  if (widthIsMax) {\n    size = window.innerWidth / unit\n    unit = \"vw\"\n  } else {\n    size = window.innerHeight / unit\n    unit = \"vh\"\n  }\n\n  const pubStyle = `background-color: rgb(255, 153, 0);border-radius:5px;border: 1px solid rgb(255, 153, 0);color: #fff;line-height:1;font-size:${\n    4 * size\n  }${unit};font-weight: 400;padding: ${size}${unit} ${size}${unit};`\n\n  const pubBtn = (btns, innerText) => {\n    let text = \"\"\n    for (const { name, url } of btns) {\n      text += `<button type=\"button\" style=\"margin:5px 10px;${pubStyle}\" onclick=\"window.open('${url}${innerText}', '_blank')\">${name}</button>`\n    }\n    return text\n  }\n\n  const showAuto = name => {\n    autoBtn.innerHTML = `<div id='auto-yuedu-bookshelf' style=\"z-index: 9999999999;position: fixed;background-color:#ffffff;bottom:0;left: 0;width:100%;\">\n        <p style=\"line-height:1;font-size:${\n          4 * size\n        }${unit};margin:5px;color: rgb(255, 153, 0);background-color:#ffffff;width:100%;text-align: center;\">${name}</p>\n        <div style=\"background-color:#f0f0f0;border-top:1px rgb(255, 153, 0) solid;display:flex;flex-wrap: wrap;\">${pubBtn(\n          list,\n          name\n        )}\n        </div>\n    </div>`\n  }\n\n  if (/\\/(book|name)\\//.test(href)) {\n    showAuto(document.getElementsByTagName(\"h1\")[0].innerText)\n  } else {\n    function onBtnStart2() {\n      autoBtn.style.display = \"none\"\n    }\n    autoBtn.style.display = \"none\"\n    autoBtn.addEventListener(\"touchstart\", onBtnStart2)\n    autoBtn.addEventListener(\"mousedown\", onBtnStart2)\n\n    let time, isLong\n    function genListener(item) {\n      const innerText = item.innerText\n      item.setAttribute(\"add-yuedu-bookshelf\", \"add-yuedu-bookshelf\")\n      const target = item.target || \"_blank\"\n      item.removeAttribute(\"target\")\n      const href = item.href\n      item.removeAttribute(\"href\")\n\n      function onBtnStart(evt) {\n        time = setTimeout(() => {\n          isLong = true\n          showAuto(\n            innerText.startsWith(\"《\") ? innerText.slice(1, -1) : innerText\n          )\n          autoBtn.style.display = \"block\"\n        }, 600)\n      }\n      function onBtnEnd(evt) {\n        if (isLong) {\n          isLong = undefined\n        } else {\n          clearTimeout(time)\n          time = undefined\n          window.open(href, target)\n        }\n      }\n      item.addEventListener(\"touchstart\", onBtnStart)\n      item.addEventListener(\"touchend\", onBtnEnd)\n      item.addEventListener(\"touchcancel\", onBtnEnd)\n      item.addEventListener(\"mousedown\", onBtnStart)\n      item.addEventListener(\"mouseup\", onBtnEnd)\n    }\n    let num = 0\n    function addListener(els) {\n      Array.from(els, item => {\n        if (\n          !item.children.length &&\n          item.getAttribute(\"add-yuedu-bookshelf\") !== \"add-yuedu-bookshelf\" &&\n          /^(https:\\/\\/www.yousuu.com)?\\/(book|name)\\//.test(item.href)\n        )\n          genListener(item)\n      })\n      num = els.length\n    }\n\n    function reAdd() {\n      const els = document.getElementsByTagName(\"a\")\n      if (els.length > num) addListener(els)\n    }\n\n    reAdd()\n\n    const observer = new ResizeObserver(reAdd)\n    observer.observe(document.body)\n  }\n  document.body.appendChild(autoBtn)\n} else {\n  if (\n    /^https:\\/\\/(so\\.toutiao\\.com\\/search\\/?|quark\\.sm\\.cn\\/s|wap\\.sogou\\.com\\/web\\/searchList\\.jsp|m\\.so\\.com\\/s|cn\\.bing\\.com\\/search|www\\.baidu\\.com\\/s)\\?/.test(\n      href\n    )\n  ) {\n    if (!document.getElementById(\"open-yuedu-bookshelf\")) {\n      let time,\n        isLong,\n        num = 0\n      function genListener(item) {\n        item.setAttribute(\"add-yuedu-bookshelf\", \"add-yuedu-bookshelf\")\n        const target = item.target || \"_blank\"\n        item.removeAttribute(\"target\")\n        const href = item.href\n        item.removeAttribute(\"href\")\n\n        function onTouchStart(evt) {\n          time = setTimeout(() => {\n            isLong = true\n            window.open(\n              `legado://import/addToBookshelf?src=${encodeURIComponent(href)}`,\n              \"_blank\"\n            )\n          }, 600)\n        }\n        function onTouchEnd(evt) {\n          if (isLong) {\n            isLong = undefined\n          } else {\n            clearTimeout(time)\n            time = undefined\n            window.open(href, target)\n          }\n        }\n\n        item.addEventListener(\"touchstart\", onTouchStart)\n        item.addEventListener(\"touchend\", onTouchEnd)\n        item.addEventListener(\"touchcancel\", onTouchEnd)\n        item.addEventListener(\"mousedown\", onTouchStart)\n        item.addEventListener(\"mouseup\", onTouchEnd)\n      }\n\n      function addListener(els) {\n        Array.from(els, item => {\n          if (\n            item.getAttribute(\"add-yuedu-bookshelf\") !==\n              \"add-yuedu-bookshelf\" &&\n            item.innerText &&\n            item.href &&\n            !/^#|^javascript:/.test(item.href)\n          )\n            genListener(item)\n        })\n        num = els.length\n      }\n\n      function reAdd() {\n        const els = document.getElementsByTagName(\"a\")\n        if (els.length > num) addListener(els)\n      }\n\n      reAdd()\n\n      const observer = new ResizeObserver(reAdd)\n      observer.observe(document.body)\n    }\n  } else {\n    const btn = document.createElement(\"div\"),\n      autoBtn = document.createElement(\"div\")\n    autoBtn.style.display = \"none\"\n    const widthIsMax = window.innerWidth > window.innerHeight\n    let size,\n      unit = 1500\n    if (widthIsMax) {\n      size = window.innerWidth / unit\n      unit = \"vw\"\n    } else {\n      size = window.innerHeight / unit\n      unit = \"vh\"\n    }\n\n    const pubStyle = `background-color: rgb(255, 153, 0);border-radius:5px;border: 1px solid rgb(255, 153, 0);color: #fff;line-height:1;font-size:${\n      4 * size\n    }${unit};font-weight: 400;padding: ${size}${unit} ${size}${unit};`\n\n    const pubBtn = btns => {\n      let text = \"\"\n      for (let i in btns) {\n        text += `<button type=\"button\" style=\"margin:5px auto;${pubStyle}\" onclick=\"window.open(\\`legado://import/addToBookshelf?src=${encodeURIComponent(\n          btns[i]\n        )},{origin:'通用书源'}\\`, '_blank')\">${i}</button>`\n      }\n      return text\n    }\n\n    btn.innerHTML = `<button type=\"button\" id='open-yuedu-bookshelf' style=\"z-index: 9999999999;position: fixed;bottom: 7%;right: 7%;${pubStyle}\">加入书架</button>`\n\n    autoBtn.innerHTML = `<div id='auto-yuedu-bookshelf' style=\"background-color:#ffffff;z-index: 99999999999;position: fixed;bottom:0;left: 0;width:100%;\">\n<div style=\"background-color:#f0f0f0;border-top:1px rgb(255, 153, 0) solid;display:flex;flex-wrap: wrap;\">${pubBtn(\n      {\n        目录识别: window.location.href,\n        尾页目录: `${window.location.href}?录`,\n        单页识别: `${window.location.href}?单`,\n        尾页正文: `${window.location.href}?[${window.location.href}]单`,\n      }\n    )}\n</div>\n<div style=\"padding:0px 5px;border-top: 1px solid rgb(255, 153, 0);\">\n  <p><span style=\"color:rgb(255, 153, 0);\">目录识别: </span>当前为目录页，且所有章节都在此页或有下一页按钮时，点\"目录识别\"按钮自动识别</p>\n  <p><span style=\"color:rgb(255, 153, 0);\">尾页目录: </span>目录页无下一页按钮且存在其他目录页时，进入最后一个目录页，点\"尾页目录\"逆推生成全部目录（此方式生成的目录无法更新）\n  </p>\n  <p><span style=\"color:rgb(255, 153, 0);\">单页识别:\n    </span></p>\n  <p>1. 当前为正文且页面下方为纯数字形式的目录时，点\"单页识别\"按钮自动识别</p>\n  <p>2. 当前为正文且当前书籍无录页但有下一页按钮时，点\"单页识别\"按钮自动识别（目录过多时需要的识别时间比较长，可考虑进入最后一个正文页点\"尾页正文\"按钮快速逆推生成整本书）</p>\n  <p><span style=\"color:rgb(255, 153, 0);\">尾页正文:\n    </span>章节链接符合数字递增规律时，进入最后一个正文页，点\"尾页正文\"逆推生成整本书（此方式生成的目录无法更新）</p>\n</div>\n<p style=\"margin:0px;background-color: rgb(255, 153, 0);color:#ffffff;width:100%;text-align: center;\">长按弹窗任意空白处关闭弹窗</p>\n</div>`\n\n    let time, isLong\n    function onBtnStart(evt) {\n      evt.preventDefault()\n      time = setTimeout(() => {\n        isLong = true\n        autoBtn.style.display = \"block\"\n      }, 600)\n    }\n    function onBtnEnd(evt) {\n      evt.preventDefault()\n      if (isLong) {\n        isLong = undefined\n      } else {\n        clearTimeout(time)\n        time = undefined\n        window.open(\n          `legado://import/addToBookshelf?src=${encodeURIComponent(\n            window.location.href\n          )}`,\n          \"_blank\"\n        )\n      }\n    }\n    btn.addEventListener(\"touchstart\", onBtnStart)\n    btn.addEventListener(\"touchend\", onBtnEnd)\n    btn.addEventListener(\"touchcancel\", onBtnEnd)\n    btn.addEventListener(\"mousedown\", onBtnStart)\n    btn.addEventListener(\"mouseup\", onBtnEnd)\n    document.body.appendChild(btn)\n\n    let time2, isLong2\n    function onBtnStart2(evt) {\n      time2 = setTimeout(() => {\n        isLong2 = true\n        autoBtn.style.display = \"none\"\n      }, 600)\n    }\n    function onBtnEnd2(evt) {\n      if (isLong2) {\n        evt.preventDefault()\n        isLong2 = undefined\n      } else {\n        clearTimeout(time2)\n        time2 = undefined\n      }\n    }\n\n    autoBtn.addEventListener(\"touchstart\", onBtnStart2)\n    autoBtn.addEventListener(\"touchend\", onBtnEnd2)\n    autoBtn.addEventListener(\"touchcancel\", onBtnEnd2)\n    autoBtn.addEventListener(\"mousedown\", onBtnStart2)\n    autoBtn.addEventListener(\"mouseup\", onBtnEnd2)\n    document.body.appendChild(autoBtn)\n  }\n}\n",
    "jsLib": "",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": false,
    "ruleArticles": "@js:\nlet labels = `${source.getVariable()}`.trim();\nlet list = [\n{\n\t\"name\":\"夸克搜索\",\n\t\"url\":\"https://quark.sm.cn/s?q=小说排行\"\n},\n{\n\t\"name\":\"搜狗搜索\",\n\t\"url\":\"https://wap.sogou.com/web/searchList.jsp?keyword=小说排行\"\n},\n{\n\t\"name\":\"头条搜索\",\n\t\"url\":\"https://so.toutiao.com/search/?keyword=小说排行\"\n},\n{\n\t\"name\":\"360搜索\",\n\t\"url\":\"https://m.so.com/s?q=小说排行\"\n},\n{\n\t\"name\":\"必应搜索\",\n\t\"url\":\"https://cn.bing.com/search?q=小说排行\"\n},\n{\n\t\"name\":\"百度搜索\",\n\t\"url\":\"https://www.baidu.com/s?wd=小说排行\"\n}\n];\n\nlabels?list.concat(labels.split(/\\s+/).map(it=>{\n\tconst href=it.split(\"::\");\n\treturn {\"name\":href[0],\"url\":href[1]}\n})):list",
    "ruleContent": "",
    "ruleDescription": "",
    "ruleImage": "",
    "ruleLink": "url",
    "ruleNextPage": "",
    "rulePubDate": "",
    "ruleTitle": "name",
    "singleUrl": false,
    "sortUrl": "",
    "sourceComment": "通用发现v5\n\n以如下格式设置源变量，可在列表后追加任意多个书签和搜索引擎\n\n夸克搜索::https://quark.sm.cn/s?q=小说排行",
    "sourceGroup": "🔍搜索",
    "sourceIcon": "https://5b0988e595225.cdn.sohucs.com/q_70,c_zoom,w_640/images/20180118/22271e695f5f48a89795e2b9858f5008.jpeg",
    "sourceName": "聚合搜索",
    "sourceUrl": "https://www.baidu.com",
    "style": "",
    "variableComment": ""
  },
  {
    "articleStyle": 0,
    "customOrder": 29,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "injectJs": "//$(\"div.layui-panel\").eq(0).remove();\nsetInterval(function () {\n    $(\"div.layui-hide-md\").css(\"display\",\"none\");\n},100)",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "🛰️ 科技,R18",
    "sourceIcon": "https://www.yckceo.com/favicon.ico",
    "sourceName": "源仓库(去底部广告）",
    "sourceUrl": "https://www.yckceo.com/"
  },
  {
    "articleStyle": 0,
    "customOrder": 30,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "header": "{\"User-Agent\":\"Mozilla/5.0 (Linux; Android 11; PCAM10 Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4103.106 Mobile Safari/537.36\"} ",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "loginUrl": "https://czy.yzfnb6.help/cn/home/web/index.php/vod/play/id/1177871/sid/1/nid/1.html",
    "ruleArticles": "[class=\"H5__content\"]@[class=\"video__wrap\"]@a",
    "ruleContent": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<title>内容提取-双模版</title>\n\n<script src=\"https://code.jquery.com/jquery-3.6.0.min.js\"></script>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.3/viewer.min.css\" />\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.3/viewer.min.js\"></script>\n<style>\n    body {font-family: Arial, sans-serif;font-size: 16px;}\n    #title, #page, #loading-status {margin: 0 auto;font-size: 20px;text-align: center;}\n    #description, #urls, #video-url, #video-sources, #messages {width: 100%;max-width: 800px;margin: 1.5px auto;font-size: 14px;text-align: left;word-wrap: break-word;white-space: pre-wrap;}\n    #text, #text :not(img), #text img + * {text-indent: 2em;width: 100%;font-size: 16px;line-height: 1.5em;margin-top: 0;margin-bottom: 0;word-wrap: break-word;white-space: pre-wrap;}\n    img, #text img {width: 100%;height: auto;display: block;margin-bottom: 1.5px;}\n    .flex-container {display: flex;justify-content: center;align-items: center;gap: 10px;margin: 1.5px 0;font-size: 14px;}\n    button, select {flex: 1 1 31%; padding: 3px;border: 1px solid #ccc;border-radius: 5px;box-sizing: border-box;cursor: pointer;background-color: #f9f9f9;transition: background-color 0.3s ease;margin: 1.5px;min-width: 0;font-size: 14px;}\n    #url-select, #video-source-select {flex: 1 1 100%; margin-left: 0;margin-right: 0;text-align: center;}\n    #video-element {width: 100%;height: auto;}\n    textarea {width: 100%;height: auto;min-height: 100px;box-sizing: border-box;resize: vertical;}\n    .error, .warn {color: red;}\n    #urls,#messages,#debug-info,#video-url,#video-container,#video-source-select,#images,#text {display:none;}\n</style>\n</head>\n<body>\n    <h3 id=\"title\">{{@@title@text||h1.0@text||h2.0@text||.title.0@text##高清在线观看|-国产剧| - 专享影视| - 热门高清|影视大全|海外华人|高清1080p|无广告影院|\\|}}</h3>\n    <p id=\"description\">{{@@.info.0@html||.jianjie@html}}</p>\n    <p id=\"page\">共<span id=\"total-pages\">1</span>页</p>\n    <p id=\"loading-status\" style=\"display:none;\"></p>\n    <div class=\"flex-container\" id=\"loading-buttons\" style=\"display:none;\">\n        <button id=\"prev-page-btn\">上一页</button>\n        <button id=\"next-page-btn\">下一页</button>\n        <button id=\"auto-load-btn\">自&nbsp;&nbsp;动</button>\n    </div>\n    <div class=\"flex-container\">\n        <select id=\"url-select\" style=\"display:none;\"></select>\n    </div>\n    <div class=\"flex-container\">\n        <button id=\"toggle-urls-btn\">显/隐网址</button>\n        <button id=\"toggle-messages-btn\">显/隐信息</button>\n        <button id=\"toggle-debug-btn\">显/隐调试</button>\n    </div>\n    <div id=\"urls\"></div>\n    <div id=\"messages\"></div>\n    <div id=\"debug-info\"></div>\n    <div id=\"video-url\"></div>\n    <div id=\"video-container\">\n        <video id=\"video-element\" controls preload=\"auto\" width=\"640\" height=\"264\">\n            <source id=\"video-source\" src=\"\" type=\"\">\n            您的浏览器不支持 video 标签。\n        </video>\n    </div>\n    <div class=\"flex-container\">\n        <select id=\"video-source-select\" onchange=\"updateVideoSource()\"></select>\n    </div>\n    <div id=\"images\"></div>\n    <div id=\"text\"></div>\n    <script>\nconst config = {    \n    videoSelector: 'body', // 视频选择器\n    imgSelector: '.gridlane-box-inside img', // 图片选择器\n    textSelector: '#content', // 文本选择器\n    debugSelector: '.player-wrapper', // 调试信息选择器\n    swapImageAttributes: false, // 是否交换图片属性\n    delayTime: 1500, // 延迟提取时间\n    retryDelayTime: 1500, // 重试加载延迟时间\n    maxLoadAttempts: 3, // 最大加载次数\n    autoLoading: false, // true自动模式，false单页模式\n    debugOnce: 0, // 只在特定索引输出一次调试信息\n         /* -网页拼接-*/    \n    totalPagesText: '{{@@.pager@li.-3@a@textNodes}}', // 总页码\n    urlSuffixToRemove: /\\.aspx$/, // 移除url后缀\n    pageUrlText: '{urlPrefix}p{i}.aspx', // 拼接URL模板        \n        /* -以上拼接模式（网址需要拼接）-*/\n        /* -上下分割线-*/\n        /* -以下列表模式（地址与目录对应，比如视频、漫画）-*/   \n    ListMode: true, // true网址列表模式，false网址拼接模式    \n    initialUrls: `{{@@#sort-item-5.0@a@href}}`, // 网址\n    initialUrlsName: `{{@@#sort-item-5.0@a@span@text}}`, // 网址名称\n    sourceurl: '', // 来源URL前缀\n};\n\nlet videoSources = [];\nlet loadAttempts = {};\nlet urls = [];\nlet imageBox;\nlet textBox;\nlet currentPageIndex = 0;\nlet canLoadNextPage = true;\nlet autoLoadInProgress = false;\n\n// 构建URL列表\nfunction buildUrls(totalPages, baseUrl) {\n    let initialUrlsArray = config.initialUrls.trim().split('\\n').filter(url => url.trim() !== '');\n    let initialUrlsNameArray = config.initialUrlsName.trim().split('\\n').filter(name => name.trim() !== '');\n\n    if (config.ListMode && initialUrlsArray.length > 0) {\n        if (initialUrlsArray.length !== initialUrlsNameArray.length) {\n            $('#messages').append(`<span class=\"warn\">警告：initialUrls 和 initialUrlsName 的长度不匹配。</span><br>`);\n        }\n\n        urls = initialUrlsArray.map(url => {\n            if (config.sourceurl && url.startsWith('/') && !/^https?:\\/\\//i.test(url)) {\n                return config.sourceurl.replace(/\\/$/, '') + url;\n            } else {\n                return url;\n            }\n        });\n\n        urls.forEach((url, index) => {\n            const name = initialUrlsNameArray[index] || `第 ${index + 1} 页`;\n            $('#url-select').append(`<option value=\"${index}\">${name}</option>`);\n            $('#urls').append(`<div>${name}: ${url}</div>`);\n        });\n    } else {\n        if (totalPages === 1) {\n            urls.push(baseUrl);\n        } else {\n            urls.push(baseUrl);\n            for (let i = 2; i <= totalPages; i++) {\n                urls.push(config.pageUrlText.replace('{urlPrefix}', baseUrl.replace(config.urlSuffixToRemove, '').replace(/\\/$/, '')).replace('{i}', i));\n            }\n        }\n\n        urls.forEach((url, index) => {\n            const name = `第 ${index + 1} 页`;\n            $('#url-select').append(`<option value=\"${index}\">${name}</option>`);\n            $('#urls').append(`<div>${name}: ${url}</div>`);\n        });\n    }\n\n    $('#total-pages').text(urls.length);\n    toggleNavigationButtons();\n}\n\nfunction normalizeUrl(url) {\n    if (typeof url!== 'string' ||!url.trim()) return '';\n    url = url.replace(/\\\\u[\\dA-F]{4}/gi, (match) => String.fromCharCode(parseInt(match.replace(/\\\\u/g, ''), 16)));\n    url = decodeURIComponent(url);\n    url = url.replace(/^http:\\/([^/])/, 'http://$1'); // 修正 http:/ 协议部分\n    url = url.replace(/^https:\\/([^/])/, 'https://$1'); // 修正 https:/ 协议部分\n    return url;\n}\n\n// 清空容器\nfunction clearContainers() {\n    $('#messages').empty();\n    $('#images').empty();\n    $('#text').empty();\n}\n\n// 更新图片的src属性\nfunction updateImageSrc(elements, shouldSwap) {\n    elements.each(function () {\n        const $this = $(this);\n        const attrsToUpdate = {};\n        if (shouldSwap) {\n            ['data-original', 'data-src', 'data-url'].forEach(attr => {\n                if ($this.attr(attr)) {\n                    attrsToUpdate['src'] = $this.attr(attr);\n                }\n            });\n        }\n        $this.attr(attrsToUpdate);\n    });\n    return elements;\n}\n\n// 切换导航按钮和选择框的显示\nfunction toggleNavigationButtons() {\n    if ($('#url-select option').length > 1  && !config.autoLoading) {\n        $('#loading-buttons').show();\n        $('#url-select').show();\n    } else {\n        $('#loading-buttons').hide();\n        $('#url-select').hide();\n    }\n}\n\n// 显示加载状态\nfunction showLoadingStatus(pageNumber) {\n    const selectedOption = $('#url-select option:selected').text();\n    $('#loading-status').text(`正在加载：${selectedOption}`).show();\n}\n\n// 隐藏加载状态\nfunction hideLoadingStatus() {\n    $('#loading-status').hide();\n}\n\n// 内容提取函数内容\nfunction loadContent(index) {\n    if (index < 0 || index >= urls.length || !canLoadNextPage) return;\n    canLoadNextPage = false;\n    currentPageIndex = index;\n    $('#url-select').val(index);\n    $('#messages').append(`<div>当前地址: <span class=\"warn\">${urls[index]}</span> </div>`);\n    if (autoLoadInProgress) {\n        showLoadingStatus(index + 1);\n    }\n    $.ajax({\n        url: urls[index],\n        type: 'GET',\n        success: function (data) {\n            try {\n                const $data = $(data);\n                let updatedHtmlContent = data.replace(/(['\"])(\\/\\/)(?!\\/)/g, '$1https://')\n                    .replace(/src=\"upload/gi, 'src=\"/upload')\n                    .replace(/style=[\"'][^'\"]+[\"']/gi, '')\n                    .replace(/\\\\\\//g, '/');\n                const parser = new DOMParser();\n                const doc = parser.parseFromString(updatedHtmlContent, \"text/html\");\n\n                  // 添加调试标签输出信息\n                if (config.debugOnce === index) {\n                    const debugElements = $(doc).find(config.debugSelector);\n                    if (debugElements.length > 0) {\n                        const debugContents = $('<pre>').html(debugElements.clone().wrapAll('<div/>').parent().html()).html();\n                        $('#debug-info').html(`<span class=\"warn\">调试信息: <textarea rows=\"10\" cols=\"80\">${debugContents}</textarea></span>`);\n                    } else {\n                        $('#debug-info').html(`<span class=\"warn\">调试信息: <textarea rows=\"10\" cols=\"80\">调试信息未提取到内容，请检查选择器！</textarea></span>`);\n                    }\n                }\n\n                // 方法1：video标签获取视频地址\n                const videoContents = $(doc).find(config.videoSelector);\n                const videoTags = $(videoContents).find('video');\n                videoTags.each(function () {\n                    const videosrc = $(this).attr('src') || $(this).attr('data-src') || $(this).attr('data-original') || '';\n                    if (videosrc) {\n                        videoSources.push(videosrc);\n                    }\n                });\n                \n                // 方法2：source标签获取视频地址\n                const sources = $(videoContents).find('source');\n                sources.each(function () {\n                    const sourceSrc = $(this).attr('src') || $(this).attr('data-src') || $(this).attr('data-original') || '';\n                    if (sourceSrc) {\n                        videoSources.push(sourceSrc);\n                    }\n                });\n                \n                // 方法3：正则表达式获取视频地址\n                const regex = /['\"]https?[^'<>\"]+\\.(m3u8|mp4|webm|ogg|flv|mp3|m4a|wav|ape|flac)['\"]/ig;\n                const matches = data.match(regex);\n                if (matches) {\n                    const uniqueMatches = matches.filter((value, idx, self) => self.indexOf(value) === idx);\n    videoSources = videoSources.concat(uniqueMatches.map((match) => {\n        // 使用replace删除引号\n                const urlWithoutQuotes = match.replace(/['\"]/g, '');\n                return normalizeUrl(urlWithoutQuotes);\n                          }));\n                }\n\n                videoSources = videoSources.map(src => normalizeUrl(src.replace(/\\\\+/g, '')));\n                videoSources = [...new Set(videoSources)];\n\n                if (videoSources.length > 0) {\n                    $('#messages').append(`<span>成功提取到视频，找到 ${videoSources.length} 个视频。</span><br>`);\n                    videoSources.forEach((src, idx) => {\n                        $('#messages').append(`<div>视频地址:<span class=\"warn\"> ${src}</span><br></div>`);\n                        $('#video-source-select').append(`<option value=\"${idx}\">视频源 ${idx + 1}</option>`);\n                    });\n                    \n                    if (videoSources.length == 1) {\n                        $('#video-container').show();\n                        $('#video-url').show();\n                        $('#video-source-select').hide();\n                        updateVideoSource(); // 自动更新视频源\n                    } else if (videoSources.length > 1) {\n                        $('#video-container').show();\n                        $('#video-url').show();\n                        $('#video-source-select').show();\n                        updateVideoSource(); // 默认选择第一个视频源\n                    } else {\n                        $('#video-container').hide();\n                        $('#video-url').hide();\n                        $('#video-source-select').hide();\n                    }\n                } else {\n                    $('#messages').append(`<span class=\"warn\">未找到视频源。</span><br>`);\n                    $('#video-container').hide();\n                    $('#video-url').hide();\n                    $('#video-source-select').hide();\n                }\n\n                // 标签获图片\n                const $imgContents = $(doc).find(config.imgSelector);\n                const shouldSwap = config.swapImageAttributes;\n                const newContents = updateImageSrc($imgContents.clone(), shouldSwap);\n                $('#images').append(newContents).show();\n                if (newContents.length > 0) {\n                    $('#messages').append(`<span>成功提取图片，共 ${newContents.length} 张。</span><br>`);\n                    newContents.each(function () {\n                        const imgSrc =$(this).attr('src') || $(this).attr('data-original') || $(this).attr('data-src') || $(this).attr('data-url');\n                        $('#messages').append(`<div>地址:<span class=\"warn\"> ${imgSrc}</span><br></div>`);\n                    });\n                } else {\n                    $('#messages').append(`<span class=\"warn\">未提取到图片。</span><br>`);\n                }\n\n                // 标签获图文\n                const textContents = $(doc).find(config.textSelector).map(function () {\n                    const $currentContents = $(this);\n                    $currentContents.find('img + br, script, video, source').remove();\n                    $currentContents.html($currentContents.html().replace(/>\\s+/gi, '>').replace(/<\\/?br\\s*([^>]*)\\s*\\/?>/gi, '\\n').replace(/\\n+/g, '\\n'));\n                    return $currentContents.html();\n                }).get().join('');\n                if (textContents.trim()) {\n                    $('#text').append(`<span>${textContents}</span><br>`).show();\n                    $('#messages').append(`<span>成功提取图文。</span><br>`);\n                } else {\n                    $('#messages').append(`<span class=\"warn\">未提取到图文。</span><br>`);\n                }\n                \n                \n                if (autoLoadInProgress && currentPageIndex < urls.length - 1) {\n                    setTimeout(() => { \n                        canLoadNextPage = true;\n                        loadContent(currentPageIndex + 1); \n                    }, config.delayTime);\n                } else {\n                    canLoadNextPage = true;\n                    if (autoLoadInProgress) {\n                        hideLoadingStatus();\n                    }\n                }\n            } catch (parseError) {\n                $('#messages').append(`<span class=\"error\">解析页面内容时发生错误: ${parseError.message}</span><br>`);\n                handleLoadFailure(urls, index);\n            } finally {\n                if (imageBox) imageBox.viewer.update();\n                if (textBox) textBox.viewer.update();\n            }\n        },\n        error: function (jqXHR, textStatus, errorThrown) {\n            let errorMessage = `内容加载失败: ${urls[index]}`;\n            switch (textStatus) {\n                case 'timeout':\n                    errorMessage += ', 请求超时';\n                    break;\n                case 'abort':\n                    errorMessage += ', 请求被取消';\n                    break;\n                case 'parsererror':\n                    errorMessage += ', 解析响应出错';\n                    break;\n                default:\n                    errorMessage += `, 状态码: ${jqXHR.status}, 错误信息: ${errorThrown}`;\n                    break;\n            }\n            $('#messages').append(`<span class=\"error\">${errorMessage}</span><br>`);\n            handleLoadFailure(urls, index);\n        }\n    });\n}\n\n// 处理加载失败的情况\nfunction handleLoadFailure(urls, index) {\n    if (!loadAttempts[urls[index]]) {\n        loadAttempts[urls[index]] = 1;\n    } else {\n        loadAttempts[urls[index]]++;\n    }\n    if (loadAttempts[urls[index]] <= config.maxLoadAttempts) {\n        const retryMessage = `第${index + 1}页加载失败，正在进行第${loadAttempts[urls[index]]}次加载！`;\n        $('#messages').append(`<span class=\"error\">${retryMessage}</span><br>`);\n        setTimeout(() => { \n            canLoadNextPage = true;\n            loadContent(index); \n        }, config.retryDelayTime);\n    } else {\n        const finalErrorMessage = `第${index + 1}页加载失败，已达到最大尝试次数(${config.maxLoadAttempts})！`;\n        $('#messages').append(`<span class=\"error\">${finalErrorMessage}</span><br>`);\n        if (autoLoadInProgress && currentPageIndex < urls.length - 1) {\n            setTimeout(() => { \n                canLoadNextPage = true;\n                loadContent(currentPageIndex + 1); \n            }, config.delayTime);\n        } else {\n            canLoadNextPage = true;\n            if (autoLoadInProgress) {\n                hideLoadingStatus();\n            }\n        }\n    }\n}\n\n// 更新视频源\nfunction updateVideoSource() {\n    const selectedIndex = parseInt(document.getElementById('video-source-select').value);\n    const selectedSource = videoSources[selectedIndex];\n    document.getElementById('video-url').textContent = `视频地址:\\n ${selectedSource}`;\n\n    // 设置 video-source 的 src 属性\n    const videoSourceElement = document.getElementById('video-source');\n    videoSourceElement.src = selectedSource;\n\n    // 更新 video 元素的 src 属性\n    const videoElement = document.getElementById('video-element');\n    videoElement.load();\n\n    // 添加调试信息\n    $('#messages').append(`<span>更新视频源为: ${selectedSource}</span><br>`);\n}\n\n// 函数执行主体\n$(document).ready(function () {\n    imageBox = document.getElementById('images');\n    textBox = document.getElementById('text');\n    if (imageBox && textBox) {\n        new Viewer(imageBox, { title: true, interval: 2000 });\n        new Viewer(textBox, { title: true, interval: 2000 });\n    }\n\n    const totalPagesText = config.totalPagesText;\n    const totalPages = parseInt(totalPagesText, 10) || 1;\n    const baseUrl = '{{baseUrl}}';\n    \n    clearContainers();\n    $('#urls').empty();\n    $('#debug-info textarea').empty();   \n    $('#video-url').empty().hide();\n    $('#video-container').hide();\n    $('#video-source-select').empty().hide();\n    \n    buildUrls(totalPages, baseUrl);\n\n    const urlSelect = document.getElementById('url-select');\n    if (urlSelect.options.length > 0) {\n        urlSelect.value = '0'; \n        \n        if (config.autoLoading) {\n            autoLoadInProgress = true;\n            for (let i = 0; i < urls.length; i++) {\n                loadContent(i);\n            }\n        } else {\n            loadContent(0);\n        }\n    } else {\n        loadContent(0);\n    }\n\n    $('#url-select').change(function () {\n        clearContainers();\n        const selectedIndex = parseInt($(this).val());\n        loadContent(selectedIndex);\n    });\n    $('#prev-page-btn').click(function () {\n        clearContainers();\n        if (currentPageIndex > 0) {\n            loadContent(currentPageIndex - 1);\n        }\n    });\n    $('#next-page-btn').click(function () {\n        clearContainers();\n        if (currentPageIndex < urls.length - 1) {\n            loadContent(currentPageIndex + 1);\n        }\n    });\n    $('#auto-load-btn').click(function () {\n        autoLoadInProgress = true;\n        showLoadingStatus(1); \n        for (let i = currentPageIndex + 1; i < urls.length; i++) {\n            loadContent(i);\n        }\n    });\n    $('#toggle-messages-btn').click(function () { $('#messages').toggle(); });\n    $('#toggle-urls-btn').click(function () { $('#urls').toggle(); });\n    $('#toggle-debug-btn').click(function () { $('#debug-info').toggle(); });\n});\n    </script>\n</body>\n</html>",
    "ruleImage": "img@src",
    "ruleLink": "a@href",
    "ruleNextPage": "page||text.下一页@href",
    "rulePubDate": "p.-1@text\n",
    "ruleTitle": "h3.-1@text",
    "singleUrl": false,
    "sortUrl": "搜索::https://czy.yzfnb6.help/cn/home/web/index.php/vod/search.html?wd={{source.getVariable()}}\n最新上传::/cn/home/web/index.php/label/new/page/{{page}}.html\n月排行::/cn/home/web/index.php/label/hot_month/page/{{page}}.html\n日排行::/cn/home/web/index.php/label/hot_day/page/{{page}}.html\n周排行::/cn/home/web/index.php/label/hot_week/page/{{page}}.html\n熟母少妇::/cn/home/web/index.php/vod/type/id/20/page/{{page}}.html\n网红直播::/cn/home/web/index.php/vod/type/id/21/page/{{page}}.html\n自拍偷拍::/cn/home/web/index.php/vod/type/id/22/page/{{page}}.html\n强奸乱伦::/cn/home/web/index.php/vod/type/id/23/page/{{page}}.html\n高清国产::/cn/home/web/index.php/vod/type/id/24/page/{{page}}.html\n韩国专区::/cn/home/web/index.php/vod/type/id/25/page/{{page}}.html\n日本有码::/cn/home/web/index.php/vod/type/id/26/page/{{page}}.html\n日本无码::/cn/home/web/index.php/vod/type/id/27/page/{{page}}.html\n欧美情色::/cn/home/web/index.php/vod/type/id/28/page/{{page}}.html\n动漫卡通::/cn/home/web/index.php/vod/type/id/29/page/{{page}}.html\n三级伦理::/cn/home/web/index.php/vod/type/id/30/page/{{page}}.html",
    "sourceComment": "By小新\n永久地址：https://bqm.avds8.com/g/\nhttps://rlblsm.yzfnb4.lat/cn/home/web/\nhttps://qrb.yzfnb3.ink/cn/home/web/\nhttps://qrb.yzfnb3.ink/cn/home/web/",
    "sourceGroup": "R-18可用免翻",
    "sourceIcon": "",
    "sourceName": "优质粉嫩鲍3",
    "sourceUrl": "https://bnk.yzfnb2.makeup"
  },
  {
    "articleStyle": 0,
    "customOrder": 31,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "1",
    "sourceIcon": "",
    "sourceName": "24凹凸",
    "sourceUrl": "https://www.24ao.cc"
  },
  {
    "articleStyle": 0,
    "customOrder": 32,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "",
    "ruleTitle": "",
    "singleUrl": true,
    "sourceComment": "想干嘛干嘛，新增绘图和视频功能，meimodu翻墙版",
    "sourceGroup": "AI自用🔞",
    "sourceIcon": "https://files.catbox.moe/6tgccz.png",
    "sourceName": "Meimodu(墙)🔞",
    "sourceUrl": "https://i.sexyai.ai/IKMum"
  },
  {
    "articleStyle": 0,
    "customOrder": 33,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\"User-Agent\":\"Mozilla/5.0 (Linux; Android 11; PCAM10 Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4103.106 Mobile Safari/537.36\"} ",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "[class=\"H5__content\"]@[class=\"video__wrap\"]@a",
    "ruleContent": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<title>内容提取-双模版</title>\n\n<script src=\"https://code.jquery.com/jquery-3.6.0.min.js\"></script>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.3/viewer.min.css\" />\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.3/viewer.min.js\"></script>\n<style>\n    body {font-family: Arial, sans-serif;font-size: 16px;}\n    #title, #page, #loading-status {margin: 0 auto;font-size: 20px;text-align: center;}\n    #description, #urls, #video-url, #video-sources, #messages {width: 100%;max-width: 800px;margin: 1.5px auto;font-size: 14px;text-align: left;word-wrap: break-word;white-space: pre-wrap;}\n    #text, #text :not(img), #text img + * {text-indent: 2em;width: 100%;font-size: 16px;line-height: 1.5em;margin-top: 0;margin-bottom: 0;word-wrap: break-word;white-space: pre-wrap;}\n    img, #text img {width: 100%;height: auto;display: block;margin-bottom: 1.5px;}\n    .flex-container {display: flex;justify-content: center;align-items: center;gap: 10px;margin: 1.5px 0;font-size: 14px;}\n    button, select {flex: 1 1 31%; padding: 3px;border: 1px solid #ccc;border-radius: 5px;box-sizing: border-box;cursor: pointer;background-color: #f9f9f9;transition: background-color 0.3s ease;margin: 1.5px;min-width: 0;font-size: 14px;}\n    #url-select, #video-source-select {flex: 1 1 100%; margin-left: 0;margin-right: 0;text-align: center;}\n    #video-element {width: 100%;height: auto;}\n    textarea {width: 100%;height: auto;min-height: 100px;box-sizing: border-box;resize: vertical;}\n    .error, .warn {color: red;}\n    #urls,#messages,#debug-info,#video-url,#video-container,#video-source-select,#images,#text {display:none;}\n</style>\n</head>\n<body>\n    <h3 id=\"title\">{{@@title@text||h1.0@text||h2.0@text||.title.0@text##高清在线观看|-国产剧| - 专享影视| - 热门高清|影视大全|海外华人|高清1080p|无广告影院|\\|}}</h3>\n    <p id=\"description\">{{@@.info.0@html||.jianjie@html}}</p>\n    <p id=\"page\">共<span id=\"total-pages\">1</span>页</p>\n    <p id=\"loading-status\" style=\"display:none;\"></p>\n    <div class=\"flex-container\" id=\"loading-buttons\" style=\"display:none;\">\n        <button id=\"prev-page-btn\">上一页</button>\n        <button id=\"next-page-btn\">下一页</button>\n        <button id=\"auto-load-btn\">自&nbsp;&nbsp;动</button>\n    </div>\n    <div class=\"flex-container\">\n        <select id=\"url-select\" style=\"display:none;\"></select>\n    </div>\n    <div class=\"flex-container\">\n        <button id=\"toggle-urls-btn\">显/隐网址</button>\n        <button id=\"toggle-messages-btn\">显/隐信息</button>\n        <button id=\"toggle-debug-btn\">显/隐调试</button>\n    </div>\n    <div id=\"urls\"></div>\n    <div id=\"messages\"></div>\n    <div id=\"debug-info\"></div>\n    <div id=\"video-url\"></div>\n    <div id=\"video-container\">\n        <video id=\"video-element\" controls preload=\"auto\" width=\"640\" height=\"264\">\n            <source id=\"video-source\" src=\"\" type=\"\">\n            您的浏览器不支持 video 标签。\n        </video>\n    </div>\n    <div class=\"flex-container\">\n        <select id=\"video-source-select\" onchange=\"updateVideoSource()\"></select>\n    </div>\n    <div id=\"images\"></div>\n    <div id=\"text\"></div>\n    <script>\nconst config = {    \n    videoSelector: 'body', // 视频选择器\n    imgSelector: '.gridlane-box-inside img', // 图片选择器\n    textSelector: '#content', // 文本选择器\n    debugSelector: '.player-wrapper', // 调试信息选择器\n    swapImageAttributes: false, // 是否交换图片属性\n    delayTime: 1500, // 延迟提取时间\n    retryDelayTime: 1500, // 重试加载延迟时间\n    maxLoadAttempts: 3, // 最大加载次数\n    autoLoading: false, // true自动模式，false单页模式\n    debugOnce: 0, // 只在特定索引输出一次调试信息\n         /* -网页拼接-*/    \n    totalPagesText: '{{@@.pager@li.-3@a@textNodes}}', // 总页码\n    urlSuffixToRemove: /\\.aspx$/, // 移除url后缀\n    pageUrlText: '{urlPrefix}p{i}.aspx', // 拼接URL模板        \n        /* -以上拼接模式（网址需要拼接）-*/\n        /* -上下分割线-*/\n        /* -以下列表模式（地址与目录对应，比如视频、漫画）-*/   \n    ListMode: true, // true网址列表模式，false网址拼接模式    \n    initialUrls: `{{@@#sort-item-5.0@a@href}}`, // 网址\n    initialUrlsName: `{{@@#sort-item-5.0@a@span@text}}`, // 网址名称\n    sourceurl: '', // 来源URL前缀\n};\n\nlet videoSources = [];\nlet loadAttempts = {};\nlet urls = [];\nlet imageBox;\nlet textBox;\nlet currentPageIndex = 0;\nlet canLoadNextPage = true;\nlet autoLoadInProgress = false;\n\n// 构建URL列表\nfunction buildUrls(totalPages, baseUrl) {\n    let initialUrlsArray = config.initialUrls.trim().split('\\n').filter(url => url.trim() !== '');\n    let initialUrlsNameArray = config.initialUrlsName.trim().split('\\n').filter(name => name.trim() !== '');\n\n    if (config.ListMode && initialUrlsArray.length > 0) {\n        if (initialUrlsArray.length !== initialUrlsNameArray.length) {\n            $('#messages').append(`<span class=\"warn\">警告：initialUrls 和 initialUrlsName 的长度不匹配。</span><br>`);\n        }\n\n        urls = initialUrlsArray.map(url => {\n            if (config.sourceurl && url.startsWith('/') && !/^https?:\\/\\//i.test(url)) {\n                return config.sourceurl.replace(/\\/$/, '') + url;\n            } else {\n                return url;\n            }\n        });\n\n        urls.forEach((url, index) => {\n            const name = initialUrlsNameArray[index] || `第 ${index + 1} 页`;\n            $('#url-select').append(`<option value=\"${index}\">${name}</option>`);\n            $('#urls').append(`<div>${name}: ${url}</div>`);\n        });\n    } else {\n        if (totalPages === 1) {\n            urls.push(baseUrl);\n        } else {\n            urls.push(baseUrl);\n            for (let i = 2; i <= totalPages; i++) {\n                urls.push(config.pageUrlText.replace('{urlPrefix}', baseUrl.replace(config.urlSuffixToRemove, '').replace(/\\/$/, '')).replace('{i}', i));\n            }\n        }\n\n        urls.forEach((url, index) => {\n            const name = `第 ${index + 1} 页`;\n            $('#url-select').append(`<option value=\"${index}\">${name}</option>`);\n            $('#urls').append(`<div>${name}: ${url}</div>`);\n        });\n    }\n\n    $('#total-pages').text(urls.length);\n    toggleNavigationButtons();\n}\n\nfunction normalizeUrl(url) {\n    if (typeof url!== 'string' ||!url.trim()) return '';\n    url = url.replace(/\\\\u[\\dA-F]{4}/gi, (match) => String.fromCharCode(parseInt(match.replace(/\\\\u/g, ''), 16)));\n    url = decodeURIComponent(url);\n    url = url.replace(/^http:\\/([^/])/, 'http://$1'); // 修正 http:/ 协议部分\n    url = url.replace(/^https:\\/([^/])/, 'https://$1'); // 修正 https:/ 协议部分\n    return url;\n}\n\n// 清空容器\nfunction clearContainers() {\n    $('#messages').empty();\n    $('#images').empty();\n    $('#text').empty();\n}\n\n// 更新图片的src属性\nfunction updateImageSrc(elements, shouldSwap) {\n    elements.each(function () {\n        const $this = $(this);\n        const attrsToUpdate = {};\n        if (shouldSwap) {\n            ['data-original', 'data-src', 'data-url'].forEach(attr => {\n                if ($this.attr(attr)) {\n                    attrsToUpdate['src'] = $this.attr(attr);\n                }\n            });\n        }\n        $this.attr(attrsToUpdate);\n    });\n    return elements;\n}\n\n// 切换导航按钮和选择框的显示\nfunction toggleNavigationButtons() {\n    if ($('#url-select option').length > 1  && !config.autoLoading) {\n        $('#loading-buttons').show();\n        $('#url-select').show();\n    } else {\n        $('#loading-buttons').hide();\n        $('#url-select').hide();\n    }\n}\n\n// 显示加载状态\nfunction showLoadingStatus(pageNumber) {\n    const selectedOption = $('#url-select option:selected').text();\n    $('#loading-status').text(`正在加载：${selectedOption}`).show();\n}\n\n// 隐藏加载状态\nfunction hideLoadingStatus() {\n    $('#loading-status').hide();\n}\n\n// 内容提取函数内容\nfunction loadContent(index) {\n    if (index < 0 || index >= urls.length || !canLoadNextPage) return;\n    canLoadNextPage = false;\n    currentPageIndex = index;\n    $('#url-select').val(index);\n    $('#messages').append(`<div>当前地址: <span class=\"warn\">${urls[index]}</span> </div>`);\n    if (autoLoadInProgress) {\n        showLoadingStatus(index + 1);\n    }\n    $.ajax({\n        url: urls[index],\n        type: 'GET',\n        success: function (data) {\n            try {\n                const $data = $(data);\n                let updatedHtmlContent = data.replace(/(['\"])(\\/\\/)(?!\\/)/g, '$1https://')\n                    .replace(/src=\"upload/gi, 'src=\"/upload')\n                    .replace(/style=[\"'][^'\"]+[\"']/gi, '')\n                    .replace(/\\\\\\//g, '/');\n                const parser = new DOMParser();\n                const doc = parser.parseFromString(updatedHtmlContent, \"text/html\");\n\n                  // 添加调试标签输出信息\n                if (config.debugOnce === index) {\n                    const debugElements = $(doc).find(config.debugSelector);\n                    if (debugElements.length > 0) {\n                        const debugContents = $('<pre>').html(debugElements.clone().wrapAll('<div/>').parent().html()).html();\n                        $('#debug-info').html(`<span class=\"warn\">调试信息: <textarea rows=\"10\" cols=\"80\">${debugContents}</textarea></span>`);\n                    } else {\n                        $('#debug-info').html(`<span class=\"warn\">调试信息: <textarea rows=\"10\" cols=\"80\">调试信息未提取到内容，请检查选择器！</textarea></span>`);\n                    }\n                }\n\n                // 方法1：video标签获取视频地址\n                const videoContents = $(doc).find(config.videoSelector);\n                const videoTags = $(videoContents).find('video');\n                videoTags.each(function () {\n                    const videosrc = $(this).attr('src') || $(this).attr('data-src') || $(this).attr('data-original') || '';\n                    if (videosrc) {\n                        videoSources.push(videosrc);\n                    }\n                });\n                \n                // 方法2：source标签获取视频地址\n                const sources = $(videoContents).find('source');\n                sources.each(function () {\n                    const sourceSrc = $(this).attr('src') || $(this).attr('data-src') || $(this).attr('data-original') || '';\n                    if (sourceSrc) {\n                        videoSources.push(sourceSrc);\n                    }\n                });\n                \n                // 方法3：正则表达式获取视频地址\n                const regex = /['\"]https?[^'<>\"]+\\.(m3u8|mp4|webm|ogg|flv|mp3|m4a|wav|ape|flac)['\"]/ig;\n                const matches = data.match(regex);\n                if (matches) {\n                    const uniqueMatches = matches.filter((value, idx, self) => self.indexOf(value) === idx);\n    videoSources = videoSources.concat(uniqueMatches.map((match) => {\n        // 使用replace删除引号\n                const urlWithoutQuotes = match.replace(/['\"]/g, '');\n                return normalizeUrl(urlWithoutQuotes);\n                          }));\n                }\n\n                videoSources = videoSources.map(src => normalizeUrl(src.replace(/\\\\+/g, '')));\n                videoSources = [...new Set(videoSources)];\n\n                if (videoSources.length > 0) {\n                    $('#messages').append(`<span>成功提取到视频，找到 ${videoSources.length} 个视频。</span><br>`);\n                    videoSources.forEach((src, idx) => {\n                        $('#messages').append(`<div>视频地址:<span class=\"warn\"> ${src}</span><br></div>`);\n                        $('#video-source-select').append(`<option value=\"${idx}\">视频源 ${idx + 1}</option>`);\n                    });\n                    \n                    if (videoSources.length == 1) {\n                        $('#video-container').show();\n                        $('#video-url').show();\n                        $('#video-source-select').hide();\n                        updateVideoSource(); // 自动更新视频源\n                    } else if (videoSources.length > 1) {\n                        $('#video-container').show();\n                        $('#video-url').show();\n                        $('#video-source-select').show();\n                        updateVideoSource(); // 默认选择第一个视频源\n                    } else {\n                        $('#video-container').hide();\n                        $('#video-url').hide();\n                        $('#video-source-select').hide();\n                    }\n                } else {\n                    $('#messages').append(`<span class=\"warn\">未找到视频源。</span><br>`);\n                    $('#video-container').hide();\n                    $('#video-url').hide();\n                    $('#video-source-select').hide();\n                }\n\n                // 标签获图片\n                const $imgContents = $(doc).find(config.imgSelector);\n                const shouldSwap = config.swapImageAttributes;\n                const newContents = updateImageSrc($imgContents.clone(), shouldSwap);\n                $('#images').append(newContents).show();\n                if (newContents.length > 0) {\n                    $('#messages').append(`<span>成功提取图片，共 ${newContents.length} 张。</span><br>`);\n                    newContents.each(function () {\n                        const imgSrc =$(this).attr('src') || $(this).attr('data-original') || $(this).attr('data-src') || $(this).attr('data-url');\n                        $('#messages').append(`<div>地址:<span class=\"warn\"> ${imgSrc}</span><br></div>`);\n                    });\n                } else {\n                    $('#messages').append(`<span class=\"warn\">未提取到图片。</span><br>`);\n                }\n\n                // 标签获图文\n                const textContents = $(doc).find(config.textSelector).map(function () {\n                    const $currentContents = $(this);\n                    $currentContents.find('img + br, script, video, source').remove();\n                    $currentContents.html($currentContents.html().replace(/>\\s+/gi, '>').replace(/<\\/?br\\s*([^>]*)\\s*\\/?>/gi, '\\n').replace(/\\n+/g, '\\n'));\n                    return $currentContents.html();\n                }).get().join('');\n                if (textContents.trim()) {\n                    $('#text').append(`<span>${textContents}</span><br>`).show();\n                    $('#messages').append(`<span>成功提取图文。</span><br>`);\n                } else {\n                    $('#messages').append(`<span class=\"warn\">未提取到图文。</span><br>`);\n                }\n                \n                \n                if (autoLoadInProgress && currentPageIndex < urls.length - 1) {\n                    setTimeout(() => { \n                        canLoadNextPage = true;\n                        loadContent(currentPageIndex + 1); \n                    }, config.delayTime);\n                } else {\n                    canLoadNextPage = true;\n                    if (autoLoadInProgress) {\n                        hideLoadingStatus();\n                    }\n                }\n            } catch (parseError) {\n                $('#messages').append(`<span class=\"error\">解析页面内容时发生错误: ${parseError.message}</span><br>`);\n                handleLoadFailure(urls, index);\n            } finally {\n                if (imageBox) imageBox.viewer.update();\n                if (textBox) textBox.viewer.update();\n            }\n        },\n        error: function (jqXHR, textStatus, errorThrown) {\n            let errorMessage = `内容加载失败: ${urls[index]}`;\n            switch (textStatus) {\n                case 'timeout':\n                    errorMessage += ', 请求超时';\n                    break;\n                case 'abort':\n                    errorMessage += ', 请求被取消';\n                    break;\n                case 'parsererror':\n                    errorMessage += ', 解析响应出错';\n                    break;\n                default:\n                    errorMessage += `, 状态码: ${jqXHR.status}, 错误信息: ${errorThrown}`;\n                    break;\n            }\n            $('#messages').append(`<span class=\"error\">${errorMessage}</span><br>`);\n            handleLoadFailure(urls, index);\n        }\n    });\n}\n\n// 处理加载失败的情况\nfunction handleLoadFailure(urls, index) {\n    if (!loadAttempts[urls[index]]) {\n        loadAttempts[urls[index]] = 1;\n    } else {\n        loadAttempts[urls[index]]++;\n    }\n    if (loadAttempts[urls[index]] <= config.maxLoadAttempts) {\n        const retryMessage = `第${index + 1}页加载失败，正在进行第${loadAttempts[urls[index]]}次加载！`;\n        $('#messages').append(`<span class=\"error\">${retryMessage}</span><br>`);\n        setTimeout(() => { \n            canLoadNextPage = true;\n            loadContent(index); \n        }, config.retryDelayTime);\n    } else {\n        const finalErrorMessage = `第${index + 1}页加载失败，已达到最大尝试次数(${config.maxLoadAttempts})！`;\n        $('#messages').append(`<span class=\"error\">${finalErrorMessage}</span><br>`);\n        if (autoLoadInProgress && currentPageIndex < urls.length - 1) {\n            setTimeout(() => { \n                canLoadNextPage = true;\n                loadContent(currentPageIndex + 1); \n            }, config.delayTime);\n        } else {\n            canLoadNextPage = true;\n            if (autoLoadInProgress) {\n                hideLoadingStatus();\n            }\n        }\n    }\n}\n\n// 更新视频源\nfunction updateVideoSource() {\n    const selectedIndex = parseInt(document.getElementById('video-source-select').value);\n    const selectedSource = videoSources[selectedIndex];\n    document.getElementById('video-url').textContent = `视频地址:\\n ${selectedSource}`;\n\n    // 设置 video-source 的 src 属性\n    const videoSourceElement = document.getElementById('video-source');\n    videoSourceElement.src = selectedSource;\n\n    // 更新 video 元素的 src 属性\n    const videoElement = document.getElementById('video-element');\n    videoElement.load();\n\n    // 添加调试信息\n    $('#messages').append(`<span>更新视频源为: ${selectedSource}</span><br>`);\n}\n\n// 函数执行主体\n$(document).ready(function () {\n    imageBox = document.getElementById('images');\n    textBox = document.getElementById('text');\n    if (imageBox && textBox) {\n        new Viewer(imageBox, { title: true, interval: 2000 });\n        new Viewer(textBox, { title: true, interval: 2000 });\n    }\n\n    const totalPagesText = config.totalPagesText;\n    const totalPages = parseInt(totalPagesText, 10) || 1;\n    const baseUrl = '{{baseUrl}}';\n    \n    clearContainers();\n    $('#urls').empty();\n    $('#debug-info textarea').empty();   \n    $('#video-url').empty().hide();\n    $('#video-container').hide();\n    $('#video-source-select').empty().hide();\n    \n    buildUrls(totalPages, baseUrl);\n\n    const urlSelect = document.getElementById('url-select');\n    if (urlSelect.options.length > 0) {\n        urlSelect.value = '0'; \n        \n        if (config.autoLoading) {\n            autoLoadInProgress = true;\n            for (let i = 0; i < urls.length; i++) {\n                loadContent(i);\n            }\n        } else {\n            loadContent(0);\n        }\n    } else {\n        loadContent(0);\n    }\n\n    $('#url-select').change(function () {\n        clearContainers();\n        const selectedIndex = parseInt($(this).val());\n        loadContent(selectedIndex);\n    });\n    $('#prev-page-btn').click(function () {\n        clearContainers();\n        if (currentPageIndex > 0) {\n            loadContent(currentPageIndex - 1);\n        }\n    });\n    $('#next-page-btn').click(function () {\n        clearContainers();\n        if (currentPageIndex < urls.length - 1) {\n            loadContent(currentPageIndex + 1);\n        }\n    });\n    $('#auto-load-btn').click(function () {\n        autoLoadInProgress = true;\n        showLoadingStatus(1); \n        for (let i = currentPageIndex + 1; i < urls.length; i++) {\n            loadContent(i);\n        }\n    });\n    $('#toggle-messages-btn').click(function () { $('#messages').toggle(); });\n    $('#toggle-urls-btn').click(function () { $('#urls').toggle(); });\n    $('#toggle-debug-btn').click(function () { $('#debug-info').toggle(); });\n});\n    </script>\n</body>\n</html>",
    "ruleImage": "img@src",
    "ruleLink": "a@href",
    "ruleNextPage": "page||text.下一页@href",
    "rulePubDate": "p.-1@text\n",
    "ruleTitle": "h3.-1@text",
    "singleUrl": false,
    "sortUrl": "搜索::https://czy.yzfnb6.help/cn/home/web/index.php/vod/search.html?wd={{source.getVariable()}}\n最新上传::/cn/home/web/index.php/label/new/page/{{page}}.html\n熟母少妇::/cn/home/web/index.php/vod/type/id/20/page/{{page}}.html\n网红直播::/cn/home/web/index.php/vod/type/id/21/page/{{page}}.html\n自拍偷拍::/cn/home/web/index.php/vod/type/id/22/page/{{page}}.html\n强奸乱伦::/cn/home/web/index.php/vod/type/id/23/page/{{page}}.html\n高清国产::/cn/home/web/index.php/vod/type/id/24/page/{{page}}.html\n韩国专区::/cn/home/web/index.php/vod/type/id/25/page/{{page}}.html\n日本有码::/cn/home/web/index.php/vod/type/id/26/page/{{page}}.html\n日本无码::/cn/home/web/index.php/vod/type/id/27/page/{{page}}.html\n欧美情色::/cn/home/web/index.php/vod/type/id/28/page/{{page}}.html\n动漫卡通::/cn/home/web/index.php/vod/type/id/29/page/{{page}}.html\n三级伦理::/cn/home/web/index.php/vod/type/id/30/page/{{page}}.html",
    "sourceComment": "By小新\n永久地址：https://bqm.avds8.com/g/",
    "sourceGroup": "R-18可用免翻,可用",
    "sourceIcon": "",
    "sourceName": "优质粉嫩鲍1",
    "sourceUrl": "https://ikz.yzfnb9.life/yzfnb/"
  },
  {
    "articleStyle": 0,
    "customOrder": 34,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceComment": "Meimodu互动AI自用，概率免翻墙，可🔞角色扮演，可绘图，可制作视频，每天签到+70电量",
    "sourceGroup": "AI自用🔞",
    "sourceIcon": "https://files.catbox.moe/6tgccz.png",
    "sourceName": "Meimodu(免墙)🔞",
    "sourceUrl": "https://i.meimoai13.com/IKMum"
  },
  {
    "articleStyle": 0,
    "customOrder": 35,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "article",
    "ruleContent": "class.dplayer@all<js>\nresult=result.match(/http.*0/)[0]##\\</js>{{@@title@text##成人黑料.*}}\n<video src=\"{{result}}\" width=\"100%\" height=\"auto\" controls></video>",
    "ruleImage": "@js:\"https://mgtv-bbqn.oss-cn-beijing.aliyuncs.com/1/2310310103284A29582395A850D3A0F5C26862354MzFE/SrRlbr0.gif\"",
    "ruleLink": "a@href",
    "ruleNextPage": "page",
    "rulePubDate": "span.1@text",
    "ruleTitle": "class.post-card-title@text",
    "singleUrl": false,
    "sortUrl": "搜索::/search/{{source.getVariable()}}/{{page}}/\n今日吃瓜::/category/wpcz/{{page}}/\n热门大瓜::/category/rdsj/{{page}}/\n学生校园::/category/xsxy/{{page}}/\n网红黑料::/category/whhl/{{page}}/\n看片娱乐::/category/ysyl/{{page}}/\n乱伦道德::/category/lldd/{{page}}/\n人人吃瓜::/category/rrcg/{{page}}/\n海外吃瓜::/category/hwcg/{{page}}/\n骚男骚女::/category/snsn/{{page}}/",
    "sourceComment": "https://cg51.com/",
    "sourceGroup": "R-18可用免翻,可用",
    "sourceIcon": "http://p6.itc.cn/images01/20201202/8d012ed623d647a78635557e7d235ab6.jpeg",
    "sourceName": "51吃瓜🥝",
    "sourceUrl": "https://51.gsfggmu.com/"
  },
  {
    "articleStyle": 0,
    "customOrder": 36,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "🎞️ 影视,R18",
    "sourceIcon": "https://ps.ssl.qhmsg.com/t02f91aae775d10f2a8.jpg",
    "sourceName": "8号影院",
    "sourceUrl": "http://www.8hyyw.com"
  },
  {
    "articleStyle": 0,
    "customOrder": 37,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceComment": "不能白嫖，需氪金，有月卡制度，可🔞绘图，可🔞视频，可🔞角色扮演",
    "sourceGroup": "AI自用🔞",
    "sourceIcon": "https://files.catbox.moe/kf0sxh.png",
    "sourceName": "风月🔞(墙)",
    "sourceUrl": "https://acepro.store?ref_id=abedde90-41eb-4c6f-a916-ab777c098d25"
  },
  {
    "articleStyle": 0,
    "customOrder": 38,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "injectJs": "if(!self._LOADYEYU){const e={hash(e){let t=String(e),r=2166136261^t.length,n=Math.imul;for(let e=0;e<t.length;e++)r=n(r^t.charCodeAt(e),16777619),r=r<<13|r>>>19;let s=2246822507,a=3266489909,o=e=>(\"00000000\"+(e>>>0).toString(16)).slice(-8);return r^=r>>>16,r=n(r,s),r^=r>>>13,r=n(r,a),r^=r>>>16,o(r)+o(n(2654435769^r,s))+o(n(r^s,a))+o(n(r^a,668265263))}},t=localStorage,r=location,n=\"referral_code\";/register/.test(r.pathname)&&self.referralCode&&(referralCode.disabled=!0);let s=Date.now()>+new Date(\"2026/4/23\")?\"Z3DCYQB2\":\"Z3DCYQB2\";if(!t[\"user-storage\"]&&!r.search.includes(\"ref\")){let e=new URL(r.href);e.searchParams.append(\"ref\",s),r.href=e}t[n]?.includes(s)||(t[n]=JSON.stringify({code:s,source:\"share_link\",timestamp:Date.now(),expiresIn:0,refFirstTouchHost:r.host})),document.styleSheets[0]?.insertRule(\"header{padding-top:0px !important}\"),document.styleSheets[0]?.insertRule(\"button#register-optional-toggle>div{opacity:0}\"),document.styleSheets[0]?.insertRule(\"#mobile-download-banner,[data-rht-toaster],.z-30 div.bg-gradient-to-r,div:has(>label[for='referralCode']){display:none}\");const a=XMLHttpRequest;XMLHttpRequest=function(){let r,n=new a,{open:o,send:i}=n;return n.open=(...e)=>{r=e[1],o.apply(n,e)},n.send=async a=>{if(a&&/sign-up\\/email$|quick-register$/.test(r))try{let r=JSON.parse(a),n=t.yeyu_code;n&&/^[0-9A-Z]{8}$/.test(n)&&(s=n),a=JSON.stringify({...r,referralCode:s,fingerprint:e.hash([r.fingerprint||Math.random(),Date.now()/432e5|0].join(\"\"))})}catch{}i.call(n,a)},n},self._LOADYEYU=!0}",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": false,
    "ruleArticles": "@js:\n[{\nhref:baseUrl,\ntitle:'夜语AI',\ntime:new Date().toLocaleString(),\nimg:\"https://yeyu.ai/install-emtry.webp\"\n}];",
    "ruleImage": "img",
    "ruleLink": "href",
    "rulePubDate": "time",
    "ruleTitle": "title",
    "singleUrl": false,
    "sortUrl": "首页::/explore/app/?ranking=overall_rank\n抽卡::/explore/random/\n签到::/user/points/\n历史收藏::/user/history/?tab=favorites\n登录注册::/user/register/",
    "sourceComment": "无限制ai对话、自定义小说创作，每日签到、任务可免费领积分",
    "sourceGroup": "1",
    "sourceIcon": "https://yeyu.ai/install-emtry.webp",
    "sourceName": "🔞夜语AI",
    "sourceUrl": "https://yeyu.ai/r/KKPVLG8F"
  },
  {
    "articleStyle": 0,
    "customOrder": 39,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "injectJs": "let c=location,d=localStorage,e=document;\nif(/\\u98ce\\u6708/.test(e.title)){if(!d.console_token&&!/ref_id/.test(c.href)){let f=d.ref_id=atob('OGExYTAzNGMtZmI2MC00Y2I4LTk3MDktNTZiZjRmNWE1MWQy'),a=new URL(c.href);a.searchParams.set('ref_id',f);c.href=a}e.styleSheets[0]?.insertRule('form\\x3e.mt-1.mb-4.text-xs{display:none}')};\n\nlet aifycheck={checkUrl(a){return new Promise((c,b)=>{let d=Date.now();setTimeout(c,4E3,4E3);a.endsWith(\"\\x3d\")&&(a+=d);fetch(a,{mode:\"no-cors\",method:\"HEAD\"}).catch(()=>c(6E3)).then(()=>c(Date.now()-d))})},checkUrls(a){return Promise.allSettled(a.map(this.checkUrl)).then(c=>c.map(b=>b.value||b.reason))},getTimeStr(a){return a===6E3?\"\\ud83d\\udeab\\u88ab\\u5899/\\u5931\\u6548/\\u6545\\u969c\":a<1E3?`\\ud83d\\udfe2\\u5ef6\\u65f6: ${a} ms`:a<1200?`\\ud83d\\udd35\\u5ef6\\u65f6: ${a} ms`:a<1500?`\\ud83d\\udfe3\\u5ef6\\u65f6: ${a} ms `:\na<2E3?`\\ud83d\\udfe0\\u5ef6\\u65f6: ${a} ms `:a===4E3?\"\\u26ab\\u5ef6\\u65f6 \\x3e 4 s\":`\\ud83d\\udd34\\u5ef6\\u65f6: ${a} ms `},checkUrlList(){let a=document.querySelectorAll(\"#all-site-list a\"),c=document.querySelector(\"#byym\");a.length===0?self.onload=()=>{this.checkUrlList();let b=document.createElement(\"style\");b.textContent=\"#all-site-list a\\x3e*{text-align:center}\";document.head.appendChild(b)}:c.text=\"\\u68c0\\u6d4b\\u7f51\\u5740\\u4e2d...\";a.forEach(async b=>{b._textContent||(b._textContent=b.textContent);\nlet d=this.getTimeStr(await this.checkUrl(b.href=b.href.replace(\"p:\",\"ps:\")));b.innerHTML=`<p><b>${(new URL(b.href)).host}</b></p><p>${b._textContent}</p><p>${d}</p>`});c?.scrollIntoView();c?.firstElementChild?.textContent.includes(\"\\u5907\\u7528\\u57df\\u540d\")&&(c.firstElementChild.innerHTML=`\\u5907\\u7528\\u57df\\u540d (${(new Date).toLocaleTimeString()})<p>\\u53cc\\u51fb\\u7f51\\u9875\\u53ef\\u5237\\u65b0\\u68c0\\u6d4b</p>`)}};\n/aify.pages.dev|aifordum.github.io/.test(location.host)&&(aifycheck.checkUrlList(),self.addEventListener(\"dblclick\",()=>aifycheck.checkUrlList()));",
    "jsLib": "datas = [[{host:\"awsprod.aiero.cc\"},{host:\"aiaha.xyz\"},{host:\"acquant.xyz\"},{host:\"acquainte.xyz\"},{host:\"beling.xyz\"},{host:\"ai-xan.xyz\"},{host:\"aiwhatis.xyz\"},{host:\"aquantancee.xyz\"},{host:\"aquante.xyz\"},{host:\"aitrader.wiki\"},{host:\"aisearches.xyz\"},{host:\"aigirlfriendnetwork.com\"},{host:\"aigirlfriendnow.com\"}],[{host:\"aifun.ltd\",url:\"https://aifun.ltd/fcWoo\",img:1},{host:\"aifordum.github.io\",url:`https://aifordum.github.io?ref_id=8a1a034c-fb60-4cb8-9709-56bf4f5a51d2&t=`,img:1},{host:\"aify.pages.dev\",img:1}]];\nid = \"8a1a034c-fb60-4cb8-9709-56bf4f5a51d2\";\ndatas.forEach(list => {\n    list.forEach((x, i) => {\n        if (!x.url) x.url = `https://${x.host}?ref_id=${id}`;\n        if (!x.title) x.title = `${i+1}【${x.host}】`;\n    });\n});\n\nfunction getTimeList(urls) {\n    return this.java.webView(`<script>function checkUrl(url){return new Promise((res,rej)=>{let t=Date.now(),id=setTimeout(rej,3e3,4e3);if(url.endsWith('='))url+=t;fetch(url,{mode:'no-cors',method:'HEAD'}).catch(()=>rej(5e3)).then(()=>res(Date.now()-t)&&clearTimeout(id))})}function checkUrls(arr){return Promise.allSettled(arr.map(checkUrl)).then(a=>a.map(x=>x.value||x.reason))}checkUrls(${JSON.stringify(urls)}).then(arr=>result=JSON.stringify(arr));</script>`, \"about:blank\", \"self.result\");\n}",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "loginUrl": "/fcWoo",
    "ruleArticles": "@js:\nlet list = datas[java.hexDecodeToString(src)];\nlet arr = JSON.parse(getTimeList(list.map(x => x.url)));\nresult = list.map((obj, i) => {\n  const x = arr[i];\n  obj.img = source.sourceIcon;\n  obj.time = x === 5000 ? '🚫被墙/失效/故障' :\n    x < 1000 ? `🟢延时：${x} ms` :\n    x < 1200 ? `🔵延时：${x} ms` :\n    x < 1500 ? `🟣延时：${x} ms ` :\n    x < 2000 ? `🟠延时：${x} ms ` :\n    x === 4000 ? '⚫延时 > 3 s' :\n    `🔴延时：${x} ms `;\n  return obj;\n});\n",
    "ruleImage": "img",
    "ruleLink": "url",
    "rulePubDate": "time",
    "ruleTitle": "title",
    "singleUrl": false,
    "sortUrl": "路线列表::data:;base64,MA==,{\"type\":0}\n发布页::data:;base64,MQ==,{\"type\":0}",
    "sourceComment": "gemini/claude/grok/GPT/deepseek\n/kimi/glm/doubao\n右上角清除后可刷新",
    "sourceGroup": "AI创作",
    "sourceIcon": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNjAiIGhlaWdodD0iMzYwIiB2aWV3Qm94PSIwIDAgMzYwIDM2MCIgZmlsbD0ibm9uZSI+PHBhdGggZD0iTTI5Mi44NiA5Ni4yNDc2QzI5NC4zNDUgOTYuMjQ3NiAyOTYuMzcgOTYuNzg3MyAzMDUuNDE1IDEwMS42NDdDMzE0Ljg2NSAxMDYuNzc3IDMxNi40ODUgMTA4LjkzOCAzMTYuNDg1IDExMS4yMzNDMzE2LjQ4NSAxMTMuMjU4IDMxNC45OTkgMTE1LjI4MyAzMDguMzg1IDExOS40NjdMMzAzLjc5NCAyNDkuNzQzQzMwMy41MjQgMjU3LjE2OCAzMDIuNzE1IDI2Mi4yOTggMzAxLjA5NSAyNjUuNDAzQzI5OS40NzUgMjY4Ljc3OCAyOTUuNDI1IDI3Mi4wMTcgMjg4LjQwNSAyNzUuNzk3QzI3OS42MyAyODAuNTIyIDI3Ni45MyAyODEuMTk4IDI3NS40NDUgMjgxLjE5OEMyNzIuNDc1IDI4MS4xOTggMjcwLjQ1IDI3OS40NDIgMjY5LjkxIDI3Ni4zMzdDMjY5LjEgMjcyLjE1MiAyNjcuNDggMjY5LjA0NyAyNjUuMTg1IDI2Ni44ODdDMjYzLjQzIDI2NS4yNjcgMjU5LjI0NSAyNjIuNTY3IDI0OC4zMSAyNTcuOTc3TDI0Ni40MTkgMjU3LjE2OEwyNDcuOTA1IDI0Ny44NTJMMjUwLjc0IDI0OC4zOTJDMjY1Ljk5NSAyNTEuNjMyIDI3MS44IDI1Mi4xNzIgMjc0LjA5NSAyNTIuMTcyQzI3OC41MDIgMjUyLjAzOSAyNzkuNjA2IDI1MS41MDkgMjc5LjYyOSAyNTEuNDk4QzI3OS42MjkgMjUxLjQ5OCAyNzkuOSAyNTAuOTU4IDI4MC4wMzUgMjQ5Ljc0M0wyODIuNzM1IDE3MS4wMzhMMjQ1Ljg3OSAxNzMuNjAyTDI0Ni4yODUgMTUyLjI3MkwyODMuNTQ0IDE0OS40MzdMMjg0LjYyNSAxMTkuMTk4TDIzMS40MzUgMTI0LjA1N0MyMzEuMDMgMTM5Ljg1MiAyMjkuMTQgMTgxLjQzMyAyMjguMTk1IDE5NS4yMDNMMjY4LjU2IDE5Mi43NzJMMjY3Ljg4NSAyMDQuNTE3TDIyNi44NDUgMjA2LjgxMkMyMjQuODIgMjI0LjYzMiAyMTkuOTYgMjM5LjM0NyAyMTIuNCAyNTAuNTUyQzIwNC43MDUgMjYyLjAyNyAxOTIuMDE0IDI3My4wOTcgMTc1LjAwNCAyODMuNjI3TDE3My4xMTUgMjg0Ljg0MkwxNjcuMzEgMjc4LjYzMkwxNjcuMTc1IDI3OC40OThMMTY5LjIgMjc2LjYwOEMxNzkuNzMgMjY2Ljg4OCAxODcuNjk0IDI1Ny40MzggMTkyLjk1OSAyNDguNjYzQzE5OC4yMjQgMjM5Ljg4OCAyMDEuODcgMjI5Ljc2MiAyMDMuODk1IDIxOC41NTdDMjA1LjkyIDIwNy4yMTcgMjA3LjI3IDE5MC43NDcgMjA3LjgxIDE2OS44MjNDMjA4LjM1IDE0OC42MjggMjA4LjYyIDEyNy43MDIgMjA4LjYyIDEwNy4wNDdWMTAzLjQwM0wyMTIuMTI5IDEwNC40ODNDMjE4LjQ3NCAxMDYuNTA4IDIyNC45NTQgMTA5LjA3MiAyMzEuMjk5IDExMi4xNzdMMjg0LjM1NSAxMDcuMTgyTDI4OC4yNyA5OS42MjI2QzI4OS43NTUgOTcuMDU3NiAyOTEuNTEgOTYuMjQ3NiAyOTIuODYgOTYuMjQ3NlpNMTM4LjQxOSA3NC4xMDc5QzEzOS45MDQgNzQuMTA3OSAxNDEuNTI1IDc0LjY0NzkgMTQ5LjIyIDc5Ljc3NzlDMTU2LjkxNSA4NC45MDc2IDE1OC40IDg3LjMzNzYgMTU4LjQgODkuNDk3NkMxNTguNCA5Mi40Njc2IDE1NS41NjQgOTQuODk3NCAxNDkuMDg0IDk3LjQ2MjRDMTQ3Ljg2OSAxMTMuNjYyIDE0Ny4xOTQgMTI5LjMyMyAxNDYuOTI0IDE0NC4wMzhDMTQ2LjY1NCAxNTkuMDIzIDE0Ny4zMjkgMTcyLjI1MyAxNDkuMDg0IDE4My4xODhDMTUwLjcwNCAxOTMuOTg4IDE1Mi44NjUgMjAxLjU0OCAxNTUuNDMgMjA2LjAwMkMxNTYuOTE1IDIwOC41NjcgMTU3Ljg2IDIwOS45MTggMTU4LjUzNSAyMTAuNzI4QzE1OS4yMSAyMDkuMTA4IDE2MC4yOSAyMDYuMTM4IDE2MS45MSAyMDEuODE4QzE2NC4wNyAxOTUuODc4IDE2Ni4zNjUgMTg4LjU4OCAxNjkuMDY1IDE3OS44MTNMMTY5Ljg3NSAxNzcuMTEzTDE3Ny4wMyAxNzkuNTQzTDE3Ni42MjUgMTgxLjgzN0MxNzMuNzkgMTk5LjY1NyAxNzIuMzA0IDIxMS4xMzMgMTcyLjE2OSAyMTUuOTkzQzE3Mi4xNjkgMjIwLjcxOCAxNzIuNDQgMjI1LjE3MyAxNzMuMjUgMjI5LjQ5M0MxNzQuNDY0IDIzNS43MDMgMTc0LjYgMjM3LjE4OCAxNzQuNiAyMzcuOTk4QzE3NC42IDI0MS42NDMgMTcyLjE3IDI0My45MzggMTY4LjUyNSAyNDMuOTM4QzE2Ni42MzUgMjQzLjkzOCAxNjMuMjU5IDI0My4yNjMgMTU0Ljc1NCAyMzcuOTk4QzE0OC40MSAyMzMuOTQ4IDE0My4xNDUgMjI3Ljg3MiAxMzkuMDk1IDIxOS42MzdDMTM1LjE4IDIxMS42NzIgMTMyLjM0NCAyMDAuODczIDEzMC41ODkgMTg3LjY0M0MxMjguODM0IDE3NC41NDggMTI4LjE2IDE1OS44MzMgMTI4LjQzIDE0My43NjhDMTI4LjcgMTI4LjY0OCAxMjkuMjM5IDExMy4xMjMgMTMwLjA0OSA5Ny4xOTI5TDY3LjgxNDkgMTAyLjg2M0M2Ny4wMDQ5IDEzOS40NDcgNjUuNzkwMiAxNjQuNDIyIDY0LjMwNTIgMTc3LjM4MkM2Mi44MjAyIDE5MC43NDcgNTkuMTc0OSAyMDMuMTY4IDUzLjc3NDkgMjE0LjM3M0M0OC4zNzQ5IDIyNS40NDMgMzkuMzI5OCAyMzcuMTg4IDI2Ljc3NDkgMjQ5LjMzN0wyNC40OCAyNTEuNjMyTDE5LjM1MDEgMjQ0LjIwOEwxOS40ODQ5IDI0NC4wNzNMMjAuNjk5NyAyNDIuNDUzQzI5Ljg3OTcgMjMwLjQzOCAzNi43NjQ3IDIxNy4wNzIgNDAuOTQ5NyAyMDIuNzYyQzQ1LjI2OTYgMTg4LjMxNyA0Ny43MDAyIDE2Ny43OTcgNDcuOTcwMiAxNDEuODc3QzQ4LjI0MDIgMTI1Ljk0OCA0Ny45Njk5IDEwNy40NTMgNDcuMDI0OSA4Ny4wNjc5VjgzLjU1ODFMNTAuMjY1MSA4NC4zNjc3QzU2LjYwOTkgODUuNzE3NyA2Mi42ODQ3IDg4LjAxMjggNjguNjI0NSA5MS4xMTc3TDEyOS42NDUgODUuNDQ3OEwxMzQuMjM1IDc3LjQ4MjlDMTM1LjMxNSA3NS40NTgxIDEzNi44IDc0LjI0MzEgMTM4LjQxOSA3NC4xMDc5Wk0xMDkuOTM1IDEyNS42NzdDMTEwLjYxIDEyOS4zMjIgMTEyLjM2NSAxMzguOTA4IDExMy4zMSAxNTAuMjQ4QzExNy4wOSAxNTEuNDYzIDEyMC44NyAxNTMuMzUzIDEyNC42NSAxNTUuOTE4TDEyNi44MSAxNTcuMjY3TDExNy40OTUgMTczLjQ2N0MxMTcuNDcgMTczLjQ1MSAxMTMuOTgzIDE3MS4xNzEgMTEzLjQ0NSAxNzAuOTAyQzExMi41IDE4My4xODcgMTA5LjM5NSAxOTIuMjMyIDEwNC40IDE5Ny45MDJDMTAwLjYyIDIwMi4wODcgOTUuNzU5OCAyMDQuMzgyIDkwLjM1OTkgMjA0LjUxN0g4OS40MTQ2TDg5LjE0NSAyMDQuMzgyQzg2Ljk4NTEgMjA0LjM4MiA4NC42OSAyMDQuMTEyIDgyLjM5NSAyMDMuNDM3Qzc0LjU2NTEgMjAxLjI3NyA2OS41Njk5IDE5NC45MzMgNjguNDg5NyAxODYuMTU4QzY3LjEzOTggMTc1LjA4OCA3Mi44MDk2IDE2Mi4yNjIgODIuMTI0NSAxNTQuOTcyQzg2LjE3NDQgMTUxLjczMiA5MC43NjQ2IDE0OS43MDcgOTUuNjI0NSAxNDguNzYyQzk1LjA4NDUgMTQyLjU1MiA5NC4xNCAxMzYuMjA3IDkzLjA2MDEgMTMwLjY3Mkw5Mi42NTQ4IDEyOC4zNzdMMTA5LjI2IDEyMi43MDhMMTA5LjkzNSAxMjUuNjc3Wk05Ni4xNjQ2IDE2Ny4yNTdDOTQuNDA5NyAxNjcuNzk3IDkyLjkyNDggMTY4LjYwNyA5MS40Mzk5IDE2OS42ODdDODYuNDQ0OSAxNzMuNjAyIDg0LjY5MDIgMTc5LjgxMiA4NS4wOTUyIDE4Mi45MThDODUuMzY1MiAxODQuODA3IDg1LjkwNDcgMTg1LjIxMyA4Ny4xMTk2IDE4NS42MThDODguMDY0NiAxODUuODg4IDg5LjAwOTggMTg2LjAyMiA4OS44MTk4IDE4Ni4wMjJDOTEuMzA0NCAxODYuMDIyIDkxLjg0NDYgMTg1LjQ4MyA5Mi4yNDk1IDE4NS4wNzhDOTMuNTk5NSAxODMuNDU4IDk1Ljg5NTMgMTc5LjEzNyA5Ni4zMDAzIDE2Ny4yNTdIOTYuMTY0NlpNMTg5LjQ1IDE2My44ODJMMTcwLjgyIDE2NC44MjhMMTcyLjAzNSAxMTEuMDk3TDE5MC44IDEwOS42MTNMMTg5LjQ1IDE2My44ODJaTTM0MC4xMSAxNDIuMTQ4TDMyMy43NzUgMTQzLjIyOEwzMjQuNDUgMTI2Ljc1N0wzNDAuNjUgMTI1LjU0M0wzNDAuMTEgMTQyLjE0OFpNMjc1LjkwMSAxNS4yMzU5QzI4MC45NzcgMTQuNTg3OSAyODUuMDggMTguMDQzNiAyODUuMDgxIDIyLjc5NTRMMjg0LjIxNyA3NC40MTk1QzI4NC4xMDkgNzkuMTcxNSAyNzkuODk3IDgzLjI3NTUgMjc0LjgyMSA4My43MDc1TDIwMC44NDEgODkuNTM5NkwxODcuNzczIDk3Ljc0NzZMMTg2LjgwMSA5MC42MTk3QzE4Mi4xNTcgOTEuMDUxNiAxNzguNDg1IDg3LjcwMzggMTc4LjQ4NSA4My4yNzU5VjM0LjY3NTNDMTc4LjQ4NSAzMC4xMzk1IDE4Mi4yNjUgMjYuMDM1NyAxODYuOTA5IDI1LjQ5NTZMMjc1Ljc5MiAxNS4yMzU5SDI3NS45MDFaTTIxOS43NDEgMzEuNTQzNUwyMDEuODEzIDc5LjA2NEwyMDcuMTA1IDc4Ljg0NzJMMjEyLjYxMyA2NC4yNjgxTDIyNi41NDQgNjMuNTExM0wyMzIuMDUzIDc3Ljg3NTVWNzcuNzY4MUwyNDAuNjkzIDc3LjQ0MzlMMjIyLjc2NSAzMS4yMTkzTDIxOS43NDEgMzEuNTQzNVpNMjQxLjg4MSAyOS4zODMzTDI0MS41NTcgNjQuOTE1NkgyNTMuMjIxTDI1My41NDQgMjguMzAzMkwyNDEuODgxIDI5LjM4MzNaTTIyNC42MDEgNTguNzU5M0wyMTQuNTU3IDU5LjI5OTNMMjE5LjYzMyA0NS45MDc3TDIyNC42MDEgNTguNzU5M1oiIGZpbGw9ImJsYWNrIi8+PC9zdmc+",
    "sourceName": "AI风月\n💞",
    "sourceUrl": "https://aifun.ltd"
  },
  {
    "articleStyle": 1,
    "customOrder": 40,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": ".thumb-block",
    "ruleContent": "body@all\n<js>var URL=result.match(/\\('(https:.*?\\.*mp4\\?.*?)'/)[1];\nresult = URL.replace(/\\\\/g,\"\");\nresult =\"<video src=\"+result+\" width=\\\"100%\\\" height=\\\"auto\\\" autoplay      muted controls>  </video>\"\n</js>",
    "ruleImage": "img@data-src",
    "ruleLink": "tag.a.0@href",
    "ruleNextPage": "class.no-page next-page@href",
    "rulePubDate": "{{@@class.duration@text}}",
    "ruleTitle": "a@title",
    "singleUrl": false,
    "sortUrl": "//搜索一设置源变量后再重进刷新下就行\n搜索一::/?k={{(source.getVariable()==''||source.getVariable()==null)?source.setVariable(''):\"\"}}{{source.getVariable()}}&p=\n\n\n//搜索二直接改搜索栏里的“k=”后面的文字就行\n搜索二::/?k=\n首页::/new/{{page}}\n说中文的色情::/lang/chinese/{{page}}\n成熟::/c/Mature-38/{{page}}\n出轨::/c/Cuckold-237/{{page}}\n调教::/c/Femdom-235/{{page}}\n肛交::/c/Anal-12/{{page}}\n家庭乱搞::/c/Fucked_Up_Family-81/{{page}}\n巨乳::/c/Big_Tits-23/{{page}}\n巨臀::/c/Big_Ass-24/{{page}}\n口交::/c/Blowjob-15/{{page}}\n美臀::/c/Ass-14/{{page}}\n女同::/c/Lesbian-26/{{page}}\n少女::/c/Teen-13/{{page}}\n中出::/c/Creampie-40/{{page}}\n亚洲::/c/Asian_Woman-32/{{page}}",
    "sourceComment": "https://penzu.com/public/42071993地址发布页",
    "sourceGroup": "R-18可用免翻,可用",
    "sourceIcon": "https://i.postimg.cc/NjQmTCJ5/1629968589491.png",
    "sourceName": "玉羞园(免翻已修复)",
    "sourceUrl": "https://tt.yxy311.icu/"
  },
  {
    "articleStyle": 1,
    "customOrder": 41,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": ".col-inner",
    "ruleContent": "blockquote,iframe,#gallery-1@html##</?a.*?>",
    "ruleImage": "img@src",
    "ruleLink": "a@href",
    "ruleNextPage": "a[aria-label=\"Next\"]@href",
    "ruleTitle": "h5@text",
    "shouldOverrideUrlLoading": "if (!/bisniscpm.asia/.test(url)) {\n    java.openUrl(url);\n    true;\n}",
    "singleUrl": false,
    "sortUrl": "Video Cosplay::https://cosplaytele.com/category/video-cosplay/\n\nCosplay Nude::https://cosplaytele.com/category/nude/\nCosplay Ero::https://cosplaytele.com/category/no-nude/\nCosplay::https://cosplaytele.com/category/cosplay/\n\n24 hours::https://cosplaytele.com/24-hours/\n3 day::https://cosplaytele.com/3-day/\n7 Day::https://cosplaytele.com/7-day/\nLive Sex Cams::https://shorturl.at/bIMCS\nUncensored JavHD::https://r.trwl1.com/c1/3a7c0a31-16c1-4983-add6-a8758b7c30d1",
    "sourceGroup": "短篇视频,1,R-18可用需翻,cos",
    "sourceIcon": "https://cosplaytele.com/wp-content/uploads/2024/01/293172358_1027749337945791_5526464405172981062_n.png",
    "sourceName": "cosplaytele",
    "sourceUrl": "https://cosplaytele.com/",
    "style": "@font-face { font-family: 'Custom'; src: url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&display=swap'); }\n* { font-family: 'Custom', sans-serif; }\n\ninput[readonly] {\n    display: none;\n}\n\n/* 文本样式 */\nblockquote {\n    width: 92% !important;\n    margin: 15px auto 20px auto;\n    padding: 5% 4%;\n    color: #f0f0f0;\n    background: linear-gradient(145deg, #3a3a3a, #2a2a2a);\n    border-radius: 12px;\n    line-height: 1.7;\n    font-size: 16px;\n    box-shadow: 0 4px 12px rgba(0,0,0,0.3);\n    border-left: 4px solid #ff4081;\n}\n\n/* 视频容器 */\niframe[src*=\"cossora.stream\"] {\n    width: 98% !important;\n    height: 240px !important;\n    max-width: 720px;\n    display: block;\n    margin: 20px auto;\n    border-radius: 12px;\n    box-shadow: 0 6px 18px rgba(0,0,0,0.4);\n    background: #000;\n}\n\n/* 图片容器 - 改为上下滚动布局 */\n#gallery-1.gallery {\n    display: flex !important;\n    flex-direction: column !important;\n    flex-wrap: nowrap !important;\n    overflow-x: hidden !important;\n    overflow-y: auto !important;\n    max-height: none !important;\n    padding: 8px 4px !important;\n    margin: 0 !important;\n    width: 100% !important;\n    background: #1a1a1a;\n    border-radius: 12px;\n}\n\n/* 图片项 - 上下排列 */\n.gallery-item {\n    display: block !important;\n    width: 100% !important;\n    margin: 0 0 20px 0 !important;\n    padding: 0 !important;\n    box-sizing: border-box !important;\n    break-inside: avoid !important;\n    page-break-inside: avoid !important;\n    -webkit-column-break-inside: avoid !important;\n}\n\n/* 高分辨率图片样式 */\nimg {\n    width: 100% !important;\n    max-width: 100% !important;\n    height: auto !important;\n    min-height: 300px !important;\n    max-height: 800px !important;\n    object-fit: contain !important;\n    object-position: center !important;\n    border-radius: 12px !important;\n    vertical-align: middle !important;\n    display: block !important;\n    margin: 0 auto !important;\n    background: #2a2a2a !important;\n    box-shadow: 0 4px 16px rgba(0,0,0,0.5) !important;\n    transition: transform 0.3s ease !important;\n}\n\n/* 图片悬停效果 */\nimg:hover {\n    transform: scale(1.02) !important;\n}\n\n/* 提升图片质量 - 尝试加载更高分辨率的图片 */\nimg[src*=\"-300x\"] {\n    content: attr(data-src) !important;\n}\n\n/* 加载指示器 */\nimg:not([src]) {\n    background: linear-gradient(90deg, #2a2a2a 25%, #3a3a3a 50%, #2a2a2a 75%) !important;\n    background-size: 200% 100% !important;\n    animation: loading 1.5s infinite !important;\n}\n\n@keyframes loading {\n    0% { background-position: 200% 0; }\n    100% { background-position: -200% 0; }\n}\n\n/* 滚动条样式 */\n#gallery-1.gallery::-webkit-scrollbar {\n    width: 6px;\n}\n\n#gallery-1.gallery::-webkit-scrollbar-track {\n    background: #2a2a2a;\n    border-radius: 3px;\n}\n\n#gallery-1.gallery::-webkit-scrollbar-thumb {\n    background: #ff4081;\n    border-radius: 3px;\n}\n\n#gallery-1.gallery::-webkit-scrollbar-thumb:hover {\n    background: #ff79a9;\n}\n\n/* 响应式调整 */\n@media screen and (min-width: 768px) {\n    #gallery-1.gallery {\n        padding: 12px 8px !important;\n    }\n    \n    .gallery-item {\n        margin-bottom: 25px !important;\n    }\n    \n    img {\n        max-height: 900px !important;\n    }\n}\n\n/* 暗色主题适配 */\nbody.dark #gallery-1.gallery {\n    background: #0a0a0a;\n}\n\nbody.dark img {\n    background: #1a1a1a !important;\n}"
  },
  {
    "articleStyle": 0,
    "customOrder": 41,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "版本",
    "sourceIcon": "",
    "sourceName": "七猫",
    "sourceUrl": "https://www.33ccpp.com/"
  },
  {
    "articleStyle": 2,
    "customOrder": 42,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\n\t\"referer\": \"{{baseUrl}}\"\n\t}",
    "injectJs": "",
    "lastUpdateTime": 1770862647307,
    "loadWithBaseUrl": true,
    "ruleArticles": ".index-group-content > .index-imgs",
    "ruleContent": "<!-- 介绍区域 -->\n<div class=\"intro-section\">\n    {{@@h1@all}}\n    <p class=\"intro\">\n      {{@@[name=\"description\"]@content}}\n    </p>\n    {{@@.text-primary@all}}\n</div>\n\n<!-- 套图区域 -->\n<div id=\"box\" class=\"gallery-section\">\n<script>\nbox=document.getElementById(\"box\");\nvar html;\ndata=\"{{@@#imgData@value}}\";\nimgs = data.split(\"|\");\n\tfor (let i = 0; i < imgs.length; i ++){\n\t  html += '<img src=\"'+atob(imgs[i])+'\" />';\n\t}\n\tbox.innerHTML+=html;\n</script>\n</div>",
    "ruleImage": "img@data-original",
    "ruleLink": "a.0@href",
    "ruleNextPage": "[aria-label=\"Next\"]@href",
    "rulePubDate": "ownText##\\?\\..*",
    "ruleTitle": ".index-imgcontent-title@text",
    "singleUrl": false,
    "sortUrl": "最新::/Articles\n无圣光::/Articles/Categories/1\n凸凹图::/Articles/Categories/2\n靓人体::/Articles/Categories/3\n写真集::/Articles/Categories/4\n\n搜索::/Articles/Search?wd={{String(source.variable) || \"美女\"}}",
    "sourceComment": "www.tuaow.top\n\n备用网址www.24ao.cc",
    "sourceGroup": "美女",
    "sourceIcon": "https://www.tuao.cc/Files/webconfigs/638254764734047980.png",
    "sourceName": "凸凹吧",
    "sourceUrl": "https://www.24ao.cc/",
    "style": "body {\n  margin: 0;\n  padding: 0;\n  font-family: sans-serif;\n}\n\n/* 介绍区域：白色背景 */\n.intro-section {\n  background-color: #ffffff;\n  color: #333;\n  padding: 16px;\n  /* 可选：加一点阴影分隔 */\n  box-shadow: 0 2px 4px rgba(0,0,0,0.05);\n}\n\n.intro-section h1 {\n  font-size: 1.5rem;\n  margin-top: 0;\n}\n\n.intro-section p {\n  font-size: 1rem;\n  line-height: 1.6;\n}\n\n/* 套图区域：黑色背景 */\n.gallery-section {\n  background-color: #000000;\n  padding: 12px; /* 图片和边缘留点空隙 */\n}\n\n.gallery-section img {\n  width: 100%;\n  height: auto;\n  display: block;\n  margin-bottom: 12px;\n  border-radius: 8px; /* 可选圆角 */\n}\n\n.text-primary {\n  display: flex;\n  flex-wrap: wrap;\n  align-items: center;\n  gap: 6px;\n}\n\n.text-primary .glyphicon-time {\n  flex-basis: 100%;\n  margin-top: 6px;\n}"
  },
  {
    "articleStyle": 1,
    "customOrder": 43,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "header": "{\"User-Agent\":\"Mozilla/5.0 (Linux; Android 11; PCAM10 Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4103.106 Mobile Safari/537.36\"} ",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "loginUrl": "https://czy.yzfnb6.help/cn/home/web/index.php/vod/play/id/1177871/sid/1/nid/1.html",
    "ruleArticles": "[class=\"H5__content\"]@[class=\"video__wrap\"]@a",
    "ruleContent": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<title>内容提取-双模版</title>\n\n<script src=\"https://code.jquery.com/jquery-3.6.0.min.js\"></script>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.3/viewer.min.css\" />\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.3/viewer.min.js\"></script>\n<style>\n    body {font-family: Arial, sans-serif;font-size: 16px;}\n    #title, #page, #loading-status {margin: 0 auto;font-size: 20px;text-align: center;}\n    #description, #urls, #video-url, #video-sources, #messages {width: 100%;max-width: 800px;margin: 1.5px auto;font-size: 14px;text-align: left;word-wrap: break-word;white-space: pre-wrap;}\n    #text, #text :not(img), #text img + * {text-indent: 2em;width: 100%;font-size: 16px;line-height: 1.5em;margin-top: 0;margin-bottom: 0;word-wrap: break-word;white-space: pre-wrap;}\n    img, #text img {width: 100%;height: auto;display: block;margin-bottom: 1.5px;}\n    .flex-container {display: flex;justify-content: center;align-items: center;gap: 10px;margin: 1.5px 0;font-size: 14px;}\n    button, select {flex: 1 1 31%; padding: 3px;border: 1px solid #ccc;border-radius: 5px;box-sizing: border-box;cursor: pointer;background-color: #f9f9f9;transition: background-color 0.3s ease;margin: 1.5px;min-width: 0;font-size: 14px;}\n    #url-select, #video-source-select {flex: 1 1 100%; margin-left: 0;margin-right: 0;text-align: center;}\n    #video-element {width: 100%;height: auto;}\n    textarea {width: 100%;height: auto;min-height: 100px;box-sizing: border-box;resize: vertical;}\n    .error, .warn {color: red;}\n    #urls,#messages,#debug-info,#video-url,#video-container,#video-source-select,#images,#text {display:none;}\n</style>\n</head>\n<body>\n    <h3 id=\"title\">{{@@title@text||h1.0@text||h2.0@text||.title.0@text##高清在线观看|-国产剧| - 专享影视| - 热门高清|影视大全|海外华人|高清1080p|无广告影院|\\|}}</h3>\n    <p id=\"description\">{{@@.info.0@html||.jianjie@html}}</p>\n    <p id=\"page\">共<span id=\"total-pages\">1</span>页</p>\n    <p id=\"loading-status\" style=\"display:none;\"></p>\n    <div class=\"flex-container\" id=\"loading-buttons\" style=\"display:none;\">\n        <button id=\"prev-page-btn\">上一页</button>\n        <button id=\"next-page-btn\">下一页</button>\n        <button id=\"auto-load-btn\">自&nbsp;&nbsp;动</button>\n    </div>\n    <div class=\"flex-container\">\n        <select id=\"url-select\" style=\"display:none;\"></select>\n    </div>\n    <div class=\"flex-container\">\n        <button id=\"toggle-urls-btn\">显/隐网址</button>\n        <button id=\"toggle-messages-btn\">显/隐信息</button>\n        <button id=\"toggle-debug-btn\">显/隐调试</button>\n    </div>\n    <div id=\"urls\"></div>\n    <div id=\"messages\"></div>\n    <div id=\"debug-info\"></div>\n    <div id=\"video-url\"></div>\n    <div id=\"video-container\">\n        <video id=\"video-element\" controls preload=\"auto\" width=\"640\" height=\"264\">\n            <source id=\"video-source\" src=\"\" type=\"\">\n            您的浏览器不支持 video 标签。\n        </video>\n    </div>\n    <div class=\"flex-container\">\n        <select id=\"video-source-select\" onchange=\"updateVideoSource()\"></select>\n    </div>\n    <div id=\"images\"></div>\n    <div id=\"text\"></div>\n    <script>\nconst config = {    \n    videoSelector: 'body', // 视频选择器\n    imgSelector: '.gridlane-box-inside img', // 图片选择器\n    textSelector: '#content', // 文本选择器\n    debugSelector: '.player-wrapper', // 调试信息选择器\n    swapImageAttributes: false, // 是否交换图片属性\n    delayTime: 1500, // 延迟提取时间\n    retryDelayTime: 1500, // 重试加载延迟时间\n    maxLoadAttempts: 3, // 最大加载次数\n    autoLoading: false, // true自动模式，false单页模式\n    debugOnce: 0, // 只在特定索引输出一次调试信息\n         /* -网页拼接-*/    \n    totalPagesText: '{{@@.pager@li.-3@a@textNodes}}', // 总页码\n    urlSuffixToRemove: /\\.aspx$/, // 移除url后缀\n    pageUrlText: '{urlPrefix}p{i}.aspx', // 拼接URL模板        \n        /* -以上拼接模式（网址需要拼接）-*/\n        /* -上下分割线-*/\n        /* -以下列表模式（地址与目录对应，比如视频、漫画）-*/   \n    ListMode: true, // true网址列表模式，false网址拼接模式    \n    initialUrls: `{{@@#sort-item-5.0@a@href}}`, // 网址\n    initialUrlsName: `{{@@#sort-item-5.0@a@span@text}}`, // 网址名称\n    sourceurl: '', // 来源URL前缀\n};\n\nlet videoSources = [];\nlet loadAttempts = {};\nlet urls = [];\nlet imageBox;\nlet textBox;\nlet currentPageIndex = 0;\nlet canLoadNextPage = true;\nlet autoLoadInProgress = false;\n\n// 构建URL列表\nfunction buildUrls(totalPages, baseUrl) {\n    let initialUrlsArray = config.initialUrls.trim().split('\\n').filter(url => url.trim() !== '');\n    let initialUrlsNameArray = config.initialUrlsName.trim().split('\\n').filter(name => name.trim() !== '');\n\n    if (config.ListMode && initialUrlsArray.length > 0) {\n        if (initialUrlsArray.length !== initialUrlsNameArray.length) {\n            $('#messages').append(`<span class=\"warn\">警告：initialUrls 和 initialUrlsName 的长度不匹配。</span><br>`);\n        }\n\n        urls = initialUrlsArray.map(url => {\n            if (config.sourceurl && url.startsWith('/') && !/^https?:\\/\\//i.test(url)) {\n                return config.sourceurl.replace(/\\/$/, '') + url;\n            } else {\n                return url;\n            }\n        });\n\n        urls.forEach((url, index) => {\n            const name = initialUrlsNameArray[index] || `第 ${index + 1} 页`;\n            $('#url-select').append(`<option value=\"${index}\">${name}</option>`);\n            $('#urls').append(`<div>${name}: ${url}</div>`);\n        });\n    } else {\n        if (totalPages === 1) {\n            urls.push(baseUrl);\n        } else {\n            urls.push(baseUrl);\n            for (let i = 2; i <= totalPages; i++) {\n                urls.push(config.pageUrlText.replace('{urlPrefix}', baseUrl.replace(config.urlSuffixToRemove, '').replace(/\\/$/, '')).replace('{i}', i));\n            }\n        }\n\n        urls.forEach((url, index) => {\n            const name = `第 ${index + 1} 页`;\n            $('#url-select').append(`<option value=\"${index}\">${name}</option>`);\n            $('#urls').append(`<div>${name}: ${url}</div>`);\n        });\n    }\n\n    $('#total-pages').text(urls.length);\n    toggleNavigationButtons();\n}\n\nfunction normalizeUrl(url) {\n    if (typeof url!== 'string' ||!url.trim()) return '';\n    url = url.replace(/\\\\u[\\dA-F]{4}/gi, (match) => String.fromCharCode(parseInt(match.replace(/\\\\u/g, ''), 16)));\n    url = decodeURIComponent(url);\n    url = url.replace(/^http:\\/([^/])/, 'http://$1'); // 修正 http:/ 协议部分\n    url = url.replace(/^https:\\/([^/])/, 'https://$1'); // 修正 https:/ 协议部分\n    return url;\n}\n\n// 清空容器\nfunction clearContainers() {\n    $('#messages').empty();\n    $('#images').empty();\n    $('#text').empty();\n}\n\n// 更新图片的src属性\nfunction updateImageSrc(elements, shouldSwap) {\n    elements.each(function () {\n        const $this = $(this);\n        const attrsToUpdate = {};\n        if (shouldSwap) {\n            ['data-original', 'data-src', 'data-url'].forEach(attr => {\n                if ($this.attr(attr)) {\n                    attrsToUpdate['src'] = $this.attr(attr);\n                }\n            });\n        }\n        $this.attr(attrsToUpdate);\n    });\n    return elements;\n}\n\n// 切换导航按钮和选择框的显示\nfunction toggleNavigationButtons() {\n    if ($('#url-select option').length > 1  && !config.autoLoading) {\n        $('#loading-buttons').show();\n        $('#url-select').show();\n    } else {\n        $('#loading-buttons').hide();\n        $('#url-select').hide();\n    }\n}\n\n// 显示加载状态\nfunction showLoadingStatus(pageNumber) {\n    const selectedOption = $('#url-select option:selected').text();\n    $('#loading-status').text(`正在加载：${selectedOption}`).show();\n}\n\n// 隐藏加载状态\nfunction hideLoadingStatus() {\n    $('#loading-status').hide();\n}\n\n// 内容提取函数内容\nfunction loadContent(index) {\n    if (index < 0 || index >= urls.length || !canLoadNextPage) return;\n    canLoadNextPage = false;\n    currentPageIndex = index;\n    $('#url-select').val(index);\n    $('#messages').append(`<div>当前地址: <span class=\"warn\">${urls[index]}</span> </div>`);\n    if (autoLoadInProgress) {\n        showLoadingStatus(index + 1);\n    }\n    $.ajax({\n        url: urls[index],\n        type: 'GET',\n        success: function (data) {\n            try {\n                const $data = $(data);\n                let updatedHtmlContent = data.replace(/(['\"])(\\/\\/)(?!\\/)/g, '$1https://')\n                    .replace(/src=\"upload/gi, 'src=\"/upload')\n                    .replace(/style=[\"'][^'\"]+[\"']/gi, '')\n                    .replace(/\\\\\\//g, '/');\n                const parser = new DOMParser();\n                const doc = parser.parseFromString(updatedHtmlContent, \"text/html\");\n\n                  // 添加调试标签输出信息\n                if (config.debugOnce === index) {\n                    const debugElements = $(doc).find(config.debugSelector);\n                    if (debugElements.length > 0) {\n                        const debugContents = $('<pre>').html(debugElements.clone().wrapAll('<div/>').parent().html()).html();\n                        $('#debug-info').html(`<span class=\"warn\">调试信息: <textarea rows=\"10\" cols=\"80\">${debugContents}</textarea></span>`);\n                    } else {\n                        $('#debug-info').html(`<span class=\"warn\">调试信息: <textarea rows=\"10\" cols=\"80\">调试信息未提取到内容，请检查选择器！</textarea></span>`);\n                    }\n                }\n\n                // 方法1：video标签获取视频地址\n                const videoContents = $(doc).find(config.videoSelector);\n                const videoTags = $(videoContents).find('video');\n                videoTags.each(function () {\n                    const videosrc = $(this).attr('src') || $(this).attr('data-src') || $(this).attr('data-original') || '';\n                    if (videosrc) {\n                        videoSources.push(videosrc);\n                    }\n                });\n                \n                // 方法2：source标签获取视频地址\n                const sources = $(videoContents).find('source');\n                sources.each(function () {\n                    const sourceSrc = $(this).attr('src') || $(this).attr('data-src') || $(this).attr('data-original') || '';\n                    if (sourceSrc) {\n                        videoSources.push(sourceSrc);\n                    }\n                });\n                \n                // 方法3：正则表达式获取视频地址\n                const regex = /['\"]https?[^'<>\"]+\\.(m3u8|mp4|webm|ogg|flv|mp3|m4a|wav|ape|flac)['\"]/ig;\n                const matches = data.match(regex);\n                if (matches) {\n                    const uniqueMatches = matches.filter((value, idx, self) => self.indexOf(value) === idx);\n    videoSources = videoSources.concat(uniqueMatches.map((match) => {\n        // 使用replace删除引号\n                const urlWithoutQuotes = match.replace(/['\"]/g, '');\n                return normalizeUrl(urlWithoutQuotes);\n                          }));\n                }\n\n                videoSources = videoSources.map(src => normalizeUrl(src.replace(/\\\\+/g, '')));\n                videoSources = [...new Set(videoSources)];\n\n                if (videoSources.length > 0) {\n                    $('#messages').append(`<span>成功提取到视频，找到 ${videoSources.length} 个视频。</span><br>`);\n                    videoSources.forEach((src, idx) => {\n                        $('#messages').append(`<div>视频地址:<span class=\"warn\"> ${src}</span><br></div>`);\n                        $('#video-source-select').append(`<option value=\"${idx}\">视频源 ${idx + 1}</option>`);\n                    });\n                    \n                    if (videoSources.length == 1) {\n                        $('#video-container').show();\n                        $('#video-url').show();\n                        $('#video-source-select').hide();\n                        updateVideoSource(); // 自动更新视频源\n                    } else if (videoSources.length > 1) {\n                        $('#video-container').show();\n                        $('#video-url').show();\n                        $('#video-source-select').show();\n                        updateVideoSource(); // 默认选择第一个视频源\n                    } else {\n                        $('#video-container').hide();\n                        $('#video-url').hide();\n                        $('#video-source-select').hide();\n                    }\n                } else {\n                    $('#messages').append(`<span class=\"warn\">未找到视频源。</span><br>`);\n                    $('#video-container').hide();\n                    $('#video-url').hide();\n                    $('#video-source-select').hide();\n                }\n\n                // 标签获图片\n                const $imgContents = $(doc).find(config.imgSelector);\n                const shouldSwap = config.swapImageAttributes;\n                const newContents = updateImageSrc($imgContents.clone(), shouldSwap);\n                $('#images').append(newContents).show();\n                if (newContents.length > 0) {\n                    $('#messages').append(`<span>成功提取图片，共 ${newContents.length} 张。</span><br>`);\n                    newContents.each(function () {\n                        const imgSrc =$(this).attr('src') || $(this).attr('data-original') || $(this).attr('data-src') || $(this).attr('data-url');\n                        $('#messages').append(`<div>地址:<span class=\"warn\"> ${imgSrc}</span><br></div>`);\n                    });\n                } else {\n                    $('#messages').append(`<span class=\"warn\">未提取到图片。</span><br>`);\n                }\n\n                // 标签获图文\n                const textContents = $(doc).find(config.textSelector).map(function () {\n                    const $currentContents = $(this);\n                    $currentContents.find('img + br, script, video, source').remove();\n                    $currentContents.html($currentContents.html().replace(/>\\s+/gi, '>').replace(/<\\/?br\\s*([^>]*)\\s*\\/?>/gi, '\\n').replace(/\\n+/g, '\\n'));\n                    return $currentContents.html();\n                }).get().join('');\n                if (textContents.trim()) {\n                    $('#text').append(`<span>${textContents}</span><br>`).show();\n                    $('#messages').append(`<span>成功提取图文。</span><br>`);\n                } else {\n                    $('#messages').append(`<span class=\"warn\">未提取到图文。</span><br>`);\n                }\n                \n                \n                if (autoLoadInProgress && currentPageIndex < urls.length - 1) {\n                    setTimeout(() => { \n                        canLoadNextPage = true;\n                        loadContent(currentPageIndex + 1); \n                    }, config.delayTime);\n                } else {\n                    canLoadNextPage = true;\n                    if (autoLoadInProgress) {\n                        hideLoadingStatus();\n                    }\n                }\n            } catch (parseError) {\n                $('#messages').append(`<span class=\"error\">解析页面内容时发生错误: ${parseError.message}</span><br>`);\n                handleLoadFailure(urls, index);\n            } finally {\n                if (imageBox) imageBox.viewer.update();\n                if (textBox) textBox.viewer.update();\n            }\n        },\n        error: function (jqXHR, textStatus, errorThrown) {\n            let errorMessage = `内容加载失败: ${urls[index]}`;\n            switch (textStatus) {\n                case 'timeout':\n                    errorMessage += ', 请求超时';\n                    break;\n                case 'abort':\n                    errorMessage += ', 请求被取消';\n                    break;\n                case 'parsererror':\n                    errorMessage += ', 解析响应出错';\n                    break;\n                default:\n                    errorMessage += `, 状态码: ${jqXHR.status}, 错误信息: ${errorThrown}`;\n                    break;\n            }\n            $('#messages').append(`<span class=\"error\">${errorMessage}</span><br>`);\n            handleLoadFailure(urls, index);\n        }\n    });\n}\n\n// 处理加载失败的情况\nfunction handleLoadFailure(urls, index) {\n    if (!loadAttempts[urls[index]]) {\n        loadAttempts[urls[index]] = 1;\n    } else {\n        loadAttempts[urls[index]]++;\n    }\n    if (loadAttempts[urls[index]] <= config.maxLoadAttempts) {\n        const retryMessage = `第${index + 1}页加载失败，正在进行第${loadAttempts[urls[index]]}次加载！`;\n        $('#messages').append(`<span class=\"error\">${retryMessage}</span><br>`);\n        setTimeout(() => { \n            canLoadNextPage = true;\n            loadContent(index); \n        }, config.retryDelayTime);\n    } else {\n        const finalErrorMessage = `第${index + 1}页加载失败，已达到最大尝试次数(${config.maxLoadAttempts})！`;\n        $('#messages').append(`<span class=\"error\">${finalErrorMessage}</span><br>`);\n        if (autoLoadInProgress && currentPageIndex < urls.length - 1) {\n            setTimeout(() => { \n                canLoadNextPage = true;\n                loadContent(currentPageIndex + 1); \n            }, config.delayTime);\n        } else {\n            canLoadNextPage = true;\n            if (autoLoadInProgress) {\n                hideLoadingStatus();\n            }\n        }\n    }\n}\n\n// 更新视频源\nfunction updateVideoSource() {\n    const selectedIndex = parseInt(document.getElementById('video-source-select').value);\n    const selectedSource = videoSources[selectedIndex];\n    document.getElementById('video-url').textContent = `视频地址:\\n ${selectedSource}`;\n\n    // 设置 video-source 的 src 属性\n    const videoSourceElement = document.getElementById('video-source');\n    videoSourceElement.src = selectedSource;\n\n    // 更新 video 元素的 src 属性\n    const videoElement = document.getElementById('video-element');\n    videoElement.load();\n\n    // 添加调试信息\n    $('#messages').append(`<span>更新视频源为: ${selectedSource}</span><br>`);\n}\n\n// 函数执行主体\n$(document).ready(function () {\n    imageBox = document.getElementById('images');\n    textBox = document.getElementById('text');\n    if (imageBox && textBox) {\n        new Viewer(imageBox, { title: true, interval: 2000 });\n        new Viewer(textBox, { title: true, interval: 2000 });\n    }\n\n    const totalPagesText = config.totalPagesText;\n    const totalPages = parseInt(totalPagesText, 10) || 1;\n    const baseUrl = '{{baseUrl}}';\n    \n    clearContainers();\n    $('#urls').empty();\n    $('#debug-info textarea').empty();   \n    $('#video-url').empty().hide();\n    $('#video-container').hide();\n    $('#video-source-select').empty().hide();\n    \n    buildUrls(totalPages, baseUrl);\n\n    const urlSelect = document.getElementById('url-select');\n    if (urlSelect.options.length > 0) {\n        urlSelect.value = '0'; \n        \n        if (config.autoLoading) {\n            autoLoadInProgress = true;\n            for (let i = 0; i < urls.length; i++) {\n                loadContent(i);\n            }\n        } else {\n            loadContent(0);\n        }\n    } else {\n        loadContent(0);\n    }\n\n    $('#url-select').change(function () {\n        clearContainers();\n        const selectedIndex = parseInt($(this).val());\n        loadContent(selectedIndex);\n    });\n    $('#prev-page-btn').click(function () {\n        clearContainers();\n        if (currentPageIndex > 0) {\n            loadContent(currentPageIndex - 1);\n        }\n    });\n    $('#next-page-btn').click(function () {\n        clearContainers();\n        if (currentPageIndex < urls.length - 1) {\n            loadContent(currentPageIndex + 1);\n        }\n    });\n    $('#auto-load-btn').click(function () {\n        autoLoadInProgress = true;\n        showLoadingStatus(1); \n        for (let i = currentPageIndex + 1; i < urls.length; i++) {\n            loadContent(i);\n        }\n    });\n    $('#toggle-messages-btn').click(function () { $('#messages').toggle(); });\n    $('#toggle-urls-btn').click(function () { $('#urls').toggle(); });\n    $('#toggle-debug-btn').click(function () { $('#debug-info').toggle(); });\n});\n    </script>\n</body>\n</html>",
    "ruleImage": "img@src",
    "ruleLink": "a@href",
    "ruleNextPage": "page||text.下一页@href",
    "rulePubDate": "p.-1@text\n",
    "ruleTitle": "h3.-1@text",
    "singleUrl": false,
    "sortUrl": "搜索::https://czy.yzfnb6.help/cn/home/web/index.php/vod/search.html?wd={{source.getVariable()}}\n最新上传::/cn/home/web/index.php/label/new/page/{{page}}.html\n月排行::/cn/home/web/index.php/label/hot_month/page/{{page}}.html\n日排行::/cn/home/web/index.php/label/hot_day/page/{{page}}.html\n周排行::/cn/home/web/index.php/label/hot_week/page/{{page}}.html\n熟母少妇::/cn/home/web/index.php/vod/type/id/20/page/{{page}}.html\n网红直播::/cn/home/web/index.php/vod/type/id/21/page/{{page}}.html\n自拍偷拍::/cn/home/web/index.php/vod/type/id/22/page/{{page}}.html\n强奸乱伦::/cn/home/web/index.php/vod/type/id/23/page/{{page}}.html\n高清国产::/cn/home/web/index.php/vod/type/id/24/page/{{page}}.html\n韩国专区::/cn/home/web/index.php/vod/type/id/25/page/{{page}}.html\n日本有码::/cn/home/web/index.php/vod/type/id/26/page/{{page}}.html\n日本无码::/cn/home/web/index.php/vod/type/id/27/page/{{page}}.html\n欧美情色::/cn/home/web/index.php/vod/type/id/28/page/{{page}}.html\n动漫卡通::/cn/home/web/index.php/vod/type/id/29/page/{{page}}.html\n三级伦理::/cn/home/web/index.php/vod/type/id/30/page/{{page}}.html",
    "sourceComment": "By小新\n永久地址：https://bqm.avds8.com/g/\nhttps://rlblsm.yzfnb4.lat/cn/home/web/\nhttps://qrb.yzfnb3.ink/cn/home/web/\nhttps://qrb.yzfnb3.ink/cn/home/web/",
    "sourceGroup": "R-18可用免翻,1",
    "sourceIcon": "",
    "sourceName": "优质粉嫩鲍",
    "sourceUrl": "https://qrb.yzfnb3.ink"
  },
  {
    "articleStyle": 1,
    "customOrder": 44,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "header": "{\"User-Agent\":\"Mozilla/5.0 (Linux; Android 11; PCAM10 Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4103.106 Mobile Safari/537.36\"} ",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "loginUrl": "https://czy.yzfnb6.help/cn/home/web/index.php/vod/play/id/1177871/sid/1/nid/1.html",
    "ruleArticles": "[class=\"H5__content\"]@[class=\"video__wrap\"]@a",
    "ruleContent": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<title>内容提取-双模版</title>\n\n<script src=\"https://code.jquery.com/jquery-3.6.0.min.js\"></script>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.3/viewer.min.css\" />\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.3/viewer.min.js\"></script>\n<style>\n    body {font-family: Arial, sans-serif;font-size: 16px;}\n    #title, #page, #loading-status {margin: 0 auto;font-size: 20px;text-align: center;}\n    #description, #urls, #video-url, #video-sources, #messages {width: 100%;max-width: 800px;margin: 1.5px auto;font-size: 14px;text-align: left;word-wrap: break-word;white-space: pre-wrap;}\n    #text, #text :not(img), #text img + * {text-indent: 2em;width: 100%;font-size: 16px;line-height: 1.5em;margin-top: 0;margin-bottom: 0;word-wrap: break-word;white-space: pre-wrap;}\n    img, #text img {width: 100%;height: auto;display: block;margin-bottom: 1.5px;}\n    .flex-container {display: flex;justify-content: center;align-items: center;gap: 10px;margin: 1.5px 0;font-size: 14px;}\n    button, select {flex: 1 1 31%; padding: 3px;border: 1px solid #ccc;border-radius: 5px;box-sizing: border-box;cursor: pointer;background-color: #f9f9f9;transition: background-color 0.3s ease;margin: 1.5px;min-width: 0;font-size: 14px;}\n    #url-select, #video-source-select {flex: 1 1 100%; margin-left: 0;margin-right: 0;text-align: center;}\n    #video-element {width: 100%;height: auto;}\n    textarea {width: 100%;height: auto;min-height: 100px;box-sizing: border-box;resize: vertical;}\n    .error, .warn {color: red;}\n    #urls,#messages,#debug-info,#video-url,#video-container,#video-source-select,#images,#text {display:none;}\n</style>\n</head>\n<body>\n    <h3 id=\"title\">{{@@title@text||h1.0@text||h2.0@text||.title.0@text##高清在线观看|-国产剧| - 专享影视| - 热门高清|影视大全|海外华人|高清1080p|无广告影院|\\|}}</h3>\n    <p id=\"description\">{{@@.info.0@html||.jianjie@html}}</p>\n    <p id=\"page\">共<span id=\"total-pages\">1</span>页</p>\n    <p id=\"loading-status\" style=\"display:none;\"></p>\n    <div class=\"flex-container\" id=\"loading-buttons\" style=\"display:none;\">\n        <button id=\"prev-page-btn\">上一页</button>\n        <button id=\"next-page-btn\">下一页</button>\n        <button id=\"auto-load-btn\">自&nbsp;&nbsp;动</button>\n    </div>\n    <div class=\"flex-container\">\n        <select id=\"url-select\" style=\"display:none;\"></select>\n    </div>\n    <div class=\"flex-container\">\n        <button id=\"toggle-urls-btn\">显/隐网址</button>\n        <button id=\"toggle-messages-btn\">显/隐信息</button>\n        <button id=\"toggle-debug-btn\">显/隐调试</button>\n    </div>\n    <div id=\"urls\"></div>\n    <div id=\"messages\"></div>\n    <div id=\"debug-info\"></div>\n    <div id=\"video-url\"></div>\n    <div id=\"video-container\">\n        <video id=\"video-element\" controls preload=\"auto\" width=\"640\" height=\"264\">\n            <source id=\"video-source\" src=\"\" type=\"\">\n            您的浏览器不支持 video 标签。\n        </video>\n    </div>\n    <div class=\"flex-container\">\n        <select id=\"video-source-select\" onchange=\"updateVideoSource()\"></select>\n    </div>\n    <div id=\"images\"></div>\n    <div id=\"text\"></div>\n    <script>\nconst config = {    \n    videoSelector: 'body', // 视频选择器\n    imgSelector: '.gridlane-box-inside img', // 图片选择器\n    textSelector: '#content', // 文本选择器\n    debugSelector: '.player-wrapper', // 调试信息选择器\n    swapImageAttributes: false, // 是否交换图片属性\n    delayTime: 1500, // 延迟提取时间\n    retryDelayTime: 1500, // 重试加载延迟时间\n    maxLoadAttempts: 3, // 最大加载次数\n    autoLoading: false, // true自动模式，false单页模式\n    debugOnce: 0, // 只在特定索引输出一次调试信息\n         /* -网页拼接-*/    \n    totalPagesText: '{{@@.pager@li.-3@a@textNodes}}', // 总页码\n    urlSuffixToRemove: /\\.aspx$/, // 移除url后缀\n    pageUrlText: '{urlPrefix}p{i}.aspx', // 拼接URL模板        \n        /* -以上拼接模式（网址需要拼接）-*/\n        /* -上下分割线-*/\n        /* -以下列表模式（地址与目录对应，比如视频、漫画）-*/   \n    ListMode: true, // true网址列表模式，false网址拼接模式    \n    initialUrls: `{{@@#sort-item-5.0@a@href}}`, // 网址\n    initialUrlsName: `{{@@#sort-item-5.0@a@span@text}}`, // 网址名称\n    sourceurl: '', // 来源URL前缀\n};\n\nlet videoSources = [];\nlet loadAttempts = {};\nlet urls = [];\nlet imageBox;\nlet textBox;\nlet currentPageIndex = 0;\nlet canLoadNextPage = true;\nlet autoLoadInProgress = false;\n\n// 构建URL列表\nfunction buildUrls(totalPages, baseUrl) {\n    let initialUrlsArray = config.initialUrls.trim().split('\\n').filter(url => url.trim() !== '');\n    let initialUrlsNameArray = config.initialUrlsName.trim().split('\\n').filter(name => name.trim() !== '');\n\n    if (config.ListMode && initialUrlsArray.length > 0) {\n        if (initialUrlsArray.length !== initialUrlsNameArray.length) {\n            $('#messages').append(`<span class=\"warn\">警告：initialUrls 和 initialUrlsName 的长度不匹配。</span><br>`);\n        }\n\n        urls = initialUrlsArray.map(url => {\n            if (config.sourceurl && url.startsWith('/') && !/^https?:\\/\\//i.test(url)) {\n                return config.sourceurl.replace(/\\/$/, '') + url;\n            } else {\n                return url;\n            }\n        });\n\n        urls.forEach((url, index) => {\n            const name = initialUrlsNameArray[index] || `第 ${index + 1} 页`;\n            $('#url-select').append(`<option value=\"${index}\">${name}</option>`);\n            $('#urls').append(`<div>${name}: ${url}</div>`);\n        });\n    } else {\n        if (totalPages === 1) {\n            urls.push(baseUrl);\n        } else {\n            urls.push(baseUrl);\n            for (let i = 2; i <= totalPages; i++) {\n                urls.push(config.pageUrlText.replace('{urlPrefix}', baseUrl.replace(config.urlSuffixToRemove, '').replace(/\\/$/, '')).replace('{i}', i));\n            }\n        }\n\n        urls.forEach((url, index) => {\n            const name = `第 ${index + 1} 页`;\n            $('#url-select').append(`<option value=\"${index}\">${name}</option>`);\n            $('#urls').append(`<div>${name}: ${url}</div>`);\n        });\n    }\n\n    $('#total-pages').text(urls.length);\n    toggleNavigationButtons();\n}\n\nfunction normalizeUrl(url) {\n    if (typeof url!== 'string' ||!url.trim()) return '';\n    url = url.replace(/\\\\u[\\dA-F]{4}/gi, (match) => String.fromCharCode(parseInt(match.replace(/\\\\u/g, ''), 16)));\n    url = decodeURIComponent(url);\n    url = url.replace(/^http:\\/([^/])/, 'http://$1'); // 修正 http:/ 协议部分\n    url = url.replace(/^https:\\/([^/])/, 'https://$1'); // 修正 https:/ 协议部分\n    return url;\n}\n\n// 清空容器\nfunction clearContainers() {\n    $('#messages').empty();\n    $('#images').empty();\n    $('#text').empty();\n}\n\n// 更新图片的src属性\nfunction updateImageSrc(elements, shouldSwap) {\n    elements.each(function () {\n        const $this = $(this);\n        const attrsToUpdate = {};\n        if (shouldSwap) {\n            ['data-original', 'data-src', 'data-url'].forEach(attr => {\n                if ($this.attr(attr)) {\n                    attrsToUpdate['src'] = $this.attr(attr);\n                }\n            });\n        }\n        $this.attr(attrsToUpdate);\n    });\n    return elements;\n}\n\n// 切换导航按钮和选择框的显示\nfunction toggleNavigationButtons() {\n    if ($('#url-select option').length > 1  && !config.autoLoading) {\n        $('#loading-buttons').show();\n        $('#url-select').show();\n    } else {\n        $('#loading-buttons').hide();\n        $('#url-select').hide();\n    }\n}\n\n// 显示加载状态\nfunction showLoadingStatus(pageNumber) {\n    const selectedOption = $('#url-select option:selected').text();\n    $('#loading-status').text(`正在加载：${selectedOption}`).show();\n}\n\n// 隐藏加载状态\nfunction hideLoadingStatus() {\n    $('#loading-status').hide();\n}\n\n// 内容提取函数内容\nfunction loadContent(index) {\n    if (index < 0 || index >= urls.length || !canLoadNextPage) return;\n    canLoadNextPage = false;\n    currentPageIndex = index;\n    $('#url-select').val(index);\n    $('#messages').append(`<div>当前地址: <span class=\"warn\">${urls[index]}</span> </div>`);\n    if (autoLoadInProgress) {\n        showLoadingStatus(index + 1);\n    }\n    $.ajax({\n        url: urls[index],\n        type: 'GET',\n        success: function (data) {\n            try {\n                const $data = $(data);\n                let updatedHtmlContent = data.replace(/(['\"])(\\/\\/)(?!\\/)/g, '$1https://')\n                    .replace(/src=\"upload/gi, 'src=\"/upload')\n                    .replace(/style=[\"'][^'\"]+[\"']/gi, '')\n                    .replace(/\\\\\\//g, '/');\n                const parser = new DOMParser();\n                const doc = parser.parseFromString(updatedHtmlContent, \"text/html\");\n\n                  // 添加调试标签输出信息\n                if (config.debugOnce === index) {\n                    const debugElements = $(doc).find(config.debugSelector);\n                    if (debugElements.length > 0) {\n                        const debugContents = $('<pre>').html(debugElements.clone().wrapAll('<div/>').parent().html()).html();\n                        $('#debug-info').html(`<span class=\"warn\">调试信息: <textarea rows=\"10\" cols=\"80\">${debugContents}</textarea></span>`);\n                    } else {\n                        $('#debug-info').html(`<span class=\"warn\">调试信息: <textarea rows=\"10\" cols=\"80\">调试信息未提取到内容，请检查选择器！</textarea></span>`);\n                    }\n                }\n\n                // 方法1：video标签获取视频地址\n                const videoContents = $(doc).find(config.videoSelector);\n                const videoTags = $(videoContents).find('video');\n                videoTags.each(function () {\n                    const videosrc = $(this).attr('src') || $(this).attr('data-src') || $(this).attr('data-original') || '';\n                    if (videosrc) {\n                        videoSources.push(videosrc);\n                    }\n                });\n                \n                // 方法2：source标签获取视频地址\n                const sources = $(videoContents).find('source');\n                sources.each(function () {\n                    const sourceSrc = $(this).attr('src') || $(this).attr('data-src') || $(this).attr('data-original') || '';\n                    if (sourceSrc) {\n                        videoSources.push(sourceSrc);\n                    }\n                });\n                \n                // 方法3：正则表达式获取视频地址\n                const regex = /['\"]https?[^'<>\"]+\\.(m3u8|mp4|webm|ogg|flv|mp3|m4a|wav|ape|flac)['\"]/ig;\n                const matches = data.match(regex);\n                if (matches) {\n                    const uniqueMatches = matches.filter((value, idx, self) => self.indexOf(value) === idx);\n    videoSources = videoSources.concat(uniqueMatches.map((match) => {\n        // 使用replace删除引号\n                const urlWithoutQuotes = match.replace(/['\"]/g, '');\n                return normalizeUrl(urlWithoutQuotes);\n                          }));\n                }\n\n                videoSources = videoSources.map(src => normalizeUrl(src.replace(/\\\\+/g, '')));\n                videoSources = [...new Set(videoSources)];\n\n                if (videoSources.length > 0) {\n                    $('#messages').append(`<span>成功提取到视频，找到 ${videoSources.length} 个视频。</span><br>`);\n                    videoSources.forEach((src, idx) => {\n                        $('#messages').append(`<div>视频地址:<span class=\"warn\"> ${src}</span><br></div>`);\n                        $('#video-source-select').append(`<option value=\"${idx}\">视频源 ${idx + 1}</option>`);\n                    });\n                    \n                    if (videoSources.length == 1) {\n                        $('#video-container').show();\n                        $('#video-url').show();\n                        $('#video-source-select').hide();\n                        updateVideoSource(); // 自动更新视频源\n                    } else if (videoSources.length > 1) {\n                        $('#video-container').show();\n                        $('#video-url').show();\n                        $('#video-source-select').show();\n                        updateVideoSource(); // 默认选择第一个视频源\n                    } else {\n                        $('#video-container').hide();\n                        $('#video-url').hide();\n                        $('#video-source-select').hide();\n                    }\n                } else {\n                    $('#messages').append(`<span class=\"warn\">未找到视频源。</span><br>`);\n                    $('#video-container').hide();\n                    $('#video-url').hide();\n                    $('#video-source-select').hide();\n                }\n\n                // 标签获图片\n                const $imgContents = $(doc).find(config.imgSelector);\n                const shouldSwap = config.swapImageAttributes;\n                const newContents = updateImageSrc($imgContents.clone(), shouldSwap);\n                $('#images').append(newContents).show();\n                if (newContents.length > 0) {\n                    $('#messages').append(`<span>成功提取图片，共 ${newContents.length} 张。</span><br>`);\n                    newContents.each(function () {\n                        const imgSrc =$(this).attr('src') || $(this).attr('data-original') || $(this).attr('data-src') || $(this).attr('data-url');\n                        $('#messages').append(`<div>地址:<span class=\"warn\"> ${imgSrc}</span><br></div>`);\n                    });\n                } else {\n                    $('#messages').append(`<span class=\"warn\">未提取到图片。</span><br>`);\n                }\n\n                // 标签获图文\n                const textContents = $(doc).find(config.textSelector).map(function () {\n                    const $currentContents = $(this);\n                    $currentContents.find('img + br, script, video, source').remove();\n                    $currentContents.html($currentContents.html().replace(/>\\s+/gi, '>').replace(/<\\/?br\\s*([^>]*)\\s*\\/?>/gi, '\\n').replace(/\\n+/g, '\\n'));\n                    return $currentContents.html();\n                }).get().join('');\n                if (textContents.trim()) {\n                    $('#text').append(`<span>${textContents}</span><br>`).show();\n                    $('#messages').append(`<span>成功提取图文。</span><br>`);\n                } else {\n                    $('#messages').append(`<span class=\"warn\">未提取到图文。</span><br>`);\n                }\n                \n                \n                if (autoLoadInProgress && currentPageIndex < urls.length - 1) {\n                    setTimeout(() => { \n                        canLoadNextPage = true;\n                        loadContent(currentPageIndex + 1); \n                    }, config.delayTime);\n                } else {\n                    canLoadNextPage = true;\n                    if (autoLoadInProgress) {\n                        hideLoadingStatus();\n                    }\n                }\n            } catch (parseError) {\n                $('#messages').append(`<span class=\"error\">解析页面内容时发生错误: ${parseError.message}</span><br>`);\n                handleLoadFailure(urls, index);\n            } finally {\n                if (imageBox) imageBox.viewer.update();\n                if (textBox) textBox.viewer.update();\n            }\n        },\n        error: function (jqXHR, textStatus, errorThrown) {\n            let errorMessage = `内容加载失败: ${urls[index]}`;\n            switch (textStatus) {\n                case 'timeout':\n                    errorMessage += ', 请求超时';\n                    break;\n                case 'abort':\n                    errorMessage += ', 请求被取消';\n                    break;\n                case 'parsererror':\n                    errorMessage += ', 解析响应出错';\n                    break;\n                default:\n                    errorMessage += `, 状态码: ${jqXHR.status}, 错误信息: ${errorThrown}`;\n                    break;\n            }\n            $('#messages').append(`<span class=\"error\">${errorMessage}</span><br>`);\n            handleLoadFailure(urls, index);\n        }\n    });\n}\n\n// 处理加载失败的情况\nfunction handleLoadFailure(urls, index) {\n    if (!loadAttempts[urls[index]]) {\n        loadAttempts[urls[index]] = 1;\n    } else {\n        loadAttempts[urls[index]]++;\n    }\n    if (loadAttempts[urls[index]] <= config.maxLoadAttempts) {\n        const retryMessage = `第${index + 1}页加载失败，正在进行第${loadAttempts[urls[index]]}次加载！`;\n        $('#messages').append(`<span class=\"error\">${retryMessage}</span><br>`);\n        setTimeout(() => { \n            canLoadNextPage = true;\n            loadContent(index); \n        }, config.retryDelayTime);\n    } else {\n        const finalErrorMessage = `第${index + 1}页加载失败，已达到最大尝试次数(${config.maxLoadAttempts})！`;\n        $('#messages').append(`<span class=\"error\">${finalErrorMessage}</span><br>`);\n        if (autoLoadInProgress && currentPageIndex < urls.length - 1) {\n            setTimeout(() => { \n                canLoadNextPage = true;\n                loadContent(currentPageIndex + 1); \n            }, config.delayTime);\n        } else {\n            canLoadNextPage = true;\n            if (autoLoadInProgress) {\n                hideLoadingStatus();\n            }\n        }\n    }\n}\n\n// 更新视频源\nfunction updateVideoSource() {\n    const selectedIndex = parseInt(document.getElementById('video-source-select').value);\n    const selectedSource = videoSources[selectedIndex];\n    document.getElementById('video-url').textContent = `视频地址:\\n ${selectedSource}`;\n\n    // 设置 video-source 的 src 属性\n    const videoSourceElement = document.getElementById('video-source');\n    videoSourceElement.src = selectedSource;\n\n    // 更新 video 元素的 src 属性\n    const videoElement = document.getElementById('video-element');\n    videoElement.load();\n\n    // 添加调试信息\n    $('#messages').append(`<span>更新视频源为: ${selectedSource}</span><br>`);\n}\n\n// 函数执行主体\n$(document).ready(function () {\n    imageBox = document.getElementById('images');\n    textBox = document.getElementById('text');\n    if (imageBox && textBox) {\n        new Viewer(imageBox, { title: true, interval: 2000 });\n        new Viewer(textBox, { title: true, interval: 2000 });\n    }\n\n    const totalPagesText = config.totalPagesText;\n    const totalPages = parseInt(totalPagesText, 10) || 1;\n    const baseUrl = '{{baseUrl}}';\n    \n    clearContainers();\n    $('#urls').empty();\n    $('#debug-info textarea').empty();   \n    $('#video-url').empty().hide();\n    $('#video-container').hide();\n    $('#video-source-select').empty().hide();\n    \n    buildUrls(totalPages, baseUrl);\n\n    const urlSelect = document.getElementById('url-select');\n    if (urlSelect.options.length > 0) {\n        urlSelect.value = '0'; \n        \n        if (config.autoLoading) {\n            autoLoadInProgress = true;\n            for (let i = 0; i < urls.length; i++) {\n                loadContent(i);\n            }\n        } else {\n            loadContent(0);\n        }\n    } else {\n        loadContent(0);\n    }\n\n    $('#url-select').change(function () {\n        clearContainers();\n        const selectedIndex = parseInt($(this).val());\n        loadContent(selectedIndex);\n    });\n    $('#prev-page-btn').click(function () {\n        clearContainers();\n        if (currentPageIndex > 0) {\n            loadContent(currentPageIndex - 1);\n        }\n    });\n    $('#next-page-btn').click(function () {\n        clearContainers();\n        if (currentPageIndex < urls.length - 1) {\n            loadContent(currentPageIndex + 1);\n        }\n    });\n    $('#auto-load-btn').click(function () {\n        autoLoadInProgress = true;\n        showLoadingStatus(1); \n        for (let i = currentPageIndex + 1; i < urls.length; i++) {\n            loadContent(i);\n        }\n    });\n    $('#toggle-messages-btn').click(function () { $('#messages').toggle(); });\n    $('#toggle-urls-btn').click(function () { $('#urls').toggle(); });\n    $('#toggle-debug-btn').click(function () { $('#debug-info').toggle(); });\n});\n    </script>\n</body>\n</html>",
    "ruleImage": "img@src",
    "ruleLink": "a@href",
    "ruleNextPage": "page||text.下一页@href",
    "rulePubDate": "p.-1@text\n",
    "ruleTitle": "h3.-1@text",
    "singleUrl": false,
    "sortUrl": "搜索::https://czy.yzfnb6.help/cn/home/web/index.php/vod/search.html?wd={{source.getVariable()}}\n最新上传::/cn/home/web/index.php/label/new/page/{{page}}.html\n月排行::/cn/home/web/index.php/label/hot_month/page/{{page}}.html\n日排行::/cn/home/web/index.php/label/hot_day/page/{{page}}.html\n周排行::/cn/home/web/index.php/label/hot_week/page/{{page}}.html\n熟母少妇::/cn/home/web/index.php/vod/type/id/20/page/{{page}}.html\n网红直播::/cn/home/web/index.php/vod/type/id/21/page/{{page}}.html\n自拍偷拍::/cn/home/web/index.php/vod/type/id/22/page/{{page}}.html\n强奸乱伦::/cn/home/web/index.php/vod/type/id/23/page/{{page}}.html\n高清国产::/cn/home/web/index.php/vod/type/id/24/page/{{page}}.html\n韩国专区::/cn/home/web/index.php/vod/type/id/25/page/{{page}}.html\n日本有码::/cn/home/web/index.php/vod/type/id/26/page/{{page}}.html\n日本无码::/cn/home/web/index.php/vod/type/id/27/page/{{page}}.html\n欧美情色::/cn/home/web/index.php/vod/type/id/28/page/{{page}}.html\n动漫卡通::/cn/home/web/index.php/vod/type/id/29/page/{{page}}.html\n三级伦理::/cn/home/web/index.php/vod/type/id/30/page/{{page}}.html",
    "sourceComment": "By小新\n永久地址：https://bqm.avds8.com/g/\nhttps://rlblsm.yzfnb4.lat/cn/home/web/\nhttps://qrb.yzfnb3.ink/cn/home/web/\nhttps://qrb.yzfnb3.ink/cn/home/web/",
    "sourceGroup": "R-18可用免翻",
    "sourceIcon": "",
    "sourceName": "优质粉嫩鲍",
    "sourceUrl": "https://cwi.yzfnb2.makeup"
  },
  {
    "articleStyle": 0,
    "customOrder": 45,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "",
    "sourceIcon": "https://www.yckceo.com/favicon.ico",
    "sourceName": "源仓库",
    "sourceUrl": "https://yckceo.vip/"
  },
  {
    "articleStyle": 0,
    "customOrder": 46,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "header": "@js:\ncache.putMemory('lycdrdm',String.raw`\n<html>\n<head>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n    <title>导入</title>\n    <style>\n        body {\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n            min-height: 80vh;\n        }\n        textarea {\n            font-size: 12px;\n            width: 96%;\n            margin: 16px 2%;\n            padding: 8px;\nbackground-color: rgba(80, 155, 84, 0.1);\nborder-radius: 10px;\n    border: 2px solid rgba(76, 175, 80, 0.3);\n        }\ntextarea:focus {\n    border-color: rgb(76, 175, 80);\n    outline: none;\n    box-shadow: 0 0 8px rgba(255, 107, 107, 0.3);\n  }\n        button {\n            user-select: none;\n            color: white;\n            border: none;\n            border-radius: 4px;\n            height: 40px;\n            width: 80px;\n            overflow: hidden;\n            transition: 0.3s;\n            font-size: 16px;\n        }\n        .an-s {\n        \ttransform: scale(0.8);\n        }\n        #btn1 {background-color: rgba(76, 175, 80, 0.9);}\n        #btn2 {background-color: rgba(175, 76, 80, 0.9);}\n        #btn3 {background-color: rgba(76, 80, 175, 0.9);}\n    </style>\n</head>\n<body>\n    <textarea id=\"copyt\" rows=\"9\" placeholder=\"在这里填写链接\n支持书源、订阅源、净化、字典等json或txt文件\n支持书籍网址（需要有对应的书源）\n支持data或base64加密链接\"></textarea>\n    <br>\n    <button id=\"btn1\" onclick=\"copy(1)\">导入</button>\n<br>\n<button id=\"btn2\" onclick=\"cleart()\">清空</button>\n<br>\n<button id=\"btn3\" onclick=\"copy(3)\">净化</button>\n    <script>\n        function copy(x) {\n            const btn = document.getElementById('btn'+x);\n            btn.classList.add('an-s');\n            const cpt = document.getElementById(\"copyt\");\n            let url = cpt.value;\nif (/[删除去消].*(?:[删除去掉].*[中汉我]|汉.*字|中.*文|文.*字)/.test(url)) url=url.replace(/[abphm]站|[一-ꀀ]/g,'');\n            url = url.replace(/\\n[一-ꀀ，。？！；…“‘、’”]*$/,'').replace(/\\s+|😂|🌚|🌝|🙄|😳|🙃|😊|😍|😘|😏|😱|😭|😒|🤔|😛|😅|🙈|🙊|🙉|🌸|🍀|🌹|🌷|💎|💄|💋|🉑|㊗️|💰|🌈|🦄|🥚|🥟|🌶️|🐔|🍺|🐮|🐻|🐶|🐼|🐖|🐴|🐈|🐕|🧸|🦌|🐟|🐇|🕊️|🦞|🖤|❤️|💚|💙|💕|☎️|🎁|🧧|🎉|🎊|🙋|🙆|👰|🇨🇳|🌏|🔥|🥱|😷|😴|😡|😌|😉|😎|🤓|🥳|🥺|🥰|🤒|🤐|🤭|👿|👻|💩|💊|🍉|🍔|🍋|🥭|🍓|🥒|🥠|🍇|⚽|🏀|🏓|🛀|🃏|🎲|🀄|🎹|🎧|📢|🚗|🚢|🚆|✈️|🚀|🈶|🈚|㊙️|🈲|♠️|♥️|♣️|♦️|➕|➖|✖️|➗|✔️|😮‍💨|😵‍💫|🥸|🔞|🤚|🫱|🫲|🫳|🫴|👌|👍|🤌|🫰|🫵|🫶|✌️|🤟|💪|👏|🤙|🙏|🙇‍♂️|🤷‍♂️|🤦‍♂️|🌺|\\[(?:酷币|受虐滑稽|微笑|哈哈哈|呵呵|呲牙|可爱|可怜|皱眉|惊讶|微笑|坏笑|流泪|抱拳|色|强|doge笑哭|doge原谅ta|旺财|OK)\\]/giu, '').replace(/(\\/.+\\.(?:json|txt))(?:[^\\/\\?\\-\\_\\.][\\S\\s]*)$/, '$1').replace(/^[\\S\\s]+?(?=https?:)/i,'').replace(/\\u0026/g,'%26');\nif (url.startsWith('data:')) url = atob(url.match(/^[^,]+,([^\\s,]+)/)[1]);\nif (/^[\\da-z\\+\\/]{2,}=*$/i.test(url)) url = atob(url);\n            setTimeout(() => {\n                btn.classList.remove('an-s');\n            }, 500);\n            if (url == '') {alert('请输入内容');return}\n            if (/^https?\\:/i.test(url)&&x==1) {\n                if (/\\/.+\\.(?:json|txt)/i.test(url)) {\n                    window.location.href = 'legado://import/Source?src=' + url;\n                }\n                else {\n                    window.location.href = 'legado://import/addToBookshelf?src=' + url;\n                }\n            }\n           else if (x==3) {cpt.value=url;}\n           else alert('链接格式错误');\n        }\nfunction cleart() {\nconst btn = document.getElementById('btn2');\nbtn.classList.add('an-s');\nconst cpt = document.getElementById(\"copyt\");\nsetTimeout(() => {\n                btn.classList.remove('an-s');\n            }, 300);\ncpt.value = '';\n  }\n    </script>\n</body>\n</html>\n`);\r\n''",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": false,
    "ruleArticles": "",
    "ruleLink": "",
    "ruleTitle": "",
    "singleUrl": true,
    "sourceComment": "版本：1.1.1\n——洛娅橙",
    "sourceGroup": "202",
    "sourceIcon": "https://gitee.com/lyc486/yuedu/raw/master/drtb.gif",
    "sourceName": "导入",
    "sourceUrl": "http@js:`data:text/html;base64,${java.base64Encode(cache.getFromMemory('lycdrdm'))}`"
  },
  {
    "articleStyle": 0,
    "customOrder": 48,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "",
    "ruleContent": "",
    "ruleImage": "",
    "ruleLink": "",
    "ruleNextPage": "",
    "ruleTitle": "",
    "singleUrl": true,
    "sourceGroup": "202",
    "sourceIcon": "https://img2.baidu.com/it/u=2497591018,1494490685&fm=253&fmt=auto&app=138&f=JPEG?w=375&h=500",
    "sourceName": "美女直播",
    "sourceUrl": "https://zh.virtualtaboo.live/",
    "style": "video{\nwidth:100%;\nheight:auto;}"
  },
  {
    "articleStyle": 0,
    "customOrder": 49,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "header": "<js>\nheaders={\n    \"User-Agent\": \"Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Mobile Safari/537.36 EdgA/127.0.0.0\",\n\"Cache-Control\": \"no-cache\",\n    \"Referer\": String(source.getKey()).replace(/(.*\\/\\/[a-z0-9.-]+).*/, '$1')\n}\nJSON.stringify(headers);\n</js>",
    "injectJs": "function setupCustomPlayer(video) {\n  // 手势滑动快进\n  let isDragging = false;\n  let startX = 0;\n  let startTime = 0;\n  \n  // 长按加速相关变量\n  let longPressTimer = null;\n  const LONG_PRESS_DELAY = 300;\n  const NORMAL_SPEED = 1.25;\n  const FAST_SPEED = 3;\n  let wasPaused = false;\n\n  // 触摸事件处理\n  function handleTouchStart(e) {\n    startX = e.touches[0].clientX;\n    startTime = video.currentTime;\n    wasPaused = video.paused;\n    \n    longPressTimer = setTimeout(() => {\n      video.playbackRate = FAST_SPEED;\n      if (wasPaused) video.play();\n    }, LONG_PRESS_DELAY);\n  }\n\n  function handleTouchMove(e) {\n    if (longPressTimer) {\n      clearTimeout(longPressTimer);\n      longPressTimer = null;\n    }\n    \n    const dx = e.touches[0].clientX - startX;\n    if (Math.abs(dx) > 10) {\n      if (!isDragging) {\n        video.pause();\n        isDragging = true;\n      }\n      const change = (dx / video.clientWidth) * video.duration;\n      video.currentTime = Math.max(0, Math.min(startTime + change, video.duration));\n    }\n  }\n\n  function handleTouchEnd() {\n    if (longPressTimer) {\n      clearTimeout(longPressTimer);\n      longPressTimer = null;\n    }\n    \n    if (isDragging) {\n      video.playbackRate = NORMAL_SPEED;\n      video.play();\n      isDragging = false;\n    } else if (video.playbackRate === FAST_SPEED) {\n      video.playbackRate = NORMAL_SPEED;\n      if (wasPaused) video.pause();\n    }\n  }\n\n  // 添加触摸事件监听\n  video.addEventListener('touchstart', handleTouchStart);\n  video.addEventListener('touchmove', handleTouchMove);\n  video.addEventListener('touchend', handleTouchEnd);\n  \n  // 初始播放速度\n  video.playbackRate = NORMAL_SPEED;\n\n  // 创建按钮的通用函数\n  function createButton(text, onClick, position, width = '20px', top = '50%', fontSize = '16px') {\n    const button = document.createElement('button');\n    button.textContent = text;\n    button.style.position = 'absolute';\n    button.style[position.horizontal] = '0';\n    button.style.top = top;\n    button.style.transform = top === '50%' ? 'translateY(-50%)' : 'none';\n    button.style.zIndex = '999';\n    button.style.padding = '1px';\n    button.style.background = 'rgba(51, 51, 51, 0)';\n    button.style.color = '#fff';\n    button.style.border = 'none';\n    button.style.cursor = 'pointer';\n    button.style.width = width;\n    button.style.height = '30px';\n    button.style.fontSize = fontSize; // 添加字体大小设置\n    button.addEventListener('click', onClick);\n    video.parentNode.appendChild(button);\n    return button;\n  }\n\n  // 旋转按钮（右侧上方） \n  createButton('⟳', () => {\n    const currentRotation = parseInt(video.getAttribute('data-rotation') || '0');\n    const newRotation = (currentRotation + 90) % 360;\n    video.setAttribute('data-rotation', newRotation);\n    \n    // 保留当前的缩放比例和反转状态\n    const currentTransform = video.style.transform || '';\n    let currentScale = 1;\n    const scaleMatch = currentTransform.match(/scale\\(([^)]+)\\)/);\n    if (scaleMatch) currentScale = parseFloat(scaleMatch[1]);\n    \n    // 获取当前反转状态\n    const isFlipped = video.getAttribute('data-flipped') === 'true';\n    const flipValue = isFlipped ? -1 : 1;\n    \n    video.style.transform = `rotate(${newRotation}deg) scale(${currentScale}) scaleX(${flipValue})`;\n  }, { horizontal: 'right' }, '20px', 'calc(50% - 20px)');\n\n  // 播放/暂停按钮（右侧下方）\n  let isPlaying = !video.paused;\n  const playPauseBtn = createButton(\n    isPlaying ? '❚❚' : '▶',\n    () => {\n      if (video.paused) {\n        video.play();\n        playPauseBtn.textContent = '❚❚';\n      } else {\n        video.pause();\n        playPauseBtn.textContent = '▶';\n      }\n    },\n    { horizontal: 'right' },\n    '22px',\n    'calc(50% + 20px)',\n    '10px' // 单独设置字体大小\n  );\n\n  // 监听视频的播放状态变化\n  video.addEventListener('play', () => {\n    playPauseBtn.textContent = '❚❚';\n    isPlaying = true;\n  });\n\n  video.addEventListener('pause', () => {\n    playPauseBtn.textContent = '▶';\n    isPlaying = false;\n  });\n\n  // 缩放按钮（左侧上方）\n  let zoomCount = 0;\n  createButton('+', () => {\n    const currentRotation = parseInt(video.getAttribute('data-rotation') || '0');\n    \n    // 获取当前缩放比例和反转状态\n    const currentTransform = video.style.transform || '';\n    let currentScale = 1;\n    const scaleMatch = currentTransform.match(/scale\\(([^)]+)\\)/);\n    if (scaleMatch) currentScale = parseFloat(scaleMatch[1]);\n    \n    // 获取当前反转状态\n    const isFlipped = video.getAttribute('data-flipped') === 'true';\n    const flipValue = isFlipped ? -1 : 1;\n    \n    if (zoomCount < 4) {\n      const newScale = currentScale * 1.25;\n      video.style.transform = `rotate(${currentRotation}deg) scale(${newScale}) scaleX(${flipValue})`;\n      zoomCount++;\n    } else {\n      video.style.transform = `rotate(${currentRotation}deg) scale(1) scaleX(${flipValue})`;\n      zoomCount = 0;\n    }\n  }, { horizontal: 'left' }, '20px', 'calc(50% - 20px)');\n\n  // 反转按钮（左侧下方）\n  const flipBtn = createButton('⇄', () => {\n    const isFlipped = video.getAttribute('data-flipped') === 'true';\n    const newFlipState = !isFlipped;\n    video.setAttribute('data-flipped', newFlipState);\n    \n    // 保留当前的旋转和缩放比例\n    const currentRotation = parseInt(video.getAttribute('data-rotation') || '0');\n    const currentTransform = video.style.transform || '';\n    let currentScale = 1;\n    const scaleMatch = currentTransform.match(/scale\\(([^)]+)\\)/);\n    if (scaleMatch) currentScale = parseFloat(scaleMatch[1]);\n    \n    const flipValue = newFlipState ? -1 : 1;\n    video.style.transform = `rotate(${currentRotation}deg) scale(${currentScale}) scaleX(${flipValue})`;\n  }, { horizontal: 'left' }, '20px', 'calc(50% + 20px)', '10px'); // 单独设置字体大小\n\n  // 快速跳转按钮（底部中央）\n  const buttonContainer = document.createElement('div');\n  buttonContainer.style.position = 'absolute';\n  buttonContainer.style.bottom = '0';\n  buttonContainer.style.left = '50%';\n  buttonContainer.style.transform = 'translateX(-50%)';\n  buttonContainer.style.display = 'flex';\n  buttonContainer.style.gap = '10px';\n  buttonContainer.style.zIndex = '999';\n  \n  // 按钮配置\n  const seekButtons = [\n    { text: '-5分', time: -300 },\n    { text: '-1分', time: -60 },\n    { text: '+1分', time: 60 },\n    { text: '+5分', time: 300 }\n  ];\n\n  seekButtons.forEach(({ text, time }) => {\n    const button = document.createElement('button');\n    button.textContent = text;\n    button.style.padding = '1px';\n    button.style.background = 'rgba(51, 51, 51, 0)';\n    button.style.color = '#fff';\n    button.style.border = 'none';\n    button.style.cursor = 'pointer';\n    button.style.width = '60px';\n    button.style.height = '30px';\n    // 快速跳转按钮使用默认字体大小\n    button.addEventListener('click', () => {\n      video.currentTime = Math.max(0, Math.min(video.currentTime + time, video.duration));\n    });\n    buttonContainer.appendChild(button);\n  });\n video.parentNode.appendChild(buttonContainer);\n\n// 跳过片头功能\n  video.addEventListener('timeupdate', () => {\n    if (video.currentTime < 10) {\n      video.currentTime = 10;\n    }\n  });\n}\n\n// 修改初始化逻辑，增加重试机制\nfunction initPlayerWithRetry() {\n  const maxRetries = 10;\n  const retryInterval = 500;\n  let retries = 0;\n  const tryInit = () => {\n    const video = document.getElementById('video');\n    if (video) {\n      setupCustomPlayer(video);\n    } else if (retries < maxRetries) {\n      retries++;\n      setTimeout(tryInit, retryInterval);\n    }\n  };\n  tryInit();\n}\n// 使用重试机制初始化播放器\ninitPlayerWithRetry();",
    "lastUpdateTime": 1770070818566,
    "loadWithBaseUrl": true,
    "ruleArticles": "$.data.list",
    "ruleContent": "{{$.data.movie_m3u8_url..url}}\n@js:\nresult=decodeURIComponent(result);\nresult=result.replace(/\\\\/g,'');\nresult=`\n<html>  \n<head>  \n<meta charset=\"utf-8\">  \n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no\">\n<meta name=\"referrer\" content=\"never\"/>\n<style>html,body{text-align:center;margin:0;padding:0;width:100%;overflow: hidden;}</style>\n</head>  \n<body>  \n<div class=\"container\"><div  class=\"title\">{{$.data.movie_name}}</div>\n<video id=\"video\" width=\"100%\" height=\"91%\" poster=\"{{$.data.movie_cover}}\"  controls autoplay muted loop>  \n    <source src=\"${result}\" type=\"application/x-mpegURL\">    \n</video></div>\n</body>  \n</html>\n`;",
    "ruleImage": "$.movie_cover",
    "ruleLink": "/api/Webapi_v1/Resource/movieInfo?movie_id={{$.movie_id}}",
    "ruleNextPage": "page",
    "rulePubDate": "{{$.movie_cover##/(20.*)/.*/##$1##}} ⏱️{{$.movie_long}}",
    "ruleTitle": "@js:\nif (\"{{$.need_vip}}\"==\"0\"){result=\"{{$.movie_name##.*屎.*|.*Ts.*|.*TS.*|.*ts.*|.*伪娘.*|.*无法抑制的热情.*}}\"}else{result=\"\"}",
    "singleUrl": false,
    "sortUrl": "\n主播随机::/api/Webapi_v1/Resource/movieList?page={{ Math.ceil(Math.random()*380) }}&num=20&sort=1&label_ids[0]=5\n\n最新::/api/Webapi_v1/Resource/movieList?page={{page}}&num=20&sort=1\n\n🔎搜索::/api/Webapi_v1/Resource/movieList?page={{page}}&num=20&sort=1&search={{v=source.getVariable();if(/^\\s*$/.test(v)||v==null)source.setVariable('奸');source.getVariable()}}\n\n自拍::/api/Webapi_v1/Resource/movieList?page={{page}}&num=20&sort=1&label_ids[0]=2\n主播::/api/Webapi_v1/Resource/movieList?page={{page}}&num=20&sort=1&label_ids[0]=5\n中字::/api/Webapi_v1/Resource/movieList?page={{page}}&num=20&sort=1&label_ids[0]=20\nAV::/api/Webapi_v1/Resource/movieList?page={{page}}&num=20&sort=1&label_ids[0]=25\n国产::/api/Webapi_v1/Resource/movieList?page={{page}}&num=20&sort=1&label_ids[0]=26\n网红::/api/Webapi_v1/Resource/movieList?page={{page}}&num=20&sort=1&label_ids[0]=21\n麻豆::/api/Webapi_v1/Resource/movieList?page={{page}}&num=20&sort=1&label_ids[0]=22\n偷拍::/api/Webapi_v1/Resource/movieList?page={{page}}&num=20&sort=1&label_ids[0]=23\n探花::/api/Webapi_v1/Resource/movieList?page={{page}}&num=20&sort=1&label_ids[0]=24\n欧美::/api/Webapi_v1/Resource/movieList?page={{page}}&num=20&sort=1&label_ids[0]=6\n动漫:/api/Webapi_v1/Resource/movieList?page={{page}}&num=20&sort=1&label_ids[0]=9\n",
    "sourceComment": "http://www.wus82.com/\n备用地址 \nhttps://www.x3o5z.com/\nhttps://www.e2d0m.com/\nhttps://www.m4e0p.com/\nhttps://www.b1b4j.com/\nhttps://www.s1b9k.com/\nhttps://www.w4x5j.com/\nhttps://www.8u0lz.com/\n",
    "sourceGroup": "视频",
    "sourceIcon": "https://img0.baidu.com/it/u=2908908160,2785784129&fm=253&fmt=auto&app=138&f=PNG",
    "sourceName": "✿吾色      S",
    "sourceUrl": "https://www.l1m9r.top/",
    "style": ".container {\n    position: relative; \n    height: 100%; \n    overflow: hidden; \n}\n.title {\n    position: absolute; \n    top: 0; \n    width: 100%;\n    overflow: hidden; \n    text-overflow: ellipsis;\n    display: -webkit-box;\n    -webkit-box-orient: vertical; \n    -webkit-line-clamp: 2;\n    z-index: 1; \n    background: #000; \n    padding: 0 0 3px 0;\n}\nvideo {\n    position: absolute; \n    top: -120px; /* 视频上移 */\n    left: 0; \n    width: 100%; \n    height: calc(96% + 120px);  /* 调整高度以适应内容 */\n    object-fit: contain; \n    z-index: 0; \n    controls=\"controls\" autoplay muted; \n} \nvideo::-webkit-media-controls-overlay-play-button {\n    display: none !important;\n}\n"
  },
  {
    "articleStyle": 0,
    "customOrder": 50,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "header": "{\n    \"User-Agent\": \"Mozilla/5.0 (Linux; Android 13; SM-G998B Build/TP1A.220624.014) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36 SearchCraft/3.9.2\",\n    \"referer\": \"{{baseUrl}}\"\n}",
    "injectJs": "function setupCustomPlayer(video) {\n  // 手势滑动快进\n  let isDragging = false;\n  let startX = 0;\n  let startTime = 0;\n  \n  // 长按加速相关变量\n  let longPressTimer = null;\n  const LONG_PRESS_DELAY = 300;\n  const NORMAL_SPEED = 1.25;\n  const FAST_SPEED = 3;\n  let wasPaused = false;\n\n  // 触摸事件处理\n  function handleTouchStart(e) {\n    startX = e.touches[0].clientX;\n    startTime = video.currentTime;\n    wasPaused = video.paused;\n    \n    longPressTimer = setTimeout(() => {\n      video.playbackRate = FAST_SPEED;\n      if (wasPaused) video.play();\n    }, LONG_PRESS_DELAY);\n  }\n\n  function handleTouchMove(e) {\n    if (longPressTimer) {\n      clearTimeout(longPressTimer);\n      longPressTimer = null;\n    }\n    \n    const dx = e.touches[0].clientX - startX;\n    if (Math.abs(dx) > 10) {\n      if (!isDragging) {\n        video.pause();\n        isDragging = true;\n      }\n      const change = (dx / video.clientWidth) * video.duration;\n      video.currentTime = Math.max(0, Math.min(startTime + change, video.duration));\n    }\n  }\n\n  function handleTouchEnd() {\n    if (longPressTimer) {\n      clearTimeout(longPressTimer);\n      longPressTimer = null;\n    }\n    \n    if (isDragging) {\n      video.playbackRate = NORMAL_SPEED;\n      video.play();\n      isDragging = false;\n    } else if (video.playbackRate === FAST_SPEED) {\n      video.playbackRate = NORMAL_SPEED;\n      if (wasPaused) video.pause();\n    }\n  }\n\n  // 添加触摸事件监听\n  video.addEventListener('touchstart', handleTouchStart);\n  video.addEventListener('touchmove', handleTouchMove);\n  video.addEventListener('touchend', handleTouchEnd);\n  \n  // 初始播放速度\n  video.playbackRate = NORMAL_SPEED;\n\n  // 创建按钮的通用函数\n  function createButton(text, onClick, position, width = '20px') {\n    const button = document.createElement('button');\n    button.textContent = text;\n    button.style.position = 'absolute';\n    button.style[position.horizontal] = '0';\n    button.style.top = '50%';\n    button.style.transform = 'translateY(-50%)';\n    button.style.zIndex = '999';\n    button.style.padding = '1px';\n    button.style.background = 'rgba(51, 51, 51, 0)';\n    button.style.color = '#fff';\n    button.style.border = 'none';\n    button.style.cursor = 'pointer';\n    button.style.width = width;\n    button.style.height = '30px';\n    button.addEventListener('click', onClick);\n    video.parentNode.appendChild(button);\n    return button;\n  }\n\n  // 旋转按钮（右侧）\n  createButton('⟳', () => {\n    const currentRotation = parseInt(video.getAttribute('data-rotation') || '0');\n    const newRotation = (currentRotation + 90) % 360;\n    video.setAttribute('data-rotation', newRotation);\n    \n    // 保留当前的缩放比例\n    const currentTransform = video.style.transform || '';\n    let currentScale = 1;\n    const scaleMatch = currentTransform.match(/scale\\(([^)]+)\\)/);\n    if (scaleMatch) currentScale = parseFloat(scaleMatch[1]);\n    \n    video.style.transform = `rotate(${newRotation}deg) scale(${currentScale})`;\n  }, { horizontal: 'right' });\n\n  // 缩放按钮（左侧）\n  let zoomCount = 0;\n  createButton('+', () => {\n    const currentRotation = parseInt(video.getAttribute('data-rotation') || '0');\n    \n    // 获取当前缩放比例\n    const currentTransform = video.style.transform || '';\n    let currentScale = 1;\n    const scaleMatch = currentTransform.match(/scale\\(([^)]+)\\)/);\n    if (scaleMatch) currentScale = parseFloat(scaleMatch[1]);\n    \n    if (zoomCount < 4) {\n      const newScale = currentScale * 1.25;\n      video.style.transform = `rotate(${currentRotation}deg) scale(${newScale})`;\n      zoomCount++;\n    } else {\n      video.style.transform = `rotate(${currentRotation}deg) scale(1)`;\n      zoomCount = 0;\n    }\n  }, { horizontal: 'left' });\n\n  // 快速跳转按钮（底部中央）\n  const buttonContainer = document.createElement('div');\n  buttonContainer.style.position = 'absolute';\n  buttonContainer.style.bottom = '0';\n  buttonContainer.style.left = '50%';\n  buttonContainer.style.transform = 'translateX(-50%)';\n  buttonContainer.style.display = 'flex';\n  buttonContainer.style.gap = '10px';\n  buttonContainer.style.zIndex = '999';\n  \n  // 按钮配置\n  const seekButtons = [\n    { text: '-5分', time: -300 },\n    { text: '-1分', time: -60 },\n    { text: '+1分', time: 60 },\n    { text: '+5分', time: 300 }\n  ];\n\n  seekButtons.forEach(({ text, time }) => {\n    const button = document.createElement('button');\n    button.textContent = text;\n    button.style.padding = '1px';\n    button.style.background = 'rgba(51, 51, 51, 0)';\n    button.style.color = '#fff';\n    button.style.border = 'none';\n    button.style.cursor = 'pointer';\n    button.style.width = '60px';\n    button.style.height = '30px';\n    button.addEventListener('click', () => {\n      video.currentTime = Math.max(0, Math.min(video.currentTime + time, video.duration));\n    });\n    buttonContainer.appendChild(button);\n  });\n\n  video.parentNode.appendChild(buttonContainer);\n\n// 跳过片头功能\n  video.addEventListener('timeupdate', () => {\n    if (video.currentTime < 5) {\n      video.currentTime = 5;\n    }\n  });\n}\n\n// 修改初始化逻辑，增加重试机制\nfunction initPlayerWithRetry() {\n  const maxRetries = 10;\n  const retryInterval = 500;\n  let retries = 0;\n  const tryInit = () => {\n    const video = document.getElementById('video');\n    if (video) {\n      setupCustomPlayer(video);\n    } else if (retries < maxRetries) {\n      retries++;\n      setTimeout(tryInit, retryInterval);\n    }\n  };\n  tryInit();\n}\n// 使用重试机制初始化播放器\ninitPlayerWithRetry();",
    "lastUpdateTime": 1769953281311,
    "loadWithBaseUrl": true,
    "ruleArticles": ".col-md-6",
    "ruleContent": "@js:\nresult=java.ajax(source.sourceUrl+\"{{@@text.第1集@href##https://.*?/}}\");\nA=result.match(\"https.*\\.(mp4|m3u8)\")[0]\nresult=`\n<html><head><meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no\" />\n<meta name=\"referrer\" content=\"never\"/>\n  <style>html, body {text-align: center;margin: 0; padding: 0;width: 100%;overflow: hidden;} </style>\n  <script src=\"https://unpkg.com/hls.js@1.4.3/dist/hls.min.js\"></script>\n</head><body>\n  <div class=\"container\">\n    <div class=\"title\">{{@@h1@text}}</div>\n    <video id=\"video\" width=\"100%\" height=\"91%\" poster=\"${java.get('pic')}\" controls autoplay muted loop></video>\n  </div>\n<script>\nconst v=document.getElementById('video'),s=[\n  \"${A}\",\n  \"\"];\nlet c=0;\nfunction setupCustomControls(e){/* 自定义功能实现 */}\nfunction playNext(){\n  c>=s.length&&(c=0); // 循环重置计数器\n  const u=s[c++];\n  // 检测Hls对象是否存在\n  if (typeof Hls !== 'undefined' && Hls.isSupported()) {\n    const h = new Hls({\n      enableSoftwareAES: true,          // 强制软件解密\n      forceKeyFrameOnDiscontinuity: true // 关键帧恢复\n    });\n    h.loadSource(u);\n    h.attachMedia(v);\n    h.on(Hls.Events.MANIFEST_PARSED,()=>v.play().then(()=>setupCustomControls(v)).catch(console.log));\n    h.on(Hls.Events.ERROR,(_,d)=>d.fatal&&playNext())\n  } else { // Hls加载失败或浏览器原生支持HLS\n    if (v.canPlayType('application/vnd.apple.mpegurl')) {\n      v.src = u;\n      v.onloadedmetadata = () => v.play().then(() => setupCustomControls(v));\n      v.onerror = playNext;\n    } else {\n      // 如果都不支持，尝试直接播放（可能支持MP4等格式）\n      v.src = u;\n      v.onerror = playNext;\n      v.play().then(() => setupCustomControls(v)).catch(playNext);\n    }\n  }\n}playNext();\n</script>\n</body></html>\n`",
    "ruleImage": "https://images.floriscope.io.cloud-ed.fr/?url={{@@a@data-original}}&w=400&h=300&fit=fill\n<js>\njava.put('pic',result)\n</js>",
    "ruleLink": "a@href##https://.*?/",
    "ruleNextPage": "text.下一页@href",
    "rulePubDate": "a@data-original##allimg/(.*)/.*.jpg##$1##||.pic-text@ownText",
    "ruleTitle": "{{@@h4@a@text}}\n<js>\nconst blockKeywords = /屎|TS|伪娘|伪男|人妖|男同|狼狗|奶狗|鲜肉|帅哥|正装|猛1|ZKtop1|体育生|大屌|双性|男男|直男|gv|父子|飞机|撸|女性向|骚0|poop|娘娘腔|变性|TGirls|鸡巴|鸡吧|阴茎|男奴|奴男|同志|苏木|西装|骚受|QS|Peter|摔跤社|基情|天菜|大鸡|肌肉|薄肌|G片|术0|宏翔|男蜜|自制口|威廉|骚男|基友|美男子|鸡儿|口活王子|融化的冰|自己射|運動生|苏婧薇|社畜|纪练深|性别|淋尿|控射|熟女|CD|肥女|老阿姨|排泄|臭脚|大便|马眼|聖水|尸|廁|圣水|豊満|黑妹|黑人女孩|坦克|黑屁股|黑人妹子|黑逼|孕妇|消遣|伦勃朗|拉丁裔|asmr|GOOD|奶奶|老妈|妈妈|母亲|儿子|爸爸|女儿|母子|父女|兄妹|亲姐|亲妹|VR|都丸富美|山本かを|守谷多香子|波多|飯岡|希島|希岛|深田|君島|君岛|田中瞳|向美奈|美原咲|华行香|藤泽丽|Hitomi|美乃雀|若菜奈|水野朝|後藤|明日花|卯水|由爱|JULIA|风间|濑圆|平冈|藤樱|藤泽|蓮実|藤沢麗央|木村玲|SILK|afchina|fway|rebd|mbdd|REBD|FWAY|眼射|水果派|解说|π|偷拍|偸拍|抄底|攝像頭|摄像头|番系列|经典番|里番|老番|国漫|王者|斗罗|穿越|斗破|仙剑|小舞|MMD|實測|女王|AIKA|喝尿|田中|Ｍ男|40岁/i;\nif (blockKeywords.test(result)) {\n  // 如果包含关键词，将标题设为空字符串\n  result = \"\";\n}\njava.put('title',result)\n</js>",
    "singleUrl": false,
    "sortUrl": "随机::/category/{{ [1959, 1960][Math.floor(Math.random()*2)] }}/time-{{ Math.ceil(Math.random()*1000) }}.html\n\n随机:/category/1958/time-{{ Math.ceil(Math.random()*2600) }}.html\n最新::/category.html\n🔎搜索::/search.html?keyword={{v=source.getVariable();if(/^\\s*$/.test(v)||v==null)source.setVariable('奸');source.getVariable()}}\n国产::/category/1959.html\n动漫::/category/1962.html\n日韩::/category/1960.html\n欧美::/category/1961.html",
    "sourceComment": "play9115@gmail.com\nhttp://170.178.166.170/\n备用地址  需改内容规则内地址\nhttps://64.32.31.83/\nhttps://64.32.31.84/\nhttps://64.32.31.85/ 到\nhttps://64.32.31.108/\nhttps://64.32.31.117/\nhttps://64.32.31.118/\nhttps://64.32.31.119/\n",
    "sourceGroup": "视频",
    "sourceIcon": "https://img0.baidu.com/it/u=2908908160,2785784129&fm=253&fmt=auto&app=138&f=PNG",
    "sourceName": "❀清清草原S",
    "sourceUrl": "https://64.32.31.100/",
    "style": ".container {\n    position: relative; /* 相对定位，用于包含视频 */\n    height: 100%; /* 容器高度与视频原始高度相同 */\n    overflow: hidden; /* 隐藏超出容器的部分 */\n}\n.title {\n    position: absolute; /* 绝对定位，相对于容器 */\n    top: 0; \n    width: 100%;\n    overflow: hidden; \n    text-overflow: ellipsis;\n    display: -webkit-box;\n    -webkit-box-orient: vertical; \n    -webkit-line-clamp: 2;\n    z-index: 1; /* 确保标题在视频之上 */\n    background: #000; /* 纯黑色背景 */ \n    padding: 0 0 3px 0;\n}\nvideo {\n    position: absolute; /* 绝对定位，相对于容器 */ \n    top: -20px; /* 视频上移 */\n    left: 0; \n    width: 100%; \n    height: calc(96% + 20px);  /* 调整高度以适应内容 */\n    object-fit: contain; /* 确保视频内容不被裁剪 */\n    z-index: 0; /* 确保视频在标题之下 */\n    controls=\"controls\" autoplay muted; \n} \n"
  },
  {
    "articleStyle": 0,
    "contentBlacklist": "https://pc.stgowan.com/,\nhttps://dmku.mhtjx.top/,\nhttps://dmku.m3u8.pw/,\nhttps://dm.bbj.icu/,\nhttps://www.superplayer.top/index.php/index/dm,\nhttps://jx.8852.top/dmku/,\nhttps://api.js1736.com:666/tj/tongji.js,\nhttps://node11.aizhantj.com:21233/tjjs/",
    "coverDecodeJs": "function toByteArray(input) {\n  var out = new Packages.java.io.ByteArrayOutputStream();\n  var buffer = java.strToBytes('\\0'.repeat(4096));\n  var bytesRead;\n  while ((bytesRead = input.read(buffer)) != -1) {\n    out.write(buffer, 0, bytesRead);\n  }\n  return out.toByteArray();\n}\n\n(function() {\n  // 1. 读取原始字节内容\n  var textBytes = toByteArray(result);\n  // 2. 如果是GIF文件，直接返回原始字节\n  if (src.endsWith('.gif')) {\n    return textBytes;\n  }\n  try {\n    // 3. 将字节转换为字符串（用于解析数据URI）\n    var dataUri = java.bytesToStr(textBytes, \"UTF-8\");\n    // 4. 判断是完整的数据URI还是纯Base64数据\n    var base64Prefix = \"base64,\";\n    var base64Index = dataUri.indexOf(base64Prefix);\n    if (base64Index === -1) {\n      // 如果没有找到base64前缀，检查是否需要截取第一个/及之后的内容\n      var firstSlashIndex = dataUri.indexOf('/');\n      if (firstSlashIndex !== -1) {\n        // 如果找到第一个/，截取/及之后的内容\n        dataUri = dataUri.substring(firstSlashIndex);\n      }\n      // 对整个内容进行Base64解码\n      return java.base64DecodeToByteArray(dataUri);\n    } else {\n      // 如果是标准data URI，提取base64编码部分解码\n      var base64Data = dataUri.substring(base64Index + base64Prefix.length);\n      return java.base64DecodeToByteArray(base64Data);\n    }\n  } catch (e) {\n    // 解码失败时返回原始字节\n    return textBytes;\n  }\n})();",
    "customOrder": 51,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "header": "{\n  \"User-Agent\": \"okhttp/4.2.2\",\n}",
    "injectJs": "function setupCustomPlayer(video) {\n  // 手势滑动快进\n  let isDragging = false;\n  let startX = 0;\n  let startTime = 0;\n  \n  // 长按加速相关变量\n  let longPressTimer = null;\n  const LONG_PRESS_DELAY = 300;\n  const NORMAL_SPEED = 1.25;\n  const FAST_SPEED = 3;\n  let wasPaused = false;\n\n  // 触摸事件处理\n  function handleTouchStart(e) {\n    startX = e.touches[0].clientX;\n    startTime = video.currentTime;\n    wasPaused = video.paused;\n    \n    longPressTimer = setTimeout(() => {\n      video.playbackRate = FAST_SPEED;\n      if (wasPaused) video.play();\n    }, LONG_PRESS_DELAY);\n  }\n\n  function handleTouchMove(e) {\n    if (longPressTimer) {\n      clearTimeout(longPressTimer);\n      longPressTimer = null;\n    }\n    \n    const dx = e.touches[0].clientX - startX;\n    if (Math.abs(dx) > 10) {\n      if (!isDragging) {\n        video.pause();\n        isDragging = true;\n      }\n      const change = (dx / video.clientWidth) * video.duration;\n      video.currentTime = Math.max(0, Math.min(startTime + change, video.duration));\n    }\n  }\n\n  function handleTouchEnd() {\n    if (longPressTimer) {\n      clearTimeout(longPressTimer);\n      longPressTimer = null;\n    }\n    \n    if (isDragging) {\n      video.playbackRate = NORMAL_SPEED;\n      video.play();\n      isDragging = false;\n    } else if (video.playbackRate === FAST_SPEED) {\n      video.playbackRate = NORMAL_SPEED;\n      if (wasPaused) video.pause();\n    }\n  }\n\n  // 添加触摸事件监听\n  video.addEventListener('touchstart', handleTouchStart);\n  video.addEventListener('touchmove', handleTouchMove);\n  video.addEventListener('touchend', handleTouchEnd);\n  \n  // 初始播放速度\n  video.playbackRate = NORMAL_SPEED;\n\n  // 创建按钮的通用函数\n  function createButton(text, onClick, position, width = '20px') {\n    const button = document.createElement('button');\n    button.textContent = text;\n    button.style.position = 'absolute';\n    button.style[position.horizontal] = '0';\n    button.style.top = '50%';\n    button.style.transform = 'translateY(-50%)';\n    button.style.zIndex = '999';\n    button.style.padding = '1px';\n    button.style.background = 'rgba(51, 51, 51, 0)';\n    button.style.color = '#fff';\n    button.style.border = 'none';\n    button.style.cursor = 'pointer';\n    button.style.width = width;\n    button.style.height = '30px';\n    button.addEventListener('click', onClick);\n    video.parentNode.appendChild(button);\n    return button;\n  }\n\n  // 旋转按钮（右侧）\n  createButton('⟳', () => {\n    const currentRotation = parseInt(video.getAttribute('data-rotation') || '0');\n    const newRotation = (currentRotation + 90) % 360;\n    video.setAttribute('data-rotation', newRotation);\n    \n    // 保留当前的缩放比例\n    const currentTransform = video.style.transform || '';\n    let currentScale = 1;\n    const scaleMatch = currentTransform.match(/scale\\(([^)]+)\\)/);\n    if (scaleMatch) currentScale = parseFloat(scaleMatch[1]);\n    \n    video.style.transform = `rotate(${newRotation}deg) scale(${currentScale})`;\n  }, { horizontal: 'right' });\n\n  // 缩放按钮（左侧）\n  let zoomCount = 0;\n  createButton('+', () => {\n    const currentRotation = parseInt(video.getAttribute('data-rotation') || '0');\n    \n    // 获取当前缩放比例\n    const currentTransform = video.style.transform || '';\n    let currentScale = 1;\n    const scaleMatch = currentTransform.match(/scale\\(([^)]+)\\)/);\n    if (scaleMatch) currentScale = parseFloat(scaleMatch[1]);\n    \n    if (zoomCount < 4) {\n      const newScale = currentScale * 1.25;\n      video.style.transform = `rotate(${currentRotation}deg) scale(${newScale})`;\n      zoomCount++;\n    } else {\n      video.style.transform = `rotate(${currentRotation}deg) scale(1)`;\n      zoomCount = 0;\n    }\n  }, { horizontal: 'left' });\n\n  // 快速跳转按钮（底部中央）\n  const buttonContainer = document.createElement('div');\n  buttonContainer.style.position = 'absolute';\n  buttonContainer.style.bottom = '0';\n  buttonContainer.style.left = '50%';\n  buttonContainer.style.transform = 'translateX(-50%)';\n  buttonContainer.style.display = 'flex';\n  buttonContainer.style.gap = '10px';\n  buttonContainer.style.zIndex = '999';\n  \n  // 按钮配置\n  const seekButtons = [\n    { text: '-5分', time: -300 },\n    { text: '-1分', time: -60 },\n    { text: '+1分', time: 60 },\n    { text: '+5分', time: 300 }\n  ];\n\n  seekButtons.forEach(({ text, time }) => {\n    const button = document.createElement('button');\n    button.textContent = text;\n    button.style.padding = '1px';\n    button.style.background = 'rgba(51, 51, 51, 0)';\n    button.style.color = '#fff';\n    button.style.border = 'none';\n    button.style.cursor = 'pointer';\n    button.style.width = '60px';\n    button.style.height = '30px';\n    button.addEventListener('click', () => {\n      video.currentTime = Math.max(0, Math.min(video.currentTime + time, video.duration));\n    });\n    buttonContainer.appendChild(button);\n  });\n\n  video.parentNode.appendChild(buttonContainer);\n}\n\n// 修改初始化逻辑，增加重试机制\nfunction initPlayerWithRetry() {\n  const maxRetries = 10;\n  const retryInterval = 500;\n  let retries = 0;\n  const tryInit = () => {\n    const video = document.getElementById('video');\n    if (video) {\n      setupCustomPlayer(video);\n    } else if (retries < maxRetries) {\n      retries++;\n      setTimeout(tryInit, retryInterval);\n    }\n  };\n  tryInit();\n}\n// 使用重试机制初始化播放器\ninitPlayerWithRetry();",
    "lastUpdateTime": 1769953204779,
    "loadWithBaseUrl": true,
    "ruleArticles": "$.rescont.data",
    "ruleContent": "<html><head><meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no\" />\n<meta name=\"referrer\" content=\"never\"/>\n  <style>html, body {text-align: center;margin: 0; padding: 0;width: 100%;overflow: hidden;} </style>\n  <script src=\"https://unpkg.com/hls.js@1.4.3/dist/hls.min.js\"></script>\n</head><body>\n  <div class=\"container\">\n    <div class=\"title\">{{$.rescont.title}}</div>\n    <video id=\"video\" width=\"100%\" height=\"91%\" poster=\"\" controls autoplay muted loop></video>\n  </div>\n<script>\nconst v=document.getElementById('video'),s=[\n  \"{{$.rescont.videopath}}\",\n  \"\"];\nlet c=0;\nfunction setupCustomControls(e){/* 自定义功能实现 */}\nfunction playNext(){\n  c>=s.length&&(c=0); // 循环重置计数器\n  const u=s[c++];\n  // 检测Hls对象是否存在\n  if (typeof Hls !== 'undefined' && Hls.isSupported()) {\n    const h = new Hls({\n      enableSoftwareAES: true,          // 强制软件解密\n      forceKeyFrameOnDiscontinuity: true // 关键帧恢复\n    });\n    h.loadSource(u);\n    h.attachMedia(v);\n    h.on(Hls.Events.MANIFEST_PARSED,()=>v.play().then(()=>setupCustomControls(v)).catch(console.log));\n    h.on(Hls.Events.ERROR,(_,d)=>d.fatal&&playNext())\n  } else { // Hls加载失败或浏览器原生支持HLS\n    if (v.canPlayType('application/vnd.apple.mpegurl')) {\n      v.src = u;\n      v.onloadedmetadata = () => v.play().then(() => setupCustomControls(v));\n      v.onerror = playNext;\n    } else {\n      // 如果都不支持，尝试直接播放（可能支持MP4等格式）\n      v.src = u;\n      v.onerror = playNext;\n      v.play().then(() => setupCustomControls(v)).catch(playNext);\n    }\n  }\n}playNext();\n</script>\n</body></html>",
    "ruleImage": "{{$.coverbase64.url}}",
    "ruleLink": "/api/videoplay/{{$.id}}",
    "ruleNextPage": "page",
    "rulePubDate": "📆 {{$.updated_at## .*}}  ⏱️ {{$.playtimes}}",
    "ruleTitle": "$.title##.*屎.*|.*Ts.*|.*TS.*|.*ts.*|.*伪娘.*|.*人妖.*|.*男同.*|.*mbrba.*|.*水果派.*|.*解说.*|.*mmraa.*|.*ss-.*|.*fway.*|.*rebd.*|.*mbdd.*|.*双性.*|.*妈妈.*|.*儿子.*|.*爸爸.*|.*女儿.*|.*母子.*|.*父女.*|.*熟女.*|.*眼射.*|.*直男.*|.*CD.*|.*肥女.*|.*黄金.*|.*骚0.*|.*gv.*|.*父子.*|.*飞机.*|.*撸.*|.*厕.*|.*老阿姨.*|.*乱伦.*",
    "singleUrl": false,
    "sortUrl": "\n随机::/api/videosort/0?page={{ Math.ceil(Math.random()*1500) }}\n最新::/api/videosort/0?page={{page}}\n🔎搜索::/api/videosort/0?serach={{v=source.getVariable();if(/^\\s*$/.test(v)||v==null)source.setVariable('强奸');source.getVariable()}}&page={{page}}\n国产自拍::/api/videosort/10?page={{page}}\nH动漫::/api/videosort/14?page={{page}}\n国产剧情::/api/videosort/52?page={{page}}\n盗摄偷拍::/api/videosort/46?page={{page}}\n宅男福利::/api/videosort/31?page={{page}}\n小编推荐::/api/videosort/30?page={{page}}\n嫩模专区::/api/videosort/37?page={{page}}\n网红主播::/api/videosort/17?page={{page}}\n明星换脸::/api/videosort/33?page={{page}}\nASMR系列::/api/videosort/51?page={{page}}\n高清无码::/api/videosort/1?page={{page}}\nAV剧情::/api/videosort/29?page={{page}}\n翘臀美穴::/api/videosort/21?page={{page}}\n自慰口交::/api/videosort/50?page={{page}}\n淫乱职场::/api/videosort/45?page={{page}}\n制服诱惑::/api/videosort/5?page={{page}}\n美乳巨乳::/api/videosort/20?page={{page}}\n长腿丝袜::/api/videosort/11?page={{page}}\n角色扮演::/api/videosort/4?page={{page}}\n师生淫乱::/api/videosort/40?page={{page}}\n人妻熟女::/api/videosort/6?page={{page}}\n特工女警::/api/videosort/41?page={{page}}\n护士医生::/api/videosort/42?page={{page}}\n近亲相奸::/api/videosort/43?page={{page}}\nAV素人::/api/videosort/24?page={{page}}\n淫欲痴汉::/api/videosort/44?page={{page}}\n有码破坏::/api/videosort/48?page={{page}}\n当红女优::/api/videosort/9?page={{page}}\n制服诱惑::/api/videosort/5?page={{page}}\n青春萝莉::/api/videosort/22?page={{page}}\n重咸口味::/api/videosort/23?page={{page}}\n女同性爱::/api/videosort/38?page={{page}}\n三级电影::/api/videosort/25?page={{page}}",
    "sourceGroup": "视频",
    "sourceIcon": "https://img0.baidu.com/it/u=2908908160,2785784129&fm=253&fmt=auto&app=138&f=PNG",
    "sourceName": "🌈向日葵   S",
    "sourceUrl": "https://api.xrkapiaba.xyz",
    "style": ".container {\n    position: relative; /* 相对定位，用于包含视频 */\n    height: 100%; /* 容器高度与视频原始高度相同 */\n    overflow: hidden; /* 隐藏超出容器的部分 */\n}\n.title {\n    position: absolute; /* 绝对定位，相对于容器 */\n    top: 0; \n    width: 100%;\n    overflow: hidden; \n    text-overflow: ellipsis;\n    display: -webkit-box;\n    -webkit-box-orient: vertical; \n    -webkit-line-clamp: 2;\n    z-index: 1; /* 确保标题在视频之上 */\n    background: #000; /* 纯黑色背景 */ \n    padding: 0 0 3px 0;\n}\nvideo {\n    position: absolute; /* 绝对定位，相对于容器 */ \n    top: -65px; /* 上移80px */\n    left: 0; \n    width: 100%; \n    height: calc(96% + 65px);  /* 调整高度以适应内容 */\n    object-fit: contain; /* 确保视频内容不被裁剪 */\n    z-index: 0; /* 确保视频在标题之下 */\n    controls=\"controls\" autoplay muted; \n} \n"
  },
  {
    "articleStyle": 0,
    "coverDecodeJs": "function decodeImage(data, keyBytes) {\n  var out = new Packages.java.io.ByteArrayOutputStream()\n  var byte\n  var count = 0\n  var keyLength = keyBytes.length\n  while ((byte = data.read()) != -1) {\n    if (count < 100) {\n      out.write(byte ^ keyBytes[count % keyLength])\n      count++\n    } else {\n      out.write(byte)\n    }\n  }\n  return out.toByteArray()\n}\nfunction toByteArray(input) {\n  var out = new Packages.java.io.ByteArrayOutputStream();\n  var buffer = java.strToBytes('\\0'.repeat(4096));\n  var bytesRead;\n  while ((bytesRead = input.read(buffer)) != -1) {\n    out.write(buffer, 0, bytesRead);\n  }\n  return out.toByteArray();\n}\nvar keyStr = \"2019ysapp7527\"\nvar keyBytes = java.strToBytes(keyStr, \"UTF-8\")\nvar excludeKeywords = ['yximgs', 'Uploads'];\nvar shouldExclude = excludeKeywords.some(function(keyword) {\n  return src.indexOf(keyword) !== -1;\n});\nif (shouldExclude) {\n  toByteArray(result)\n} else {\n  decodeImage(result, keyBytes)\n}",
    "customOrder": 52,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "header": "{\n    \"User-Agent\": \"Mozilla/5.0 (Linux; Android 13; SM-G998B Build/TP1A.220624.014) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36 SearchCraft/3.9.2 okhttp/4.2.2\",\n    \"referer\": \"{{baseUrl}}\"\n}",
    "injectJs": "function setupCustomPlayer(video) {\n  let isDragging = false;\n  let startX = 0;\n  let startTime = 0;\n  let longPressTimer = null;\n  const LONG_PRESS_DELAY = 300;\n  const NORMAL_SPEED = 1.25;\n  const FAST_SPEED = 3;\n  let wasPaused = false;\n  function handleTouchStart(e) {\n    startX = e.touches[0].clientX;\n    startTime = video.currentTime;\n    wasPaused = video.paused;\n    longPressTimer = setTimeout(() => {\n      video.playbackRate = FAST_SPEED;\n      if (wasPaused) video.play();\n    }, LONG_PRESS_DELAY);\n  }\n  function handleTouchMove(e) {\n    if (longPressTimer) {\n      clearTimeout(longPressTimer);\n      longPressTimer = null;\n    }\n    const dx = e.touches[0].clientX - startX;\n    if (Math.abs(dx) > 10) {\n      if (!isDragging) {\n        video.pause();\n        isDragging = true;\n      }\n      const change = (dx / video.clientWidth) * video.duration;\n      video.currentTime = Math.max(0, Math.min(startTime + change, video.duration));\n    }\n  }\n  function handleTouchEnd() {\n    if (longPressTimer) {\n      clearTimeout(longPressTimer);\n      longPressTimer = null;\n    }\n    if (isDragging) {\n      video.playbackRate = NORMAL_SPEED;\n      video.play();\n      isDragging = false;\n    } else if (video.playbackRate === FAST_SPEED) {\n      video.playbackRate = NORMAL_SPEED;\n      if (wasPaused) video.pause();\n    }\n  }\n  video.addEventListener('touchstart', handleTouchStart);\n  video.addEventListener('touchmove', handleTouchMove);\n  video.addEventListener('touchend', handleTouchEnd);\n  video.playbackRate = NORMAL_SPEED;\n  function createButton(text, onClick, position, width = '20px', top = '50%') {\n    const button = document.createElement('button');\n    button.textContent = text;\n    button.style.position = 'absolute';\n    button.style[position.horizontal] = '0';\n    button.style.top = top;\n    button.style.transform = top === '50%' ? 'translateY(-50%)' : 'none';\n    button.style.zIndex = '999';\n    button.style.padding = '1px';\n    button.style.background = 'rgba(51, 51, 51, 0)';\n    button.style.color = '#fff';\n    button.style.border = 'none';\n    button.style.cursor = 'pointer';\n    button.style.width = width;\n    button.style.height = '30px';\n    button.addEventListener('click', onClick);\n    video.parentNode.appendChild(button);\n    return button;\n  }\n  createButton('⟳', () => {\n    const currentRotation = parseInt(video.getAttribute('data-rotation') || '0');\n    const newRotation = (currentRotation + 90) % 360;\n    video.setAttribute('data-rotation', newRotation);\n    const currentTransform = video.style.transform || '';\n    let currentScale = 1;\n    const scaleMatch = currentTransform.match(/scale\\(([^)]+)\\)/);\n    if (scaleMatch) currentScale = parseFloat(scaleMatch[1]);\n    const isFlipped = video.getAttribute('data-flipped') === 'true';\n    const flipValue = isFlipped ? -1 : 1;\n    video.style.transform = `rotate(${newRotation}deg) scale(${currentScale}) scaleX(${flipValue})`;\n  }, { horizontal: 'right' }, '20px', 'calc(50% - 20px)');\n  let isPlaying = !video.paused;\n  const playPauseBtn = createButton(\n    isPlaying ? '❚❚' : '▶',\n    () => {\n      if (video.paused) {\n        video.play();\n        playPauseBtn.textContent = '❚❚';\n      } else {\n        video.pause();\n        playPauseBtn.textContent = '▶';\n      }\n    },\n    { horizontal: 'right' },\n    '20px',\n    'calc(50% + 20px)'\n  );\n  video.addEventListener('play', () => {\n    playPauseBtn.textContent = '❚❚';\n    isPlaying = true;\n  });\n  video.addEventListener('pause', () => {\n    playPauseBtn.textContent = '▶';\n    isPlaying = false;\n  });\n  let zoomCount = 0;\n  createButton('+', () => {\n    const currentRotation = parseInt(video.getAttribute('data-rotation') || '0');\n    const currentTransform = video.style.transform || '';\n    let currentScale = 1;\n    const scaleMatch = currentTransform.match(/scale\\(([^)]+)\\)/);\n    if (scaleMatch) currentScale = parseFloat(scaleMatch[1]);\n    const isFlipped = video.getAttribute('data-flipped') === 'true';\n    const flipValue = isFlipped ? -1 : 1;\n    if (zoomCount < 4) {\n      const newScale = currentScale * 1.25;\n      video.style.transform = `rotate(${currentRotation}deg) scale(${newScale}) scaleX(${flipValue})`;\n      zoomCount++;\n    } else {\n      video.style.transform = `rotate(${currentRotation}deg) scale(1) scaleX(${flipValue})`;\n      zoomCount = 0;\n    }\n  }, { horizontal: 'left' }, '20px', 'calc(50% - 20px)');\n  createButton('⇄', () => {\n    const isFlipped = video.getAttribute('data-flipped') === 'true';\n    const newFlipState = !isFlipped;\n    video.setAttribute('data-flipped', newFlipState);\n    const currentRotation = parseInt(video.getAttribute('data-rotation') || '0');\n    const currentTransform = video.style.transform || '';\n    let currentScale = 1;\n    const scaleMatch = currentTransform.match(/scale\\(([^)]+)\\)/);\n    if (scaleMatch) currentScale = parseFloat(scaleMatch[1]);\n    const flipValue = newFlipState ? -1 : 1;\n    video.style.transform = `rotate(${currentRotation}deg) scale(${currentScale}) scaleX(${flipValue})`;\n  }, { horizontal: 'left' }, '20px', 'calc(50% + 20px)');\n  const buttonContainer = document.createElement('div');\n  buttonContainer.style.position = 'absolute';\n  buttonContainer.style.bottom = '0';\n  buttonContainer.style.left = '50%';\n  buttonContainer.style.transform = 'translateX(-50%)';\n  buttonContainer.style.display = 'flex';\n  buttonContainer.style.gap = '10px';\n  buttonContainer.style.zIndex = '999';\n  const seekButtons = [\n    { text: '-5分', time: -300 },\n    { text: '-1分', time: -60 },\n    { text: '+1分', time: 60 },\n    { text: '+5分', time: 300 }\n  ];\n  seekButtons.forEach(({ text, time }) => {\n    const button = document.createElement('button');\n    button.textContent = text;\n    button.style.padding = '1px';\n    button.style.background = 'rgba(51, 51, 51, 0)';\n    button.style.color = '#fff';\n    button.style.border = 'none';\n    button.style.cursor = 'pointer';\n    button.style.width = '60px';\n    button.style.height = '30px';\n    button.addEventListener('click', () => {\n      video.currentTime = Math.max(0, Math.min(video.currentTime + time, video.duration));\n    });\n    buttonContainer.appendChild(button);\n  });\n\n  video.parentNode.appendChild(buttonContainer);\n}\nfunction initPlayerWithRetry() {\n  const maxRetries = 10;\n  const retryInterval = 500;\n  let retries = 0;\n  const tryInit = () => {\n    const video = document.getElementById('video');\n    if (video) {\n      setupCustomPlayer(video);\n    } else if (retries < maxRetries) {\n      retries++;\n      setTimeout(tryInit, retryInterval);\n    }\n  };\n  tryInit();\n}\ninitPlayerWithRetry();",
    "jsLib": "function decrypt(encryptedText) {\n  let result = '';\n  for (let i = 0; i < encryptedText.length; i++) {\n    result += String.fromCharCode(128 ^ encryptedText.charCodeAt(i));\n  }\n  return result;\n}",
    "lastUpdateTime": 1766110000613,
    "loadWithBaseUrl": true,
    "ruleArticles": ".vodbox",
    "ruleContent": "@js:\nplayer = baseUrl.match(/id=(.*.m3u8)/)[1];\nconst tokens = (result.match(/token=([^',]+)/g) || []).map(match => match.replace('token=', ''));\nlet token = tokens[3] || '';\nvar sources = [\n  `${player}?token=${token}`,\n];\nvar sourceButtons = \"\";\nif (sources.length > 1) {\n    for (var i = 0; i < sources.length; i++) {\n        sourceButtons += `<button class=\"source-btn\" data-index=\"${i}\">源${i+1}</button>`;\n    }\n}\nresult=`\n<html>  \n<head>  \n<meta charset=\"utf-8\">  \n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no\">\n<meta name=\"referrer\" content=\"never\"/>\n<script src=\"https://s4.zstatic.net/ajax/libs/hls.js/1.6.13/hls.min.js\"></script>\n<style>\nhtml, body { text-align: center;margin: 0; padding: 0; width: 100%; overflow: hidden; }\n.source-container { position: absolute; top: 23px; right: 1px; z-index: 10; display: flex; gap: 1px; }\n.source-btn { color: #ff0; background: rgba(0,0,0,0.7); padding: 1px 5px; border-radius: 10px; font-size: 13px; border: none; cursor: pointer; }\n.source-btn.active { color: red !important; }\n</style>\n</head>  \n<body>  \n<div class=\"container\">\n    <div class=\"title\">{{java.get('title')}}</div>\n    ${sources.length > 1 ? `<div class=\"source-container\">${sourceButtons}</div>` : ''}\n    <video id=\"video\" width=\"100%\" height=\"91%\" poster=\"\" controls autoplay muted loop></video>\n<script>\n    const video = document.getElementById('video');\n    const sources = ${JSON.stringify(sources)};\n    let hls = null;\n    let currentSource = 0;\n    function playHLS(url) {\n        if (hls) hls.destroy();\n        if (Hls.isSupported()) {\n            hls = new Hls({\n                enableSoftwareAES: true,\n                maxBufferLength: 30,\n                maxMaxBufferLength: 60\n            });\n            hls.on(Hls.Events.ERROR, function(event, data) {\n                if (data.fatal) {\n                    switchToNextSource();\n                }\n            });\n            hls.loadSource(url);\n            hls.attachMedia(video);\n        } else if (video.canPlayType('application/vnd.apple.mpegurl')) {\n            video.src = url;\n        }\n        video.onerror = function() {\n            switchToNextSource();\n        };\n    }\n    function switchToNextSource() {\n        if (sources.length <= 1) return;\n        currentSource = (currentSource + 1) % sources.length;\n        playHLS(sources[currentSource]);\n        updateButtons();\n    }\n    function switchSource(index) {\n        currentSource = index;\n        playHLS(sources[index]);\n        updateButtons();\n    }\n    function updateButtons() {\n        document.querySelectorAll('.source-btn').forEach((btn, i) => {\n            btn.classList.toggle('active', i === currentSource);\n        });\n    }\n    video.onended = function() {\n        if (sources.length === 1) {\n            video.currentTime = 0;\n            video.play();\n        } else {\n            switchToNextSource();\n        }\n    };\n    document.querySelectorAll('.source-btn').forEach(btn => {\n        btn.addEventListener('click', () => switchSource(parseInt(btn.dataset.index)));\n    });\n    if (sources.length > 0) switchSource(0);\n</script>\n</div>\n</body>  \n</html>\n`;",
    "ruleImage": "{{@@img@data-original}}",
    "ruleLink": "{{@@a.0@href}}",
    "ruleNextPage": "page",
    "rulePubDate": "{{@@img.0@data-original##cn\\/cf(.*?)\\/##$1##}}\n@js:\nresult = result !== \"\" ? result : \"点击播放\";",
    "ruleTitle": "{{@@.km-script@text}}\n<js>\nconst blockKeywords = /TS|Latina|自他屏蔽关键自行添加/i;\nresult = decrypt(result);\nif (blockKeywords.test(result)) {\n  // 如果包含关键词，将标题设为空字符串\n  result = \"\";\n}\njava.put('title',result)\n</js>",
    "singleUrl": false,
    "sortUrl": "\n随机::/index.php/vod/type/id/1/page/{{ Math.ceil(Math.random()*1570) }}.html\n最新::/index.php/vod/type/id/1/page/{{page}}.html\n\n🔎搜索::/index.php/vod/type/id/1/wd/{{v=source.getVariable();if(/^\\s*$/.test(v)||v==null)source.setVariable('奸');source.getVariable()}}/page/{{page}}.html\n\n国产::/index.php/vod/type/id/54/page/{{page}}.html\n其他分类自行添加\n动漫::/index.php/vod/type/id/9/page/{{page}}.html",
    "sourceComment": "备用网址\nhttps://618879.xyz/\nhttps://618051.xyz/\nhttps://618082.xyz/\nhttps://618063.xyz/\nhttps://618070.xyz/\n\nhttps://d2m1d86x8ze4id.cloudfront.net\n\n",
    "sourceGroup": "视频",
    "sourceIcon": "https://img0.baidu.com/it/u=2908908160,2785784129&fm=253&fmt=auto&app=138&f=PNG",
    "sourceName": "🌈md视频    S",
    "sourceUrl": "https://618061.xyz/",
    "style": ".container {\n    position: relative; \n    height: 100%; \n    overflow: hidden;\n}\n.title {\ntext-align:center;\n    position: absolute; \n    top: 0; \n    width: 100%;\n    overflow: hidden; \n    text-overflow: ellipsis;\n    display: -webkit-box;\n    -webkit-box-orient: vertical; \n    -webkit-line-clamp: 2;\n    z-index: 1; \n    background: #000; \n    padding: 0 0 3px 0;\n}\nvideo {\n    position: absolute; \n    top: +20px; \n    left: 0; \n    width: 100%; \n    height: calc(93% + 0px);  \n    object-fit: contain; \n    z-index: 0; \n    controls=\"controls\" autoplay muted; \n} \nvideo::-webkit-media-controls-overlay-play-button {\n    display: none !important;\n}\nvideo::-webkit-media-controls-fullscreen-button {\n    display: none !important;\n}"
  },
  {
    "articleStyle": 0,
    "customOrder": 53,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "header": "{\n    \"User-Agent\": \"Mozilla/5.0 (Linux; Android 13; SM-G998B Build/TP1A.220624.014) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36 SearchCraft/3.9.2 \",\n    \"referer\": \"{{baseUrl}}\"\n}",
    "lastUpdateTime": 1765680387004,
    "loadWithBaseUrl": true,
    "ruleArticles": ".item",
    "ruleContent": "@js:\n// 定义所有视频源\nvar sources = [\n `{{@@source.0@src}}`, \n `{{@@source.1@src}}`,\n `{{@@source.2@src}}`,\n];\n\n// 生成源按钮 - 只生成非空源的按钮\nvar sourceButtons = \"\";\nvar validSources = []; // 存储有效源的索引\n\n// 收集所有非空的有效源\nfor (var i = 0; i < sources.length; i++) {\n    // 检查源是否为空（去除空格后判断）\n    if (sources[i] && sources[i].trim() !== '') {\n        validSources.push(i);\n    }\n}\n\n// 只有当有效源数量大于1时才显示按钮\nif (validSources.length > 1) {\n    for (var j = 0; j < validSources.length; j++) {\n        var index = validSources[j];\n        sourceButtons += `<button class=\"source-btn\" data-index=\"${index}\">源${index+1}</button>`;\n    }\n}\n\nresult=`\n<html>  \n<head>  \n<meta charset=\"utf-8\">  \n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no\">\n<meta name=\"referrer\" content=\"never\"/>\n<script src=\"https://s4.zstatic.net/ajax/libs/hls.js/1.6.13/hls.min.js\"></script>\n<style>\nhtml, body { margin: 0; padding: 0; width: 100%; overflow: hidden; }\n.source-container { position: absolute; top: 23px; right: 1px; z-index: 10; display: flex; gap: 1px; }\n.source-btn { color: #ff0; background: rgba(0,0,0,0.7); padding: 1px 5px; border-radius: 10px; font-size: 13px; border: none; cursor: pointer; }\n.source-btn.active { color: red !important; }\n</style>\n</head>  \n<body>  \n<div class=\"container\">\n    <div class=\"title\"><span>{{@@title@text##- J163视频}}</span></div>\n    ${sourceButtons ? `<div class=\"source-container\">${sourceButtons}</div>` : ''}\n    <video id=\"video\" width=\"100%\" height=\"91%\" poster=\"{{@@script@all##preview_url: '(.*?)',##$1##}}\" controls autoplay muted loop></video>\n<script>\n    const video = document.getElementById('video');\n    const sources = ${JSON.stringify(sources)};\n    const validSources = ${JSON.stringify(validSources)}; // 有效源的索引数组\n    let hls = null;\n    let currentSource = 0;\n    \n    // 初始化HLS播放\n    function playHLS(url) {\n        if (hls) hls.destroy();\n        \n        if (Hls.isSupported()) {\n            hls = new Hls({\n                enableSoftwareAES: true,\n                maxBufferLength: 30,\n                maxMaxBufferLength: 60\n            });\n            \n            // 添加错误监听\n            hls.on(Hls.Events.ERROR, function(event, data) {\n                if (data.fatal) {\n                    switchToNextSource();\n                }\n            });\n            \n            hls.loadSource(url);\n            hls.attachMedia(video);\n        } else if (video.canPlayType('application/vnd.apple.mpegurl')) {\n            video.src = url;\n        }\n        \n        // 视频元素错误监听\n        video.onerror = function() {\n            switchToNextSource();\n        };\n    }\n\n    // 获取下一个有效源索引\n    function getNextValidSourceIndex() {\n        if (validSources.length <= 1) return currentSource;\n        \n        const currentIndex = validSources.indexOf(currentSource);\n        if (currentIndex === -1) return validSources[0];\n        \n        const nextIndex = (currentIndex + 1) % validSources.length;\n        return validSources[nextIndex];\n    }\n    \n    // 切换到下一个有效源\n    function switchToNextSource() {\n        if (validSources.length <= 1) return;\n        \n        currentSource = getNextValidSourceIndex();\n        playHLS(sources[currentSource]);\n        updateButtons();\n    }\n    \n    // 切换视频源\n    function switchSource(index) {\n        // 确保索引有效且源不为空\n        if (validSources.includes(index) && sources[index] && sources[index].trim() !== '') {\n            currentSource = index;\n            playHLS(sources[index]);\n            updateButtons();\n        }\n    }\n    \n    // 更新按钮状态\n    function updateButtons() {\n        document.querySelectorAll('.source-btn').forEach(btn => {\n            const index = parseInt(btn.dataset.index);\n            btn.classList.toggle('active', index === currentSource);\n        });\n    }\n    \n    // 获取第一个有效源\n    function getFirstValidSource() {\n        for (let i = 0; i < sources.length; i++) {\n            if (sources[i] && sources[i].trim() !== '') {\n                return i;\n            }\n        }\n        return 0; // 如果没有有效源，返回0\n    }\n    \n    // 监听播放结束事件\n    video.onended = function() {\n        if (validSources.length === 1) {\n            // 单源循环播放\n            video.currentTime = 0;\n            video.play();\n        } else {\n            // 多源顺序播放\n            switchToNextSource();\n        }\n    };\n    \n    // 绑定按钮事件\n    document.querySelectorAll('.source-btn').forEach(btn => {\n        btn.addEventListener('click', () => switchSource(parseInt(btn.dataset.index)));\n    });\n    \n    // 播放第一个有效源\n    const firstValidSource = getFirstValidSource();\n    if (sources.length > 0 && sources[firstValidSource]) {\n        currentSource = firstValidSource;\n        switchSource(firstValidSource);\n    }\n</script>\n\n</div>\n</body>  \n</html>\n`;",
    "ruleImage": "img@data-original\n<js>\njava.put('pic',result)\n</js>",
    "ruleLink": "{{@@a.0@href##(.*)/videos/##$1##}}/embed/{{@@a.0@href##videos/(.*)/.*/##$1##}}",
    "ruleNextPage": "page",
    "rulePubDate": "{{@@.added@text}}  ⏱️{{@@.duration@text}}",
    "ruleTitle": "@js:\nif (\"{{@@.ico-private@text}}\" || \"{{@@.line-private@all}}\") {\n    result = \"\";\n} else {\n    result = \"{{@@strong@text}}\";\n}",
    "singleUrl": false,
    "sortUrl": "\n随机::/latest-updates/?mode=async&function=get_block&block_id=list_videos_latest_videos_list&duration_from=600&sort_by=post_date&from={{ Math.ceil(Math.random()*3000) }}\n\n最新::/latest-updates/{{page}}/\n\n国产::/tags/guo-chan/?mode=async&function=get_block&block_id=list_videos_common_videos_list&sort_by=post_date&from={{page}}\n传媒::/tags/chuan-mei/?mode=async&function=get_block&block_id=list_videos_common_videos_list&sort_by=post_date&from={{page}}\n强奸::/tags/qiang-jian/?mode=async&function=get_block&block_id=list_videos_common_videos_list&sort_by=post_date&from={{page}}\n丝袜::/tags/si-wa/?mode=async&function=get_block&block_id=list_videos_common_videos_list&sort_by=post_date&from={{page}}\n性感::/tags/xing-gan/?mode=async&function=get_block&block_id=list_videos_common_videos_list&sort_by=post_date&from={{page}}",
    "sourceComment": "\n备用地址\nhttps://boboporn.net/\nhttps://boboporn.com/\n\n",
    "sourceGroup": "视频",
    "sourceIcon": "https://img0.baidu.com/it/u=2908908160,2785784129&fm=253&fmt=auto&app=138&f=PNG",
    "sourceName": "❀boboporn",
    "sourceUrl": "https://boboporn.com/",
    "style": ".container {\n    position: relative; /* 相对定位，用于包含视频 */\n    height: 100%; /* 容器高度与视频原始高度相同 */\n    overflow: hidden; /* 隐藏超出容器的部分 */\n}\n.title {\n\ttext-align: center;\n    position: absolute; /* 绝对定位，相对于容器 */\n    top: 0; \n    width: 100%;\n    overflow: hidden; \n    text-overflow: ellipsis;\n    display: -webkit-box;\n    -webkit-box-orient: vertical; \n    -webkit-line-clamp: 2;\n    z-index: 1; /* 确保标题在视频之上 */\n    background: #000; /* 纯黑色背景 */ \n    padding: 0 0 3px 0;\n}\nvideo {\n    position: absolute; /* 绝对定位，相对于容器 */ \n    top: +20px; /* 视频上移 */\n    left: 0; \n    width: 100%; \n    height: calc(93% + 0px);  /* 调整高度以适应内容 */\n    object-fit: contain; /* 确保视频内容不被裁剪 */\n    z-index: 0; /* 确保视频在标题之下 */\n    controls=\"controls\" autoplay muted; \n} \n"
  },
  {
    "articleStyle": 1,
    "customOrder": 56,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\"User-Agent\":\"Mozilla/5.0 (Linux; Android 11; PCAM10 Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4103.106 Mobile Safari/537.36\"} ",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "",
    "ruleContent": "",
    "ruleImage": "",
    "ruleLink": "",
    "ruleNextPage": "",
    "rulePubDate": "",
    "ruleTitle": "",
    "singleUrl": true,
    "sortUrl": "",
    "sourceComment": "",
    "sourceGroup": "网页",
    "sourceIcon": "https://m.acgnfl.com/24/07/content_33/525867/087.webp",
    "sourceName": "网页6",
    "sourceUrl": "https://bqm.avds8.com/g/"
  },
  {
    "articleStyle": 0,
    "customOrder": 57,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "网页",
    "sourceIcon": "https://m.acgnfl.com/24/07/content_33/525867/087.webp",
    "sourceName": "网页8",
    "sourceUrl": "https://baf7baf7.shewo11.cc"
  },
  {
    "articleStyle": 1,
    "customOrder": 58,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "$.list",
    "ruleDescription": "<br><h3>{{$.vod_name}}</h3>\n<h6>[{{$.vod_score}}分] [{{$.vod_class ##\\,##] [}}]<b>发布于 {{$.vod_time}}</b></h6>\n\n<video src=\"{{$.vod_play_url ##^.*?\\$}}\" poster=\"{{$.vod_pic}}\" controls></video>",
    "ruleImage": "$.vod_pic",
    "ruleLink": "/api.php/provide/vod/?ac=detail&ids={{$.vod_id}}",
    "ruleNextPage": "page",
    "rulePubDate": "⏱️ {{$.vod_duration}}　{{$.vod_score}}分　{{$.vod_time}}",
    "ruleTitle": "$.vod_name",
    "singleUrl": false,
    "sortUrl": "精品推荐::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=20\n🔎 视频搜索::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&wd={{source.getVariable()}}\n国产视频::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=22\n主播直播::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=23\n日本无码::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=24\n日本有码::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=25\n中文字幕::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=26\n巨乳美乳::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=27\n制服丝袜::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=34\n角色扮演::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=35\n熟女人妻::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=28\n强奸乱伦::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=29\n欧美精品::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=30\n少女萝莉::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=31\n三级伦理::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=32\n成人动漫::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=33\n自拍偷拍::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=34\n制服丝袜::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=35\n口交颜射::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=36\n日本精品::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=37\nCosplay::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=38\n素人自拍::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=39\n台湾辣妹::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=40\n韩国御姐::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=41\n唯美港姐::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=42\n东南亚AV::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=43\n欺辱凌辱::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=44\n剧情介绍::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=45\n多人多P::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=46\n91探花::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=47\n网红流出::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=48\n野外露出::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=49\n古装扮演::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=50\n女优系列::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=51\n可爱学生::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=52\n风情旗袍::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=53\n兽耳系列::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=54\n瑜伽裤::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=55\n闷骚护士::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=56\n过膝袜::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=57\n网爆门::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=58\n传媒出品::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=59\n女同性恋::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=60\n男同性恋::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=61\n练腿狂魔::https://slapibf.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=63",
    "sourceComment": "★源URL的填写链接为【list】格式\n\t网站网址\n\t网站网址/api.php/provide/vod/?ac=【list】\n\n例：\nhttps://apittzy.com\nhttps://apittzy.com/api.php/provide/vod/?ac=list\n\nps：\n\t使用【list】格式查看分类和分类id以组成分类URL\n\n\n\n★分类URL的填写链接为【detail】格式\n\t视频搜索::网站网址/api.php/provide/vod/?ac=【detail】&pg={{page}}&wd=关键词\n\t分类名称::网站网址/api.php/provide/vod/?ac=【detail】&pg={{page}}&t=分类id\n\n例：\n\t视频搜索::https://apittzy.com/api.php/provide/vod/?ac=detail&pg={{page}}&wd=按摩\n\t精品推荐::https://apittzy.com/api.php/provide/vod/?ac=detail&pg={{page}}&t=1\n\nps：\n\t分类URL写成【list】格式也行，但是没有详细信息。需要通过正文链接跳转正文页再填写正文规则。而且没有封面！\n\n\n\n★正文规则\n\t因为分类URL使用了【detail】格式，需要的信息都显示了。(视频链接)\n\t所以我们在描述规则填写正文规则就行了，这样子就省的再跳转一次正文链接了。\n\t但是链接规则还是要写的，不然不会加载列表。\n\n\n\n☆【vod】和【art】\n视频分类链接为【vod】格式\n\t网站网址/api.php/provide/vod/?ac=list\n图文分类链接为【art】格式\n\t网站网址/api.php/provide/art/?ac=list\n通过【list】格式查看分类和分类id以组成分类URL\n\nps：\n\t图片和小说链接都是【art】格式，这样子不好分割，建议把小说分类相关链接移除\n\t因为【art】格式的【detail】链接并不会显示全部套图，所以需要填写正确的链接规则跳转正文页再填写正文规则而不是直接在描述规则处填写规则\n\n\n\n☆详情页链接规则\n\t详情页链接仅支持【detail】格式\n网站网址/api.php/provide/(vod/art)/?ac=detail&ids=(视频id/图文id)\n\n\t如果分类URL只填写了网址，那么链接规则补充剩下的链接就行了\n例：\n\t/api.php/provide/vod/?ac=detail&ids=视频id\n❗仅限【vod】/【art】单格式使用\n\n\t如果订阅同时写了【vod】和【art】两种格式，链接就需要使用js判定\n@js:\nif(baseUrl.match(/art/)){\n\t网站网址/api.php/provide/art/?ac=detail&ids={{$.art_id}}\n}else{\n\t网站网址/api.php/provide/vod/?ac=detail&ids={{$.vod_id}}\n}\nps：\n\t使用两种格式时，此js在正文规则也会需要用到。\n\n\n\n\n\n‼️以下网址加上【list】链接可更改为json格式，查看分类及分类id\n\n\t因为json链接格式固定？\n\t所以修改一下网站之间的分类URL差别即可使用此订阅格式套用，，，大概\n\nps：\n\t注意【list】和【detail】格式以及【vod】和【art】链接的差别\n\n\n共30个网址：\n\n\t★鲨鱼::https://shayuapi.com\n\t\tps：老朋友了\n\n\n\t老鸭资源失效::http://laoyazy50.cc\n\t\tps：网站有时效性？\n\n\n\t老鸭资源2失效::https://api.apilyzy.com\n\n\n\n\t水蜜桃失效::http://51smt4.xyz\n\n\n\t99资源失效::http://99zy.pw\n\n\n\t99资源吧失效::http://99zyba.com\n\n\n\t丝袜资源失效::http://siwazyw.net\n\n\n\t浪潮资源失效::http://langchaozy6.com\n\n\n\tCK资源失效::http://www.feifei67.com\n\n\n\t大雕资源失效::http://www.dd-01.com\n\n\n\t银龙资源失效::https://yinlong.tv\n\n\n\t苍天资源失效::http://cj.cangtiancj.com\n\n\n\t骚色资源失效::http://api.saosezy.icu\n\n\n\t芒果资源失效::https://mgzyz1.com\n\n\n\t酷豆资源失效::https://kudouzy.com\n\n\n\t酷伦理资源失效::https://api.kudian70.com\n\n\n\t速播资源失效::https://api.suboapi.com\n\n\n\t国产精品::https://zy.difi.life\n\n\n\t痴汉队长失效::https://javcaptain.com\n\n\n\t秀色资源失效::https://api.xiuseapi.com\n\n\n\t苹果资源失效::https://www.pg111222.com\n\n\n\t茄子资源失效::http://www.qiezizy8.com\n\n\n\t辣椒资源失效::https://www.lajiaozy18.com\n\n\n\t花椒资源失效::https://apihjzy.com/api.php/provide/vod/?ac=list\n\t\tps：网站无法打开，json链接可以\n\n\n\t桃色资源失效::https://api.taoseapi.com/api.php/provide/vod/?ac=list\n\t\tps：网站无法打开，json链接可以\n\n\n\t乐播资源::https://lbapi9.com/api.php/provide/vod/?ac=list\n\t\tps：网站无法打开，json链接可以\n\n\n\t佳丽资源失效::https://jializyzapi.com/api.php/provide/vod/?ac=list\n\t\tps：网站无法打开，json链接可以\n\n\n\t番号资源::http://fhapi9.com/api.php/provide/vod/?ac=list\n\t\tps：网站无法打开，json链接可以\n\n\n\tx8优酷失效::https://gov.gooder.bar\n\t\tps：没有vod格式？\n\n\n\t土狗采集失效::http://vip-04.tgzy.cc\n\t\tpa：vod格式好像是音乐？\n\n\n\n☆使用【vod】和【art】两种链接的正文规则参考\n<br><h3>{{$.list..vod_name||$.list..art_name}}</h3>\n<h6>[{{$.list..type_name}}]<b>发布于 {{$.list..vod_time||$.list..art_time}}</b></h6>\n\n<video src=\"{{$.list..vod_play_url ##^.*?\\$}}\" poster=\"{{$.list..vod_pic}}\" controls>视频加载失败</video>\n\n<div id=\"TúPiàn\">\n{{$.list..art_content ##</?(br|p)>}}\n</div>\n<link rel=\"stylesheet\" href=\"https://cdn.bootcdn.net/ajax/libs/viewerjs/1.10.2/viewer.min.css\">\n<script src=\"https://cdn.bootcdn.net/ajax/libs/viewerjs/1.10.2/viewer.min.js\"></script>\n<script>\n  new Viewer(\n    document.getElementById(\"TúPiàn\")    ,{\n//设置图片地址来源\n    url: 'src',\n//是否显示图片标题(true/false)\n    title: false,\n//设置播放间隔(单位毫秒，1秒=1000毫秒)\n    interval: 3000\n    }\n  );\n</script>\n\n@js:\nif(baseUrl.match(/art/)){\n\tresult.replace(/<vid[\\s\\S]+deo>/,'')\n}else{\n\tresult.replace(/<div[\\s\\S]+ipt>/,'')\n}",
    "sourceGroup": "202",
    "sourceIcon": "https://i.postimg.cc/sXtXHZDM/IMG_20220716_190738.png",
    "sourceName": "森林资源",
    "sourceUrl": "https://slapibf.com/api.php/provide/vod/?ac=list",
    "style": "h3{text-align:center}\nh6{margin-bottom:0}\nb{float:right}\n\nvideo{width:100%;max-height:285px;border-radius:5px}"
  },
  {
    "articleStyle": 0,
    "customOrder": 59,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 1775405861793,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "2222",
    "sourceIcon": "https://nsvod.me/static/ds5/img/favicon.png",
    "sourceName": "耐视点播",
    "sourceUrl": "https://nsvod.me"
  },
  {
    "articleStyle": 0,
    "contentBlacklist": "https://pc.stgowan.com/,\nhttps://dmku.mhtjx.top/,\nhttps://dmku.m3u8.pw/,\nhttps://dm.bbj.icu/,\nhttps://www.superplayer.top/index.php/index/dm",
    "coverDecodeJs": "function toByteArray(input) {\n  var out = new Packages.java.io.ByteArrayOutputStream();\n  var buffer = java.strToBytes('\\0'.repeat(4096));\n  var bytesRead;\n  while ((bytesRead = input.read(buffer)) != -1) {\n    out.write(buffer, 0, bytesRead);\n  }\n  return out.toByteArray();\n}\n\n(function() {\n  // 1. 读取原始字节内容\n  var textBytes = toByteArray(result);\n  // 2. 如果是GIF文件，直接返回原始字节\n  if (src.endsWith('.gif')) {\n    return textBytes;\n  }\n  try {\n    // 3. 将字节转换为字符串（用于解析数据URI）\n    var dataUri = java.bytesToStr(textBytes, \"UTF-8\");\n    // 4. 判断是完整的数据URI还是纯Base64数据\n    var base64Prefix = \"base64,\";\n    var base64Index = dataUri.indexOf(base64Prefix);\n    if (base64Index === -1) {\n      // 如果没有找到base64前缀，检查是否需要截取第一个/及之后的内容\n      var firstSlashIndex = dataUri.indexOf('/');\n      if (firstSlashIndex !== -1) {\n        // 如果找到第一个/，截取/及之后的内容\n        dataUri = dataUri.substring(firstSlashIndex);\n      }\n      // 对整个内容进行Base64解码\n      return java.base64DecodeToByteArray(dataUri);\n    } else {\n      // 如果是标准data URI，提取base64编码部分解码\n      var base64Data = dataUri.substring(base64Index + base64Prefix.length);\n      return java.base64DecodeToByteArray(base64Data);\n    }\n  } catch (e) {\n    // 解码失败时返回原始字节\n    return textBytes;\n  }\n})();",
    "customOrder": 60,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\n\t\"User-Agent\":\"Mozilla/5.0 (Linux; U; Android 10; zh-cn; MI CC 11)  AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4896.127 Mobile Safari/537.36 XiaoMi/MiuiBrowser/18.1.8 swan-mibrowser\",\n\t\"referer\": \"{{baseUrl}}\"\n}",
    "injectJs": "function setupCustomPlayer(video) {\n  // 手势滑动快进\n  let isDragging = false;\n  let startX = 0;\n  let startTime = 0;\n  \n  // 长按加速相关变量\n  let longPressTimer = null;\n  const LONG_PRESS_DELAY = 300;\n  const NORMAL_SPEED = 1.25;\n  const FAST_SPEED = 3;\n  let wasPaused = false;\n\n  // 触摸事件处理\n  function handleTouchStart(e) {\n    startX = e.touches[0].clientX;\n    startTime = video.currentTime;\n    wasPaused = video.paused;\n    \n    longPressTimer = setTimeout(() => {\n      video.playbackRate = FAST_SPEED;\n      if (wasPaused) video.play();\n    }, LONG_PRESS_DELAY);\n  }\n\n  function handleTouchMove(e) {\n    if (longPressTimer) {\n      clearTimeout(longPressTimer);\n      longPressTimer = null;\n    }\n    \n    const dx = e.touches[0].clientX - startX;\n    if (Math.abs(dx) > 10) {\n      if (!isDragging) {\n        video.pause();\n        isDragging = true;\n      }\n      const change = (dx / video.clientWidth) * video.duration;\n      video.currentTime = Math.max(0, Math.min(startTime + change, video.duration));\n    }\n  }\n\n  function handleTouchEnd() {\n    if (longPressTimer) {\n      clearTimeout(longPressTimer);\n      longPressTimer = null;\n    }\n    \n    if (isDragging) {\n      video.playbackRate = NORMAL_SPEED;\n      video.play();\n      isDragging = false;\n    } else if (video.playbackRate === FAST_SPEED) {\n      video.playbackRate = NORMAL_SPEED;\n      if (wasPaused) video.pause();\n    }\n  }\n\n  // 添加触摸事件监听\n  video.addEventListener('touchstart', handleTouchStart);\n  video.addEventListener('touchmove', handleTouchMove);\n  video.addEventListener('touchend', handleTouchEnd);\n  \n  // 初始播放速度\n  video.playbackRate = NORMAL_SPEED;\n\n  // 创建按钮的通用函数\n  function createButton(text, onClick, position, width = '20px') {\n    const button = document.createElement('button');\n    button.textContent = text;\n    button.style.position = 'absolute';\n    button.style[position.horizontal] = '0';\n    button.style.top = '50%';\n    button.style.transform = 'translateY(-50%)';\n    button.style.zIndex = '999';\n    button.style.padding = '1px';\n    button.style.background = 'rgba(51, 51, 51, 0)';\n    button.style.color = '#fff';\n    button.style.border = 'none';\n    button.style.cursor = 'pointer';\n    button.style.width = width;\n    button.style.height = '30px';\n    button.addEventListener('click', onClick);\n    video.parentNode.appendChild(button);\n    return button;\n  }\n\n  // 旋转按钮（右侧）\n  createButton('⟳', () => {\n    const currentRotation = parseInt(video.getAttribute('data-rotation') || '0');\n    const newRotation = (currentRotation + 90) % 360;\n    video.setAttribute('data-rotation', newRotation);\n    \n    // 保留当前的缩放比例\n    const currentTransform = video.style.transform || '';\n    let currentScale = 1;\n    const scaleMatch = currentTransform.match(/scale\\(([^)]+)\\)/);\n    if (scaleMatch) currentScale = parseFloat(scaleMatch[1]);\n    \n    video.style.transform = `rotate(${newRotation}deg) scale(${currentScale})`;\n  }, { horizontal: 'right' });\n\n  // 缩放按钮（左侧）\n  let zoomCount = 0;\n  createButton('+', () => {\n    const currentRotation = parseInt(video.getAttribute('data-rotation') || '0');\n    \n    // 获取当前缩放比例\n    const currentTransform = video.style.transform || '';\n    let currentScale = 1;\n    const scaleMatch = currentTransform.match(/scale\\(([^)]+)\\)/);\n    if (scaleMatch) currentScale = parseFloat(scaleMatch[1]);\n    \n    if (zoomCount < 4) {\n      const newScale = currentScale * 1.25;\n      video.style.transform = `rotate(${currentRotation}deg) scale(${newScale})`;\n      zoomCount++;\n    } else {\n      video.style.transform = `rotate(${currentRotation}deg) scale(1)`;\n      zoomCount = 0;\n    }\n  }, { horizontal: 'left' });\n\n  // 快速跳转按钮（底部中央）\n  const buttonContainer = document.createElement('div');\n  buttonContainer.style.position = 'absolute';\n  buttonContainer.style.bottom = '0';\n  buttonContainer.style.left = '50%';\n  buttonContainer.style.transform = 'translateX(-50%)';\n  buttonContainer.style.display = 'flex';\n  buttonContainer.style.gap = '10px';\n  buttonContainer.style.zIndex = '999';\n  \n  // 按钮配置\n  const seekButtons = [\n    { text: '-5分', time: -300 },\n    { text: '-1分', time: -60 },\n    { text: '+1分', time: 60 },\n    { text: '+5分', time: 300 }\n  ];\n\n  seekButtons.forEach(({ text, time }) => {\n    const button = document.createElement('button');\n    button.textContent = text;\n    button.style.padding = '1px';\n    button.style.background = 'rgba(51, 51, 51, 0)';\n    button.style.color = '#fff';\n    button.style.border = 'none';\n    button.style.cursor = 'pointer';\n    button.style.width = '60px';\n    button.style.height = '30px';\n    button.addEventListener('click', () => {\n      video.currentTime = Math.max(0, Math.min(video.currentTime + time, video.duration));\n    });\n    buttonContainer.appendChild(button);\n  });\n\n  video.parentNode.appendChild(buttonContainer);\n}\n\n// 修改初始化逻辑，增加重试机制\nfunction initPlayerWithRetry() {\n  const maxRetries = 10;\n  const retryInterval = 500;\n  let retries = 0;\n  const tryInit = () => {\n    const video = document.getElementById('video');\n    if (video) {\n      setupCustomPlayer(video);\n    } else if (retries < maxRetries) {\n      retries++;\n      setTimeout(tryInit, retryInterval);\n    }\n  };\n  tryInit();\n}\n// 使用重试机制初始化播放器\ninitPlayerWithRetry();",
    "lastUpdateTime": 1775588357478,
    "loadWithBaseUrl": true,
    "ruleArticles": "$.rescont.data[*]",
    "ruleContent": "<html><head><meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no\" />\n<meta name=\"referrer\" content=\"never\"/>\n  <style>html, body {text-align: center;margin: 0; padding: 0;width: 100%;overflow: hidden;} </style>\n  <script src=\"https://unpkg.com/hls.js@1.4.3/dist/hls.min.js\"></script>\n</head><body>\n  <div class=\"container\">\n    <div class=\"title\">{{$.rescont.title}}</div>\n    <video id=\"video\" width=\"100%\" height=\"91%\" poster=\"\" controls autoplay muted loop></video>\n  </div>\n<script>\nconst v=document.getElementById('video'),s=[\n  \"{{$.rescont.videopath}}\",\n  \"\"];\nlet c=0;\nfunction setupCustomControls(e){/* 自定义功能实现 */}\nfunction playNext(){\n  c>=s.length&&(c=0); // 循环重置计数器\n  const u=s[c++];\n  // 检测Hls对象是否存在\n  if (typeof Hls !== 'undefined' && Hls.isSupported()) {\n    const h = new Hls({\n      enableSoftwareAES: true,          // 强制软件解密\n      forceKeyFrameOnDiscontinuity: true // 关键帧恢复\n    });\n    h.loadSource(u);\n    h.attachMedia(v);\n    h.on(Hls.Events.MANIFEST_PARSED,()=>v.play().then(()=>setupCustomControls(v)).catch(console.log));\n    h.on(Hls.Events.ERROR,(_,d)=>d.fatal&&playNext())\n  } else { // Hls加载失败或浏览器原生支持HLS\n    if (v.canPlayType('application/vnd.apple.mpegurl')) {\n      v.src = u;\n      v.onloadedmetadata = () => v.play().then(() => setupCustomControls(v));\n      v.onerror = playNext;\n    } else {\n      // 如果都不支持，尝试直接播放（可能支持MP4等格式）\n      v.src = u;\n      v.onerror = playNext;\n      v.play().then(() => setupCustomControls(v)).catch(playNext);\n    }\n  }\n}playNext();\n</script>\n</body></html>",
    "ruleImage": "{{$.coverbase64.url}}",
    "ruleLink": "/api/videoplay/{{$.id}}?uuid=1",
    "ruleNextPage": "$.rescont.next_page_url",
    "rulePubDate": "📆{{$.updated_at## .*}}  ⏱️{{$.playtimes}}",
    "ruleTitle": "$.title##.*屎.*|.*Ts.*|.*TS.*|.*ts.*|.*伪娘.*|.*人妖.*|.*男同.*|.*mbrba.*|.*水果派.*|.*解说.*|.*mmraa.*|.*ss-.*|.*fway.*|.*rebd.*|.*mbdd.*|.*双性.*|.*妈妈.*|.*儿子.*|.*爸爸.*|.*女儿.*|.*母子.*|.*父女.*|.*熟女.*|.*眼射.*|.*直男.*|.*CD.*|.*肥女.*|.*黄金.*|.*骚0.*|.*gv.*|.*父子.*|.*飞机.*|.*撸.*|.*厕.*|.*老阿姨.*|.*乱伦.*",
    "singleUrl": false,
    "sortUrl": "\n随机::/api/videosort/0?page={{ Math.ceil(Math.random()*1500) }}\n最新::/api/videosort/0?page={{page}}\n🔎搜索::/api/videosort/0?serach={{v=source.getVariable();if(/^\\s*$/.test(v)||v==null)source.setVariable('强奸');source.getVariable()}}&page={{page}}\n国产自拍::/api/videosort/10?page={{page}}\nH动漫::/api/videosort/14?page={{page}}\n扶她姐妹::/api/videosort/58?page={{page}}\n国产AV::/api/videosort/60?page={{page}}\n网红主播::/api/videosort/17?page={{page}}\n嫩模专区::/api/videosort/37?page={{page}}\n偷拍盗摄::/api/videosort/53?page={{page}}\n萌妹酱篇::/api/videosort/54?page={{page}}\n精彩短片::/api/videosort/55?page={{page}}\n外流视频::/api/videosort/32?page={{page}}\n明星淫梦::/api/videosort/40?page={{page}}\n鹿少女集::/api/videosort/56?page={{page}}\n高清无码::/api/videosort/1?page={{page}}\n制服诱惑::/api/videosort/5?page={{page}}\n长腿丝袜::/api/videosort/11?page={{page}}\nAV剧情::/api/videosort/29?page={{page}}\nAV素人::/api/videosort/24?page={{page}}\n淫荡痴女::/api/videosort/51?page={{page}}\n巨乳咪咪::/api/videosort/20?page={{page}}\n人妻熟女::/api/videosort/6?page={{page}}\n近亲乱伦::/api/videosort/49?page={{page}}\n淫乱师生::/api/videosort/46?page={{page}}\n角色扮演::/api/videosort/4?page={{page}}\n青春萝莉::/api/videosort/22?page={{page}}\n魔镜系列::/api/videosort/39?page={{page}}\n中文无码::/api/videosort/57?page={{page}}\n当红女优::/api/videosort/9?page={{page}}\n中文字幕::/api/videosort/19?page={{page}}\n259LUXU::/api/videosort/36?page={{page}}\n重咸口味::/api/videosort/23?page={{page}}\n丝瓜推荐::/api/videosort/30?page={{page}}\n三级电影::/api/videosort/25?page={{page}}\n电车之狼::/api/videosort/52?page={{page}}\n中外合拍::/api/videosort/59?page={{page}}\n苍老师::/api/videosort/44?page={{page}}\n女同性爱::/api/videosort/38?page={{page}}\n欧美AV::/api/videosort/16?page={{page}}\n恐怖情色::/api/videosort/35?page={{page}}",
    "sourceGroup": "2222",
    "sourceIcon": "https://kp-i25985.com/Uploads/vod/2023-06-21/1141.mp4.gif",
    "sourceName": "🌈丝瓜    S",
    "sourceUrl": "https://api.sgapiaba.xyz",
    "style": ".container {\n    position: relative; /* 相对定位，用于包含视频 */\n    height: 100%; /* 容器高度与视频原始高度相同 */\n    overflow: hidden; /* 隐藏超出容器的部分 */\n}\n.title {\n    position: absolute; /* 绝对定位，相对于容器 */\n    top: 0; \n    width: 100%;\n    overflow: hidden; \n    text-overflow: ellipsis;\n    display: -webkit-box;\n    -webkit-box-orient: vertical; \n    -webkit-line-clamp: 2;\n    z-index: 1; /* 确保标题在视频之上 */\n    background: #000; /* 纯黑色背景 */ \n    padding: 0 0 3px 0;\n}\nvideo {\n    position: absolute; /* 绝对定位，相对于容器 */ \n    top: -65px; /* 上移80px */\n    left: 0; \n    width: 100%; \n    height: calc(96% + 65px);  /* 调整高度以适应内容 */\n    object-fit: contain; /* 确保视频内容不被裁剪 */\n    z-index: 0; /* 确保视频在标题之下 */\n    controls=\"controls\" autoplay muted; \n} \n"
  },
  {
    "articleStyle": 1,
    "customOrder": 61,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\"User-Agent\": \"Mozilla/5.0 (Linux; Android 10;Xiaomi 10pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.104 Mobile Safari/537.36\"}",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "$..data[*]",
    "ruleContent": "$..videopath##.*\\$\n\n@js:\nurl=result;\n\nloadding=java.get(\"pic\")\n\nhtml=\n`<link rel=\"stylesheet\" type=\"text/css\" href=\"https://muiplayer.js.org/css/mui-player.min.css\" />\n\n<script type=\"text/javascript\" src=\"https://cdn.jsdelivr.net/gh/ljun223/reader3@main/js/mui-player.min.js\"></script>\n\n<script type=\"text/javascript\" src=\"https://cdn.jsdelivr.net/gh/ljun223/reader3@main/js/mui-player-mobile-plugin.min.js\"></script>\n\n<div class=\"dz\">`+url+`</div>\n\n<div id=\"mui-player\" style=\"width:100%;height:300px\"></div>\n\n<script>\n   var mp = new MuiPlayer(\t{\n \t\t  \"container\": \"#mui-player\",\n \t\t  \"src\": \"`+url+`\",\n \t\t  \"poster\":\"`+loadding+`\",\n \t\t  \"autoFit\":false,\n \t\t  \"lang\": \"zh-cn\",\n \t  \t\"height\":\"300px\",\n \t\t  plugins: [\n \t\t    new MuiPlayerMobilePlugin({\n \t\t\t    \"key\":\n \t\t\t \"01I01I01H01J01L01K01J01I01K01J01H01D01J01G01E\",\n \t\t    \t\"showMenuButton\": true,\n \t\t\t    \"pageGesture\":true,\n \t\t\t   })\n    ]\n   }); \n </script>`",
    "ruleImage": "coverpath@put:{\"pic\":\"$.coverpath\"}",
    "ruleLink": "https://77gmk8o.com/api/videoplay/{{$.id}}?uuid=1",
    "ruleNextPage": "page",
    "rulePubDate": "authername",
    "ruleTitle": "title",
    "singleUrl": false,
    "sortUrl": "@js:\n\ndata=java.ajax(\"https://77gmk8o.com/api/videosort\");\n\njson=JSON.parse(data);\n\nvar list=[];\nvar num=json.rescont.length;\nfor(var i=1;i<num;i++){\nlist+=json.rescont[i].name+\"::\"+\"https://77gmk8o.com/api/videosort/\"+json.rescont[i].id+\"?orderby=&page={{page}}\"+\"\\n\"\n\t};\n\"搜索用::https://77gmk8o.com/api/videosort/0?page={{page}}&serach={{source.getVariable()}}\"+\"\\n\"+list",
    "sourceGroup": "202",
    "sourceIcon": "https://img0.baidu.com/it/u=2908908160,2785784129&fm=253&fmt=auto&app=138&f=PNG",
    "sourceName": "葫芦视频",
    "sourceUrl": "https://77gmk8o.com"
  },
  {
    "articleStyle": 2,
    "customOrder": 62,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "@js:\n(()=>{\nlet headerss={};\nheaderss['User-Agent']=java.getWebViewUA();\n return JSON.stringify(headerss);\n})();",
    "lastUpdateTime": 1773945742824,
    "loadWithBaseUrl": true,
    "ruleArticles": "div.home-rows-videos-wrapper@a:not([target])||div.horizontal-row>div.video-item-container",
    "ruleContent": "<js>\nlet title = java.getString('#shareBtn-title@text')\nlet page_arr = java.getStringList('#playlist-scroll@a.overlay[-1:0]@href');\nlet video_arr = [];\nfor (let a = 0 ; a < page_arr.length ; a++){\nif (baseUrl == page_arr[a]) {\nvideo_arr.push(java.getString('video#player@source.0@src'));\n} else {\nlet content = java.get(page_arr[a], {}).body();\nvideo_arr.push(java.getString('video#player@source.0@src', content));\n}\n}\nresult = {};\nresult.title = title;\nresult.url = video_arr;\nresult.page = page_arr;\nresult;\n</js>\n<!DOCTYPE html>\n<html lang=\"zh-Hans\">\n<head>\n<title>{{result.title}}</title>\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no\">\n<meta name=\"referrer\" content=\"no-referrer\">\n<link href=\"https://cdn.bootcdn.net/ajax/libs/plyr/3.7.8/plyr.css\" rel=\"stylesheet\">\n</head>\n<body>\n<p></p>\n<div class=\"video-container\">\n  <video id=\"player\" playsinline controls preload=\"auto\" >\n  </video>\n</div>\n<details>\n  <summary>\n    <h3></h3>\n  </summary>\n  <img>\n</details>\n<div class=\"all-info\">\n<div>\n    <p>🕵 片名：{{result.title}}</p>\n</div>\n<div class=\"jiekou\" style=\"\">\n<p>🎬 集数： </p>\n<div id=\"selected-jiekou\" onclick=\"jiekouList()\"><button data-id=\"0\"><b>无尽视频<sup>1</sup></b></button></div><div id=\"jiekou-list\" style=\"display: none;\"></div></div>\n\n{{\n\nlet dom = `<div class=\"jishu\" style=\"display:block;\"><p>`;\nfor (let b = 0 ; b < result.url.length ; b++){\ndom += `<button onclick=\"jishu(this)\" data-src=\"${result.url[b]}\"><b>${b + 1}</b></button>`\n}\ndom  +=`</p></div>`;\ndom;\n}}\n\n\n</div>\n\n<script src=\"https://cdn.bootcdn.net/ajax/libs/hls.js/1.6.12/hls.min.js\"></script>\n<script src=\"https://cdn.bootcdn.net/ajax/libs/plyr/3.7.8/plyr.min.js\"></script>\n\n<script>\n\nconst JKkey = \"{{java.md5Encode16(baseUrl.replace(/.*\\}([^\\}\\`]+)\\`/,'$1'))}}\";\nconst JDkey = \"{{java.md5Encode16(baseUrl.replace(/.*\\}([^\\}\\`]+)\\`/,'$1') + 'time')}}\";\nconst PTtime = {{/^\\d+$/.test('跳过片头：') ?'跳过片头：' : 0}};\nconst PWtime = {{/^\\d+$/.test('跳过片尾：') ? '跳过片尾：' : 0}};\nconst BSspeed = {{/^\\d+$/.test('长按倍速：') ? '长按倍速：' : 2}};\nconst ImageUrl = \"{{/^http/.test('背景图片：') ? '背景图片：' : ''}}\";\nconst Opacity1 = \"{{/0|1|^0\\.\\d+$/.test('图片透明度：') ? '图片透明度：' : ''}}\";\nconst Opacity2 = \"{{/0|1|^0\\.\\d+$/.test('按钮透明度：') ? '按钮透明度：' : ''}}\";\n\n// 获取视频URL并更新视频源\nasync function geturl() {\n    try {\n        let src = String($(\".jishu button.active\")[0].dataset.src);\n\n        // 获取页面信息\n        let fm = \"\";\n\n        // 获取视频源\n        let zyurl = [];\n        if (/mxcontent/.test(src)) {\n            zyurl.push({src:src,size:\"1\"});\n        } else {\n            zyurl.push({src:src,size:\"1\"});\n        }\n\n        // 更新详情封面\n        $(\"img\")[0].src = fm;\n\n        // 更新视频封面\n        $(\".video-container\")[0].style.background = `#000 url('${fm}') no-repeat center center / cover`;\n\n        // 返回视频源\n        let sources = zyurl;\n        return { sources: sources };\n    } catch (error) {\n        weblog(error, '错误:', true);\n        console.error(\"错误:\", error);\n        throw error;\n    }\n}\n\n// 点击集数按钮时调用的函数\nasync function jishu(item) {\n    var video = $('video')[0];\n    var wasPlaying = (video && !video.paused) || localStorage.getItem('fromEnded') === 'true';\n    if (localStorage.getItem('fromEnded') === 'true') {\n        localStorage.removeItem('fromEnded');\n    }\n    omit($('.jishu button.active'));\n    item.className = \"active\";\n    const { sources } = await geturl();\n    setTimeout(updatePadding, 100);\n    var index1 = $('#selected-jiekou button')[0].dataset.id;\n    var index2 = Array.from(item.parentNode.children).indexOf(item);\n    var Progress = {\n        index1: index1,\n        index2: index2\n    };\n    localStorage.setItem(JKkey, JSON.stringify(Progress));\n    localStorage.removeItem(JDkey);\n    initializePlayer(sources, JDkey, PTtime, PWtime, BSspeed, 1);\n    if (wasPlaying && video) {\n        const tryAutoPlay = () => {\n            if (video.readyState >= 3) {\n                video.play().catch(e => {\n                    console.log(\"自动播放被阻止:\", e);\n                    $('.plyr__control--overlaid').show();\n                });\n                video.removeEventListener('canplay', tryAutoPlay);\n            }\n        };\n        if (video.readyState >= 3) {\n            video.play().catch(e => console.log(\"立即播放失败:\", e));\n        } else {\n            video.addEventListener('canplay', tryAutoPlay);\n        }\n    }\n}\n\n// 页面加载时初始化播放器\n(async () => {\n    var m = 0,n = 0;\n    var Progress = localStorage.getItem(JKkey);\n    if (Progress) {\n        var history = JSON.parse(Progress);\n        m = history.index1;\n        n = history.index2;\n    }\n    if (m > 0) {\n        const buttonList = $('#jiekou-list')[0].querySelectorAll('button');\n        const targetButton = Array.from(buttonList).find(btn => btn.getAttribute('data-id') == m);\n        jiekou(targetButton);\n        const allButtons = $('.jishu')[m].querySelectorAll('button');\n        active(allButtons, n);\n    } else {\n        active($('.jishu button'), n);\n    }\n    const { sources } = await geturl();\n    setTimeout(updatePadding, 100);\n    localStorage.setItem('HistoryTAG', 1);\n    initializePlayer(sources, JDkey, PTtime, PWtime, BSspeed, 1);\n})();\n\n/*=================js 库================*/\n// 弹窗提示\nfunction weblog(message, title = '提示：', copy = false) {\n    // 0. 全屏状态处理（仅退出不恢复）\n    if (document.fullscreenElement) {\n        document.exitFullscreen().catch(err => {\n            console.warn('退出全屏失败:', err);\n        });\n        setTimeout(updatePadding, 100);\n    }\n\n    // 1. 保存页面原始状态\n    const previousOverflow = document.body.style.overflow;\n    const previousActiveElement = document.activeElement;\n    document.body.style.overflow = 'hidden';\n\n    // 2. 创建遮罩层\n    const overlay = document.createElement('div');\n    overlay.style.cssText = `\n        position: fixed;\n        top: 0;\n        left: 0;\n        width: 100%;\n        height: 100%;\n        background-color: rgba(0, 0, 0, 0.7);\n        z-index: 2147483647;\n        backdrop-filter: blur(3px);\n        opacity: 0;\n        transition: opacity 0.3s ease;\n        pointer-events: auto;\n    `;\n\n    // 3. 创建弹窗容器\n    const popup = document.createElement('div');\n    popup.className = 'popup';\n    popup.tabIndex = -1;\n\n    // 4. 创建标题\n    const titleElement = document.createElement('h3');\n    titleElement.textContent = title;\n    titleElement.className = 'titleElement';\n    popup.appendChild(titleElement);\n\n    // 5. 创建内容区域\n    const contentElement = document.createElement('div');\n    contentElement.textContent = message;\n    contentElement.className = 'contentElement';\n    popup.appendChild(contentElement);\n\n    // 6. 创建按钮容器\n    const buttonContainer = document.createElement('div');\n    buttonContainer.style.cssText = `\n        display: flex;\n        justify-content: flex-end;\n        gap: 12px;\n    `;\n\n    // 7. 根据copy参数决定是否显示复制按钮\n    if (copy) {\n        const copyButton = document.createElement('button');\n        copyButton.textContent = '复制文本';\n        copyButton.style.cssText = `\n            padding: 8px 18px;\n            cursor: pointer;\n            background-color: #4CAF50;\n            color: #eee;\n            border: none;\n            border-radius: 6px;\n            font-size: 14px;\n            font-weight: 500;\n            transition: all 0.2s;\n            height: 36px;\n            box-sizing: border-box;\n            line-height: 1;\n            display: inline-flex;\n            align-items: center;\n            justify-content: center;\n        `;\n\n        // 复制功能实现\n        copyButton.onclick = async () => {\n            const originalText = copyButton.textContent;\n\n            copyButton.disabled = true;\n            copyButton.style.opacity = '0.7';\n            copyButton.textContent = '复制中...';\n\n            try {\n                if (navigator.clipboard) {\n                    await navigator.clipboard.writeText(message);\n                } else {\n                    const textarea = document.createElement('textarea');\n                    textarea.value = message;\n                    textarea.style.position = 'fixed';\n                    document.body.appendChild(textarea);\n                    textarea.select();\n                    document.execCommand('copy');\n                    document.body.removeChild(textarea);\n                }\n\n                copyButton.textContent = '✓ 已复制';\n                copyButton.style.backgroundColor = '#2196F3';\n\n                setTimeout(() => {\n                    copyButton.textContent = originalText;\n                    copyButton.style.backgroundColor = '#4CAF50';\n                    copyButton.disabled = false;\n                    copyButton.style.opacity = '1';\n                }, 2000);\n            } catch (err) {\n                console.error('复制失败:', err);\n                copyButton.textContent = '复制失败';\n                setTimeout(() => {\n                    copyButton.textContent = originalText;\n                    copyButton.disabled = false;\n                    copyButton.style.opacity = '1';\n                }, 2000);\n            }\n        };\n\n        buttonContainer.appendChild(copyButton);\n    }\n\n    // 8. 创建关闭按钮\n    const closeButton = document.createElement('button');\n    closeButton.textContent = '关闭';\n    closeButton.style.cssText = `\n        padding: 8px 18px;\n        cursor: pointer;\n        background-color: #3493b6;\n        color: #eee;\n        border: none;\n        border-radius: 6px;\n        font-size: 14px;\n        font-weight: 500;\n        transition: all 0.2s;\n        height: 36px;\n        box-sizing: border-box;\n        line-height: 1;\n        display: inline-flex;\n        align-items: center;\n        justify-content: center;\n    `;\n    buttonContainer.appendChild(closeButton);\n    popup.appendChild(buttonContainer);\n\n    // 9. 关闭功能\n    const removePopup = () => {\n        popup.style.opacity = '0';\n        popup.style.transform = 'translate(-50%, -50%) scale(0.95)';\n        overlay.style.opacity = '0';\n\n        setTimeout(() => {\n            // 移除元素\n            if (overlay.parentNode) overlay.parentNode.removeChild(overlay);\n            if (popup.parentNode) popup.parentNode.removeChild(popup);\n\n            // 恢复页面状态\n            document.body.style.overflow = previousOverflow;\n            previousActiveElement?.focus();\n            document.removeEventListener('keydown', escHandler);\n        }, 300);\n    };\n\n    closeButton.onclick = removePopup;\n    overlay.onclick = removePopup;\n\n    // 10. 添加到页面\n    document.body.appendChild(overlay);\n    document.body.appendChild(popup);\n\n    // 触发动画\n    setTimeout(() => {\n        overlay.style.opacity = '1';\n        popup.style.opacity = '1';\n        popup.style.transform = 'translate(-50%, -50%) scale(1)';\n    }, 10);\n\n    // 11. ESC键关闭\n    const escHandler = (e) => {\n        if (e.key === 'Escape') {\n            removePopup();\n        }\n    };\n    document.addEventListener('keydown', escHandler);\n}\n\n// 选中标签\nfunction $(rule) {\n    return document.querySelectorAll(rule);\n}\n\n// 删除选中标签的class\nfunction omit(items) {\n    return Array.from(items, (item) => {\n        item.className = \"\";\n    });\n}\n\n// 选中标签的class增加active\nfunction active(items, index) {\n    items[index].className = \"active\";\n}\n\nlet isButtonListVisible = false;\n\n//切换候选列表显示\nfunction jiekouList() {\n    const selectedButton = $('#selected-jiekou > button')[0];\n    const buttonList = $('#jiekou-list')[0];\n    isButtonListVisible = !isButtonListVisible;\n    if (isButtonListVisible) {\n        if (buttonList.querySelectorAll('button').length > 0) {\n            selectedButton.style.borderRadius = '0';\n            buttonList.style.display = 'block';\n        }\n        selectedButton.style.opacity = '1';\n        // 添加全局点击事件监听\n        document.addEventListener('click', function globalClickListener(e) {\n            const clickedInsideButtonList = buttonList.contains(e.target);\n            const clickedSelectedButton = $('#selected-jiekou > button')[0].contains(e.target);\n            if (!clickedInsideButtonList && !clickedSelectedButton) {\n                selectedButton.style.borderRadius = '';\n                selectedButton.style.opacity = '';\n                buttonList.style.display = 'none';\n                isButtonListVisible = false;\n                document.removeEventListener('click', globalClickListener);\n            }\n        });\n    } else {\n        selectedButton.style.borderRadius = '';\n        selectedButton.style.opacity = '';\n        buttonList.style.display = 'none';\n    }\n}\n\n//切换列表接口\nfunction jiekou(clickedButton) {\n    const selectedContainer = $('#selected-jiekou')[0];\n    const selectedButton = selectedContainer.querySelector('button');\n    if (selectedButton) {\n        selectedButton.style.borderRadius = '';\n        selectedButton.style.opacity = '';\n    }\n    const buttonList = $('#jiekou-list')[0];\n    buttonList.appendChild(selectedContainer.querySelector('button'));\n    selectedContainer.appendChild(clickedButton);\n    isButtonListVisible = false;\n    buttonList.style.display = 'none';\n    const allButtons = buttonList.querySelectorAll('button');\n    allButtons.forEach(button => {\n        button.setAttribute('onclick', 'jiekou(this)');\n    });\n    const buttonsArray = Array.from(buttonList.querySelectorAll('button'));\n    buttonsArray.sort((a, b) => {\n        return parseInt(a.getAttribute('data-id')) - parseInt(b.getAttribute('data-id'));\n    });\n    buttonList.innerHTML = '';\n    buttonsArray.forEach(button => {\n        buttonList.appendChild(button);\n    });\n    JishuList(clickedButton);\n}\n\n// 切换集数列表显示\nfunction JishuList(clickedButton) {\n    const dataId = clickedButton.getAttribute('data-id');\n    const allJishuLists = $('.jishu');\n    allJishuLists.forEach(list => {\n        list.style.display = 'none';\n    });\n    allJishuLists[dataId].style.display = 'block';\n}\n\n// 保存原生的 fetch 函数\nconst originalFetch = window.fetch;\n\n// 重新定义全局的 fetch 函数\nwindow.fetch = async function(input, init = {}) {\n    const url = typeof input === 'string' ? input : input.url;\n\n    // 准备请求选项\n    let requestOptions = {\n        method: init.method || 'GET',\n        headers: {\n            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',\n            'Accept-Encoding': 'gzip, deflate, br',\n            'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',\n            ...init.headers\n        },\n        cache: 'no-cache',\n        ...init\n    };\n\n    // 处理请求体\n    if (init.body) {\n        const body = init.body;\n        if (!requestOptions.headers['Content-Type']) {\n            requestOptions.headers['Content-Type'] = typeof body === 'object'\n                ? 'application/json'\n                : 'application/x-www-form-urlencoded';\n        }\n\n        if (typeof body === 'object' && !(body instanceof FormData) && !(body instanceof URLSearchParams)) {\n            requestOptions.body = JSON.stringify(body);\n        } else if (typeof body === 'string') {\n            requestOptions.body = body.replace(/\\+/g, '%2B');\n        } else {\n            requestOptions.body = body;\n        }\n    }\n\n    // 如果没有请求体但存在 Content-Type 头，则删除它\n    if (!init.body && requestOptions.headers['Content-Type']) {\n        delete requestOptions.headers['Content-Type'];\n    }\n\n    // 使用降级策略\n    return await fetchWithFallback(input, init, url, requestOptions);\n};\n\n// 降级策略函数\nasync function fetchWithFallback(input, init, url, requestOptions) {\n    // 确定当前可用的方法级别\n    let methodLevel = 1; // 从最高级别开始尝试\n\n    while (methodLevel <= 2) {\n        try {\n            switch (methodLevel) {\n                case 1: // 第一级：legado\n                    if (typeof window.run === 'function') {\n                        console.log('Using legado (level 1)');\n                        return await useWindowRun(url, requestOptions);\n                    }\n                    break;\n\n                case 2: // 第二级：原生 fetch\n                    console.log('Using fetch (level 2)');\n                    return await originalFetch(input, init);\n            }\n        } catch (error) {\n            console.warn(`Method level ${methodLevel} failed:`, error);\n            // 当前级别失败，尝试下一级别\n        }\n\n        methodLevel++; // 尝试下一级别\n    }\n\n    // 使用原生 fetch 作为最终保底\n    console.error('All method levels failed, using native fetch as final fallback');\n    return await originalFetch(input, init);\n}\n\n// 使用 legado 发送请求\nasync function useWindowRun(url, requestOptions) {\n    const origin = window.location.origin;\n    const rawText = await window.run(`\n        let response = java.connect('${/^http/.test(url) ? url : (origin + url)},${JSON.stringify(requestOptions)}');\n        response.code() + '#|#' + response.body();\n    `);\n    const raw = rawText.split(\"#|#\");\n\n    // 判断状态码\n    let status = parseInt(raw[0]);\n\n    // 状态码对应的文本\n    const statusTexts = {\n        100: 'Continue',\n        101: 'Switching Protocols',\n        102: 'Processing',\n        200: 'OK',\n        201: 'Created',\n        202: 'Accepted',\n        203: 'Non-Authoritative Information',\n        204: 'No Content',\n        205: 'Reset Content',\n        206: 'Partial Content',\n        207: 'Multi-Status',\n        208: 'Already Reported',\n        226: 'IM Used',\n        300: 'Multiple Choices',\n        301: 'Moved Permanently',\n        302: 'Found',\n        303: 'See Other',\n        304: 'Not Modified',\n        305: 'Use Proxy',\n        307: 'Temporary Redirect',\n        308: 'Permanent Redirect',\n        400: 'Bad Request',\n        401: 'Unauthorized',\n        402: 'Payment Required',\n        403: 'Forbidden',\n        404: 'Not Found',\n        405: 'Method Not Allowed',\n        406: 'Not Acceptable',\n        407: 'Proxy Authentication Required',\n        408: 'Request Timeout',\n        409: 'Conflict',\n        410: 'Gone',\n        411: 'Length Required',\n        412: 'Precondition Failed',\n        413: 'Payload Too Large',\n        414: 'URI Too Long',\n        415: 'Unsupported Media Type',\n        416: 'Range Not Satisfiable',\n        417: 'Expectation Failed',\n        418: 'I\\'m a teapot',\n        421: 'Misdirected Request',\n        422: 'Unprocessable Entity',\n        423: 'Locked',\n        424: 'Failed Dependency',\n        425: 'Too Early',\n        426: 'Upgrade Required',\n        428: 'Precondition Required',\n        429: 'Too Many Requests',\n        431: 'Request Header Fields Too Large',\n        451: 'Unavailable For Legal Reasons',\n        500: 'Internal Server Error',\n        501: 'Not Implemented',\n        502: 'Bad Gateway',\n        503: 'Service Unavailable',\n        504: 'Gateway Timeout',\n        505: 'HTTP Version Not Supported',\n        506: 'Variant Also Negotiates',\n        507: 'Insufficient Storage',\n        508: 'Loop Detected',\n        510: 'Not Extended',\n        511: 'Network Authentication Required'\n    };\n\n    // 提取响应体\n    const responseBody = raw.length > 1 ? raw[1] : '';\n\n    // 判断Content-Type\n    let contentType = 'text/plain;charset=utf-8';\n\n    // 先检查URL扩展名\n    const urlLower = url.toLowerCase();\n    if (urlLower.includes('.ts') || urlLower.includes('.m3u8') || urlLower.includes('.mpeg')) {\n        contentType = 'video/mp2t';\n    } else if (urlLower.includes('.mp4') || urlLower.includes('.m4v')) {\n        contentType = 'video/mp4';\n    } else if (urlLower.includes('.webm')) {\n        contentType = 'video/webm';\n    } else if (urlLower.includes('.avi')) {\n        contentType = 'video/x-msvideo';\n    } else if (urlLower.includes('.mov')) {\n        contentType = 'video/quicktime';\n    } else if (urlLower.includes('.flv')) {\n        contentType = 'video/x-flv';\n    } else if (urlLower.includes('.mkv')) {\n        contentType = 'video/x-matroska';\n    } else if (urlLower.includes('.jpg') || urlLower.includes('.jpeg')) {\n        contentType = 'image/jpeg';\n    } else if (urlLower.includes('.png')) {\n        contentType = 'image/png';\n    } else if (urlLower.includes('.gif')) {\n        contentType = 'image/gif';\n    } else if (urlLower.includes('.svg')) {\n        contentType = 'image/svg+xml';\n    } else if (urlLower.includes('.webp')) {\n        contentType = 'image/webp';\n    } else if (urlLower.includes('.json')) {\n        contentType = 'application/json;charset=utf-8';\n    } else if (urlLower.includes('.xml')) {\n        contentType = 'application/xml;charset=utf-8';\n    } else if (urlLower.includes('.html') || urlLower.includes('.htm')) {\n        contentType = 'text/html;charset=utf-8';\n    } else if (urlLower.includes('.css')) {\n        contentType = 'text/css;charset=utf-8';\n    } else if (urlLower.includes('.js')) {\n        contentType = 'application/javascript;charset=utf-8';\n    } else if (urlLower.includes('.pdf')) {\n        contentType = 'application/pdf';\n    } else if (urlLower.includes('.zip')) {\n        contentType = 'application/zip';\n    } else if (urlLower.includes('.rar')) {\n        contentType = 'application/x-rar-compressed';\n    } else if (urlLower.includes('.7z')) {\n        contentType = 'application/x-7z-compressed';\n    } else if (urlLower.includes('.tar')) {\n        contentType = 'application/x-tar';\n    } else if (urlLower.includes('.gz')) {\n        contentType = 'application/gzip';\n    } else {\n        // 如果没有通过URL判断出来，尝试通过内容判断\n        if (responseBody && responseBody.length > 0) {\n            // 尝试判断是否为JSON\n            try {\n                // 检查是否以{或[开头\n                const trimmed = responseBody.trim();\n                if (trimmed.startsWith('{') || trimmed.startsWith('[')) {\n                    JSON.parse(responseBody);\n                    contentType = 'application/json;charset=utf-8';\n                }\n            } catch (e) {\n                // 不是JSON，继续检查\n            }\n\n            // 检查是否为HTML\n            if (responseBody.includes('<!DOCTYPE') ||\n                responseBody.includes('<html') ||\n                responseBody.includes('<head>') ||\n                responseBody.includes('<body>')) {\n                contentType = 'text/html;charset=utf-8';\n            }\n\n            // 检查是否为CSS\n            else if (responseBody.includes('{') && responseBody.includes('}') &&\n                    (responseBody.includes('color:') ||\n                     responseBody.includes('font-size:') ||\n                     responseBody.includes('background:'))) {\n                contentType = 'text/css;charset=utf-8';\n            }\n\n            // 检查是否为JavaScript\n            else if (responseBody.includes('function') ||\n                    responseBody.includes('var ') ||\n                    responseBody.includes('const ') ||\n                    responseBody.includes('let ') ||\n                    responseBody.includes('console.log')) {\n                contentType = 'application/javascript;charset=utf-8';\n            }\n\n            // 检查是否包含大量非ASCII字符或控制字符（可能是二进制数据）\n            else if (responseBody.length > 100) {\n                let binaryCount = 0;\n                for (let i = 0; i < Math.min(responseBody.length, 1000); i++) {\n                    const charCode = responseBody.charCodeAt(i);\n                    // 控制字符（除了常见的空白字符）或非ASCII字符\n                    if ((charCode < 32 && charCode !== 9 && charCode !== 10 && charCode !== 13) || charCode > 127) {\n                        binaryCount++;\n                    }\n                }\n\n                // 如果超过5%的字符是二进制特征，认为是二进制数据\n                if (binaryCount > Math.min(responseBody.length, 1000) * 0.05) {\n                    contentType = 'application/octet-stream';\n                }\n            }\n        }\n    }\n\n    // 创建并返回Response对象\n    return new Response(responseBody, {\n        status: status,\n        statusText: statusTexts[status] || 'Unknown Status',\n        headers: new Headers({\n            'Content-Type': contentType\n        })\n    });\n}\n\n// fetchRequest 函数\nasync function fetchRequest(url, headers, body = null) {\n    try {\n        const init = {\n            headers: headers\n        };\n\n        if (body) {\n            init.method = 'POST';\n            init.body = body;\n        }\n\n        const response = await fetch(url, init);\n\n        if (!response.ok) {\n            throw new Error(`HTTP error! Status: ${response.status}`);\n        }\n\n        const rawText = await response.text();\n\n        // 尝试解析 JSON\n        try {\n            const jsonData = JSON.parse(rawText);\n            return jsonData;\n        } catch (e) {\n            // 如果不是 JSON，返回原始文本\n            return rawText;\n        }\n    } catch (error) {\n        weblog(error, '请求失败:', true);\n        return null;\n    }\n}\n\n// 全局时间管理器\nconst TimeManager = {\n    currentVideoUrl: '',\n    headtime: 0,\n    endtime: 0,\n    listeners: [],\n\n    init(videoUrl) {\n        this.currentVideoUrl = videoUrl;\n        this._loadFromStorage();\n        this._setupListeners();\n    },\n\n    _loadFromStorage() {\n        const head = localStorage.getItem('head' + this.currentVideoUrl);\n        const end = localStorage.getItem('end' + this.currentVideoUrl);\n        this.headtime = head ? parseFloat(head) : 0;\n        this.endtime = end ? parseFloat(end) : 0;\n        this._notifyAll();\n    },\n\n    _setupListeners() {\n        window.addEventListener('storage', (e) => {\n            if (e.key === 'head' + this.currentVideoUrl) {\n                this.headtime = e.newValue ? parseFloat(e.newValue) : 0;\n                this._notify('head', this.headtime);\n            }\n            if (e.key === 'end' + this.currentVideoUrl) {\n                this.endtime = e.newValue ? parseFloat(e.newValue) : 0;\n                this._notify('end', this.endtime);\n            }\n        });\n    },\n\n    setHeadTime(time) {\n        this.headtime = time;\n        localStorage.setItem('head' + this.currentVideoUrl, time);\n        this._notify('head', time);\n    },\n\n    setEndTime(time) {\n        this.endtime = time;\n        localStorage.setItem('end' + this.currentVideoUrl, time);\n        this._notify('end', time);\n    },\n\n    clearMarks() {\n        localStorage.removeItem('head' + this.currentVideoUrl);\n        localStorage.removeItem('end' + this.currentVideoUrl);\n        this.headtime = 0;\n        this.endtime = 0;\n        this._notifyAll();\n    },\n\n    addListener(callback) {\n        this.listeners.push(callback);\n    },\n\n    _notify(type, value) {\n        this.listeners.forEach(cb => cb({ type, value }));\n    },\n\n    _notifyAll() {\n        this._notify('head', this.headtime);\n        this._notify('end', this.endtime);\n    }\n};\n\n// 初始设置\nlet player = null;\nlet timeManager = null;\nlet currentHls = null;\nlet isSwitching = false;\n\n// 初始化播放器\nfunction initializePlayer(sources, currentVideoUrl, defaultHeadtime, defaultEndtime, speed, autonext) {\n    const video = $('video')[0];\n    video.style.height = '56.25vw';\n    const qualityOptions = sources.map(source => parseInt(source.size));\n\n    // 修改图片和透明度\n    updateBackground(\n        typeof ImageUrl !== 'undefined' ? ImageUrl : undefined,\n        typeof Opacity1 !== 'undefined' ? Opacity1 : undefined,\n        typeof Opacity2 !== 'undefined' ? Opacity2 : undefined\n    );\n\n    // 初始化时间管理器\n    if (!timeManager || timeManager.currentVideoUrl !== currentVideoUrl) {\n        timeManager = Object.create(TimeManager);\n        timeManager.init(currentVideoUrl);\n\n        // 设置默认值（如果localStorage中没有）\n        if (!localStorage.getItem('head' + currentVideoUrl) && defaultHeadtime) {\n            timeManager.setHeadTime(defaultHeadtime);\n        }\n        if (!localStorage.getItem('end' + currentVideoUrl) && defaultEndtime) {\n            timeManager.setEndTime(defaultEndtime);\n        }\n    }\n\n    // 如果播放器已存在，则只更新视频源\n    if (player) {\n        // 获取当前画质\n        let currentQuality = qualityOptions[0];\n        if (player.storage && player.storage.get) {\n            const savedQuality = player.storage.get('quality');\n            if (savedQuality && qualityOptions.includes(parseInt(savedQuality))) {\n                currentQuality = parseInt(savedQuality);\n            }\n        }\n        if (!currentQuality) {\n            currentQuality = Math.max(...qualityOptions);\n        }\n\n        // 加载当前画质的视频源\n        const selectedSource = sources.find(source => source.size === currentQuality.toString()) || sources[0];\n        const savedProgress = localStorage.getItem(currentVideoUrl);\n        const progress = (savedProgress && savedProgress > timeManager.headtime) ? savedProgress : timeManager.headtime;\n\n        // 更新画质配置\n        player.config.quality.options = qualityOptions;\n        player.config.quality.default = currentQuality;\n        player.config.quality.onChange = (newQuality) => {\n            changeVideoQuality(newQuality, sources);\n        };\n\n        // 更新主菜单的画质显示\n        mainMenuQuality(currentQuality)\n\n        // 更新画质菜单选项\n        updateQualityOptions(qualityOptions, currentQuality, sources);\n\n        // 更新p标签显示当前源\n        $(\"body>p\")[0].innerHTML = `\n          <div style=\"display: flex; align-items: center; justify-content: space-between; width: 100%;\">\n            <a href=\"legadovideo://${encodeURIComponent(selectedSource.src)}\">\n              ${selectedSource.src}\n            </a>\n            <button\n              onclick=\"navigator.clipboard.writeText('${selectedSource.src.replace(/'/g, \"\\\\'\")}')\n                .then(() => weblog('链接已复制到剪贴板'))\n                .catch(() => weblog('复制链接失败'))\"\n            >\n              复制\n            </button>\n          </div>\n        `;\n\n        setTimeout(() => (isSwitching = false), 2000);\n\n        if (Hls.isSupported() && /m3u8|hls/.test(selectedSource.src)) {\n            initializeHlsPlayer(selectedSource.src, selectedSource.headersOrReferer, video, progress);\n        } else {\n            initializeRegularPlayer(selectedSource.src, selectedSource.headersOrReferer, video, progress);\n        }\n\n        return player;\n    }\n\n    // 创建新的播放器实例\n    player = new Plyr(video, {\n        controls: [\n            'play-large',   // 大播放按钮\n            'rewind',       // 倒退\n            'play',         // 播放\n            'fast-forward', // 快进\n            'progress',     // 进度条\n            'current-time', // 当前时间\n            'duration',     // 总时长\n            'mute',         // 静音\n            'volume',       // 音量\n            'captions',     // 字幕\n            'settings',     // 设置\n            'pip',          // 画中画\n            'airplay',      // Airplay\n            'fullscreen'    // 全屏\n        ],\n        settings: ['quality', 'speed'],\n        quality: {\n            default: qualityOptions[0],\n            options: qualityOptions,\n            forced: true,\n            onChange: (newQuality) => {\n                changeVideoQuality(newQuality, sources);\n            }\n        },\n        fullscreen: {\n            enabled: true,\n            fallback: true,\n            iosNative: true,\n            container: null,\n        },\n        speed: {\n            selected: 1, // 设置默认播放倍数\n            options: [8,5,4,3,2.5, 2, 1.5, 1, 0.5, 0.25],\n        },\n        i18n: {\n            restart: '重新开始',\n            rewind: '倒退 {seektime} 秒',\n            play: '播放',\n            pause: '暂停',\n            fastForward: '快进 {seektime} 秒',\n            seek: '进度',\n            seekLabel: '{currentTime} / {duration}',\n            played: '播放',\n            buffered: '缓冲',\n            currentTime: '当前时间',\n            duration: '持续时间',\n            volume: '音量',\n            mute: '静音',\n            unmute: '取消静音',\n            enableCaptions: '启用字幕',\n            disableCaptions: '禁用字幕',\n            enterFullscreen: '进入全屏',\n            exitFullscreen: '退出全屏',\n            frameTitle: '播放器',\n            captions: '字幕',\n            settings: '设置',\n            speed: '速度',\n            normal: '正常',\n            quality: '画质',\n            qualityLabel: {\n                0: '自动',\n            },\n            pip: '画中画',\n            loop: '循环',\n            start: '开始',\n            end: '结束',\n            all: '全部',\n            reset: '重置',\n            disabled: '禁用',\n            advertisement: '广告'\n        },\n        keyboard: {\n            focused: true,\n            global: true,\n        },\n        tooltips: {\n            controls: true,\n            seek: true\n        },\n        captions: {\n            active: true,\n            update: true,\n            language: 'auto',\n        },\n    });\n\n    player.on('ready', () => {\n        video.style.visibility = 'visible';\n\n        // 添加显示集数\n        addEpisodeBarToPlayer();\n\n        // 添加跳过菜单项\n        addSkipMenuItems(currentVideoUrl, timeManager);\n\n        // 初始化播放器方向控制功能\n        initPlayerOrientationControl(player);\n\n        // 设置进度记录\n        progressRecording(currentVideoUrl, video);\n\n        // 设置自动下一集监听\n        autoNextListener(currentVideoUrl, autonext, video);\n\n        // 添加上下集按钮\n        addEpisodeButtons(currentVideoUrl, autonext);\n\n        // 设置手势控制\n        gestureControls(player, video, speed);\n\n        // 设置全屏和按钮显示处理\n        fullscreenControls(autonext, video);\n\n        // 初始化处理全屏状态\n        updateFullscreen(autonext, video);\n\n        // 播放开始自动改为黑色背景\n        player.on('play', () => {\n            $(\".video-container\")[0].style.background = '#000';\n        });\n\n        // 进度大于0时自动改为黑色背景\n        player.on('timeupdate', () => {\n            if (video.currentTime > 0) $(\".video-container\")[0].style.background = '#000';\n        });\n\n        // 获取保存的播放进度\n        const savedProgress = localStorage.getItem(currentVideoUrl);\n        const progress = (savedProgress && savedProgress > timeManager.headtime) ? parseFloat(savedProgress) : timeManager.headtime;\n        if (!isNaN(progress) && progress > 0) {\n            video.currentTime = progress;\n        }\n\n        // 调用切换画质函数加载默认画质\n        changeVideoQuality(qualityOptions[0], sources);\n    });\n\n    return player;\n}\n\n// 修改图片和透明度\nfunction updateBackground(imageUrl, opacity1, opacity2) {\n    if (!imageUrl || imageUrl === '') imageUrl = '';\n    if (!opacity1 || opacity1 === '') opacity1 = 0.2;\n    if (!opacity2 || opacity2 === '') opacity2 = 0.6;\n    document.body.style.setProperty('--bg-image', `url('${imageUrl}')`);\n    document.body.style.setProperty('--bg-opacity1', opacity1);\n    document.body.style.setProperty('--bg-opacity2', opacity2);\n}\n\n// 更新画质菜单选项\nfunction updateQualityOptions(qualityOptions, currentQuality, sources) {\n    if (!player || !player.elements || !player.elements.settings) return;\n\n    try {\n        const settings = player.elements.settings;\n        const qualityPanel = settings.panels.quality;\n        if (!qualityPanel) return;\n        const menuContainer = qualityPanel.querySelector('[role=\"menu\"]');\n        if (!menuContainer) return;\n        menuContainer.innerHTML = '';\n        qualityOptions.forEach(quality => {\n            const isSelected = quality === currentQuality;\n            const button = createQualityButton(quality, isSelected, sources);\n            menuContainer.appendChild(button);\n        });\n    } catch (error) {\n        console.error('更新画质菜单选项失败:', error);\n    }\n}\n\n// 创建画质按钮\nfunction createQualityButton(quality, isSelected, sources) {\n    const button = document.createElement('button');\n    button.type = 'button';\n    button.className = 'plyr__control';\n    button.setAttribute('role', 'menuitemradio');\n    button.setAttribute('aria-checked', isSelected ? 'true' : 'false');\n    button.setAttribute('data-plyr', 'quality');\n    button.value = quality;\n\n    // 根据画质生成对应的按钮\n    const badge = getQualityBadge(quality);\n    button.innerHTML = `\n        <span>${quality}p${badge ? `<span class=\"plyr__menu__value\"><span class=\"plyr__badge\">${badge}</span></span>` : '</span>'}\n    `;\n\n    // 绑定点击事件\n    button.addEventListener('click', function(e) {\n        e.preventDefault();\n        e.stopPropagation();\n\n        const quality = parseInt(this.value);\n\n        // 1. 触发画质变更事件\n        if (player.quality) {\n            player.quality.current = quality;\n            if (player.quality.set) {\n                player.quality.set(quality);\n            }\n            player.emit('qualitychange', quality);\n        }\n\n        // 2. 更新配置\n        player.config.quality.current = quality;\n\n        // 3. 保存到Plyr存储\n        if (player.storage && player.storage.set) {\n            player.storage.set({ quality: quality });\n        }\n\n        // 4. 更新画质菜单选中状态\n        qualitySelection(quality);\n\n        // 5. 更新主菜单的画质显示\n        mainMenuQuality(quality);\n\n        // 6. 调用画质切换函数\n        changeVideoQuality(quality, sources);\n\n        // 7. 返回主菜单\n        backToMainMenu();\n    });\n\n    // 设置初始选中状态\n    if (isSelected) {\n        button.classList.add('plyr__control--selected');\n        const checkSpan = button.querySelector('.plyr__control--checked');\n        if (checkSpan) {\n            checkSpan.style.display = 'block';\n            checkSpan.innerHTML = '✓';\n        }\n    }\n\n    return button;\n}\n\n// 更新画质菜单选中状态\nfunction qualitySelection(selectedQuality) {\n    if (!player || !player.elements.settings) return;\n\n    const settings = player.elements.settings;\n    const qualityPanel = settings.panels.quality;\n    if (!qualityPanel) return;\n\n    const menuContainer = qualityPanel.querySelector('[role=\"menu\"]');\n    if (!menuContainer) return;\n\n    const allButtons = menuContainer.querySelectorAll('[data-plyr=\"quality\"]');\n    allButtons.forEach(btn => {\n        const quality = parseInt(btn.value);\n        const isSelected = quality === selectedQuality;\n\n        btn.setAttribute('aria-checked', isSelected ? 'true' : 'false');\n\n        if (isSelected) {\n            btn.classList.add('plyr__control--selected');\n            const checkSpan = btn.querySelector('.plyr__control--checked');\n            if (checkSpan) {\n                checkSpan.style.display = 'block';\n                checkSpan.innerHTML = '✓';\n                checkSpan.style.color = 'var(--plyr-control-toggle-checked-background, #00b3ff)';\n            }\n        } else {\n            btn.classList.remove('plyr__control--selected');\n            const checkSpan = btn.querySelector('.plyr__control--checked');\n            if (checkSpan) {\n                checkSpan.style.display = 'none';\n            }\n        }\n    });\n}\n\n// 在home菜单中查找画质按钮\nfunction findQualityMenu(homeMenu) {\n    const allButtons = homeMenu.querySelectorAll('[data-plyr=\"settings\"]');\n\n    for (let button of allButtons) {\n        const buttonText = button.textContent || button.innerText;\n\n        if (buttonText.includes('画质')) {\n            return button;\n        }\n    }\n\n    console.log('未找到包含关键词的按钮');\n    return null;\n}\n\n// 更新主菜单的画质显示\nfunction mainMenuQuality(quality) {\n    try {\n        // 查找设置弹出层容器\n        const menuContainer = document.querySelector('.plyr__menu__container');\n        if (!menuContainer) {\n            console.log('未找到菜单容器');\n            return;\n        }\n\n        // 查找主菜单（包含\"-home\"的ID）\n        const homeMenu = menuContainer.querySelector('[id*=\"-home\"]');\n        if (!homeMenu) {\n            console.log('未找到主菜单');\n            return;\n        }\n\n        // 在主菜单中查找画质按钮\n        const qualityButton = findQualityMenu(homeMenu);\n        if (!qualityButton) {\n            console.log('未找到画质按钮');\n            return;\n        }\n\n        // 更新画质显示\n        const valueSpan = qualityButton.querySelector('.plyr__menu__value');\n        if (valueSpan) {\n            valueSpan.innerHTML = `${quality}p`;\n        } else {\n            console.log('未找到valueSpan');\n        }\n\n    } catch (error) {\n        console.error('更新主菜单显示失败:', error);\n    }\n}\n\n// 返回主菜单\nfunction backToMainMenu() {\n    try {\n        // 查找设置弹出层容器\n        const menuContainer = document.querySelector('.plyr__menu__container');\n        if (!menuContainer) {\n            console.log('未找到菜单容器');\n            return;\n        }\n\n        // 更改home菜单和quality菜单显示\n        const homeMenu = menuContainer.querySelector('[id*=\"-home\"]');\n        const qualityMenu = menuContainer.querySelector('[id*=\"-quality\"]');\n\n        if (homeMenu && qualityMenu) {\n            homeMenu.removeAttribute('hidden');\n            qualityMenu.setAttribute('hidden', '');\n\n            return;\n        }\n\n        console.log('未找到需要的菜单');\n\n    } catch (error) {\n        console.error('返回主菜单失败:', error);\n    }\n}\n\n// 根据画质返回对应的徽章文本\nfunction getQualityBadge(quality) {\n    if (quality >= 2160) return '4K';\n    if (quality >= 1440) return '2K';\n    if (quality >= 1080) return 'FHD';\n    if (quality >= 720) return 'HD';\n    if (quality >= 480) return 'SD';\n    if (quality >= 360) return 'LD';\n    if (quality >= 240) return 'ULD';\n    return '';\n}\n\n// 设置进度记录\nfunction progressRecording(currentVideoUrl, video) {\n    const progressInterval = setInterval(() => {\n        const currentTime = video.currentTime;\n        localStorage.setItem(currentVideoUrl, currentTime.toString());\n        localStorage.setItem('HistoryTIME', Date.now());\n    }, 5000);\n}\n\n// 设置自动下一集监听\nfunction autoNextListener(currentVideoUrl, autonext, video) {\n    player.on('timeupdate', () => {\n        if (!autonext || video.paused || timeManager.endtime === 0 || video.duration <= 0) return;\n        if ((video.duration - video.currentTime) < timeManager.endtime) {\n            const randomDelay = Math.floor(Math.random() * 200) + 100;\n            setTimeout(() => {\n                if (isSwitching) return;\n                switchToNextEpisode(currentVideoUrl, autonext);\n            }, randomDelay);\n        }\n    });\n\n    player.on('ended', () => {\n        if (isSwitching || !autonext || video.duration <= 0) return;\n        const randomDelay = Math.floor(Math.random() * 200) + 100;\n        setTimeout(() => {\n            if (isSwitching) return;\n            localStorage.setItem('fromEnded', 'true');\n            switchToNextEpisode(currentVideoUrl, autonext);\n        }, randomDelay);\n    });\n}\n\n// 添加上下集按钮\nfunction addEpisodeButtons(currentVideoUrl, autonext) {\n    if (autonext) {\n        const style = document.createElement('style');\n        style.textContent = `\n            .plyr__control--episode-prev,\n            .plyr__control--episode-next {\n                display: none;\n                margin: 1px;\n            }\n            .plyr__controls [data-plyr=\"rewind\"],\n            .plyr__controls [data-plyr=\"fast-forward\"] {\n                margin: 1px;\n            }\n        `;\n        document.head.appendChild(style);\n\n        const controlsContainer = document.querySelector('.plyr__controls');\n        if (controlsContainer) {\n            // 获取参考按钮\n            const rewindBtn = controlsContainer.querySelector('[data-plyr=\"rewind\"]');\n            const fastForwardBtn = controlsContainer.querySelector('[data-plyr=\"fast-forward\"]');\n\n            // 创建上一集按钮（放在后退前）\n            if (rewindBtn && !document.querySelector('.plyr__control--episode-prev')) {\n                const prevBtn = document.createElement('button');\n                prevBtn.className = 'plyr__control plyr__control--episode-prev';\n                prevBtn.innerHTML = `\n                    <svg aria-hidden=\"true\" focusable=\"false\" width=\"18\" height=\"18\">\n                        <use xlink:href=\"#plyr-prev-episode\"></use>\n                    </svg>\n                    <span class=\"plyr__tooltip\">上一集</span>\n                `;\n                prevBtn.onclick = (e) => {\n                    e.preventDefault();\n                    switchToPrevEpisode(currentVideoUrl, autonext);\n                };\n                rewindBtn.parentNode.insertBefore(prevBtn, rewindBtn);\n            }\n\n            // 创建下一集按钮（放在快进后）\n            if (fastForwardBtn && !document.querySelector('.plyr__control--episode-next')) {\n                const nextBtn = document.createElement('button');\n                nextBtn.className = 'plyr__control plyr__control--episode-next';\n                nextBtn.innerHTML = `\n                    <svg aria-hidden=\"true\" focusable=\"false\" width=\"18\" height=\"18\">\n                        <use xlink:href=\"#plyr-next-episode\"></use>\n                    </svg>\n                    <span class=\"plyr__tooltip\">下一集</span>\n                `;\n                nextBtn.onclick = (e) => {\n                    e.preventDefault();\n                    switchToNextEpisode(currentVideoUrl, autonext);\n                };\n                fastForwardBtn.parentNode.insertBefore(nextBtn, fastForwardBtn.nextSibling);\n            }\n        }\n    }\n}\n\n// 设置手势控制\nfunction gestureControls(player, video, speed) {\n    const gesture = {\n        startX: 0,\n        startY: 0,\n        startTime: 0,\n        isLongPress: false,\n        initialSpeed: 1,\n        isSeeking: false,\n        longPressTimer: null,\n        wasPlaying: false,\n        lastTime: 0,\n        initialBrightness: 1,\n        isBrightnessControl: false,\n        initialVolume: 1,\n        isVolumeControl: false,\n        gestureType: null,\n        threshold: 15\n    };\n\n    // 提示工具\n    const controlTooltip = document.createElement('div');\n    controlTooltip.className = 'plyr__center-tooltip';\n    controlTooltip.innerHTML = `\n        <span class=\"control-icon\" style=\"font-weight:bold\"></span>\n        <span class=\"control-value\"></span>\n    `;\n    document.querySelector('.plyr__video-wrapper').appendChild(controlTooltip);\n\n    // 获取系统亮度（如果支持）\n    const getSystemBrightness = () => {\n        return parseFloat(localStorage.getItem('systemBrightness')) || 1;\n    };\n\n    // 设置系统亮度（模拟实现）\n    const setSystemBrightness = (brightness) => {\n        localStorage.setItem('systemBrightness', brightness.toString());\n\n        if ('screen' in window && 'brightness' in window.screen) {\n            try {\n                window.screen.brightness = brightness;\n            } catch (e) {\n                console.log('Screen Brightness API not supported');\n            }\n        }\n\n        let brightnessOverlay = document.getElementById('brightness-overlay');\n        if (!brightnessOverlay) {\n            brightnessOverlay = document.createElement('div');\n            brightnessOverlay.id = 'brightness-overlay';\n            brightnessOverlay.style.cssText = `\n                position: fixed;\n                top: 0;\n                left: 0;\n                width: 100%;\n                height: 100%;\n                background: black;\n                pointer-events: none;\n                z-index: 2147483647;\n                opacity: 0;\n                transition: opacity 0.2s ease;\n            `;\n            document.body.appendChild(brightnessOverlay);\n\n            document.addEventListener('fullscreenchange', updateBrightnessOverlay);\n            document.addEventListener('webkitfullscreenchange', updateBrightnessOverlay);\n        }\n        brightnessOverlay.style.opacity = (1 - brightness).toString();\n\n        updateBrightnessOverlay();\n    };\n\n    // 更新亮度覆盖层位置\n    const updateBrightnessOverlay = () => {\n        const brightnessOverlay = document.getElementById('brightness-overlay');\n        if (!brightnessOverlay) return;\n\n        const isFullscreen = document.fullscreenElement ||\n                           document.webkitFullscreenElement ||\n                           document.mozFullScreenElement ||\n                           document.msFullscreenElement;\n\n        if (isFullscreen) {\n            const fullscreenElement = document.fullscreenElement ||\n                                    document.webkitFullscreenElement ||\n                                    document.mozFullScreenElement ||\n                                    document.msFullscreenElement;\n\n            if (fullscreenElement) {\n                if (fullscreenElement !== document.body) {\n                    if (!fullscreenElement.contains(brightnessOverlay)) {\n                        fullscreenElement.appendChild(brightnessOverlay);\n                    }\n                    brightnessOverlay.style.position = 'absolute';\n                    brightnessOverlay.style.zIndex = '2147483647';\n                } else {\n                    if (document.body.contains(brightnessOverlay)) {\n                        document.body.appendChild(brightnessOverlay);\n                    }\n                    brightnessOverlay.style.position = 'fixed';\n                    brightnessOverlay.style.zIndex = '2147483647';\n                }\n            }\n        } else {\n            if (!document.body.contains(brightnessOverlay)) {\n                document.body.appendChild(brightnessOverlay);\n            }\n            brightnessOverlay.style.position = 'fixed';\n            brightnessOverlay.style.zIndex = '2147483647';\n        }\n    };\n\n    // 检查是否在全屏模式\n    const isFullscreen = () => {\n        return document.fullscreenElement ||\n               document.webkitFullscreenElement ||\n               document.mozFullScreenElement ||\n               document.msFullscreenElement;\n    };\n\n    // 检查是否在控制区域（全屏时排除顶部10%）\n    const isInControlArea = (startX, startY) => {\n        // 只有在全屏模式下才排除顶部区域\n        if (isFullscreen()) {\n            const screenHeight = window.innerHeight;\n            // 全屏时顶部10%区域用于系统手势（如下拉通知栏）\n            if (startY < screenHeight * 0.1) {\n                return false;\n            }\n        }\n\n        return true;\n    };\n\n    // 确定手势类型\n    const determineGestureType = (diffX, diffY, startX) => {\n        // 如果已经确定了手势类型，就保持原样\n        if (gesture.gestureType) {\n            return gesture.gestureType;\n        }\n\n        const absDiffX = Math.abs(diffX);\n        const absDiffY = Math.abs(diffY);\n\n        // 只有当移动距离超过阈值时才确定手势类型\n        if (absDiffX < gesture.threshold && absDiffY < gesture.threshold) {\n            return null;\n        }\n\n        // 判断主要移动方向\n        if (absDiffX > absDiffY) {\n            // 主要横向移动 - 进度控制\n            return 'seek';\n        } else {\n            // 主要纵向移动 - 根据起始位置判断是亮度还是音量\n            const isLeftSide = startX < window.innerWidth / 2;\n            return isLeftSide ? 'brightness' : 'volume';\n        }\n    };\n\n    // 显示控制提示\n    const showControlTooltip = (icon, value = '') => {\n        controlTooltip.style.opacity = '1';\n        controlTooltip.querySelector('.control-icon').textContent = icon;\n        controlTooltip.querySelector('.control-value').textContent = value;\n    };\n\n    // 隐藏控制提示\n    const hideControlTooltip = () => {\n        controlTooltip.style.opacity = '0';\n    };\n\n    // 长按倍数播放\n    const onTouchStart = (e) => {\n        if (e.touches?.length > 1) return;\n\n        const clientX = e.clientX || e.touches[0].clientX;\n        const clientY = e.clientY || e.touches[0].clientY;\n\n        // 检查是否在控制区域（全屏时排除顶部10%）\n        if (!isInControlArea(clientX, clientY)) return;\n\n        gesture.startX = clientX;\n        gesture.startY = clientY;\n        gesture.startTime = video.currentTime;\n        gesture.initialSpeed = player.speed;\n        gesture.isLongPress = false;\n        gesture.isSeeking = false;\n        gesture.wasPlaying = !video.paused;\n        gesture.lastTime = Date.now();\n        gesture.gestureType = null;\n\n        gesture.initialBrightness = getSystemBrightness();\n        gesture.initialVolume = video.volume;\n        gesture.isBrightnessControl = false;\n        gesture.isVolumeControl = false;\n\n        gesture.longPressTimer = setTimeout(() => {\n            if (!gesture.isSeeking && !gesture.gestureType) {\n                gesture.isLongPress = true;\n                player.speed = speed;\n\n                // 显示长按倍速提示\n                showControlTooltip('倍速', `${speed}×`);\n            }\n        }, 800);\n    };\n\n    // 滑动控制进度、亮度和音量\n    const onTouchMove = (e) => {\n        if (!gesture.startX || gesture.isLongPress) return;\n\n        const currentX = e.clientX || e.touches[0].clientX;\n        const currentY = e.clientY || e.touches[0].clientY;\n        const diffX = currentX - gesture.startX;\n        const diffY = currentY - gesture.startY;\n\n        // 确定手势类型（如果尚未确定）\n        if (!gesture.gestureType) {\n            gesture.gestureType = determineGestureType(diffX, diffY, gesture.startX);\n            if (gesture.gestureType) {\n                clearTimeout(gesture.longPressTimer);\n            }\n        }\n\n        // 根据确定的手势类型执行相应操作\n        switch (gesture.gestureType) {\n            case 'brightness':\n                handleBrightnessControl(diffY);\n                break;\n\n            case 'volume':\n                handleVolumeControl(diffY);\n                break;\n\n            case 'seek':\n                handleSeekControl(diffX);\n                break;\n\n            default:\n                // 手势类型未确定，不执行任何操作\n                return;\n        }\n\n        gesture.lastTime = Date.now();\n    };\n\n    // 处理亮度控制\n    const handleBrightnessControl = (diffY) => {\n        const brightnessChange = -diffY / window.innerHeight;\n        let newBrightness = Math.max(0.1, Math.min(1, gesture.initialBrightness + brightnessChange));\n\n        setSystemBrightness(newBrightness);\n\n        showControlTooltip('亮度', `${Math.round(newBrightness * 100)}%`);\n    };\n\n    // 处理音量控制\n    const handleVolumeControl = (diffY) => {\n        const volumeChange = -diffY / window.innerHeight;\n        let newVolume = Math.max(0, Math.min(1, gesture.initialVolume + volumeChange));\n\n        video.volume = newVolume;\n        player.volume = newVolume;\n\n        const iconText = newVolume === 0 ? '静音' : '音量';\n        showControlTooltip(iconText, `${Math.round(newVolume * 100)}%`);\n    };\n\n    // 处理进度控制\n    const handleSeekControl = (diffX) => {\n        if (!gesture.isSeeking) {\n            gesture.isSeeking = true;\n            gesture.wasPlaying = !video.paused;\n            if (gesture.wasPlaying) {\n                document.querySelector('.plyr__control--overlaid').classList.add('hidden');\n                video.pause();\n            }\n        }\n\n        const seekAmount = Math.round((diffX / window.innerWidth) * 300);\n        const newTime = Math.max(0, Math.min(\n            gesture.startTime + seekAmount,\n            video.duration\n        ));\n\n        if (Math.abs(video.currentTime - newTime) >= 1) {\n            $(\".video-container\")[0].style.background = '#000';\n            video.currentTime = newTime;\n        }\n\n        if (newTime <= 0) {\n            showControlTooltip('已到开头');\n        } else if (newTime >= video.duration) {\n            showControlTooltip('已到结尾');\n        } else {\n            const directionText = seekAmount > 0 ? '前进' : '后退';\n            showControlTooltip(directionText, `${Math.abs(seekAmount)}秒`);\n        }\n    };\n\n    // 触摸结束\n    const onTouchEnd = () => {\n        clearTimeout(gesture.longPressTimer);\n        if (gesture.isLongPress) {\n            player.speed = gesture.initialSpeed;\n            // 立即隐藏提示\n            hideControlTooltip();\n        }\n        else if (gesture.wasPlaying && !gesture.isLongPress && gesture.isSeeking) {\n            video.play().catch(e => console.log(\"播放恢复失败:\", e));\n            setTimeout(() => {\n                document.querySelector('.plyr__control--overlaid').classList.remove('hidden');\n            }, 100);\n            // 延迟隐藏提示\n            setTimeout(hideControlTooltip, 500);\n        } else {\n            // 其他情况延迟隐藏提示\n            setTimeout(hideControlTooltip, 500);\n        }\n\n        // 重置所有状态\n        gesture.startX = 0;\n        gesture.isSeeking = false;\n        gesture.isLongPress = false;\n        gesture.isBrightnessControl = false;\n        gesture.isVolumeControl = false;\n        gesture.gestureType = null;\n    };\n\n    // 事件监听\n    const playerContainer = document.querySelector('.plyr__video-wrapper');\n    playerContainer.addEventListener('touchstart', onTouchStart, { passive: true });\n    playerContainer.addEventListener('mousedown', onTouchStart);\n    playerContainer.addEventListener('touchmove', onTouchMove, { passive: false });\n    playerContainer.addEventListener('mousemove', onTouchMove);\n    playerContainer.addEventListener('touchend', onTouchEnd);\n    playerContainer.addEventListener('mouseup', onTouchEnd);\n    playerContainer.addEventListener('mouseleave', onTouchEnd);\n\n    setSystemBrightness(getSystemBrightness());\n\n    document.addEventListener('fullscreenchange', updateBrightnessOverlay);\n    document.addEventListener('webkitfullscreenchange', updateBrightnessOverlay);\n\n    // 注入CSS样式\n    const style = document.createElement('style');\n    style.textContent = `\n        .plyr__center-tooltip {\n            position: absolute;\n            top: calc(50% - 75px);\n            left: 50%;\n            transform: translate(-50%, -50%);\n            background-color: transparent;\n            color: white;\n            padding: 10px 20px;\n            border-radius: 5px;\n            z-index: 1000;\n            font-size: 18px;\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n            pointer-events: none;\n            opacity: 0;\n            transition: opacity 0.3s ease;\n            text-shadow: 0 0 5px rgba(0, 0, 0, 0.6), 0 0 10px rgba(0, 0, 0, 0.3);\n        }\n        .plyr__center-tooltip span {\n            font-weight: bold;\n            text-shadow: inherit;\n        }\n        .plyr__center-tooltip .control-value {\n            font-weight: normal;\n        }\n\n        #brightness-overlay {\n            background: black;\n            pointer-events: none;\n            opacity: 0;\n            transition: opacity 0.2s ease;\n            z-index: 2147483647 !important;\n        }\n    `;\n    document.head.appendChild(style);\n}\n\n// 根据当前方向更新按钮可见状态\nfunction updateButtonVisibility(autonext) {\n    if (!document.fullscreenElement || !autonext) return;\n\n    const isPortrait = window.innerHeight > window.innerWidth;\n    if (isPortrait) {\n        $('[data-plyr=\"rewind\"], [data-plyr=\"fast-forward\"]').forEach(btn => {\n            btn.style.display = 'none';\n        });\n    } else {\n        $('[data-plyr=\"rewind\"], [data-plyr=\"fast-forward\"]').forEach(btn => {\n            btn.style.display = 'flex';\n        });\n    }\n}\n\n// 处理全屏状态\nfunction updateFullscreen(autonext, video) {\n    if (!document.fullscreenElement) {\n        // 退出全屏时的处理\n        video.style.height = '56.25vw';\n        video.style.removeProperty('min-height');\n        $('.plyr__menu__container > div').forEach(menu => {\n            menu.style.maxHeight = '44vw';\n            menu.style.overflowY = 'auto';\n        });\n        if (autonext) {\n            $('.plyr__control--episode-prev, .plyr__control--episode-next').forEach(btn => {\n                btn.style.display = 'none';\n            });\n        }\n        $('[data-plyr=\"rewind\"], [data-plyr=\"fast-forward\"]').forEach(btn => {\n            btn.style.display = 'flex';\n        });\n        setTimeout(updatePadding, 100);\n    } else {\n        // 进入全屏时的处理\n        video.style.minHeight = '100%';\n        video.style.removeProperty('height');\n        $('.plyr__menu__container > div').forEach(menu => {\n            menu.style.maxHeight = '';\n            menu.style.overflowY = '';\n        });\n        if (autonext) {\n            $('.plyr__control--episode-prev, .plyr__control--episode-next').forEach(btn => {\n                btn.style.display = 'flex';\n            });\n            updateButtonVisibility(autonext); // 根据当前方向更新按钮\n        }\n\n        // 强制重绘\n        setTimeout(() => {\n            const videoWrapper = document.querySelector('.plyr__video-wrapper');\n            if (videoWrapper) {\n                videoWrapper.style.display = 'flex';\n                videoWrapper.style.alignItems = 'center';\n                videoWrapper.style.justifyContent = 'center';\n                video.style.maxWidth = '100%';\n                video.style.maxHeight = '100%';\n                video.style.width = 'auto';\n                video.style.height = 'auto';\n            }\n        }, 100);\n        setTimeout(updatePadding, 100);\n    }\n}\n\n// 设置全屏和按钮显示处理\nfunction fullscreenControls(autonext, video) {\n    // 添加事件监听器\n    document.addEventListener('fullscreenchange', () => updateFullscreen(autonext, video));\n    window.addEventListener('resize', () => updateButtonVisibility(autonext));\n    window.addEventListener('orientationchange', () => {\n        setTimeout(() => updateButtonVisibility(autonext), 100);\n    });\n}\n\n// 锁定屏幕方向为横屏（实时跟随设备方向）\nfunction lockLandscapeOrientation() {\n    if (screen.orientation && screen.orientation.lock) {\n        // 移除之前的监听器\n        if (lockLandscapeOrientation.currentListener) {\n            window.removeEventListener('deviceorientation', lockLandscapeOrientation.currentListener);\n        }\n\n        let lastDirection = null;\n        let hasSetInitial = false;\n        const DEAD_ZONE = 20; // 死区范围，避免轻微偏转就切换\n\n        const handleOrientation = (event) => {\n            const gamma = event.gamma;\n            const beta = event.beta; // 前后倾斜角度\n\n            // 在死区内不切换方向\n            if (Math.abs(gamma) < DEAD_ZONE) {\n                return;\n            }\n\n            let newDirection;\n\n            // 根据屏幕朝向调整方向判断\n            if (Math.abs(beta) > 90) {\n                // 屏幕朝下，需要反向判断\n                if (gamma > 0) {\n                    newDirection = 'landscape-primary'; // 屏幕朝下时，向右倾斜用右横屏\n                } else {\n                    newDirection = 'landscape-secondary'; // 屏幕朝下时，向左倾斜用左横屏\n                }\n            } else {\n                // 屏幕朝上，正常判断\n                if (gamma > 0) {\n                    newDirection = 'landscape-secondary'; // 设备向右，左横屏\n                } else {\n                    newDirection = 'landscape-primary'; // 设备向左，右横屏\n                }\n            }\n\n            // 初始设置：立即根据第一个有效的gamma值设置方向\n            if (!hasSetInitial) {\n                hasSetInitial = true;\n                lastDirection = newDirection;\n                console.log('初始设置方向:', newDirection, 'gamma:', gamma, 'beta:', beta, '屏幕朝下:', Math.abs(beta) > 90);\n                screen.orientation.lock(newDirection).catch(error => {\n                    console.warn('初始方向锁定失败:', error);\n                });\n                return;\n            }\n\n            // 后续切换：只有当方向确实改变时才锁定\n            if (newDirection !== lastDirection) {\n                lastDirection = newDirection;\n                console.log('切换横屏方向:', newDirection, 'gamma:', gamma, 'beta:', beta, '屏幕朝下:', Math.abs(beta) > 90);\n                screen.orientation.lock(newDirection).catch(error => {\n                    console.warn('横屏方向切换失败:', error);\n                });\n            }\n        };\n\n        // 开始监听\n        window.addEventListener('deviceorientation', handleOrientation);\n        lockLandscapeOrientation.currentListener = handleOrientation;\n\n        // 不设置默认方向，等待第一个设备方向事件\n        console.log('等待设备方向数据...');\n    }\n}\n\n// 锁定屏幕方向为竖屏\nfunction lockPortraitOrientation() {\n    if (screen.orientation && screen.orientation.lock) {\n        // 移除横屏的监听器（如果有）\n        if (lockLandscapeOrientation.currentListener) {\n            window.removeEventListener('deviceorientation', lockLandscapeOrientation.currentListener);\n            lockLandscapeOrientation.currentListener = null;\n        }\n\n        console.log('锁定竖屏方向');\n        // 强制锁定竖屏，忽略当前设备方向\n        screen.orientation.lock('portrait').catch(error => {\n            console.warn('竖屏锁定失败:', error);\n        });\n    }\n}\n\n// 解锁屏幕方向\nfunction unlockOrientation() {\n    if (screen.orientation && screen.orientation.unlock) {\n        screen.orientation.unlock();\n    }\n\n    // 移除设备方向监听\n    if (lockLandscapeOrientation.currentListener) {\n        window.removeEventListener('deviceorientation', lockLandscapeOrientation.currentListener);\n        lockLandscapeOrientation.currentListener = null;\n    }\n}\n\n// 检测视频方向\nfunction checkVideoOrientation(player) {\n    const video = player.media;\n    if (video.videoWidth && video.videoHeight) {\n        const aspectRatio = video.videoWidth / video.videoHeight;\n        return aspectRatio > 1; // 大于1为横屏，小于1为竖屏\n    }\n    return false;\n}\n\n// 初始化播放器方向控制\nfunction initPlayerOrientationControl(player) {\n    let isLandscapeVideo = false;\n\n    // 视频元数据加载时检测视频方向\n    player.on('loadedmetadata', () => {\n        isLandscapeVideo = checkVideoOrientation(player);\n        console.log('视频方向:', isLandscapeVideo ? '横屏' : '竖屏');\n    });\n\n    // 进入全屏时根据视频方向锁定屏幕\n    player.on('enterfullscreen', () => {\n        isLandscapeVideo = checkVideoOrientation(player);\n        console.log('进入全屏，视频方向:', isLandscapeVideo ? '横屏' : '竖屏');\n\n        // 立即锁定方向，不等待\n        if (isLandscapeVideo) {\n            lockLandscapeOrientation();\n        } else {\n            lockPortraitOrientation();\n        }\n    });\n\n    // 退出全屏时解锁方向\n    player.on('exitfullscreen', () => {\n        console.log('退出全屏，解锁方向');\n        unlockOrientation();\n    });\n}\n\n// 添加顶部集数显示（上移动画版）\nfunction addEpisodeBarToPlayer() {\n    // 添加顶部集数显示条\n    const episodeBar = document.createElement('div');\n    episodeBar.className = 'plyr__episode-bar';\n    episodeBar.style.transform = 'translateY(0)';\n    episodeBar.style.opacity = '1';\n\n    // 创建标题元素\n    const titleElement = document.createElement('div');\n    titleElement.className = 'plyr__episode-title';\n\n    // 初始化集数标题\n    const updateEpisodeTitle = () => {\n        const activeButton = document.querySelector('.jishu button.active');\n        if (activeButton) {\n            titleElement.textContent = activeButton.textContent.trim();\n        }\n    };\n\n    // 初始设置标题\n    updateEpisodeTitle();\n    episodeBar.appendChild(titleElement);\n    document.querySelector('.plyr__video-wrapper').appendChild(episodeBar);\n\n    // 同步播放器控件状态（顶部条上移，底部条下移）\n    const syncWithControls = () => {\n        const controls = player.elements.controls;\n        const controlsStyle = window.getComputedStyle(controls);\n\n        // 根据底部控制栏状态决定顶部条状态\n        if (controlsStyle.transform === 'none' || controlsStyle.opacity === '1') {\n            // 控制栏显示时：顶部条下滑进入\n            episodeBar.style.transform = 'translateY(0)';\n            episodeBar.style.opacity = '1';\n        } else {\n            // 控制栏隐藏时：顶部条上滑隐藏\n            episodeBar.style.transform = 'translateY(-100%)';\n            episodeBar.style.opacity = '0';\n        }\n    };\n\n    // 使用Plyr原生事件同步状态\n    player.on('controlsshown', () => {\n        episodeBar.style.transform = 'translateY(0)';\n        episodeBar.style.opacity = '1';\n    });\n\n    player.on('controlshidden', () => {\n        episodeBar.style.transform = 'translateY(-100%)';\n        episodeBar.style.opacity = '0';\n    });\n\n    // 监听集数切换事件\n    const observeEpisodeChange = () => {\n        const activeButtonObserver = new MutationObserver(() => {\n            updateEpisodeTitle();\n            // 切换集数时短暂显示\n            //episodeBar.style.transform = 'translateY(0)';\n            //episodeBar.style.opacity = '1';\n            //setTimeout(syncWithControls, 500);\n        });\n\n        const buttons = document.querySelectorAll('.jishu button');\n        buttons.forEach(button => {\n            activeButtonObserver.observe(button, { attributes: true });\n        });\n    };\n\n    // 全屏适配\n    player.on('enterfullscreen exitfullscreen', () => {\n        if (player.fullscreen.active) {\n            episodeBar.style.height = '60px';\n            episodeBar.querySelector('.plyr__episode-title').style.fontSize = '18px';\n        } else {\n            episodeBar.style.height = '40px';\n            episodeBar.querySelector('.plyr__episode-title').style.fontSize = '14px';\n        }\n    });\n\n    // 初始同步\n    setTimeout(() => {\n        // 绑定与Plyr相同的鼠标事件\n        const container = player.elements.container;\n\n        container.addEventListener('mousemove', () => {\n            episodeBar.style.transform = 'translateY(0)';\n            episodeBar.style.opacity = '1';\n        });\n\n        container.addEventListener('mouseleave', syncWithControls);\n\n        syncWithControls();\n        observeEpisodeChange();\n    }, 50);\n\n    // 添加样式\n    const style = document.createElement('style');\n    style.textContent = `\n        .plyr__episode-bar {\n            position: absolute;\n            top: 0;\n            left: 0;\n            right: 0;\n            height: 40px;\n            background: linear-gradient(\n              to bottom,\n              rgba(0,0,0,0.8) 0%,\n              rgba(0,0,0,0.5) 30%,\n              rgba(0,0,0,0) 100%\n            );\n            color: white;\n            display: flex;\n            align-items: center;\n            padding-left: 15px;\n            z-index: 3;\n            transform: translateY(-100%);\n            opacity: 0;\n            transition: all 0.4s ease-in-out;\n            pointer-events: none;\n        }\n        .plyr__episode-title {\n            font-size: 14px;\n            text-shadow: 0 0 5px rgba(0,0,0,0.5);\n            white-space: nowrap;\n            overflow: hidden;\n            text-overflow: ellipsis;\n            width: 75%;\n            display: block;\n        }\n        .plyr--fullscreen .plyr__episode-bar {\n            height: 60px;\n            padding-left: 20px;\n        }\n        .plyr--fullscreen .plyr__episode-title {\n            font-size: 18px;\n        }\n    `;\n    document.head.appendChild(style);\n}\n\n// 添加跳过菜单项\nfunction addSkipMenuItems(currentVideoUrl, timeManager) {\n    // 等待设置菜单加载完成\n    setTimeout(() => {\n        const settingsMenu = document.querySelector('.plyr__menu__container');\n        if (!settingsMenu) return;\n\n        // 创建跳过菜单项\n        const skipMenuItem = document.createElement('div');\n        skipMenuItem.className = 'plyr__skip-menu-item';\n        skipMenuItem.style.margin = '0 8px';\n        skipMenuItem.style.boxShadow = `\n            0 -1px 0 #ccc,\n            0 -2px 0 var(--plyr-menu-back-border-shadow-color, #fff)\n        `;\n        skipMenuItem.innerHTML = `\n            <span style=\"display: block; text-align: center; font-size: 15px; margin: 8px;\">标记片头/片尾</span>\n        `;\n        skipMenuItem.setAttribute('role', 'menuitem');\n\n        // 创建子菜单容器\n        const submenuContainer = document.createElement('div');\n        submenuContainer.className = 'plyr__skip-submenu';\n        submenuContainer.setAttribute('hidden', '');\n        submenuContainer.setAttribute('role', 'menu');\n\n        // 创建返回项\n        const backItem = document.createElement('div');\n        backItem.style.margin = '4px 0';\n        backItem.style.boxShadow = `\n            0 1px 0 var(--plyr-menu-back-border-shadow-color, #fff),\n            0 2px 0 #ccc\n        `;\n        backItem.innerHTML = `\n            <span style=\"display: block; text-align: center; height: 32px; font-size: 15px; margin: 4px 10px;\">返回上级菜单</span>\n        `;\n        backItem.setAttribute('role', 'menuitem');\n\n        // 实时获取标记时间\n        const getMarkTimes = () => ({\n            head: localStorage.getItem('head' + currentVideoUrl),\n            end: localStorage.getItem('end' + currentVideoUrl)\n        });\n\n        // 创建子菜单项\n        const submenuItems = `\n            <div style=\"display: flex; align-items: center; justify-content: space-between; padding: 4px 8px; margin: 2px 4px;\">\n                <div style=\"display: flex; align-items: center;\">\n                    <div style=\"font-size: 14px;\" data-action=\"mark-start\" role=\"menuitem\">\n                        ${getMarkTimes().head ? '已设片头' : '标记片头'}\n                    </div>\n                    <div style=\"font-size: 14px; color: #999; margin-left: 10px;\" class=\"head-time-display\">\n                        ${getMarkTimes().head ? formatTime(getMarkTimes().head) : '无'}\n                    </div>\n                </div>\n            </div>\n\n            <div style=\"display: flex; align-items: center; justify-content: space-between; padding: 4px 8px; margin: 2px 4px;\">\n                <div style=\"display: flex; align-items: center;\">\n                    <div style=\"font-size: 14px;\" data-action=\"mark-end\" role=\"menuitem\">\n                        ${getMarkTimes().end ? '已设片尾' : '标记片尾'}\n                    </div>\n                    <div style=\"font-size: 14px; color: #999; margin-left: 10px;\" class=\"end-time-display\">\n                        ${getMarkTimes().end ? formatTime(getMarkTimes().end) : '无'}\n                    </div>\n                </div>\n            </div>\n\n            <div style=\"display: flex; justify-content: center; padding: 4px 8px; margin: 2px 0 0 0;\">\n                <div style=\"font-size: 14px;\" data-action=\"clear-marks\" role=\"menuitem\">\n                    清除全部标记\n                </div>\n            </div>\n        `;\n\n        submenuContainer.appendChild(backItem);\n        submenuContainer.insertAdjacentHTML('beforeend', submenuItems);\n\n        // 添加到DOM - 插入到菜单最后面\n        settingsMenu.appendChild(skipMenuItem);\n        settingsMenu.appendChild(submenuContainer);\n\n        // 存储原始菜单项\n        const originalMenuItems = Array.from(settingsMenu.children).filter(\n            child => !child.classList.contains('plyr__skip-menu-item') &&\n                    !child.classList.contains('plyr__skip-submenu')\n        );\n\n        // 更新时间显示函数\n        function updateTimeDisplay() {\n            const { head, end } = getMarkTimes();\n            const headDisplay = submenuContainer.querySelector('.head-time-display');\n            const endDisplay = submenuContainer.querySelector('.end-time-display');\n            const markStartBtn = submenuContainer.querySelector('[data-action=\"mark-start\"]');\n            const markEndBtn = submenuContainer.querySelector('[data-action=\"mark-end\"]');\n\n            if (headDisplay) {\n                headDisplay.textContent = head ? formatTime(head) : '无';\n                headDisplay.style.color = head ? '#4CAF50' : '#999';\n                markStartBtn.textContent = head ? '已设片头' : '标记片头';\n            }\n\n            if (endDisplay) {\n                endDisplay.textContent = end ? formatTime(end) : '无';\n                endDisplay.style.color = end ? '#FF5722' : '#999';\n                markEndBtn.textContent = end ? '已设片尾' : '标记片尾';\n            }\n        }\n\n        // 添加事件监听\n        skipMenuItem.addEventListener('click', (e) => {\n            e.stopPropagation();\n            updateTimeDisplay();\n            originalMenuItems.forEach(item => item.style.display = 'none');\n            skipMenuItem.style.display = 'none';\n            submenuContainer.removeAttribute('hidden');\n        });\n\n        // 返回按钮点击事件\n        backItem.addEventListener('click', () => {\n            submenuContainer.setAttribute('hidden', '');\n            originalMenuItems.forEach(item => item.style.display = '');\n            skipMenuItem.style.display = '';\n        });\n\n        // 标记片头点击事件\n        submenuContainer.querySelector('[data-action=\"mark-start\"]').addEventListener('click', () => {\n            let headtime = getMarkTimes().head;\n            timeManager.setHeadTime(player.currentTime);\n            showTemporaryMessage(`已${headtime ? '重设' : '标记'}片头: ${formatTime(timeManager.headtime)}`);\n        });\n\n        // 标记片尾点击事件\n        submenuContainer.querySelector('[data-action=\"mark-end\"]').addEventListener('click', () => {\n            let endtime = getMarkTimes().end;\n            timeManager.setEndTime(player.duration - player.currentTime);\n            showTemporaryMessage(`已${endtime ? '重设' : '标记'}片尾: ${formatTime(timeManager.endtime)}`);\n        });\n\n        // 清除标记点击事件\n        submenuContainer.querySelector('[data-action=\"clear-marks\"]').addEventListener('click', () => {\n            timeManager.clearMarks();\n            showTemporaryMessage('已清除全部标记');\n        });\n\n        // 添加时间更新监听\n        timeManager.addListener(({ type }) => {\n            updateTimeDisplay();\n\n            // 如果是清除操作，确保UI同步更新\n            if (type === 'clear') {\n                const markStartBtn = submenuContainer.querySelector('[data-action=\"mark-start\"]');\n                const markEndBtn = submenuContainer.querySelector('[data-action=\"mark-end\"]');\n                if (markStartBtn) markStartBtn.textContent = '标记片头';\n                if (markEndBtn) markEndBtn.textContent = '标记片尾';\n            }\n        });\n\n        // 显示临时消息\n        function showTemporaryMessage(message) {\n            const messageEl = document.createElement('div');\n            messageEl.className = 'plyr__skip-message';\n            messageEl.textContent = message;\n            document.querySelector('.plyr').appendChild(messageEl);\n\n            setTimeout(() => {\n                messageEl.classList.add('fade-out');\n                setTimeout(() => messageEl.remove(), 300);\n            }, 2000);\n        }\n\n        // 添加样式\n        if (!document.querySelector('#plyrSkipMessageStyle')) {\n            const style = document.createElement('style');\n            style.id = 'plyrSkipMessageStyle';\n            style.textContent = `\n                .plyr__skip-message {\n                    position: fixed;\n                    top: 30px;\n                    left: 15px;\n                    transform: none;\n                    background-color: rgba(0, 0, 0, 0.5);\n                    color: white;\n                    padding: 10px 20px;\n                    border-radius: 4px;\n                    z-index: 1000;\n                    text-align: left;\n                    font-size: 14px;\n                    transition: opacity 0.3s ease;\n                }\n                .plyr__skip-message.fade-out {\n                    opacity: 0;\n                }\n                .plyr__skip-menu-item {\n                    cursor: pointer;\n                }\n                .plyr__skip-menu-item:hover {\n                    background-color: rgba(255,255,255,0.1);\n                }\n            `;\n            document.head.appendChild(style);\n        }\n\n        // 初始显示菜单项\n        skipMenuItem.style.display = '';\n\n        // 监听显示菜单项\n        function observeMainMenuState() {\n            const observer = new MutationObserver((mutations) => {\n                mutations.forEach((mutation) => {\n                    const homeMenu = document.querySelector('[id^=\"plyr-settings-\"][id$=\"-home\"]');\n                    const subMenu = document.querySelector('.plyr__skip-submenu');\n                    if (homeMenu && subMenu) {\n                        const homeIsHidden = homeMenu.hasAttribute('hidden');\n                        const subIsHidden = subMenu.hasAttribute('hidden');\n                        skipMenuItem.style.display = homeIsHidden || !subIsHidden ? 'none' : '';\n                    }\n                });\n            });\n\n            // 监听整个 document（因为菜单可能动态加载）\n            observer.observe(document.body, {\n                childList: true,    // 监听子元素增删\n                subtree: true,      // 监听所有后代元素\n                attributes: true,   // 监听属性变化\n                attributeFilter: ['hidden', 'id'] // 只监听 hidden 和 id 变化\n            });\n\n            // 初始检查\n            const initialHomeMenu = document.querySelector('[id^=\"plyr-settings-\"][id$=\"-home\"]');\n            const initialSubMenu = document.querySelector('.plyr__skip-submenu');\n            if (initialHomeMenu && initialSubMenu) {\n                const homeIsHidden = initialHomeMenu.hasAttribute('hidden');\n                const subIsHidden = initialSubMenu.hasAttribute('hidden');\n                skipMenuItem.style.display = homeIsHidden || !subIsHidden ? 'none' : '';\n            }\n        }\n\n        // 启动监听\n        observeMainMenuState();\n    }, 500);\n}\n\n// 格式化时间显示\nfunction formatTime(seconds) {\n    seconds = parseFloat(seconds);\n    const date = new Date(0);\n    date.setSeconds(seconds);\n    const timeString = date.toISOString().substr(11, 8);\n    return timeString.startsWith('00:') ? timeString.substr(3) : timeString;\n}\n\n// HLS播放-检测网络状况并自适应调整\nfunction getOptimalHlsConfig() {\n    const connection = navigator.connection || {};\n    const downlink = connection.downlink || 5;\n\n    if (downlink > 10) {\n        return adaptiveConfigManager.getHighSpeedConfig();\n    } else if (downlink > 5) {\n        return adaptiveConfigManager.getMediumSpeedConfig();\n    } else {\n        return adaptiveConfigManager.getLowSpeedConfig();\n    }\n}\n\n// 自适应配置管理器\nconst adaptiveConfigManager = {\n    performanceMetrics: {\n        loadTimes: [],\n        bufferingEvents: 0,\n        averageLoadTime: 0,\n        lastUpdateTime: 0\n    },\n\n    // 配置模板\n    configTemplates: {\n        highSpeed: {\n            // 缓冲区设置\n            maxBufferSize: 800 * 1024 * 1024,  // 800MB\n            maxBufferLength: 600,              // 10分钟缓冲区\n            maxMaxBufferLength: 1200,          // 20分钟最大缓冲区\n            backBufferLength: 300,             // 5分钟后缓冲区\n\n            // 预加载优化\n            preloadTime: 90,                   // 预加载90秒\n            initialLiveManifestSize: 5,\n\n            // 网络优化\n            maxLoadingDelay: 1,\n            maxSeekHole: 0.5,\n            maxFragLookUpTolerance: 0.05,\n            highBufferWatchdogPeriod: 0.5,\n            nudgeOffset: 0.02,\n            nudgeMaxRetry: 15,\n            maxStarvationDelay: 1\n        },\n        mediumSpeed: {\n            // 缓冲区设置\n            maxBufferSize: 600 * 1024 * 1024,  // 600MB\n            maxBufferLength: 450,              // 7.5分钟缓冲区\n            maxMaxBufferLength: 900,           // 15分钟最大缓冲区\n            backBufferLength: 240,             // 4分钟后缓冲区\n\n            // 预加载优化\n            preloadTime: 75,                   // 预加载75秒\n            initialLiveManifestSize: 4,\n\n            // 网络优化\n            maxLoadingDelay: 1.5,\n            maxSeekHole: 1,\n            maxFragLookUpTolerance: 0.08,\n            highBufferWatchdogPeriod: 1,\n            nudgeOffset: 0.03,\n            nudgeMaxRetry: 12,\n            maxStarvationDelay: 2\n        },\n        lowSpeed: {\n            // 缓冲区设置\n            maxBufferSize: 500 * 1024 * 1024,  // 500MB\n            maxBufferLength: 360,              // 6分钟缓冲区\n            maxMaxBufferLength: 720,           // 12分钟最大缓冲区\n            backBufferLength: 180,             // 3分钟后缓冲区\n\n            // 预加载优化\n            preloadTime: 60,                   // 预加载60秒\n            initialLiveManifestSize: 3,\n\n            // 网络优化\n            maxLoadingDelay: 2,\n            maxSeekHole: 1.5,\n            maxFragLookUpTolerance: 0.1,\n            highBufferWatchdogPeriod: 1.5,\n            nudgeOffset: 0.05,\n            nudgeMaxRetry: 15,\n            maxStarvationDelay: 3\n        }\n    },\n\n    // 根据性能指标调整配置\n    adaptConfigBasedOnPerformance() {\n        const metrics = this.performanceMetrics;\n\n        // 计算平均加载时间\n        if (metrics.loadTimes.length > 0) {\n            metrics.averageLoadTime = metrics.loadTimes.reduce((a, b) => a + b) / metrics.loadTimes.length;\n        }\n\n        // 基于性能指标选择配置\n        if (metrics.averageLoadTime < 2000 && metrics.bufferingEvents < 2) {\n            console.log('加载状况良好，使用高速配置');\n            return this.getHighSpeedConfig();\n        } else if (metrics.averageLoadTime < 5000 && metrics.bufferingEvents < 5) {\n            console.log('加载状况中等，使用平衡配置');\n            return this.getMediumSpeedConfig();\n        } else {\n            console.log('加载状况较差，使用保守配置');\n            return this.getLowSpeedConfig();\n        }\n    },\n\n    getHighSpeedConfig() {\n        return { ...this.configTemplates.highSpeed };\n    },\n\n    getMediumSpeedConfig() {\n        return { ...this.configTemplates.mediumSpeed };\n    },\n\n    getLowSpeedConfig() {\n        return { ...this.configTemplates.lowSpeed };\n    },\n\n    // 应用配置到HLS实例\n    applyConfigToHls(hlsInstance, config) {\n        Object.keys(config).forEach(key => {\n            if (hlsInstance.hasOwnProperty(key)) {\n                hlsInstance[key] = config[key];\n            }\n        });\n    },\n\n    // 动态调整配置\n    adaptHlsConfig(hlsInstance) {\n        if (this.performanceMetrics.loadTimes.length >= 3) {\n            const newConfig = this.adaptConfigBasedOnPerformance();\n            this.applyConfigToHls(hlsInstance, newConfig);\n            console.log('已根据加载性能动态调整HLS配置');\n        }\n    },\n\n    // 记录片段加载时间\n    recordFragmentLoadTime(duration) {\n        this.performanceMetrics.loadTimes.push(duration);\n\n        // 只保留最近10个记录\n        if (this.performanceMetrics.loadTimes.length > 10) {\n            this.performanceMetrics.loadTimes.shift();\n        }\n    },\n\n    // 记录缓冲事件\n    recordBufferingEvent() {\n        this.performanceMetrics.bufferingEvents++;\n    },\n\n    // 重置性能指标\n    resetMetrics() {\n        this.performanceMetrics.loadTimes = [];\n        this.performanceMetrics.bufferingEvents = 0;\n        this.performanceMetrics.averageLoadTime = 0;\n    }\n};\n\n// HLS播放\nfunction initializeHlsPlayer(source, headersOrReferer = null, video, currentTime, callback) {\n    if (currentHls) {\n        currentHls.stopLoad();\n        currentHls.detachMedia();\n        currentHls.destroy();\n    }\n\n    // 处理参数兼容性\n    let headers = null;\n    if (headersOrReferer) {\n        if (typeof headersOrReferer === 'string') {\n            headers = { 'Referer': headersOrReferer };\n        } else {\n            headers = headersOrReferer;\n        }\n    }\n\n    // 广告拦截配置\n    const adBlockConfig = {\n        enabled: true, // 设为false来禁用广告拦截\n        // 广告片段识别关键词\n        adKeywords: ['/ad/', 'ad_', '_ad', 'commercial', 'midroll', 'preroll', 'postroll'],\n        // 处理方式：'skip'=跳过，'empty'=返回空数据\n        strategy: 'skip'\n    };\n\n    // 获取初始配置\n    const initialConfig = getOptimalHlsConfig();\n\n    currentHls = new Hls({\n        ...initialConfig,\n        // 通用优化设置\n        enableWorker: true,\n        enableSoftwareAES: true,\n        stretchShortVideoTrack: true,\n        forceKeyFrameOnDiscontinuity: true,\n        optimizeAudioOnly: false,\n        lowLatencyMode: false,\n\n        // 使用 xhrSetup\n        xhrSetup: function(xhr, url) {\n            const startTime = performance.now();\n            const connection = navigator.connection || {};\n            const downlink = connection.downlink || 5;\n            const timeout = downlink > 10 ? 90000 : downlink > 5 ? 60000 : 30000;\n\n            // 设置超时\n            xhr.timeout = timeout;\n\n            // 设置响应类型\n            xhr.responseType = 'arraybuffer';\n\n            // 检查是否为广告片段\n            if (adBlockConfig.enabled && isAdSegment(url)) {\n                return handleAdRequest(xhr, url);\n            }\n\n            // 添加自定义 headers\n            if (headers) {\n                Object.keys(headers).forEach(key => {\n                    xhr.setRequestHeader(key, headers[key]);\n                });\n            }\n\n            // 监听加载完成事件\n            const originalSend = xhr.send;\n            xhr.send = function(body) {\n                this.addEventListener('loadend', function() {\n                    if (this.status >= 200 && this.status < 300) {\n                        const loadTime = performance.now() - startTime;\n                        adaptiveConfigManager.recordFragmentLoadTime(loadTime);\n\n                        // 如果加载时间过长，动态调整配置\n                        if (loadTime > 5000) {\n                            adaptiveConfigManager.adaptHlsConfig(currentHls);\n                        }\n                    }\n                });\n                originalSend.call(this, body);\n            };\n\n            // 监听超时事件\n            xhr.addEventListener('timeout', function() {\n                console.warn('XHR request timed out after', timeout, 'ms');\n            });\n\n            // 监听错误事件\n            xhr.addEventListener('error', function() {\n                console.error('XHR request failed');\n            });\n        }\n    });\n\n    // 广告检测函数\n    function isAdSegment(url) {\n        if (!adBlockConfig.enabled) return false;\n\n        const lowerUrl = url.toLowerCase();\n\n        // 检查URL是否包含广告关键词\n        for (const keyword of adBlockConfig.adKeywords) {\n            if (lowerUrl.includes(keyword.toLowerCase())) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    // 处理广告请求\n    function handleAdRequest(xhr, url) {\n        console.log('拦截广告片段:', url.substring(0, 100));\n\n        switch (adBlockConfig.strategy) {\n            case 'skip':\n                // 返回空数据，让HLS跳过这个片段\n                return createMockResponse(xhr);\n\n            case 'empty':\n                // 返回一个小型的合法视频片段（避免解码错误）\n                return createEmptySegmentResponse(xhr);\n\n            default:\n                return createMockResponse(xhr);\n        }\n    }\n\n    // 创建模拟响应（跳过广告）\n    function createMockResponse(xhr) {\n        // 设置XHR状态为已完成\n        Object.defineProperties(xhr, {\n            'readyState': { value: 4, writable: false },\n            'status': { value: 200, writable: false },\n            'response': { value: new ArrayBuffer(0), writable: false },\n            'responseText': { value: '', writable: false }\n        });\n\n        // 异步触发事件\n        setTimeout(() => {\n            // 触发readyStateChange\n            if (xhr.onreadystatechange) {\n                xhr.onreadystatechange.call(xhr);\n            }\n\n            // 触发load事件\n            if (xhr.onload) {\n                xhr.onload.call(xhr);\n            }\n\n            // 触发原生事件\n            const events = ['readystatechange', 'load', 'loadend'];\n            events.forEach(eventName => {\n                try {\n                    xhr.dispatchEvent(new Event(eventName));\n                } catch (e) {\n                    // 忽略事件分发错误\n                }\n            });\n        }, 0);\n\n        // 阻止实际网络请求\n        xhr.send = function() {\n            // 什么都不做，已经模拟了响应\n        };\n\n        return true;\n    }\n\n    // 创建空片段响应（更稳定的方案）\n    function createEmptySegmentResponse(xhr) {\n        // 创建一个非常小的视频片段（避免解码器错误）\n        // 这是一个H.264 NAL unit的简单示例（空片段）\n        const emptySegment = new Uint8Array([\n            0x00, 0x00, 0x00, 0x01, // NALU start code\n            0x09, 0xF0,             // NALU type: Access Unit Delimiter\n            0x00, 0x00, 0x00, 0x01, // NALU start code\n            0x06, 0x05              // NALU type: SEI\n        ]);\n\n        Object.defineProperties(xhr, {\n            'readyState': { value: 4, writable: false },\n            'status': { value: 200, writable: false },\n            'response': { value: emptySegment.buffer, writable: false }\n        });\n\n        setTimeout(() => {\n            if (xhr.onload) xhr.onload.call(xhr);\n            try {\n                xhr.dispatchEvent(new Event('load'));\n            } catch (e) {\n                // 忽略错误\n            }\n        }, 10);\n\n        xhr.send = function() {\n            // 阻止实际发送\n        };\n\n        return true;\n    }\n\n    // 监听HLS事件来优化广告检测\n    currentHls.on(Hls.Events.FRAG_LOADING, (event, data) => {\n        const frag = data.frag;\n        // 可以在片段加载时进行额外检测\n        if (frag.duration < 10 && frag.duration > 0) {\n            // 短片段可能是广告，但这里只是记录不处理\n            frag._isPotentialAd = true;\n        }\n    });\n\n    currentHls.loadSource(source);\n    currentHls.attachMedia(video);\n\n    // 监听缓冲事件\n    currentHls.on(Hls.Events.ERROR, (event, data) => {\n        if (data.details === Hls.ErrorDetails.BUFFER_STALLED_ERROR) {\n            adaptiveConfigManager.recordBufferingEvent();\n\n            // 如果有多次缓冲事件，立即调整配置\n            if (adaptiveConfigManager.performanceMetrics.bufferingEvents >= 3) {\n                adaptiveConfigManager.adaptHlsConfig(currentHls);\n            }\n        }\n\n        // 处理广告拦截可能引起的错误\n        if (data.details === Hls.ErrorDetails.FRAG_LOAD_ERROR ||\n            data.details === Hls.ErrorDetails.FRAG_LOAD_TIMEOUT) {\n            if (data.frag && isAdSegment(data.frag.url)) {\n                console.log('广告片段加载错误已忽略');\n                data.recovered = true;\n            }\n        }\n    });\n\n    currentHls.on(Hls.Events.MANIFEST_PARSED, () => {\n        if (currentTime > 0) {\n            video.currentTime = parseFloat(currentTime);\n            $(\".video-container\")[0].style.background = '#000';\n        }\n        if (callback) callback();\n    });\n\n    // 定期检查性能并调整配置（每30秒）\n    const performanceCheckInterval = setInterval(() => {\n        if (adaptiveConfigManager.performanceMetrics.loadTimes.length >= 5) {\n            adaptiveConfigManager.adaptHlsConfig(currentHls);\n        }\n    }, 30000);\n\n    // 清理interval当HLS实例被销毁时\n    currentHls.on(Hls.Events.DESTROYING, () => {\n        clearInterval(performanceCheckInterval);\n    });\n}\n\n// 可选：提供一个函数来启用/禁用广告拦截\nfunction setAdBlockEnabled(enabled) {\n    if (window.initializeHlsPlayer && window.initializeHlsPlayer.adBlockConfig) {\n        window.initializeHlsPlayer.adBlockConfig.enabled = enabled;\n    }\n}\n\n// 可选：添加广告关键词\nfunction addAdKeyword(keyword) {\n    if (window.initializeHlsPlayer && window.initializeHlsPlayer.adBlockConfig) {\n        if (!window.initializeHlsPlayer.adBlockConfig.adKeywords.includes(keyword)) {\n            window.initializeHlsPlayer.adBlockConfig.adKeywords.push(keyword);\n        }\n    }\n}\n\n// 普通播放\nfunction initializeRegularPlayer(source, headersOrReferer = null, video, currentTime, callback) {\n    video.src = '';\n    video.load();\n    video.preload = \"auto\";\n\n    // 处理参数兼容性\n    let headers = null;\n    if (headersOrReferer) {\n        if (typeof headersOrReferer === 'string') {\n            headers = { 'Referer': headersOrReferer };\n        } else {\n            headers = headersOrReferer;\n        }\n    }\n\n    if (headers) {\n        const xhr = new XMLHttpRequest();\n        xhr.open('HEAD', source, true);\n\n        Object.keys(headers).forEach(key => {\n            xhr.setRequestHeader(key, headers[key]);\n        });\n\n        xhr.withCredentials = true;\n        xhr.timeout = 10000;\n\n        xhr.onload = function() {\n            const acceptRanges = xhr.getResponseHeader('Accept-Ranges');\n            const contentLength = xhr.getResponseHeader('Content-Length');\n\n            console.log('服务器响应:', {\n                acceptRanges: acceptRanges,\n                contentLength: contentLength,\n                status: xhr.status\n            });\n\n            if (acceptRanges === 'bytes' && contentLength) {\n                console.log('服务器支持range请求，使用MediaSource播放');\n                setVideoSourceWithHeaders();\n            } else {\n                console.log('服务器不支持range请求，直接加载');\n                directLoadVideo();\n            }\n        };\n\n        xhr.onerror = function() {\n            console.error('HEAD请求失败');\n            directLoadVideo();\n        };\n\n        xhr.ontimeout = function() {\n            console.warn('HEAD请求超时');\n            directLoadVideo();\n        };\n\n        try {\n            xhr.send();\n        } catch (error) {\n            console.error('发送HEAD请求异常:', error);\n            directLoadVideo();\n        }\n    } else {\n        directLoadVideo();\n    }\n\n    function setVideoSourceWithHeaders() {\n        if ('MediaSource' in window && MediaSource.isTypeSupported('video/mp4')) {\n            console.log('使用MediaSource API');\n            const mediaSource = new MediaSource();\n            video.src = URL.createObjectURL(mediaSource);\n\n            mediaSource.addEventListener('sourceopen', function() {\n                const mimeCodec = 'video/mp4; codecs=\"avc1.42E01E,mp4a.40.2\"';\n                const sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);\n\n                const xhr = new XMLHttpRequest();\n                xhr.open('GET', source, true);\n                xhr.responseType = 'arraybuffer';\n\n                Object.keys(headers).forEach(key => {\n                    xhr.setRequestHeader(key, headers[key]);\n                });\n\n                xhr.onload = function() {\n                    if (xhr.status >= 200 && xhr.status < 300) {\n                        console.log('视频数据加载完成，大小:', (xhr.response.byteLength / 1024 / 1024).toFixed(2), 'MB');\n                        sourceBuffer.appendBuffer(xhr.response);\n                        sourceBuffer.addEventListener('updateend', function() {\n                            if (!sourceBuffer.updating) {\n                                mediaSource.endOfStream();\n                                handleVideoReady();\n                            }\n                        });\n                    } else {\n                        console.error('视频数据请求失败，状态码:', xhr.status);\n                        directLoadVideo();\n                    }\n                };\n\n                xhr.onerror = function() {\n                    console.error('视频数据请求网络错误');\n                    directLoadVideo();\n                };\n\n                xhr.send();\n            });\n        } else {\n            console.log('浏览器不支持MediaSource，直接设置src');\n            video.src = source;\n            video.addEventListener('loadedmetadata', function() {\n                handleVideoReady();\n            }, { once: true });\n            video.load();\n        }\n    }\n\n    function directLoadVideo() {\n        video.src = source;\n        video.load();\n        handleVideoReady();\n    }\n\n    function handleVideoReady() {\n        const onLoaded = () => {\n            if (currentTime > 0) {\n                video.currentTime = parseFloat(currentTime);\n                $(\".video-container\")[0].style.background = '#000';\n            }\n            if (callback) callback();\n        };\n\n        if (video.readyState >= 1) {\n            setTimeout(onLoaded, 0);\n        } else {\n            video.addEventListener('loadedmetadata', onLoaded, { once: true });\n        }\n    }\n}\n\n// 上一集函数\nfunction switchToPrevEpisode(currentVideoUrl, autonext) {\n    if (isSwitching || !autonext) return;\n\n    isSwitching = true;\n    localStorage.removeItem(currentVideoUrl);\n    const currentButton = $('.jishu button.active')[0];\n    const prevButton = currentButton?.previousElementSibling;\n\n    if (prevButton && prevButton.innerText !== \"\" && !localStorage.getItem(currentVideoUrl)) {\n        prevButton.click();\n    } else {\n        weblog('已经是第一集了！');\n    }\n}\n\n// 下一集函数\nfunction switchToNextEpisode(currentVideoUrl, autonext) {\n    if (isSwitching || !autonext) return;\n\n    isSwitching = true;\n    localStorage.removeItem(currentVideoUrl);\n    const currentButton = $('.jishu button.active')[0];\n    const nextButton = currentButton?.nextElementSibling;\n\n    if (nextButton && nextButton.innerText !== \"\") {\n        nextButton.click();\n    } else {\n        weblog('没有下一集了！');\n    }\n}\n\n// 切换视频质量的函数\nasync function changeVideoQuality(quality, sources) {\n    const video = $('video')[0];\n    const selectedSource = sources.find(source => source.size === quality.toString());\n    const currentTime = video.currentTime;\n    const wasPlaying = !video.paused;\n\n    if (wasPlaying) {\n        $(\".video-container\")[0].style.background = '#000';\n    }\n    $(\"body>p\")[0].innerHTML = `\n      <div style=\"display: flex; align-items: center; justify-content: space-between; width: 100%;\">\n        <a href=\"legadovideo://${encodeURIComponent(selectedSource.src)}\">\n          ${selectedSource.src}\n        </a>\n        <button\n          onclick=\"navigator.clipboard.writeText('${selectedSource.src.replace(/'/g, \"\\\\'\")}')\n            .then(() => weblog('链接已复制到剪贴板'))\n            .catch(() => weblog('复制链接失败'))\"\n        >\n          复制\n        </button>\n      </div>\n    `;\n\n    if (selectedSource) {\n        if (Hls.isSupported() && /m3u8|hls/.test(selectedSource.src)) {\n            initializeHlsPlayer(selectedSource.src, selectedSource.headersOrReferer, video, currentTime, () => {\n                if (wasPlaying) {\n                    video.play();\n                }\n            });\n        } else {\n            initializeRegularPlayer(selectedSource.src, selectedSource.headersOrReferer, video, currentTime, () => {\n                if (wasPlaying) {\n                    video.play();\n                }\n            });\n        }\n    }\n}\n\n// 页面信息高度调整\nfunction updatePadding() {\n    var videoheight = $(\"video\")[0].offsetHeight;\n    var h3height = $(\"h3\")[0].offsetHeight;\n    var selectedButton = $('#selected-jiekou > button')[0];\n    $(\"img\")[0].style.top = `calc(16px + ${videoheight}px + ${h3height}px)`;\n    $(\".all-info\")[0].style.paddingTop = `calc(20px + ${videoheight}px + ${h3height}px)`;\n    if ($('#selected-jiekou')[0] && $('#jiekou-list')[0]) {\n        $('#selected-jiekou')[0].style.top = `calc(16px + ${videoheight}px + ${h3height}px)`;\n        $('#jiekou-list')[0].style.top = `calc(15.9px + ${videoheight}px + ${h3height}px + ${selectedButton.offsetHeight}px)`;\n        $('#jiekou-list')[0].style.width = `${selectedButton.offsetWidth - 1.9}px`;\n    }\n}\nwindow.addEventListener('resize', updatePadding);\n\n// SVG图标JS动态注入\ndocument.write(`\n<svg xmlns=\"http://www.w3.org/2000/svg\" style=\"display:none\">\n  <symbol id=\"plyr-next-episode\" viewBox=\"0 0 18 18\">\n    <path d=\"M4 1v16l10-8z\" stroke-width=\"0.5\"/>\n    <rect x=\"14\" y=\"1\" width=\"4\" height=\"16\" rx=\"1\" stroke-width=\"0.5\"/>\n  </symbol>\n  <symbol id=\"plyr-prev-episode\" viewBox=\"0 0 18 18\">\n    <path d=\"M14 1v16L4 9z\" stroke-width=\"0.5\"/>\n    <rect x=\"0\" y=\"1\" width=\"4\" height=\"16\" rx=\"1\" stroke-width=\"0.5\"/>\n  </symbol>\n</svg>\n`);\n\ndocument.write(`\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" style=\"display: none;\">\n  <symbol id=\"plyr-airplay\" viewBox=\"0 0 18 18\">\n    <path d=\"M16 1H2a1 1 0 00-1 1v10a1 1 0 001 1h3v-2H3V3h12v8h-2v2h3a1 1 0 001-1V2a1 1 0 00-1-1z\"/>\n    <path d=\"M4 17h10l-5-6z\"/>\n  </symbol>\n  <symbol id=\"plyr-captions-off\" viewBox=\"0 0 18 18\">\n    <path d=\"M1 1c-.6 0-1 .4-1 1v11c0 .6.4 1 1 1h4.6l2.7 2.7c.2.2.4.3.7.3.3 0 .5-.1.7-.3l2.7-2.7H17c.6 0 1-.4 1-1V2c0-.6-.4-1-1-1H1zm4.52 10.15c1.99 0 3.01-1.32 3.28-2.41l-1.29-.39c-.19.66-.78 1.45-1.99 1.45-1.14 0-2.2-.83-2.2-2.34 0-1.61 1.12-2.37 2.18-2.37 1.23 0 1.78.75 1.95 1.43l1.3-.41C8.47 4.96 7.46 3.76 5.5 3.76c-1.9 0-3.61 1.44-3.61 3.7 0 2.26 1.65 3.69 3.63 3.69zm7.57 0c1.99 0 3.01-1.32 3.28-2.41l-1.29-.39c-.19.66-.78 1.45-1.99 1.45-1.14 0-2.2-.83-2.2-2.34 0-1.61 1.12-2.37 2.18-2.37 1.23 0 1.78.75 1.95 1.43l1.3-.41c-.28-1.15-1.29-2.35-3.25-2.35-1.9 0-3.61 1.44-3.61 3.7 0 2.26 1.65 3.69 3.63 3.69z\" fill-rule=\"evenodd\" fill-opacity=\".5\"/>\n  </symbol>\n  <symbol id=\"plyr-captions-on\" viewBox=\"0 0 18 18\">\n    <path d=\"M1 1c-.6 0-1 .4-1 1v11c0 .6.4 1 1 1h4.6l2.7 2.7c.2.2.4.3.7.3.3 0 .5-.1.7-.3l2.7-2.7H17c.6 0 1-.4 1-1V2c0-.6-.4-1-1-1H1zm4.52 10.15c1.99 0 3.01-1.32 3.28-2.41l-1.29-.39c-.19.66-.78 1.45-1.99 1.45-1.14 0-2.2-.83-2.2-2.34 0-1.61 1.12-2.37 2.18-2.37 1.23 0 1.78.75 1.95 1.43l1.3-.41C8.47 4.96 7.46 3.76 5.5 3.76c-1.9 0-3.61 1.44-3.61 3.7 0 2.26 1.65 3.69 3.63 3.69zm7.57 0c1.99 0 3.01-1.32 3.28-2.41l-1.29-.39c-.19.66-.78 1.45-1.99 1.45-1.14 0-2.2-.83-2.2-2.34 0-1.61 1.12-2.37 2.18-2.37 1.23 0 1.78.75 1.95 1.43l1.3-.41c-.28-1.15-1.29-2.35-3.25-2.35-1.9 0-3.61 1.44-3.61 3.7 0 2.26 1.65 3.69 3.63 3.69z\" fill-rule=\"evenodd\"/>\n  </symbol>\n  <symbol id=\"plyr-download\" viewBox=\"0 0 18 18\">\n    <path d=\"M9 13c.3 0 .5-.1.7-.3L15.4 7 14 5.6l-4 4V1H8v8.6l-4-4L2.6 7l5.7 5.7c.2.2.4.3.7.3zm-7 2h14v2H2z\"/>\n  </symbol>\n  <symbol id=\"plyr-enter-fullscreen\" viewBox=\"0 0 18 18\">\n    <path d=\"M10 3h3.6l-4 4L11 8.4l4-4V8h2V1h-7zM7 9.6l-4 4V10H1v7h7v-2H4.4l4-4z\"/>\n  </symbol>\n  <symbol id=\"plyr-exit-fullscreen\" viewBox=\"0 0 18 18\">\n    <path d=\"M1 12h3.6l-4 4L2 17.4l4-4V17h2v-7H1zM16 .6l-4 4V1h-2v7h7V6h-3.6l4-4z\"/>\n  </symbol>\n  <symbol id=\"plyr-fast-forward\" viewBox=\"0 0 18 18\">\n    <path d=\"M7.875 7.171L0 1v16l7.875-6.171V17L18 9 7.875 1z\"/>\n  </symbol>\n  <symbol id=\"plyr-logo-vimeo\" viewBox=\"0 0 18 18\">\n    <path d=\"M17 5.3c-.1 1.6-1.2 3.7-3.3 6.4-2.2 2.8-4 4.2-5.5 4.2-.9 0-1.7-.9-2.4-2.6C5 10.9 4.4 6 3 6c-.1 0-.5.3-1.2.8l-.8-1c.8-.7 3.5-3.4 4.7-3.5 1.2-.1 2 .7 2.3 2.5.3 2 .8 6.1 1.8 6.1.9 0 2.5-3.4 2.6-4 .1-.9-.3-1.9-2.3-1.1.8-2.6 2.3-3.8 4.5-3.8 1.7.1 2.5 1.2 2.4 3.3z\"/>\n  </symbol>\n  <symbol id=\"plyr-logo-youtube\" viewBox=\"0 0 18 18\">\n    <path d=\"M16.8 5.8c-.2-1.3-.8-2.2-2.2-2.4C12.4 3 9 3 9 3s-3.4 0-5.6.4C2 3.6 1.3 4.5 1.2 5.8 1 7.1 1 9 1 9s0 1.9.2 3.2c.2 1.3.8 2.2 2.2 2.4C5.6 15 9 15 9 15s3.4 0 5.6-.4c1.4-.3 2-1.1 2.2-2.4.2-1.3.2-3.2.2-3.2s0-1.9-.2-3.2zM7 12V6l5 3-5 3z\"/>\n  </symbol>\n  <symbol id=\"plyr-muted\" viewBox=\"0 0 18 18\">\n    <path d=\"M12.4 12.5l2.1-2.1 2.1 2.1 1.4-1.4L15.9 9 18 6.9l-1.4-1.4-2.1 2.1-2.1-2.1L11 6.9 13.1 9 11 11.1zM3.786 6.008H.714C.286 6.008 0 6.31 0 6.76v4.512c0 .452.286.752.714.752h3.072l4.071 3.858c.5.3 1.143 0 1.143-.602V2.752c0-.601-.643-.977-1.143-.601L3.786 6.008z\"/>\n  </symbol>\n  <symbol id=\"plyr-pause\" viewBox=\"0 0 18 18\">\n    <path d=\"M6 1H3c-.6 0-1 .4-1 1v14c0 .6.4 1 1 1h3c.6 0 1-.4 1-1V2c0-.6-.4-1-1-1zm6 0c-.6 0-1 .4-1 1v14c0 .6.4 1 1 1h3c.6 0 1-.4 1-1V2c0-.6-.4-1-1-1h-3z\"/>\n  </symbol>\n  <symbol id=\"plyr-pip\" viewBox=\"0 0 18 18\">\n    <path d=\"M13.293 3.293L7.022 9.564l1.414 1.414 6.271-6.271L17 7V1h-6z\"/>\n    <path d=\"M13 15H3V5h5V3H2a1 1 0 00-1 1v12a1 1 0 001 1h12a1 1 0 001-1v-6h-2v5z\"/>\n  </symbol>\n  <symbol id=\"plyr-play\" viewBox=\"0 0 18 18\">\n    <path d=\"M15.562 8.1L3.87.225c-.818-.562-1.87 0-1.87.9v15.75c0 .9 1.052 1.462 1.87.9L15.563 9.9c.584-.45.584-1.35 0-1.8z\"/>\n  </symbol>\n  <symbol id=\"plyr-restart\" viewBox=\"0 0 18 18\">\n    <path d=\"M9.7 1.2l.7 6.4 2.1-2.1c1.9 1.9 1.9 5.1 0 7-.9 1-2.2 1.5-3.5 1.5-1.3 0-2.6-.5-3.5-1.5-1.9-1.9-1.9-5.1 0-7 .6-.6 1.4-1.1 2.3-1.3l-.6-1.9C6 2.6 4.9 3.2 4 4.1 1.3 6.8 1.3 11.2 4 14c1.3 1.3 3.1 2 4.9 2 1.9 0 3.6-.7 4.9-2 2.7-2.7 2.7-7.1 0-9.9L16 1.9l-6.3-.7z\"/>\n  </symbol>\n  <symbol id=\"plyr-rewind\" viewBox=\"0 0 18 18\">\n    <path d=\"M10.125 1L0 9l10.125 8v-6.171L18 17V1l-7.875 6.171z\"/>\n  </symbol>\n  <symbol id=\"plyr-settings\" viewBox=\"0 0 18 18\">\n    <path d=\"M16.135 7.784a2 2 0 01-1.23-2.969c.322-.536.225-.998-.094-1.316l-.31-.31c-.318-.318-.78-.415-1.316-.094a2 2 0 01-2.969-1.23C10.065 1.258 9.669 1 9.219 1h-.438c-.45 0-.845.258-.997.865a2 2 0 01-2.969 1.23c-.536-.322-.999-.225-1.317.093l-.31.31c-.318.318-.415.781-.093 1.317a2 2 0 01-1.23 2.969C1.26 7.935 1 8.33 1 8.781v.438c0 .45.258.845.865.997a2 2 0 011.23 2.969c-.322.536-.225.998.094 1.316l.31.31c.319.319.782.415 1.316.094a2 2 0 012.969 1.23c.151.607.547.865.997.865h.438c.45 0 .845-.258.997-.865a2 2 0 012.969-1.23c.535.321.997.225 1.316-.094l.31-.31c.318-.318.415-.781.094-1.316a2 2 0 011.23-2.969c.607-.151.865-.547.865-.997v-.438c0-.451-.26-.846-.865-.997zM9 12a3 3 0 110-6 3 3 0 010 6z\"/>\n  </symbol>\n  <symbol id=\"plyr-volume\" viewBox=\"0 0 18 18\">\n    <path d=\"M15.6 3.3c-.4-.4-1-.4-1.4 0-.4.4-.4 1 0 1.4C15.4 5.9 16 7.4 16 9c0 1.6-.6 3.1-1.8 4.3-.4.4-.4 1 0 1.4.2.2.5.3.7.3.3 0 .5-.1.7-.3C17.1 13.2 18 11.2 18 9s-.9-4.2-2.4-5.7z\"/>\n    <path d=\"M11.282 5.282a.909.909 0 000 1.316c.735.735.995 1.458.995 2.402 0 .936-.425 1.917-.995 2.487a.909.909 0 000 1.316c.145.145.636.262 1.018.156a.725.725 0 00.298-.156C13.773 11.733 14.13 10.16 14.13 9c0-.17-.002-.34-.011-.51-.053-.992-.319-2.005-1.522-3.208a.909.909 0 00-1.316 0zm-7.496.726H.714C.286 6.008 0 6.31 0 6.76v4.512c0 .452.286.752.714.752h3.072l4.071 3.858c.5.3 1.143 0 1.143-.602V2.752c0-.601-.643-.977-1.143-.601L3.786 6.008z\"/>\n  </symbol>\n</svg>\n`);\n\n// localStorage数据\nconst allStorage = {};\nfor (let i = 0; i < localStorage.length; i++) {\n    const key = localStorage.key(i);\n    try {\n        allStorage[key] = JSON.parse(localStorage.getItem(key));\n    } catch (e) {\n        allStorage[key] = localStorage.getItem(key);\n    }\n}\n//weblog(JSON.stringify(allStorage), 'localStorage 数据：', true);\n\n/*==================js 库=================*/\n\n\n\n</script>\n</body>\n</html>\n<js>\nresult\n.replace(/：\\s*/g,'：')\n.replace(/\\{\\{.*播放源\\)/g,'')\n.replace(/<p>(?!.*集数)(.*：)<\\/p>/gm, '<p style=\"display:none;\">$1</p>');\n</js>",
    "ruleImage": "img@src",
    "ruleLink": "@href||a.0@href",
    "ruleNextPage": "page",
    "ruleTitle": "div.home-rows-videos-title@text||div.title@text",
    "singleUrl": false,
    "sortUrl": "裏番::/search?genre=裏番&page={{page}}\n搜索::https://hanime1.me/search?query={{(source.getVariable()==''||source.getVariable()==null)?'丝袜':source.getVariable()}}&page={{page}}\n泡麵番::/search?genre=泡麵番&page={{page}}\nMotion Anime::/search?genre=Motion%20Anime&page={{page}}\n3D::/search?genre=3DCG&page={{page}}\n2.5D::/search?genre=2.5D&page={{page}}\n2D::/search?genre=2D動畫&page={{page}}\nAI生成::/search?genre=AI生成&page={{page}}\nMMD::/search?genre=MMD&page={{page}}\nCosplay::/search?genre=Cosplay&page={{page}}",
    "sourceComment": "版本：0.0.1",
    "sourceGroup": "vpn",
    "sourceIcon": "https://vdownload.hembed.com/image/icon/tab_logo.png?secure=EJYLwnrDlidVi_wFp3DaGw==,4867726124",
    "sourceName": "hanime（黄漫视频）🚀",
    "sourceUrl": "https://hanime1.me/",
    "style": "* {\n    z-index: 0;\n    margin: 0;\n    padding: 0;\n}\n\nbody {\n    margin: auto;\n    background: #bbb;\n    width: 100%;\n}\n\nbody::before {\n    content: '';\n    position: fixed;\n    top: calc(56.25vw + 15px);\n    left: 0;\n    width: 100%;\n    height: calc(100% - (56.25vw + 15px));\n    background-image: var(--bg-image);\n    background-size: cover;\n    background-position: center;\n    opacity: var(--bg-opacity1);\n    z-index: -1;\n    pointer-events: none;\n}\n\nbody>p:first-of-type {\n    width: 100%;\n    position: fixed;\n    top: 0px;\n    text-indent: 0px;\n    height: 16px;\n    font-size: 0.7rem;\n    border-radius: 0px 0px 0px 0px;\n    background: #000;\n    z-index: 200;\n    display: flex;\n    align-items: center;\n}\n\nbody>p:first-of-type a {\n    color: #888;\n    text-decoration: none;\n    white-space: nowrap;\n    overflow-x: auto;\n    overflow-y: hidden;\n    display: block;\n    flex: 1;\n    min-width: 0;\n}\n\nbody>p:first-of-type button {\n    width: 30px;\n    height: 16px;\n    font-size: 0.6rem;\n    white-space: nowrap;\n    background: #333;\n    border: 0;\n    color: #888;\n    cursor: pointer;\n    flex-shrink: 0;\n    position: relative;\n    z-index: 201;\n}\n\nvideo {\n    visibility: hidden;\n}\n\n.video-container {\n    position: fixed;\n    top: 15px;\n    width: 100%;\n    height: 56.25vw;\n    z-index: 200;\n}\n\n#player {\n    position: relative;\n    width: 100%;\n}\n\n:root {\n    color-scheme: only light;\n    --plyr-color-main: #00aaff;/* 播放器主要颜色 */\n    --plyr-control-color: #fff;/* 播放器控件图标颜色 */\n    --plyr-control-background: transparent;/* 播放器控件背景颜色 */\n    --plyr-video-background: transparent;/* 视频背景颜色 */\n    --plyr-range-fill-background: #0099ee;/* 进度条已填充部分的颜色 */\n    --plyr-range-thumb-background: #fff;/* 进度条滑块的颜色 */\n}\n\n.plyr {\n    height: 100% !important;\n    width: 100% !important;\n    object-fit: cover;\n}\n\n.plyr__video-wrapper * {\n    touch-action: none !important;\n}\n\n.plyr__video-wrapper video {\n    touch-action: none !important;\n}\n\n.plyr__controls {\n    touch-action: none !important;\n}\n\n.plyr__control--overlaid {\n    background: transparent;\n    border: 0;\n    border-radius: 100%;\n    color: #fff;\n    left: calc(50% - 25px);\n    top: calc(50% - 45px);\n    transform: none;\n    width: 60px;\n    height: 48px;\n    padding: 0;\n    z-index: 2;\n}\n\n.plyr__control--overlaid svg {\n    width: 50px;\n    height: 50px;\n    left: calc(50% - 25px);\n    top: calc(50% - 10px);\n    transform: none;\n    fill: #fff;/* 大播放器控件图标颜色 */\n    filter: \n        drop-shadow(0 0 20px rgba(0, 0, 0, 0.3))\n        drop-shadow(0 0 30px rgba(0, 0, 0, 0.1));\n}\n\n.plyr__control--overlaid.hidden {\n    display: none !important;\n    opacity: 0 !important;\n    pointer-events: none !important;\n}\n\n.plyr--video .plyr__control.plyr__tab-focus,.plyr--video .plyr__control:hover,.plyr--video .plyr__control[aria-expanded=true] {\n    background: transparent;/* 播放器控件悬停/点击背景颜色 */\n    color: #00aaff;/* 播放器控件悬停/点击图标颜色 */\n}\n\n.plyr__controls .plyr__controls__item {\n    margin-left: auto;\n    margin: calc(var(--plyr-control-spacing,10px)/4);\n}\n\n.plyr__time--duration {\n    display: inline-block !important;\n}\n\n.plyr__time+.plyr__time:before {\n    margin-right: 8px !important;\n}\n\n@media (max-width: 640px) {\n    .plyr__captions {\n        margin-bottom:-8px\n    }\n\n    .plyr__progress__container {\n        margin-right: 5px\n    }\n\n    .plyr__time {\n        position: absolute;\n        bottom: 29px;\n    }\n\n    .plyr__time--current {\n        left: 106px\n    }\n\n    .plyr__time+.plyr__time:before {\n        content: \"\"!important\n    }\n\n    .plyr__time--duration {\n        right: 110px;\n    }\n\n    .plyr__volume {\n        width: auto;\n        max-width: 32px!important;\n        min-width: 32px!important\n    }\n\n    input[id^=plyr-volume-] {\n        display: none!important;\n    }\n\n    .plyr--airplay-supported [data-plyr=airplay],.plyr--captions-enabled [data-plyr=captions],.plyr--pip-supported [data-plyr=pip] {\n        display: none!important;\n    }\n}\n\ndetails {\n    width: 100%;\n    height: auto;\n    margin: auto;\n}\n\ndetails>img {\n    position: fixed;\n    width: 100%;\n    max-height: 90vw;\n    object-fit: contain;\n    background: #000;\n    border-bottom: 0.5px solid #333;\n    top: calc(56.25vw + 16px + 1.5em);\n    z-index: 50;\n}\n\ndetails[open]>summary {\n    background: #bbb;/* 标题背景颜色 */\n}\n\nsummary {\n    position: fixed;\n    background: rgba(221, 221, 221, var(--bg-opacity2));/* 标题背景颜色和透明度 */\n    backdrop-filter: blur(5px);\n    -webkit-backdrop-filter: blur(5px);\n    color: #111;/* 标题文字颜色 */\n    box-shadow: 0 0.5px 3px #555;/* 标题阴影颜色 */\n    list-style: none;\n    width: 100%;\n    padding-top: calc(56.25vw + 16px);\n    outline: none;\n    line-height: 1.5;\n    text-align: left;\n    word-wrap: break-word;\n    z-index: 100;\n}\n\nsummary>h3 {\n    width: 95%;\n    margin: auto;\n}\n\nsummary::-webkit-details-marker {\n    display: none;\n}\n\n.all-info {\n    position: relative;\n    color: #333;/* 详情信息文字颜色 */\n    margin: auto;\n    width: 100%;\n    height: auto;\n    padding-top: calc(56.25vw + 24px + 1.5em);\n}\n\n.all-info>div {\n    width: 100%;\n    margin: auto;\n}\n\n.all-info>p {\n    text-indent: 0px;\n}\n\n.all-info>div>p {\n    width: 90%;\n    margin: 5px 5%;\n    outline: none;\n    text-align: left;\n    word-wrap: break-word;\n}\n\n.jiekou {\n    display: flex;\n}\n\n#selected-jiekou {\n    display: flex;\n    position: fixed;\n    justify-content: flex-end;\n    top: calc(56.25vw + 19.9px + 1.5em);\n    width: 150px;\n    right: 5px;\n}\n\n#selected-jiekou button {\n    width: 125px;\n    height: 28px;\n    padding: 2px;\n    background: rgba(204, 204, 204, var(--bg-opacity2));/* 已选接口背景颜色 */\n    backdrop-filter: blur(5px);\n    -webkit-backdrop-filter: blur(5px);\n    overscroll-behavior-y: none;\n    -webkit-overflow-scrolling: auto;\n    color: #4a89a9;\n    border: 1px solid #666;\n    border-radius: 0 0 3px 3px;\n    opacity: 0.5;\n}\n\n#jiekou-list {\n    display: none;\n    position: fixed;\n    overflow-y: auto;\n    max-height: 200px;\n    top: 0;\n    right: 5px;\n    background: rgba(204, 204, 204, var(--bg-opacity2));/* 接口列表背景颜色 */\n    backdrop-filter: blur(5px);\n    -webkit-backdrop-filter: blur(5px);\n    border: 1px solid #888;\n    border-top: none;\n    border-radius: 0 0 3px 3px;\n    z-index: 100;\n    margin: auto;\n}\n\n#jiekou-list button {\n    display: block;\n    width: 100%;\n    height: 28px;\n    margin: auto;\n    padding: 2px;\n    background: rgba(187, 187, 187, 0.1);/* 待选接口按钮背景颜色 */\n    color: #333;/* 待选接口按钮文字颜色 */\n    border: 1px solid #888;\n    border-top: none;\n    border-left: none;\n    border-right: none;\n    border-radius: 0px;\n    cursor: pointer;\n}\n\n#jiekou-list button:last-of-type {\n    border-bottom: none;\n    border-radius: 0 0 3px 3px;\n}\n\nsup {\n    font-size: 0.4em;\n    vertical-align: top;\n    position: relative;\n    top: -0.6em;\n}\n\n.jishu button:hover {\n    background: rgba(204, 204, 204, var(--bg-opacity2));/* 按钮悬停背景颜色 */\n    border: 1px solid #4a89a9;/* 按钮悬停边框颜色 */\n}\n\n.jishu button {\n    width: 30%;\n    margin: 1.25%;\n    padding: 5px;\n    outline: none;\n    border-radius: 8px;\n    border: 1px solid #666;\n    background: rgba(204, 204, 204, var(--bg-opacity2));/* 集数按钮背景颜色 */\n    color: #333;/* 集数按钮文字颜色 */\n    font-size: 0.7rem;\n    white-space: nowrap;\n    overflow: hidden;\n    text-overflow: ellipsis;\n}\n\n.jishu button.active {\n    background: rgba(204, 204, 204, var(--bg-opacity2));/* 已选集数按钮背景颜色 */\n    color: #4a89a9;\n    border: 1px solid #4a89a9;\n    position: sticky;\n    left: 0;\n    right: 0;\n}\n\n.popup {\n    position: fixed;\n    top: 50%;\n    left: 50%;\n    transform: translate(-50%, -50%) scale(0.95);\n    background-color: #ccc;\n    padding: 20px;\n    border-radius: 8px;\n    box-shadow: 0 4px 24px rgba(0, 0, 0, 0.3);\n    z-index: 2147483647;\n    width: 80%;\n    max-height: 80vh;\n    overflow: auto;\n    font-family: system-ui, -apple-system, sans-serif;\n    opacity: 0;\n    transition: all 0.3s ease;\n    pointer-events: auto;\n}\n\n.titleElement {\n    margin: 0 0 16px 0;\n    color: #333;\n    font-size: 18px;\n    font-weight: 600;\n}\n\n.contentElement {\n    white-space: pre-wrap;\n    word-wrap: break-word;\n    overflow-wrap: break-word;\n    max-height: calc(80vh - 150px);\n    overflow-y: auto;\n    padding: 16px;\n    background-color: #bbb;\n    color: #000;\n    border-radius: 6px;\n    margin-bottom: 20px;\n    font-size: 14px;\n    line-height: 1.6;\n    border: 1px solid #999;\n}"
  },
  {
    "articleStyle": 1,
    "customOrder": 63,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\"User-Agent\": \"Mozilla/5.0 (Linux; U; Android 14; zh-cn; M2102K1AC Build/UKQ1.231207.002) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/109.0.5414.118 Mobile Safari/537.36 MQQBrowser/10.1.0\"}",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": ".thumbnail-group@li",
    "ruleContent": "<js>\np=result.match(/vod\\_data.*url\\\"\\:\\\"(.*?)\\\"\\,\\\"url/);\np=(p?p[1]:1).replace(/\\\\/g,'')||1; pi=java.getString('.breadcrumbs@span@text')||1;\n`<html>\n    <head>\n        <meta name=\"viewport\" content=\"width=device-width\">\n        <style>\n            body {\n                margin: 0;\n                font-family: Arial, sans-serif;\n                background: linear-gradient(135deg, #ece9e6, #ffffff);\n                display: flex;\n                flex-direction: column;\n                align-items: center;\n                justify-content: flex-start;\n                padding: 20px;\n            }\n            .container {\n                width: 100%;\n                max-width: 800px;\n                background: #fff;\n                border-radius: 10px;\n                box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n                overflow: hidden;\n                margin-bottom: 20px;\n            }\n            h3 {\n                margin: 0;\n                padding: 10px 20px;\n                font-size: 0.9em;\n                background: #333;\n                color: #fff;\n                border-radius: 10px 10px 0 0;\n            }\n            .video-container {\n                width: 100%;\n                background: #000;\n                position: relative;\n            }\n            video {\n                width: 100%;\n                height: auto;\n                display: block;\n            }\n            .info-container {\n                padding: 20px;\n            }\n            .info-container p {\n                margin: 10px 0;\n                color: #555;\n            }\n            .info-container p span {\n                font-weight: bold;\n                color: #000;\n            }\n        </style>\n    </head>\n    <body>\n        <div class=\"container\">\n        <h3>${pi}</h3>\n            <div class=\"video-container\">\n                <video controls autoplay name=\"media\" id=\"videoPlayer\">\n                    <source src=\"${p}\" type=\"video/mp4\">\n                </video>\n            </div>\n            <div class=\"info-container\">\n                \n            </div>\n        </div>\n\n        <script>\n            // 获取视频元素\n            const video = document.getElementById('videoPlayer');\n            let touchStartX = 0;\n            let touchStartY = 0;\n            let touchStartTime = 0;\n            let isLongPress = false;\n\n            // 滑动快进\n            video.addEventListener('touchstart', (e) => {\n                touchStartX = e.touches[0].clientX;\n                touchStartY = e.touches[0].clientY;\n                touchStartTime = Date.now();\n                isLongPress = false;\n            });\n\n            video.addEventListener('touchmove', (e) => {\n                const deltaX = e.touches[0].clientX - touchStartX;\n                const deltaY = e.touches[0].clientY - touchStartY;\n\n                // 如果是水平滑动，且未进入长按状态\n                if (Math.abs(deltaX) > Math.abs(deltaY) && !isLongPress) {\n                    const duration = video.duration;\n                    const seekTime = video.currentTime + (deltaX / 100); // 每滑动100px快进1秒\n                    video.currentTime = Math.min(Math.max(seekTime, 0), duration);\n                }\n            });\n\n            // 长按快进\n            video.addEventListener('touchend', (e) => {\n                const touchEndTime = Date.now();\n                const touchDuration = touchEndTime - touchStartTime;\n\n                // 如果长按时间超过500ms，进入长按快进状态\n                if (touchDuration > 500) {\n                    isLongPress = true;\n\n                    // 在长按状态下，根据滑动距离快进\n                    const deltaX = e.changedTouches[0].clientX - touchStartX;\n                    const duration = video.duration;\n                    const seekTime = video.currentTime + (deltaX / 100); // 每滑动100px快进1秒\n                    video.currentTime = Math.min(Math.max(seekTime, 0), duration);\n                } else {\n                    isLongPress = false;\n                }\n            });\n\n            // 防止默认行为（如页面滚动）\n            video.addEventListener('touchmove', (e) => {\n                e.preventDefault();\n            });\n        </script>\n    </body>\n</html>`;\n\n</js>",
    "ruleImage": "img@src",
    "ruleLink": "a@href",
    "ruleNextPage": "text.下一页@href",
    "rulePubDate": "p@text",
    "ruleTitle": "h5@text||img@alt",
    "singleUrl": false,
    "sortUrl": "搜索🔍::/index.php/vod/search/page/{{page}}/wd/{{source.getVariable()}}.html\n伦理三级::/index.php/vod/type/id/6/page/{{page}}.html\n国产精品::/index.php/vod/type/id/7/page/{{page}}.html\n偷拍自拍::/index.php/vod/type/id/8/page/{{page}}.html\n主播大秀::/index.php/vod/type/id/9/page/{{page}}.html\n卡通动漫::/index.php/vod/type/id/10/page/{{page}}.html\n制服丝袜::/index.php/vod/type/id/11/page/{{page}}.html\n少女萝莉::/index.php/vod/type/id/12/page/{{page}}.html\n巨乳美乳::/index.php/vod/type/id/20/page/{{page}}.html\n熟女人妻::/index.php/vod/type/id/21/page/{{page}}.html\n亚洲有码::/index.php/vod/type/id/22/page/{{page}}.html\n强奸乱伦::/index.php/vod/type/id/23/page/{{page}}.html\n亚洲无码::/index.php/vod/type/id/25/page/{{page}}.html\n中文字幕::/index.php/vod/type/id/26/page/{{page}}.html\n同性专区::/index.php/vod/type/id/27/page/{{page}}.html\nAl换脸::/index.php/vod/type/id/28/page/{{page}}.html\n欧美精品::/index.php/vod/type/id/32/page/{{page}}.html\n国产传媒::/index.php/vod/type/id/33/page/{{page}}.html\n口交颜射::/index.php/vod/type/id/34/page/{{page}}.html\n女优明星::/index.php/vod/type/id/35/page/{{page}}.html\n素人自拍::/index.php/vod/type/id/36/page/{{page}}.html\n多人群交::/index.php/vod/type/id/37/page/{{page}}.html\n网曝门::/index.php/vod/type/id/39/page/{{page}}.html\n探花系列::/index.php/vod/type/id/41/page/{{page}}.html\n麻豆传媒::/index.php/vod/type/id/43/page/{{page}}.html\n天美传媒::/index.php/vod/type/id/46/page/{{page}}.html\nSA国际传媒::/index.php/vod/type/id/47/page/{{page}}.html\n果冻传媒::/index.php/vod/type/id/50/page/{{page}}.html\n星空无限::/index.php/vod/type/id/51/page/{{page}}.html\n精东影业::/index.php/vod/type/id/52/page/{{page}}.html\n蜜桃传媒::/index.php/vod/type/id/54/page/{{page}}.html\nAV解说::/index.php/vod/type/id/56/page/{{page}}.html\nVR视角::/index.php/vod/type/id/57/page/{{page}}.html\nJVID::/index.php/vod/type/id/59/page/{{page}}.html\nSWAG::/index.php/vod/type/id/60/page/{{page}}.html \ncosplay::/index.php/vod/type/id/61/page/{{page}}.html\n抖音视频::/index.php/vod/type/id/62/page/{{page}}.html\n热门头条::/index.php/vod/type/id/63/page/{{page}}.html\n素人搭讪::/index.php/vod/type/id/80/page/{{page}}.html\n欺辱凌辱::/index.php/vod/type/id/81/page/{{page}}.html\n野外激情::/index.php/vod/type/id/82/page/{{page}}.html\n学生诱惑::/index.php/vod/type/id/83/page/{{page}}.html\nSM调教::/index.php/vod/type/id/84/page/{{page}}.html\n水果派::/index.php/vod/type/id/86/page/{{page}}.html\n91传媒::/index.php/vod/type/id/88/page/{{page}}.html\n糖心传媒::/index.php/vod/type/id/90/page/{{page}}.html\n一本道::/index.php/vod/type/id/93/page/{{page}}.html\n",
    "sourceComment": "发布页：https://wuxiants.github.io/",
    "sourceGroup": "R-18可用免翻",
    "sourceIcon": "https://images.icon-icons.com/1147/PNG/512/1486486316-arrow-film-movie-play-player-start-video_81236.png",
    "sourceName": "无限臀山",
    "sourceUrl": "https://wxts.wuxiants510.com/"
  },
  {
    "articleStyle": 0,
    "customOrder": 64,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceComment": "视频",
    "sourceGroup": "视频",
    "sourceIcon": "https://img.fy6b.com/2024/06/13/7ca5da52f9cc0.jpg",
    "sourceName": "红桃视频",
    "sourceUrl": "https://www.htng415.vip:9527/"
  },
  {
    "articleStyle": 0,
    "customOrder": 65,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "header": "{\"User-Agent\": \"okhttp/3.8.1\"}",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "$.posts[*]||$.gameapps[*]",
    "ruleContent": "<h3>{{$.post.title}}</h3>\n{{$.post.detail##<image>(.*?),.*?</image>##<img src=\"$1\">}}\n🩹{{$.post.images[*]}}🩹\n<br><hr><br>\n<h1>评论</h1>\n\n@js:\nresult=result.replace(/\\n/g,'<br>').replace(/<\\/*text>/g,'');\nlist=result.match(/🩹[\\s\\S]+?🩹/)?result.match(/🩹([\\s\\S]+?)🩹/)[1]:'';\nlist=list?list.split('<br>'):[];\n\ncomments=JSON.parse(src).comments;\npp='';\n\nfor(i in comments){\nauthor=comments[i].user.nick;\nauthorimg='<img class=\"author\" src=\"'+comments[i].user.avatar+'\">';\nimgs=comments[i].images?comments[i].images:[];\ntime='<a class=\"time\">'+java.timeFormat(comments[i].createTime)+\"</a>\";\nt=comments[i].text;\nimglist='';\nfor(i in imgs){\nimglist+='<details><summary style=\"color:red\">点击查看图片</summary><img src=\"'+imgs[i]+'\"></details>\\n'\n}\nnick=comments[i].refComment?comments[i].refComment.nick:'';\n\nrep=comments[i].refComment?comments[i].refComment.text:'';\n\nref=nick?'<div class=\"ref\"><p>回复  '+nick+'</p><p>'+rep+'</p></div>'+t:''\ntext=ref?ref:t;\n\npp+=authorimg+author+'<br>'+String(text).replace(/\\n/g,'<br>')+imglist+'<br>'+time+'<br><br><br>';\n}\nresult=result+pp;\nimg='';\nfor(i in list){\nimg+='<details><summary>点击查看图片</summary><img src=\"'+list[i]+'\"></details>\\n'\n}\nresult=String(result).replace(/🩹[\\s\\S]+?🩹|🩹🩹/g,img);\nresult=result.replace(/([^\"])(http[^<\\s\"]+)/g,'$1<a href=\"$2\">$2</a>')",
    "ruleDescription": "<img style=\"width:40px;height:40px\" src=\"{{$.applogo}}\">   {{$.apptitle}}<br>\n<p class=\"tag\">{{$.appsize}}m   {{$.applanguage}}   {{$.appauthorization}}   version{{$.appversion}}   {{$.system}}<p>\n<a href=\"{{$.localurl.url}}\">点击下载</a><br>\n{{$.appdesc}}\n\n<js>result=baseUrl.match(/search/)?result:''</js>",
    "ruleImage": "$.images[0]||$.applogo",
    "ruleLink": "http://floor.huluxia.com/post/detail/ANDROID/2.3?platform=2&gkey=000000&app_version=4.1.1.3&versioncode=320&market_id=tool_web&post_id={{$.postID||$.shareurl##(\\d+)##$1###}}&page_no=1&page_size=20&doc=1",
    "ruleNextPage": "page",
    "rulePubDate": "<js>\nif(baseUrl.match(/search/)){\nappsize='{{$.appsize}}m';\ntag='{{$.apptags}}';\ntime=java.timeFormat('{{$.createTime}}000');\nresult=appsize+'•'+tag+'•'+time\n}else{result=java.timeFormat('{{$.createTime}}')}\n</js>",
    "ruleTitle": "$.title||$.apptitle",
    "singleUrl": false,
    "sortUrl": "实用软件::http://floor.huluxia.com/post/list/ANDROID/2.1?platform=2&gkey=000000&app_version=4.1.1.3&versioncode=320&market_id=tool_web&start={{Date.now()}}&count=200&cat_id=43&tag_id=0&sort_by=1\n\n绿色软件::http://floor.huluxia.com/post/list/ANDROID/2.1?platform=2&gkey=000000&app_version=4.1.1.3&versioncode=320&market_id=tool_web&start={{Date.now()}}&count=200&cat_id=43&tag_id=4301&sort_by=1\n原创工具::http://floor.huluxia.com/post/list/ANDROID/2.1?platform=2&gkey=000000&app_version=4.1.1.3&versioncode=320&market_id=tool_web&start={{Date.now()}}&count=200&cat_id=43&tag_id=4302&sort_by=0\n影音播放::http://floor.huluxia.com/post/list/ANDROID/2.1?platform=2&gkey=000000&app_version=4.1.1.3&versioncode=320&market_id=tool_web&start={{Date.now()}}&count=200&cat_id=43&tag_id=4304&sort_by=0\n集合贴::http://floor.huluxia.com/post/list/ANDROID/2.1?platform=2&gkey=000000&app_version=4.1.1.3&versioncode=320&market_id=tool_web&start={{Date.now()}}&count=200&cat_id=43&tag_id=4303&sort_by=0\n\n玩机教程::http://floor.huluxia.com/post/list/ANDROID/2.1?platform=2&gkey=000000&app_version=4.1.1.3&versioncode=320&market_id=tool_web&start={{Date.now()}}&count=200&cat_id=44&tag_id=0&sort_by=0\n优选教程::http://floor.huluxia.com/post/list/ANDROID/2.1?platform=2&gkey=000000&app_version=4.1.1.3&versioncode=320&market_id=tool_web&start={{Date.now()}}&count=200&cat_id=44&tag_id=4406&sort_by=0\n软件使用::http://floor.huluxia.com/post/list/ANDROID/2.1?platform=2&gkey=000000&app_version=4.1.1.3&versioncode=320&market_id=tool_web&start={{Date.now()}}&count=200&cat_id=44&tag_id=4401&sort_by=0\n刷机相关::http://floor.huluxia.com/post/list/ANDROID/2.1?platform=2&gkey=000000&app_version=4.1.1.3&versioncode=320&market_id=tool_web&start={{Date.now()}}&count=200&cat_id=44&tag_id=4403&sort_by=0\nROM资源::http://floor.huluxia.com/post/list/ANDROID/2.1?platform=2&gkey=000000&app_version=4.1.1.3&versioncode=320&market_id=tool_web&start={{Date.now()}}&count=200&cat_id=44&tag_id=4405&sort_by=0\n搜索软件::http://search.huluxia.com/game/search/ANDROID/4.0.1?platform=2&gkey=000000&app_version=4.1.1.3&versioncode=320&market_id=tool_web&start={{(page-1)*20}}&count=20&keyword={{source.getVariable()}}",
    "sourceComment": "按发布时间排序 sort_by=1\n按回复时间排序 sort_by=0\n按本版精华排序 sort_by=2",
    "sourceGroup": "工具 订阅",
    "sourceIcon": "http://peco-img.uc.cn/image/quark_baike/upload/2022/27HwTN1fq0c2u3v/bed0926027b99ff2fa8cdb16b16f416d.jpg",
    "sourceName": "葫芦侠",
    "sourceUrl": "http://floor.huluxia.com",
    "style": "img{\nwidth:100%;\nheight:auto\n}\n.author{\nwidth:20px;\nheight:20px\n}\n.ref{\ncolor:#888\n}\n.time{\nfont-size:12px\n}\n.tag{\ncolor:#555;\nfont-size:12px\n}"
  },
  {
    "articleStyle": 0,
    "customOrder": 66,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "图片",
    "sourceIcon": "",
    "sourceName": "AI",
    "sourceUrl": "http://www.flmeitu.com/chis/AImeinv/11.html"
  },
  {
    "articleStyle": 0,
    "customOrder": 67,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceComment": "",
    "sourceGroup": "视频,R18",
    "sourceIcon": "https://m.acgnfl.com/24/07/content_33/525867/073.webp",
    "sourceName": "蜜桃视频",
    "sourceUrl": "https://www.mt314iu.vip:9527/"
  },
  {
    "articleStyle": 0,
    "customOrder": 68,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "",
    "ruleContent": "",
    "ruleDescription": "",
    "ruleImage": "",
    "ruleLink": "",
    "ruleNextPage": "",
    "shouldOverrideUrlLoading": "",
    "singleUrl": true,
    "sortUrl": "",
    "sourceComment": "https://www.sshs.pw/\n\t",
    "sourceGroup": "❤️",
    "sourceIcon": "https://www.10357756.xyz/static/favicon.ico",
    "sourceName": "绅士会所",
    "sourceUrl": "https://www.10357756.xyz/"
  },
  {
    "articleStyle": 2,
    "customOrder": 69,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\n\t \"User-Agent\": \"Mozilla/5.0 (Linux; U; Android 9; zh-cn; MIX 2S Build/PKQ1.180729.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4896.127 Mobile Safari/537.36 XiaoMi/MiuiBrowser/16.7.35 swan-mibrowser\",\n\t \"Referer\": \"{{baseUrl}}\"\n}",
    "injectJs": "(function() {\nfunction fixImages() {\nconst imgs = document.querySelectorAll(\"img\");\nimgs.forEach(img => {\nlet real = img.getAttribute(\"data-original\") || img.getAttribute(\"src\");\n        if (real && real.includes(\"/LoadImage.ashx\")) {\n            // 补全域名\n            let url = real.startsWith(\"http\") ? real : \"https://www.tuao.cc\" + real;\n\n            // 强制替换\n            img.src = url;\n        }\n    });\n}\n// 初始执行\nfixImages();\n// 监听动态加载\nconst observer = new MutationObserver(() => {\n    fixImages();\n});\nobserver.observe(document.body, {\n    childList: true,\n    subtree: true\n});\n})();",
    "lastUpdateTime": 1770862647307,
    "loadWithBaseUrl": true,
    "ruleArticles": ".index-group-content > .index-imgs",
    "ruleContent": "<!-- 介绍区域 -->\n<div class=\"intro-section\">\n    {{@@h1@all}}\n    <p class=\"intro\">\n      {{@@[name=\"description\"]@content}}\n    </p>\n    {{@@.text-primary@all}}\n</div>\n\n<!-- 套图区域 -->\n<div class=\"gallery-section\">\n    {{@@#rawContent p img@html}}\n   \n</div>",
    "ruleImage": "img@data-original||img@src",
    "ruleLink": "a.0@href",
    "ruleNextPage": "[aria-label=\"Next\"]@href",
    "rulePubDate": "ownText##\\?\\..*",
    "ruleTitle": ".index-imgcontent-title@text",
    "singleUrl": false,
    "sortUrl": "最新::/Articles/\n无圣光::/Articles/Categories/1\n凸凹图::/Articles/Categories/2\n靓人体::/Articles/Categories/3\n写真集::/Articles/Categories/4\n\n搜索::/Articles/Search?wd={{String(source.variable) || \"美女\"}}",
    "sourceComment": "www.tuaow.top",
    "sourceGroup": "美女",
    "sourceIcon": "https://www.tuao.cc/Files/webconfigs/638254764734047980.png",
    "sourceName": "凹凸吧",
    "sourceUrl": "https://www.tuao.cc",
    "style": "body {\n  margin: 0;\n  padding: 0;\n  font-family: sans-serif;\n}\n\n/* 介绍区域：白色背景 */\n.intro-section {\n  background-color: #ffffff;\n  color: #333;\n  padding: 16px;\n  /* 可选：加一点阴影分隔 */\n  box-shadow: 0 2px 4px rgba(0,0,0,0.05);\n}\n\n.intro-section h1 {\n  font-size: 1.5rem;\n  margin-top: 0;\n}\n\n.intro-section p {\n  font-size: 1rem;\n  line-height: 1.6;\n}\n\n/* 套图区域：黑色背景 */\n.gallery-section {\n  background-color: #000000;\n  padding: 12px; /* 图片和边缘留点空隙 */\n}\n\n.gallery-section img {\n  width: 100%;\n  height: auto;\n  display: block;\n  margin-bottom: 12px;\n  border-radius: 8px; /* 可选圆角 */\n}\n\n.text-primary {\n  display: flex;\n  flex-wrap: wrap;\n  align-items: center;\n  gap: 6px;\n}\n\n.text-primary .glyphicon-time {\n  flex-basis: 100%;\n  margin-top: 6px;\n}"
  },
  {
    "articleStyle": 1,
    "customOrder": 70,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\"User-Agent\": \"Mozilla/5.0 (Linux; Android 12; 22041211AC Build/SP1A.210812.016) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.104 Mobile Safari/537.36\"}",
    "lastUpdateTime": 1775584094755,
    "loadWithBaseUrl": true,
    "ruleArticles": ".list@li",
    "ruleContent": "<js>\nvar v = result.match(/source\\s*=\\s*[\"']([^\"']*?\\.(m3u8|mp4)\\b[^\"']*)[\"']/i);\nvar p = v ? v[1].replace(/\\\\/g,'') : '';\nvar t = '@get:{t}';\nvar d = java.getString('[property=\"video:tag\"]@content');\nvar sign1 = java.base64Decode('44CQ5aSc5piO56m644CR55qE5pKt5pS+5Zmo');\nvar sign2 = java.base64Decode('5LuF5L6b5Liq5Lq65a2m5Lmg5L2/55So77yM5Lil56aB5YiG5Lqr44CB5YCS5Y2W5Y+K5Lu75L2V6L+d5rOV6KGM5Li677yB');\nvar sign3 = java.base64Decode('5L2/55So6ICF6Ieq6KGM5om/5ouF6aOO6Zmp5LiO6LSj5Lu7');\n`<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>${t}</title>\n<style>\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,sans-serif;background:#f0f9ff;padding:10px}\n.v-box{max-width:800px;margin:0 auto;background:white;border-radius:12px;box-shadow:0 5px 15px rgba(0,0,0,0.1);overflow:hidden}\n.header{padding:12px;border-bottom:1px solid #eee;display:flex;flex-wrap:wrap;justify-content:space-between}\n.sign{background:#e9f7ff;padding:6px;border-radius:6px;margin-bottom:8px;font-size:14px;color:#1a73e8;width:100%}\n.title{font-size:18px;font-weight:600;margin-bottom:8px;width:100%}\n.tags{color:#5f6368;font-size:14px;flex:1;min-width:60%;word-break:break-all}\n.time{color:#5f6368;font-size:14px;text-align:right;flex-basis:35%}\n.v-wrap{position:relative;padding-top:56.25%;background:#000}\n.video{position:absolute;top:0;left:0;width:100%;height:100%}\n.footer{padding:8px;text-align:center;color:#5f6368;font-size:13px}\n.info-box{padding:15px;font-size:14px;line-height:1.6}\n.info-box p{margin:8px 0}\n.hint{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background:rgba(0,0,0,0.7);color:#fff;padding:12px 20px;border-radius:20px;font-size:1.1rem;z-index:10;display:none}\n.controls{position:absolute;top:0;left:0;width:100%;height:4px;background:rgba(255,255,255,0.3);z-index:5;transition:opacity 0.3s}\n.progress{height:100%;background:#4a9eff;width:0}\n</style>\n</head>\n<body>\n<div class=\"v-box\">\n<div class=\"header\">\n<div class=\"sign\" style=\"text-align:center;padding:5px 0\">\n<div>${sign1}</div>\n<div style=\"text-align:left; padding-top:4px\">\n${sign2}<br>${sign3}</div>\n</div>\n<div class=\"title\">${t}</div>\n<div class=\"tags\">${d}</div>\n<div class=\"time\" id=\"timeDisplay\">00:00/00:00</div></div>\n<div class=\"v-wrap\">\n<div class=\"controls\"><div class=\"progress\" id=\"progressBar\"></div></div>\n<div class=\"hint\" id=\"hint\">快进中 &gt;&gt;</div>\n<video class=\"video\" id=\"v\" controls playsinline>\n<source src=\"${p}\" type=\"video/mp4\">您的浏览器不支持HTML5视频\n</video>\n</div>\n<div class=\"footer\">滑动调整进度 | 长按2倍速</div>\n</div>\n<script>\nvar v = document.getElementById('v');\nvar tDisplay = document.getElementById('timeDisplay');\nvar pBar = document.getElementById('progressBar');\nvar hint = document.getElementById('hint');\nvar startX = 0, startTime = 0;\nvar longPressTimer;\nvar sensitivity = 0.1;\nvar longPressTime = 500;\nvar hintDuration = 2000;\nfunction updateTime() {\nif (!v.duration) return;\nvar m1 = Math.floor(v.currentTime / 60);\nvar s1 = Math.floor(v.currentTime % 60);\nvar m2 = Math.floor(v.duration / 60);\nvar s2 = Math.floor(v.duration % 60);\ntDisplay.textContent = m1 + ':' + (s1 < 10 ? '0' : '') + s1 + '/' + m2 + ':' + (s2 < 10 ? '0' : '') + s2;\npBar.style.width = (v.currentTime / v.duration) * 100 + '%';}\nv.addEventListener('timeupdate', updateTime);\nv.addEventListener('loadedmetadata', updateTime);\nv.addEventListener('touchstart', function(e) {\nstartX = e.touches[0].clientX;\nstartTime = Date.now();\nif (longPressTimer) clearTimeout(longPressTimer);\nhint.style.display = 'none';\nlongPressTimer = setTimeout(function() {\nv.playbackRate = 2.0;\nhint.style.display = 'block';\nsetTimeout(function() { hint.style.display = 'none'; }, hintDuration);}, longPressTime);});\nv.addEventListener('touchmove', function(e) {\ne.preventDefault();\nclearTimeout(longPressTimer);\nvar diffX = e.touches[0].clientX - startX;\nvar change = diffX * sensitivity * v.duration / 100;\nv.currentTime = Math.max(0, Math.min(v.currentTime + change, v.duration));\nstartX = e.touches[0].clientX;updateTime();});\nv.addEventListener('touchend', function() {\nv.playbackRate = 1.0;\nclearTimeout(longPressTimer);});\n</script>\n</body>\n</html>`\n</js>",
    "ruleImage": "img@data-original",
    "ruleLink": "a.0@href",
    "ruleNextPage": "page",
    "rulePubDate": "{{@@.vodlist_img@html##(\\d+)-(\\d+)-(\\d+)##$0###}} | {{@@.vodlist_img@span.0@text}}",
    "ruleTitle": ".title@text@put:{\"t\":\"@@.title@text\"}",
    "singleUrl": false,
    "sortUrl": "搜索 🔍::/s/page/{{page}}/wd/{{source.getVariable()}}/\n最新::/label/hot/by/time/page/{{page}}/\n日榜::/label/hot/by/hits_day/page/{{page}}/\n周榜::/label/hot/by/hits_week/page/{{page}}/\n月榜::/label/hot/by/hits_month/page/{{page}}/\n国产 🎞::/t/1-{{page}}/\n自拍::/t/5-{{page}}/\n主播大秀::/t/6-{{page}}/\n主播诱惑::/t/36-{{page}}/\n探花::/t/7-{{page}}/\n偷拍::/t/8-{{page}}/\n乱伦::/t/8-{{page}}/\n吃瓜::/t/10-{{page}}/\n抖阴::/t/11-{{page}}/\nAV::/t/12-{{page}}/\n福利姬::/t/20-{{page}}/\n侵犯::/t/37-{{page}}/\n日韩 🎞::/t/2-{{page}}/\n日韩自拍::/t/13-{{page}}/\n日本无码::/t/14-{{page}}/\n字幕::/t/15-{{page}}/\n解说::/t/17-{{page}}/\n换脸::/t/18-{{page}}/\n欧美 🎞::/t/3-{{page}}/\n自拍::/t/21-{{page}}/\n字幕::/t/22-{{page}}/\n伦理 🎞::/t/4-{{page}}/\n三级::/t/29-{{page}}/\n日韩::/t/30-{{page}}/\n动漫 🎞::/t/16-{{page}}/\n剧集::/t/26-{{page}}/\n3D::/t/27-{{page}}/\n次元::/t/28-{{page}}/\n另类 🎞::/t/39-{{page}}/\n同性恋::/t/38-{{page}}/\n变性::/t/40-{{page}}/\n重口味::/t/23-{{page}}/",
    "sourceComment": "<声明>\n//2025.8.10 作者：夜明空\n//源社区：https://taoba.cf\n//仅供个人学习使用，严禁分享、倒卖及任何违法行为！使用者自行承担风险与责任\n</声明>\n\n//网址更新频繁，有需要请到发布页自行更新\n//发布页：\nhttps://18j.18hu.link/mdce\n18j.vip\n18zy.vip\n51zy.vip",
    "sourceGroup": "美涩",
    "sourceIcon": "https://18oc.life/18link/18j/images/favicon.ico",
    "sourceName": "18J-夜明空",
    "sourceUrl": "https://18oc.life/label/tag/"
  },
  {
    "articleStyle": 1,
    "customOrder": 71,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "header": "{\"accept-language\":\"zh-CN,zh;q=0.9\"}",
    "injectJs": "",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "class.well well-sm videos-text-align",
    "ruleContent": "<js>\nresult=decodeURIComponent(result.match(/strencode2\\(\"(.*?)\"\\)/)[1]).match(/src='(.*?)'/)[1];\n`<html>\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no\" />\n{{@@title@all}}\n</head>\n<body>\n<video src=\"${result}\" poster=\"{{@@video@poster}}\" width=\"100%\" height=\"auto\" controls=\"controls\" ></video>\n{{@@#videodetails.0@h4@all}}\n</body>\n</html>`\n</js>",
    "ruleImage": "img@src",
    "ruleLink": "a@href",
    "ruleNextPage": "page",
    "rulePubDate": "@text##.*?(\\d{2}:\\d{2}).*时间:(.*?前).*##时长:$1  上传于:$2",
    "ruleTitle": "a@span.1@text",
    "singleUrl": false,
    "sortUrl": "91原创::https://f407.a2507app.com/v.php?category=ori&viewtype=basic&page={{page}},{'webView': true}\n当前最热::https://f407.a2507app.com/v.php?category=hot&viewtype=basic&page={{page}},{'webView': true}\n本月最热::https://f407.a2507app.com/v.php?category=top&viewtype=basic&page={{page}},{'webView': true}\n10分钟以上 ::https://f407.a2507app.com/v.php?category=long&viewtype=basic&page={{page}},{'webView': true}\n20分钟以上 ::https://f407.a2507app.com/v.php?category=longer&viewtype=basic&page={{page}},{'webView': true}\n本月收藏::https://f407.a2507app.com/v.php?category=tf&viewtype=basic&page={{page}},{'webView': true}\n 收藏最多::https://f407.a2507app.com/v.php?category=mf&viewtype=basic&page={{page}},{'webView': true}\n最近加精::https://f407.a2507app.com/v.php?category=rf&viewtype=basic&page={{page}},{'webView': true}\n高清::https://f407.a2507app.com/v.php?category=hd&viewtype=basic&page={{page}},{'webView': true}\n上月最热::https://f407.a2507app.com/v.php?category=top&m=-1&viewtype=basic&page={{page}},{'webView': true}\n本月讨论::https://f407.a2507app.com/v.php?category=md&viewtype=basic&page={{page}},{'webView': true}\n",
    "sourceComment": "发布页::http://91freedz.com/",
    "sourceGroup": "视频，我",
    "sourceIcon": "",
    "sourceName": "91pron",
    "sourceUrl": "https://f407.a2507app.com/",
    "style": ""
  },
  {
    "articleStyle": 0,
    "customOrder": 72,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\"User-Agent\":\"Mozilla/5.0 (Linux; Android 10; TEL-AN00 Build/HONORTEL-AN00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/92.0.4515.105 Mobile Safari/537.36\"}",
    "lastUpdateTime": 1777783596017,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "1",
    "sourceIcon": "",
    "sourceName": "幻境导航",
    "sourceUrl": "https://hjdh.xyz"
  },
  {
    "articleStyle": 0,
    "customOrder": 73,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceComment": "魔法",
    "sourceGroup": "AI自用🔞",
    "sourceIcon": "https://files.catbox.moe/ym0bje.png",
    "sourceName": "魔法墙工具",
    "sourceUrl": "https://xx.ffg-g.net/register?code=nXM5fmbo"
  },
  {
    "articleStyle": 0,
    "customOrder": 74,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceComment": "使用需搭配加速器 不要相信里面的任何广告\n点击弹窗下方红色按钮即可跳过广告\n欢迎各位大佬对本源进行二创\n书源交流群：374309405（加群可获取福利）",
    "sourceGroup": "1",
    "sourceIcon": "https://ogfap.com/logo.png",
    "sourceName": "成人tik（源注释必看）",
    "sourceUrl": "https://xxxtik.com/"
  },
  {
    "articleStyle": 3,
    "customOrder": 75,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "header": "{\n\"User-Agent\": \"Mozilla/5.0 (Android)\"\n}",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "$.blocks..models[*]&&$.models[*]",
    "ruleContent": "<js>\nconst parts = baseUrl.split(',').map(function(item) { return item.trim(); });\nconst domain = parts[0].split('/').slice(0, 3).join('/');\nconst username = parts[0].split('/').pop() || parts[0];\n\nconst camAjax = java.ajax(domain + '/api/front/v2/models/username/' + username + '/cam?uniq=0');\nconst configAjax = java.ajax(domain + '/api/front/v3/config/initial');\nconst membersAjax = java.ajax(domain + '/api/front/v2/models/username/' + username + '/members?uniq=0');\n\nlet responseData = { status: \"offline\", avatarUrl: \"\", startTime: \"\", coverImg: \"\", userDescription: \"\", goalDescription: \"\", fanClubDescription: \"\", topic: \"\", username: username, stream: \"\", topBestPlace: \"\", hlsLines: [], cdn: \"\", pixelatedResolutions: [], membersCount: 0, tipMenuPriceList: [], isLive: false, tipMenuCreatedAt: \"\", websocketUrl: \"\", websocketToken: \"\", modelId: \"\" };\n\nif (camAjax) {\n    const camData = JSON.parse(camAjax);\n    const user = camData.user && camData.user.user ? camData.user.user : {};\n    const cam = camData.cam ? camData.cam : {};\n    \n    responseData.status = user.status || \"offline\";\n    responseData.avatarUrl = user.avatarUrl || \"\";\n    responseData.startTime = user.statusChangedAt || \"\";\n    responseData.userDescription = user.description || \"\";\n    responseData.goalDescription = cam.goal && cam.goal.description ? cam.goal.description : \"\";\n    responseData.fanClubDescription = cam.userFanClub && cam.userFanClub.description ? cam.userFanClub.description : \"\";\n    responseData.topic = cam.topic || \"\";\n    responseData.stream = cam.streamName || \"\";\n    responseData.topBestPlace = user.topBestPlace || \"\";\n    responseData.modelId = user.id || \"\";\n    \n    if (user.snapshotTimestamp && responseData.modelId) {\n        responseData.coverImg = \"https://img.doppiocdn.live/thumbs/\" + user.snapshotTimestamp + \"/\" + responseData.modelId;\n    }\n    \n    if (cam.broadcastSettings && cam.broadcastSettings.presets) {\n        const presets = cam.broadcastSettings.presets;\n        var allResolutions = [];\n        \n        if (presets.default && presets.default.constructor === Array) {\n            allResolutions = allResolutions.concat(presets.default);\n        }\n        \n        if (presets.pixelated && presets.pixelated.constructor === Array) {\n            allResolutions = allResolutions.concat(presets.pixelated);\n        }\n        \n        if (presets.testing && presets.testing.constructor === Array) {\n            allResolutions = allResolutions.concat(presets.testing);\n        }\n        \n        if (presets.h265 && presets.h265.constructor === Array) {\n            allResolutions = allResolutions.concat(presets.h265);\n        }\n        \n        if (presets.vr && presets.vr.constructor === Array) {\n            allResolutions = allResolutions.concat(presets.vr);\n        }\n        \n        var uniqueResolutions = [];\n        for (var i = 0; i < allResolutions.length; i++) {\n            if (uniqueResolutions.indexOf(allResolutions[i]) === -1) {\n                uniqueResolutions.push(allResolutions[i]);\n            }\n        }\n        \n        uniqueResolutions.sort(function(a, b) {\n            var numA = parseInt(a);\n            var numB = parseInt(b);\n            if (isNaN(numA)) numA = 0;\n            if (isNaN(numB)) numB = 0;\n            if (a === \"auto\") return 1;\n            if (b === \"auto\") return -1;\n            if (a === \"160p_blurred\") return 1;\n            if (b === \"160p_blurred\") return -1;\n            return numB - numA;\n        });\n        \n        responseData.pixelatedResolutions = uniqueResolutions;\n    }\n    \n    responseData.isLive = user.isOnline === true;\n    responseData.tipMenuCreatedAt = cam.tipMenu && cam.tipMenu.createdAt ? cam.tipMenu.createdAt : \"\";\n    \n    if (cam.tipMenu && cam.tipMenu.settings) {\n        responseData.tipMenuPriceList = cam.tipMenu.settings.map(function(item) {\n            return {\n                activity: item.activity || \"\",\n                price: item.price || 0\n            };\n        });\n    }\n}\n\nif (configAjax) {\n    const configData = JSON.parse(configAjax);\n    const hosts = configData.initial && configData.initial.common && configData.initial.common.hlsStreamHosts ? configData.initial.common.hlsStreamHosts : {};\n    var hlsLines = [];\n    if (hosts.A) hlsLines.push(hosts.A);\n    if (hosts.B) hlsLines.push(hosts.B);\n    if (hosts.C) hlsLines.push(hosts.C);\n    if (hosts.D) hlsLines.push(hosts.D);\n    if (hosts.E) hlsLines.push(hosts.E);\n    if (hosts.F) hlsLines.push(hosts.F);\n    responseData.hlsLines = hlsLines;\n    responseData.cdn = responseData.hlsLines[0] || \"\";\n    \n    const client = configData.initial && configData.initial.client ? configData.initial.client : {};\n    responseData.websocketUrl = client.websocket && client.websocket.url ? client.websocket.url : \"\";\n    responseData.websocketToken = client.websocket && client.websocket.token ? client.websocket.token : \"\";\n}\n\nif (membersAjax) {\n    try {\n        const membersData = JSON.parse(membersAjax);\n        responseData.membersCount = \n            (membersData && membersData.guests ? membersData.guests : 0) + \n            (membersData && membersData.spies ? membersData.spies : 0) + \n            (membersData && membersData.invisibles ? membersData.invisibles : 0) + \n            (membersData && membersData.greens ? membersData.greens : 0) + \n            (membersData && membersData.golds ? membersData.golds : 0) + \n            (membersData && membersData.regulars ? membersData.regulars : 0);\n    } catch (error) {\n        responseData.membersCount = 0;\n    }\n}\n\nJSON.stringify(responseData);\n</js>\n<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n</head>\n    <style>\n        * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Microsoft Yahei', sans-serif; }\n        body { color: #333; padding: 0.1rem; min-height: 100vh; background: #f5f5f5; }\n        .app-container { display: grid; grid-template-columns: 1fr; gap: 1rem; max-width: 1200px; margin: 0 auto; }\n        .live-section { border-radius: 12px; overflow: hidden; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); border: 1px solid #eaeaea; background: #fff; }\n        .topic-section { padding: 14px 20px; border-bottom: 1px solid #eaeaea; background: #fff; display: none; }\n        .topic-label { font-size: 12px; color: #666; margin-bottom: 6px; display: flex; align-items: center; gap: 8px; font-weight: 500; }\n        .topic-content { font-size: 15px; color: #333; font-weight: 500; line-height: 1.4; }\n        .chat-section { border-radius: 12px; padding: 1rem; display: flex; flex-direction: column; height: 500px; border: 1px solid #eaeaea; background: #fff; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); }\n        .chat-messages { flex: 1; overflow-y: auto; padding-right: 0.5rem; width: 100%; }\n        .chat-messages::-webkit-scrollbar { width: 6px; }\n        .chat-messages::-webkit-scrollbar-track { background: #f0f0f0; border-radius: 3px; }\n        .chat-messages::-webkit-scrollbar-thumb { background: #c0c0c0; border-radius: 3px; }\n        .message-wrapper { display: block; margin-bottom: 0.3rem; width: 100%; }\n        .message-item { padding: 0.3rem 0.6rem; border-radius: 16px; font-size: 0.85rem; line-height: 1.3; border: 1px solid rgba(224, 224, 224, 0.6); display: block; background: #f8f8f8; color: #333; width: 100%; word-break: break-word; box-sizing: border-box; }\n        .lovense-item { border-color: #e0e0e0; background: #f8f8f8; }\n        .tip-item { border-color: #e0e0e0; background: #f8f8f8; }\n        .system-message { border-color: #e0e0e0; color: #666; font-size: 0.85rem; margin: 0 auto 0.3rem auto; background: #f8f8f8; }\n        .user-name { font-weight: 600; color: #222; margin-left: 0.4rem; }\n        .level-tag { font-size: 0.75rem; color: #666; background: #f0f0f0; padding: 0.1rem 0.4rem; border-radius: 8px; }\n        .tip-amount { color: #e74c3c; font-weight: 600; }\n        .live-header { padding: 16px 20px; border-bottom: 1px solid #eaeaea; display: flex; align-items: center; gap: 15px; background: #fff; }\n        .avatar-container { width: 56px; height: 56px; flex-shrink: 0; }\n        .avatar { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; border: 3px solid #007aff; }\n        .host-info { flex: 1; min-width: 0; }\n        .host-info h2 { font-size: 18px; margin-bottom: 6px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #333; }\n        .status-container { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }\n        .live-badge { display: inline-flex; align-items: center; background: #ff3b30; color: white; padding: 4px 10px; border-radius: 4px; font-size: 12px; font-weight: 600; letter-spacing: 0.3px; }\n        .live-badge::before { content: ''; display: inline-block; width: 6px; height: 6px; background-color: white; border-radius: 50%; margin-right: 6px; animation: blink 1.5s infinite; }\n        @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }\n        .viewer-count { font-size: 13px; color: #666; display: flex; align-items: center; gap: 5px; }\n        .player-container { position: relative; background: #000000; overflow: hidden; }\n        .player-container:fullscreen { display: flex; align-items: center; justify-content: center; }\n        .player-container:-webkit-full-screen { display: flex; align-items: center; justify-content: center; }\n        #dplayer { width: 100% !important; height: 100% !important; display: flex; align-items: center; }\n        #dplayer video { object-fit: contain !important; }\n        .dplayer-controller { display: none !important; }\n        .dplayer-notice { display: none !important; }\n        .custom-controls { position: absolute; bottom: 0; left: 0; right: 0; padding: 12px 15px 6px; display: flex; align-items: center; justify-content: space-between; opacity: 0; transition: opacity 0.2s; z-index: 1000; pointer-events: none; }\n        .player-container.controls-visible .custom-controls { opacity: 1; pointer-events: auto; }\n        .player-container.controls-hidden .custom-controls { opacity: 0; pointer-events: none; }\n        .left-controls, .right-controls { display: flex; align-items: center; gap: 8px; pointer-events: auto; }\n        .rotate-btn { background: rgba(255, 255, 255, 0.15); border: 1px solid rgba(255, 255, 255, 0.25); color: rgba(255, 255, 255, 0.9); padding: 6px 10px; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 500; white-space: nowrap; display: flex; align-items: center; justify-content: center; transition: all 0.15s; min-width: 52px; pointer-events: auto; }\n        .rotate-btn:hover { background: rgba(255, 255, 255, 0.25); color: white; }\n        .control-btn { background: rgba(255, 255, 255, 0.15); border: 1px solid rgba(255, 255, 255, 0.25); color: #ffffff; width: 36px; height: 36px; border-radius: 6px; display: flex; align-items: center; justify-content: center; cursor: pointer; font-size: 16px; transition: all 0.15s; pointer-events: auto; }\n        .control-btn:disabled { opacity: 0.5; cursor: not-allowed; }\n        .selector-btn { background: rgba(255, 255, 255, 0.15); border: 1px solid rgba(255, 255, 255, 0.25); color: #ffffff; padding: 6px 10px; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 500; white-space: nowrap; display: flex; align-items: center; gap: 5px; transition: all 0.15s; min-width: 65px; justify-content: center; pointer-events: auto; }\n        .selector-menu { position: absolute; bottom: 42px; background: #ffffff; border-radius: 8px; min-width: 90px; display: none; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.16); border: 1px solid #d1d1d6; overflow: hidden; z-index: 1001; pointer-events: auto; }\n        .menu-item { padding: 8px 12px; color: #333; cursor: pointer; font-size: 13px; transition: all 0.15s; border-bottom: 1px solid #eaeaea; display: flex; align-items: center; justify-content: space-between; pointer-events: auto; }\n        .menu-item:last-child { border-bottom: none; }\n        .menu-item:hover:not(:disabled) { background: #007aff; color: white; }\n        .menu-item.active { background: rgba(10, 132, 255, 0.1); color: #007aff; }\n        .menu-item.active:after { content: \"✓\"; font-size: 12px; color: #007aff; }\n        .loading-indicator { position: absolute; top: 15px; left: 15px; background: rgba(0, 0, 0, 0.8); color: white; padding: 6px 12px; border-radius: 4px; font-size: 12px; z-index: 1002; display: none; border: 1px solid rgba(255, 255, 255, 0.1); }\n        .floating-button { position: fixed; bottom: 20px; right: 20px; width: 60px; height: 60px; border-radius: 50%; background: #007aff; color: white; display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: 0 4px 12px rgba(0, 122, 255, 0.3); z-index: 10000; border: none; font-size: 24px; }\n        .floating-panel { position: fixed; bottom: 90px; right: 20px; width: 400px; background: #ffffff; border-radius: 12px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15); padding: 20px; z-index: 9999; border: 1px solid #eaeaea; display: none; max-height: 80vh; overflow-y: auto; }\n        .floating-panel::-webkit-scrollbar { width: 6px; }\n        .floating-panel::-webkit-scrollbar-track { background: #f0f0f0; border-radius: 3px; }\n        .floating-panel::-webkit-scrollbar-thumb { background: #c0c0c0; border-radius: 3px; }\n        .floating-panel-title { font-size: 18px; font-weight: 600; margin-bottom: 15px; color: #333; padding-bottom: 10px; border-bottom: 1px solid #eaeaea; }\n        .floating-info-section { margin-bottom: 20px; }\n        .floating-info-section-title { font-size: 15px; color: #007aff; margin-bottom: 12px; font-weight: 600; display: flex; align-items: center; gap: 8px; }\n        .floating-info-item { margin-bottom: 12px; display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #f5f5f5; }\n        .floating-info-item:last-child { border-bottom: none; margin-bottom: 0; }\n        .floating-info-label { font-size: 13px; color: #666; min-width: 120px; }\n        .floating-info-value { font-size: 14px; color: #333; font-weight: 500; text-align: right; flex: 1; }\n        .floating-content { background: #f8f9fa; border: 1px solid #eaeaea; border-radius: 8px; padding: 12px; font-size: 14px; color: #333; line-height: 1.5; margin-bottom: 15px; }\n        .floating-price-list { display: flex; flex-direction: column; gap: 8px; }\n        .floating-price-item { background: #ffffff; border: 1px solid #eaeaea; border-radius: 8px; padding: 10px 12px; display: flex; align-items: center; justify-content: space-between; transition: all 0.2s; }\n        .floating-price-item:hover { border-color: #007aff; }\n        .floating-price-activity { font-size: 14px; color: #333; flex: 1; }\n        .floating-price-value { font-size: 14px; color: #ff3b30; font-weight: 600; }\n        @media (max-width: 768px) {\n            .floating-panel { width: 350px; right: 10px; bottom: 80px; }\n            .floating-button { width: 50px; height: 50px; font-size: 20px; right: 15px; bottom: 15px; }\n            .live-header { padding: 14px 16px; }\n            .avatar-container { width: 48px; height: 48px; }\n            .host-info h2 { font-size: 16px; }\n        }\n        @media (max-width: 480px) {\n            .floating-panel { width: 300px; }\n            .chat-section { height: 400px; }\n            .app-container { padding: 0.5rem; gap: 1rem; }\n        }\n    </style>\n<body>\n    <div id=\"config\" style=\"display:none;\">\n        <div id=\"liveData\" style=\"display:none;\">{{result}}</div>\n    </div>\n    \n    <div class=\"app-container\">\n        <div class=\"live-section\">\n            <div class=\"topic-section\" id=\"topicContainer\">\n                <div class=\"topic-label\">\n                    <i class=\"fas fa-bullhorn\"></i> 直播标题\n                </div>\n                <div class=\"topic-content\" id=\"topic\"></div>\n            </div>\n            \n            <div class=\"live-header\">\n                <div class=\"avatar-container\">\n                    <img class=\"avatar\" id=\"avatarImg\" src=\"\" alt=\"\">\n                </div>\n                <div class=\"host-info\">\n                    <h2 id=\"hostName\">正在加载...</h2>\n                    <div class=\"status-container\">\n                        <span class=\"live-badge\">直播中</span>\n                        <div class=\"viewer-count\">\n                            <i class=\"fas fa-users\"></i>\n                            <span id=\"membersCount\">--</span> 人\n                        </div>\n                    </div>\n                </div>\n            </div>\n            \n            <div class=\"player-container\" id=\"playerContainer\">\n                <div id=\"dplayer\"></div>\n                <div class=\"loading-indicator\" id=\"loadingIndicator\">正在切换...</div>\n                <div class=\"custom-controls\">\n                    <div class=\"left-controls\">\n                        <button class=\"control-btn\" id=\"refreshBtn\" title=\"刷新播放\">\n                            <i class=\"fas fa-redo-alt\"></i>\n                        </button>\n                        <button class=\"control-btn\" id=\"volumeBtn\" title=\"静音/取消静音\">\n                            <i class=\"fas fa-volume-up\"></i>\n                        </button>\n                        <div class=\"rotate-btn\" id=\"rotateBtn\">竖屏</div>\n                    </div>\n                    <div class=\"right-controls\">\n                        <div class=\"line-selector\">\n                            <div class=\"selector-btn\" id=\"lineBtn\" title=\"选择线路\">线路1 <i class=\"fas fa-chevron-down\"></i></div>\n                            <div class=\"selector-menu\" id=\"lineMenu\"></div>\n                        </div>\n                        <div class=\"quality-selector\">\n                            <div class=\"selector-btn\" id=\"qualityBtn\" title=\"选择清晰度\">默认 <i class=\"fas fa-chevron-down\"></i></div>\n                            <div class=\"selector-menu\" id=\"qualityMenu\"></div>\n                        </div>\n                        <button class=\"control-btn\" id=\"fullscreenBtn\" title=\"全屏\">\n                            <i class=\"fas fa-expand\"></i>\n                        </button>\n                    </div>\n                </div>\n            </div>\n        </div>\n        \n        <div class=\"chat-section\">\n             <div class=\"chat-messages\" id=\"chatContainer\"></div>\n        </div>\n    </div>\n    \n    <button class=\"floating-button\" id=\"floatingBtn\">\n        <i class=\"fas fa-info\"></i>\n    </button>\n    \n    <div class=\"floating-panel\" id=\"floatingPanel\">\n        <div class=\"floating-panel-title\">直播信息</div>\n        \n        <div class=\"floating-info-section\">\n            <div class=\"floating-info-section-title\">\n                <i class=\"fas fa-user\"></i> 主播信息\n            </div>\n            <div class=\"floating-info-item\">\n                <span class=\"floating-info-label\">主播名称:</span>\n                <span class=\"floating-info-value\" id=\"floatingHostName\">--</span>\n            </div>\n            <div class=\"floating-info-item\">\n                <span class=\"floating-info-label\">历史最高排行:</span>\n                <span class=\"floating-info-value\" id=\"floatingTopBestPlace\">--</span>\n            </div>\n            <div class=\"floating-info-item\">\n                <span class=\"floating-info-label\">总人数:</span>\n                <span class=\"floating-info-value\" id=\"floatingMembersCount\">--</span>\n            </div>\n            <div class=\"floating-info-item\">\n                <span class=\"floating-info-label\">首次开播日期:</span>\n                <span class=\"floating-info-value\" id=\"floatingTipMenuCreatedAt\">--</span>\n            </div>\n            <div class=\"floating-info-item\">\n                <span class=\"floating-info-label\" id=\"floatingDurationLabel\">时长标签:</span>\n                <span class=\"floating-info-value\" id=\"floatingDuration\">--</span>\n            </div>\n            <div class=\"floating-info-item\">\n                <span class=\"floating-info-label\" id=\"floatingTimeLabel\">时间标签:</span>\n                <span class=\"floating-info-value\" id=\"floatingStatusTime\">--</span>\n            </div>\n        </div>\n        \n        <div class=\"floating-info-section\" id=\"floatingUserDescriptionSection\">\n            <div class=\"floating-info-section-title\">\n                <i class=\"fas fa-user-circle\"></i> 主播介绍\n            </div>\n            <div class=\"floating-content\" id=\"floatingUserDescription\"></div>\n        </div>\n        \n        <div class=\"floating-info-section\" id=\"floatingGoalSection\">\n            <div class=\"floating-info-section-title\">\n                <i class=\"fas fa-bullseye\"></i> 直播目标\n            </div>\n            <div class=\"floating-content\" id=\"floatingGoalDescription\"></div>\n        </div>\n        \n        <div class=\"floating-info-section\" id=\"floatingFanClubSection\">\n            <div class=\"floating-info-section-title\">\n                <i class=\"fas fa-users\"></i> 粉丝团留言\n            </div>\n            <div class=\"floating-content\" id=\"floatingFanClubDescription\"></div>\n        </div>\n        \n        <div class=\"floating-info-section\">\n            <div class=\"floating-info-section-title\">\n                <i class=\"fas fa-gift\"></i> 打赏菜单\n            </div>\n            <div class=\"floating-price-list\" id=\"floatingPriceList\"></div>\n        </div>\n        \n        <div class=\"floating-info-section\">\n            <div class=\"floating-info-section-title\">\n                <i class=\"fas fa-tv\"></i> 播放设置\n            </div>\n            <div class=\"floating-info-item\">\n                <span class=\"floating-info-label\">当前线路:</span>\n                <span class=\"floating-info-value\" id=\"floatingLine\">线路1</span>\n            </div>\n            <div class=\"floating-info-item\">\n                <span class=\"floating-info-label\">清晰度:</span>\n                <span class=\"floating-info-value\" id=\"floatingQuality\">默认</span>\n            </div>\n        </div>\n    </div>\n\n    <script src=\"https://cdn.jsdelivr.net/npm/dplayer@1.27.1/dist/DPlayer.min.js\"></script>\n    <script src=\"https://cdn.jsdelivr.net/npm/hls.js@1.4.10/dist/hls.min.js\"></script>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/js/all.min.js\"></script>\n    <script>\n        const liveDataElement = document.getElementById('liveData');\n        let liveData = {};\n        \n        if (liveDataElement.textContent) {\n            try {\n                liveData = JSON.parse(liveDataElement.textContent);\n            } catch (e) {}\n        }\n        \n        const chatContainer = document.getElementById('chatContainer');\n        let chatWs = null;\n\n        function addSystemMessage(text) {\n            const systemDiv = document.createElement('div');\n            systemDiv.className = 'message-item system-message';\n            systemDiv.textContent = text;\n            chatContainer.prepend(systemDiv);\n            chatContainer.scrollTop = 0;\n        }\n        \n        function initChat() {\n            if (!liveData.modelId || !liveData.websocketUrl || !liveData.websocketToken) return;\n\n            addSystemMessage('开始连接弹幕服务器');\n            \n            const timeoutMs = 10000;\n            let connectTimeoutTimer = setTimeout(() => {\n                if (chatWs && chatWs.readyState !== WebSocket.OPEN) {\n                    chatWs.close();\n                    addSystemMessage('连接超时：未能成功连接弹幕服务器');\n                }\n            }, timeoutMs);\n            \n            if (chatWs && chatWs.readyState === WebSocket.OPEN) {\n                chatWs.close();\n            }\n            \n            chatWs = new WebSocket(`${liveData.websocketUrl}`);\n            const sendQueue = [\n                '{\"connect\":{\"token\":\"' + liveData.websocketToken + '\"},\"id\":1}',\n                `{\"subscribe\":{\"channel\":\"newChatMessage@${liveData.modelId}\"},\"id\":2}`\n            ];\n            \n            function getUserLevelTag(userData) {\n                return userData?.userRanking?.level ? `<span class=\"level-tag\">Lv.${userData.userRanking.level}</span>` : '';\n            }\n            \n            function createMessageElement(data) {\n                const messageDiv = document.createElement('div');\n                messageDiv.className = 'message-item';\n                \n                const { type, userData, details } = data.message;\n                const levelTag = getUserLevelTag(userData);\n                \n                let content = '';\n                switch(type) {\n                    case 'text':\n                        messageDiv.className += ' text-item';\n                        content = `${levelTag}<span class=\"user-name\">${userData.username}</span>: ${details.body}`;\n                        break;\n                    case 'tip':\n                        messageDiv.className += ' tip-item';\n                        content = `${levelTag}<span class=\"user-name\">${userData.username}</span>: 已支付<span class=\"tip-amount\">${details.amount}</span>代币`;\n                        break;\n                    case 'lovense':\n                        messageDiv.className += ' lovense-item';\n                        const { power, time, amount } = details.lovenseDetails.detail;\n                        const powerText = power === 'low' ? '低' : power === 'medium' ? '中' : '高';\n                        const clientLevelTag = getUserLevelTag(details.lovenseDetails.clientUserInfo);\n                        content = `${clientLevelTag}<span class=\"user-name\">${details.lovenseDetails.clientUserInfo.username}</span>: ${powerText}强度 · ${time}秒`;\n                        break;\n                    default:\n                        return null;\n                }\n                \n                messageDiv.innerHTML = content;\n                return messageDiv;\n            }\n            \n            function addMessageToPanel(messageData) {\n                const messageElement = createMessageElement(messageData);\n                if (messageElement) {\n                    const messageWrapper = document.createElement('div');\n                    messageWrapper.className = 'message-wrapper';\n                    messageWrapper.appendChild(messageElement);\n                    chatContainer.prepend(messageWrapper);\n                    chatContainer.scrollTop = 0;\n                }\n            }\n            \n            chatWs.onopen = () => {\n                clearTimeout(connectTimeoutTimer);\n                sendQueue.forEach(cmd => chatWs.send(cmd));\n                addSystemMessage('弹幕服务器连接正常');\n            };\n            \n            chatWs.onmessage = (e) => {\n                if (e.data.trim() === '{}') {\n                    chatWs.send('{}');\n                    return;\n                }\n                try {\n                    const data = JSON.parse(e.data);\n                    if (data.ping) {\n                        chatWs.send(JSON.stringify({ pong: data.ping }));\n                    }\n                    if (data.push?.channel === `newChatMessage@${liveData.modelId}`) {\n                        addMessageToPanel(data.push.pub.data);\n                    }\n                } catch (error) {}\n            };\n            \n            chatWs.onerror = (err) => {\n                const errorDiv = document.createElement('div');\n                errorDiv.className = 'message-item system-message';\n                errorDiv.textContent = '连接错误';\n                chatContainer.prepend(errorDiv);\n                chatContainer.scrollTop = 0;\n            };\n            \n            chatWs.onclose = (e) => {\n                const closeDiv = document.createElement('div');\n                closeDiv.className = 'message-item system-message';\n                closeDiv.textContent = `连接关闭 | 错误码: ${e.code}`;\n                chatContainer.prepend(closeDiv);\n                chatContainer.scrollTop = 0;\n            };\n        }\n        \n        const elements = {\n            avatarImg: document.getElementById('avatarImg'),\n            hostName: document.getElementById('hostName'),\n            refreshBtn: document.getElementById('refreshBtn'),\n            volumeBtn: document.getElementById('volumeBtn'),\n            lineBtn: document.getElementById('lineBtn'),\n            lineMenu: document.getElementById('lineMenu'),\n            qualityBtn: document.getElementById('qualityBtn'),\n            qualityMenu: document.getElementById('qualityMenu'),\n            fullscreenBtn: document.getElementById('fullscreenBtn'),\n            loadingIndicator: document.getElementById('loadingIndicator'),\n            playerContainer: document.getElementById('playerContainer'),\n            membersCount: document.getElementById('membersCount'),\n            floatingBtn: document.getElementById('floatingBtn'),\n            floatingPanel: document.getElementById('floatingPanel'),\n            floatingHostName: document.getElementById('floatingHostName'),\n            floatingTopBestPlace: document.getElementById('floatingTopBestPlace'),\n            floatingMembersCount: document.getElementById('floatingMembersCount'),\n            floatingTipMenuCreatedAt: document.getElementById('floatingTipMenuCreatedAt'),\n            floatingTopic: document.getElementById('floatingTopic'),\n            floatingTopicSection: document.getElementById('floatingTopicSection'),\n            floatingGoalDescription: document.getElementById('floatingGoalDescription'),\n            floatingGoalSection: document.getElementById('floatingGoalSection'),\n            floatingUserDescription: document.getElementById('floatingUserDescription'),\n            floatingUserDescriptionSection: document.getElementById('floatingUserDescriptionSection'),\n            floatingFanClubDescription: document.getElementById('floatingFanClubDescription'),\n            floatingFanClubSection: document.getElementById('floatingFanClubSection'),\n            floatingPriceList: document.getElementById('floatingPriceList'),\n            floatingDurationLabel: document.getElementById('floatingDurationLabel'),\n            floatingDuration: document.getElementById('floatingDuration'),\n            floatingTimeLabel: document.getElementById('floatingTimeLabel'),\n            floatingStatusTime: document.getElementById('floatingStatusTime'),\n            floatingLine: document.getElementById('floatingLine'),\n            floatingQuality: document.getElementById('floatingQuality'),\n            topicContainer: document.getElementById('topicContainer'),\n            topic: document.getElementById('topic'),\n            rotateBtn: document.getElementById('rotateBtn')\n        };\n        \n        let dp = null;\n        let isMuted = false;\n        let isFullscreen = false;\n        let hlsInstance = null;\n        let durationInterval = null;\n        let config = {};\n        let hideControlsTimer = null;\n        \n        const getStreamUrl = (lineIndex = config.currentLine || 0, quality = config.currentQuality || 'auto') => {\n            const line = config.hlsLines?.[lineIndex];\n            if (!line || !config.stream) return '';\n            \n            const pureStatus = (config.status || '').toLowerCase();\n            let suffix = '_auto';\n            \n            if (pureStatus !== 'public') {\n                suffix = '_160p_blurred';\n            } else if (quality === 'auto') {\n                suffix = '_auto';\n            } else {\n                suffix = '_' + quality;\n            }\n            \n            return `https://edge-hls.${line}/hls/${config.stream}/master/${config.stream}${suffix}.m3u8?pkey=bXorqTB5ZhP5FcpX`;\n        };\n        \n        function showControls() {\n            elements.playerContainer.classList.remove('controls-hidden');\n            elements.playerContainer.classList.add('controls-visible');\n            if (hideControlsTimer) {\n                clearTimeout(hideControlsTimer);\n            }\n            hideControlsTimer = setTimeout(() => {\n                elements.playerContainer.classList.remove('controls-visible');\n                elements.playerContainer.classList.add('controls-hidden');\n            }, 3000);\n        }\n        \n        function switchStream(url) {\n            if (!dp || !dp.video || !url) return;\n            \n            config.isSwitching = true;\n            elements.loadingIndicator.style.display = 'block';\n            showControls();\n            \n            const video = dp.video;\n            video.pause();\n            video.src = '';\n            video.load();\n            \n            if (hlsInstance) {\n                try {\n                    hlsInstance.stopLoad();\n                    setTimeout(() => {\n                        hlsInstance.destroy();\n                        hlsInstance = null;\n                        startNewStream(url, video);\n                    }, 50);\n                } catch (e) {\n                    hlsInstance.destroy();\n                    hlsInstance = null;\n                    startNewStream(url, video);\n                }\n            } else {\n                startNewStream(url, video);\n            }\n        }\n        \n        function startNewStream(url, video) {\n            video.src = url;\n            \n            if (Hls.isSupported()) {\n                hlsInstance = new Hls({\n                    enableWorker: true,\n                    lowLatencyMode: true,\n                    backBufferLength: 60,\n                    maxBufferSize: 30 * 1000 * 1000,\n                    maxBufferLength: 30\n                });\n                \n                hlsInstance.loadSource(url);\n                hlsInstance.attachMedia(video);\n                \n                hlsInstance.on(Hls.Events.MANIFEST_PARSED, () => {\n                    completeSwitch();\n                    video.play().catch(e => {});\n                });\n                \n                hlsInstance.on(Hls.Events.ERROR, (event, data) => {\n                    if (data.fatal) {\n                        switch(data.type) {\n                            case Hls.ErrorTypes.NETWORK_ERROR:\n                                hlsInstance.startLoad();\n                                break;\n                            case Hls.ErrorTypes.MEDIA_ERROR:\n                                hlsInstance.recoverMediaError();\n                                break;\n                            default:\n                                completeSwitch();\n                                break;\n                        }\n                    }\n                });\n                \n                setTimeout(() => {\n                    if (config.isSwitching) {\n                        completeSwitch();\n                    }\n                }, 5000);\n                \n            } else if (video.canPlayType('application/vnd.apple.mpegurl')) {\n                video.addEventListener('loadedmetadata', () => {\n                    completeSwitch();\n                    video.play().catch(e => {});\n                });\n                \n                video.addEventListener('error', () => {\n                    completeSwitch();\n                });\n                \n                setTimeout(() => {\n                    if (config.isSwitching) {\n                        completeSwitch();\n                    }\n                }, 5000);\n            } else {\n                completeSwitch();\n            }\n        }\n        \n        function completeSwitch() {\n            config.isSwitching = false;\n            elements.loadingIndicator.style.display = 'none';\n        }\n        \n        function initPlayer() {\n            config = { ...liveData, currentLine: 0, currentQuality: 'auto', isSwitching: false };\n            \n            const url = getStreamUrl();\n            if (!url) return;\n            \n            if (dp) {\n                dp.destroy();\n                dp = null;\n            }\n            \n            dp = new DPlayer({\n                container: document.getElementById('dplayer'),\n                live: true,\n                autoplay: true,\n                theme: '#00a1d6',\n                loop: false,\n                lang: 'zh-cn',\n                screenshot: false,\n                hotkey: false,\n                preload: 'auto',\n                volume: 0.7,\n                mutex: true,\n                controls: false,\n                video: {\n                    url: url,\n                    pic: config.coverImg,\n                    type: 'customHls',\n                    customType: {\n                        customHls: function(video, player) {}\n                    }\n                },\n                contextmenu: [],\n                danmaku: false\n            });\n            \n            const videoElement = dp.video;\n            if (videoElement) {\n                videoElement.style.pointerEvents = 'none';\n                videoElement.addEventListener('click', function(e) {\n                    e.preventDefault();\n                    e.stopPropagation();\n                    return false;\n                });\n            }\n            \n            const dplayerContainer = dp.container;\n            dplayerContainer.style.pointerEvents = 'none';\n            dplayerContainer.addEventListener('click', function(e) {\n                e.preventDefault();\n                e.stopPropagation();\n                return false;\n            });\n            \n            isMuted = dp.video.muted;\n            elements.volumeBtn.innerHTML = isMuted \n                ? '<i class=\"fas fa-volume-mute\"></i>'\n                : '<i class=\"fas fa-volume-up\"></i>';\n            \n            switchStream(url);\n        }\n\n        function refreshPlayer() {\n            if (config.isSwitching || !config.stream) return;\n            const url = getStreamUrl(config.currentLine, config.currentQuality);\n            switchStream(url);\n        }\n        \n        function switchLine(lineIndex) {\n            if (config.isSwitching || !config.hlsLines || lineIndex >= config.hlsLines.length) return;\n            config.currentLine = lineIndex;\n            elements.lineBtn.innerHTML = `线路${lineIndex + 1} <i class=\"fas fa-chevron-down\"></i>`;\n            elements.floatingLine.textContent = `线路${lineIndex + 1}`;\n            updateLineMenuHighlights();\n            elements.lineMenu.style.display = 'none';\n            \n            const url = getStreamUrl(lineIndex, config.currentQuality);\n            switchStream(url);\n        }\n        \n        function switchQuality(quality) {\n            if (config.isSwitching) return;\n            config.currentQuality = quality;\n            const displayText = quality === 'auto' ? '默认' : quality;\n            elements.qualityBtn.innerHTML = `${displayText} <i class=\"fas fa-chevron-down\"></i>`;\n            elements.floatingQuality.textContent = displayText;\n            updateQualityMenuHighlights();\n            elements.qualityMenu.style.display = 'none';\n            \n            const url = getStreamUrl(config.currentLine, quality);\n            switchStream(url);\n        }\n        \n        function formatDuration(seconds) {\n            if (!seconds) return '0秒';\n            \n            const days = Math.floor(seconds / (24 * 60 * 60));\n            const hours = Math.floor((seconds % (24 * 60 * 60)) / (60 * 60));\n            const minutes = Math.floor((seconds % (60 * 60)) / 60);\n            const secs = Math.floor(seconds % 60);\n            \n            let result = '';\n            if (days > 0) result += `${days}天`;\n            if (hours > 0) result += `${hours}小时`;\n            if (minutes > 0) result += `${minutes}分钟`;\n            if (secs > 0 || result === '') result += `${secs}秒`;\n            \n            return result;\n        }\n        \n        function updateTimeInfo() {\n            if (!config.status || !config.startTime) return;\n            \n            const pureStatus = config.status.replace(/^状态：/, '').toLowerCase();\n            const isPublic = pureStatus === 'public';\n            const startTime = config.startTime ? new Date(config.startTime).getTime() : null;\n            const now = Date.now();\n            \n            if (config.isLive && startTime) {\n                if (isPublic) {\n                    elements.floatingDurationLabel.textContent = '直播时长:';\n                    elements.floatingTimeLabel.textContent = '直播时间:';\n                    \n                    const duration = Math.floor((now - startTime) / 1000);\n                    const durationText = formatDuration(duration);\n                    elements.floatingDuration.textContent = durationText;\n                    \n                    const startDate = new Date(startTime);\n                    elements.floatingStatusTime.textContent = startDate.toLocaleString();\n                } else {\n                    elements.floatingDurationLabel.textContent = '持续时长:';\n                    elements.floatingTimeLabel.textContent = '私密直播:';\n                    \n                    const duration = Math.floor((now - startTime) / 1000);\n                    const durationText = formatDuration(duration);\n                    elements.floatingDuration.textContent = durationText;\n                    \n                    const startDate = new Date(startTime);\n                    elements.floatingStatusTime.textContent = startDate.toLocaleString();\n                }\n            } else if (startTime) {\n                elements.floatingDurationLabel.textContent = '持续时长:';\n                elements.floatingTimeLabel.textContent = '下播时间:';\n                \n                const duration = Math.floor((now - startTime) / 1000);\n                let durationText = formatDuration(duration);\n                elements.floatingDuration.textContent = durationText;\n                \n                const endDate = new Date(startTime);\n                elements.floatingStatusTime.textContent = endDate.toLocaleString();\n            } else {\n                elements.floatingDuration.textContent = '--';\n                elements.floatingStatusTime.textContent = '--';\n            }\n        }\n        \n        function startDurationUpdate() {\n            if (durationInterval) {\n                clearInterval(durationInterval);\n            }\n            \n            updateTimeInfo();\n            durationInterval = setInterval(updateTimeInfo, 1000);\n        }\n        \n        function updateFloatingPanel() {\n            const pureUsername = (config.username || '').split('/').pop() || config.username || '';\n            elements.floatingHostName.textContent = pureUsername || '未知主播';\n            elements.membersCount.textContent = config.membersCount > 0 ? config.membersCount.toLocaleString() : '--';\n            elements.floatingMembersCount.textContent = config.membersCount > 0 ? config.membersCount.toLocaleString() : '--';\n            \n            if (config.topBestPlace > 0) {\n                const rankText = `TOP ${config.topBestPlace}`;\n                elements.floatingTopBestPlace.textContent = rankText;\n            } else {\n                elements.floatingTopBestPlace.textContent = '未上榜';\n            }\n            \n            if (config.tipMenuCreatedAt) {\n                const createdAt = new Date(config.tipMenuCreatedAt);\n                elements.floatingTipMenuCreatedAt.textContent = createdAt.toLocaleString();\n            } else {\n                elements.floatingTipMenuCreatedAt.textContent = '--';\n            }\n            \n            if (config.userDescription && config.userDescription.trim() !== '') {\n                elements.floatingUserDescription.textContent = config.userDescription;\n                elements.floatingUserDescriptionSection.style.display = 'block';\n            } else {\n                elements.floatingUserDescriptionSection.style.display = 'none';\n            }\n            \n            if (config.goalDescription && config.goalDescription.trim() !== '') {\n                elements.floatingGoalDescription.textContent = config.goalDescription;\n                elements.floatingGoalSection.style.display = 'block';\n            } else {\n                elements.floatingGoalSection.style.display = 'none';\n            }\n            \n            if (config.fanClubDescription && config.fanClubDescription.trim() !== '') {\n                elements.floatingFanClubDescription.textContent = config.fanClubDescription;\n                elements.floatingFanClubSection.style.display = 'block';\n            } else {\n                elements.floatingFanClubSection.style.display = 'none';\n            }\n            \n            if (config.tipMenuPriceList && config.tipMenuPriceList.length > 0) {\n                elements.floatingPriceList.innerHTML = '';\n                config.tipMenuPriceList.forEach((tip) => {\n                    const priceItem = document.createElement('div');\n                    priceItem.className = 'floating-price-item';\n                    \n                    const activityDiv = document.createElement('div');\n                    activityDiv.className = 'floating-price-activity';\n                    activityDiv.textContent = tip.activity || '未命名';\n                    \n                    const priceDiv = document.createElement('div');\n                    priceDiv.className = 'floating-price-value';\n                    priceDiv.textContent = `${tip.price || 0} 代币`;\n                    \n                    priceItem.appendChild(activityDiv);\n                    priceItem.appendChild(priceDiv);\n                    elements.floatingPriceList.appendChild(priceItem);\n                });\n            } else {\n                elements.floatingPriceList.innerHTML = '<div class=\"floating-price-item\"><div class=\"floating-price-activity\">暂无打赏菜单</div></div>';\n            }\n            \n            startDurationUpdate();\n        }\n        \n        function initUI() {\n            const pureUsername = (config.username || '').split('/').pop() || config.username || '';\n            elements.hostName.textContent = pureUsername || '未知主播';\n            \n            if (config.topic && config.topic.trim() !== '') {\n                elements.topic.textContent = config.topic;\n                elements.topicContainer.style.display = 'block';\n                document.title = config.topic;\n            } else {\n                elements.topicContainer.style.display = 'none';\n                document.title = pureUsername || '直播间';\n            }\n            \n            if (config.avatarUrl) {\n                const prefix = 'https://static-cdn.strpst.com';\n                if (config.avatarUrl.startsWith(prefix + prefix)) {\n                    config.avatarUrl = config.avatarUrl.replace(prefix + prefix, prefix);\n                }\n                elements.avatarImg.src = config.avatarUrl;\n            } else {\n                elements.avatarImg.src = '主播';\n            }\n            \n            updateFloatingPanel();\n        }\n        \n        function initLineMenu() {\n            elements.lineMenu.innerHTML = '';\n            \n            if (!config.hlsLines || config.hlsLines.length === 0) {\n                const item = document.createElement('div');\n                item.className = 'menu-item';\n                item.textContent = '无线路';\n                item.style.opacity = '0.6';\n                elements.lineMenu.appendChild(item);\n                return;\n            }\n            \n            config.hlsLines.forEach((line, index) => {\n                const item = document.createElement('div');\n                item.className = `menu-item ${index === config.currentLine ? 'active' : ''}`;\n                item.textContent = `线路${index + 1}`;\n                item.dataset.index = index;\n                item.onclick = (e) => {\n                    e.stopPropagation();\n                    switchLine(index);\n                };\n                elements.lineMenu.appendChild(item);\n            });\n        }\n        \n        function initQualityMenu() {\n            elements.qualityMenu.innerHTML = '';\n            const pureStatus = (config.status || '').replace(/^状态：/, '').toLowerCase();\n            \n            let availableQualities = [];\n            availableQualities.push({ value: 'auto', display: '默认' });\n            \n            if (pureStatus !== 'public') {\n                availableQualities = [{ value: '160p_blurred', display: '模糊' }];\n                config.currentQuality = '160p_blurred';\n            } else if (config.pixelatedResolutions && config.pixelatedResolutions.length > 0) {\n                config.pixelatedResolutions.forEach(resolution => {\n                    if (resolution !== '160p_blurred') {\n                        availableQualities.push({ \n                            value: resolution, \n                            display: resolution \n                        });\n                    }\n                });\n            }\n            \n            availableQualities.forEach((quality) => {\n                const isActive = quality.value === config.currentQuality;\n                const item = document.createElement('div');\n                item.className = `menu-item ${isActive ? 'active' : ''}`;\n                item.textContent = quality.display;\n                item.dataset.quality = quality.value;\n                item.onclick = (e) => {\n                    e.stopPropagation();\n                    switchQuality(quality.value);\n                };\n                elements.qualityMenu.appendChild(item);\n            });\n            \n            const currentQuality = availableQualities.find(q => q.value === config.currentQuality);\n            const displayText = currentQuality ? currentQuality.display : '默认';\n            elements.qualityBtn.innerHTML = `${displayText} <i class=\"fas fa-chevron-down\"></i>`;\n            elements.floatingQuality.textContent = displayText;\n        }\n        \n        function updateLineMenuHighlights() {\n            const items = elements.lineMenu.querySelectorAll('.menu-item');\n            items.forEach((item, index) => {\n                if (index === config.currentLine) {\n                    item.classList.add('active');\n                } else {\n                    item.classList.remove('active');\n                }\n            });\n        }\n        \n        function updateQualityMenuHighlights() {\n            const items = elements.qualityMenu.querySelectorAll('.menu-item');\n            items.forEach((item) => {\n                const quality = item.dataset.quality;\n                if (quality === config.currentQuality) {\n                    item.classList.add('active');\n                } else {\n                    item.classList.remove('active');\n                }\n            });\n        }\n        \n        async function handleRotateClick() {\n            try {\n                if (!document.fullscreenElement) {\n                    await elements.playerContainer.requestFullscreen();\n                }\n                \n                if (screen.orientation) {\n                    const type = screen.orientation.type;\n                    if (type.startsWith('portrait')) {\n                        await screen.orientation.lock('landscape');\n                        elements.rotateBtn.textContent = '横屏';\n                    } else {\n                        await screen.orientation.lock('portrait');\n                        elements.rotateBtn.textContent = '横屏';\n                    }\n                }\n                showControls();\n            } catch (err) {}\n        }\n        \n        function bindEvents() {\n            elements.refreshBtn.addEventListener('click', (e) => {\n                e.stopPropagation();\n                refreshPlayer();\n                showControls();\n            });\n            \n            elements.volumeBtn.addEventListener('click', (e) => {\n                e.stopPropagation();\n                if (dp && dp.video && !config.isSwitching) {\n                    isMuted = !isMuted;\n                    dp.video.muted = isMuted;\n                    elements.volumeBtn.innerHTML = isMuted \n                        ? '<i class=\"fas fa-volume-mute\"></i>'\n                        : '<i class=\"fas fa-volume-up\"></i>';\n                }\n                showControls();\n            });\n            \n            elements.fullscreenBtn.addEventListener('click', (e) => {\n                e.stopPropagation();\n                if (!isFullscreen) {\n                    const container = document.querySelector('.player-container');\n                    if (container.requestFullscreen) {\n                        container.requestFullscreen();\n                    } else if (container.webkitRequestFullscreen) {\n                        container.webkitRequestFullscreen();\n                    }\n                    elements.fullscreenBtn.innerHTML = '<i class=\"fas fa-compress\"></i>';\n                } else {\n                    if (document.exitFullscreen) {\n                        document.exitFullscreen();\n                    } else if (document.webkitExitFullscreen) {\n                        document.webkitExitFullscreen();\n                    }\n                    elements.fullscreenBtn.innerHTML = '<i class=\"fas fa-expand\"></i>';\n                }\n                isFullscreen = !isFullscreen;\n                showControls();\n            });\n            \n            elements.lineBtn.addEventListener('click', (e) => {\n                e.stopPropagation();\n                elements.lineMenu.style.display = \n                    elements.lineMenu.style.display === 'block' ? 'none' : 'block';\n                elements.qualityMenu.style.display = 'none';\n                updateLineMenuHighlights();\n                showControls();\n            });\n            \n            elements.qualityBtn.addEventListener('click', (e) => {\n                e.stopPropagation();\n                elements.qualityMenu.style.display = \n                    elements.qualityMenu.style.display === 'block' ? 'none' : 'block';\n                elements.lineMenu.style.display = 'none';\n                updateQualityMenuHighlights();\n                showControls();\n            });\n            \n            elements.rotateBtn.addEventListener('click', (e) => {\n                e.stopPropagation();\n                handleRotateClick();\n            });\n            \n            elements.playerContainer.addEventListener('touchstart', (e) => {\n                if (e.target.closest('.custom-controls, .selector-menu, .control-btn, .selector-btn, .menu-item, .rotate-btn')) {\n                    showControls();\n                    return;\n                }\n                \n                if (elements.playerContainer.classList.contains('controls-hidden')) {\n                    showControls();\n                } else {\n                    elements.playerContainer.classList.remove('controls-visible');\n                    elements.playerContainer.classList.add('controls-hidden');\n                    if (hideControlsTimer) {\n                        clearTimeout(hideControlsTimer);\n                        hideControlsTimer = null;\n                    }\n                }\n            });\n            \n            document.addEventListener('click', (e) => {\n                if (!e.target.closest('.selector-btn')) {\n                    elements.lineMenu.style.display = 'none';\n                    elements.qualityMenu.style.display = 'none';\n                }\n            });\n            \n            document.addEventListener('fullscreenchange', handleFullscreenChange);\n            document.addEventListener('webkitfullscreenchange', handleFullscreenChange);\n            \n            elements.floatingBtn.addEventListener('click', (e) => {\n                e.stopPropagation();\n                elements.floatingPanel.style.display = \n                    elements.floatingPanel.style.display === 'block' ? 'none' : 'block';\n            });\n            \n            document.addEventListener('click', (e) => {\n                if (!e.target.closest('.floating-button') && !e.target.closest('.floating-panel')) {\n                    elements.floatingPanel.style.display = 'none';\n                }\n            });\n        }\n        \n        function handleFullscreenChange() {\n            const isFullscreenNow = !!(document.fullscreenElement || \n                document.webkitFullscreenElement);\n            if (!isFullscreenNow) {\n                elements.fullscreenBtn.innerHTML = '<i class=\"fas fa-expand\"></i>';\n                isFullscreen = false;\n            }\n        }\n        \n        function initializeApp() {\n            if (!liveData || Object.keys(liveData).length === 0) return;\n            \n            addSystemMessage('正在读取直播间信息');\n            \n            config = { ...liveData, currentLine: 0, currentQuality: 'auto', isSwitching: false };\n            \n            initUI();\n            initLineMenu();\n            initQualityMenu();\n            initPlayer();\n            bindEvents();\n            initChat();\n            \n            elements.playerContainer.classList.add('controls-visible');\n            showControls();\n        }\n        \n        document.addEventListener('DOMContentLoaded', initializeApp);\n    </script>\n</body>\n</html>",
    "ruleImage": "https://img.doppiocdn.live/thumbs/{$.popularSnapshotTimestamp}/{$..id}_webp",
    "ruleLink": "/{$.username}",
    "rulePubDate": "{$.isLive}观众：{$.viewersCount}人 状态：{$.status}@js:result.replace(/(状态：)public/g, \"$1公开\").replace(/(状态：)(?!公开).+/g, \"$1付费\").replace(/false.*/g, '状态：未直播').replace(/true/g, '')",
    "ruleTitle": "$.username",
    "singleUrl": false,
    "sortUrl": "全部直播::/api/front/v2/models?limit=60&primaryTag=girls\n直播推荐::/api/front/models?limit=60&primaryTag=girls&filterGroupTags=[[\"recommended\"]]\n竖屏直播::/api/front/models?limit=60&primaryTag=girls&filterGroupTags=[[\"mobile\"]]\n中文直播::/api/front/models?limit=60&primaryTag=girls&filterGroupTags=[[\"tagLanguageChinese\"]]\n日本直播::/api/front/models?limit=60&primaryTag=girls&filterGroupTags=[[\"tagLanguageJapanese\"]]\n韩国直播::/api/front/models?limit=60&primaryTag=girls&filterGroupTags=[[\"tagLanguageKorean\"]]\n户外直播::/api/front/models?limit=60&primaryTag=girls&filterGroupTags=[[\"doPublicPlace\"]]\n青少年直播::/api/front/models?limit=60&primaryTag=girls&filterGroupTags=[[\"ageTeen\"]]\n俄罗斯直播::/api/front/models?limit=60&primaryTag=girls&filterGroupTags=[[\"tagLanguageRussianSpeaking\"]]\nASMR直播::/api/front/models?limit=60&primaryTag=girls&filterGroupTags=[[\"asmr\"]]\nCOS直播::/api/front/models?limit=60&primaryTag=girls&filterGroupTags=[[\"doCosplay\"]]\n情侣直播::/api/front/models?limit=60&primaryTag=couples\n变性直播::/api/front/models?limit=60&primaryTag=trans\n新人直播::/api/front/models?limit=60&primaryTag=girls&filterGroupTags=[[\"autoTagNew\"]]\n互动玩具::/api/front/models?limit=60&primaryTag=girls&filterGroupTags=[[\"autoTagInteractiveToy\"]]\n炮机直播::/api/front/models?limit=60&primaryTag=girls&filterGroupTags=[[\"fuckMachine\"]]",
    "sourceComment": "备用：\nhttps://zh.virtualtaboo.live\nhttps://zh.spiritzone.top\nhttps://zh.stripchat.webcam\nhttps://zh.mywebcamroom.com\nhttps://zh.topcams.tv\nhttps://zh.stripchatgirls.com\nhttps://zh.stripchat.com\nhttps://zh.xhamsterlive.com\nhttps://zh.hotzcam.com\nhttps://zh.tklivechat.com\nhttps://zh.spankbanglive.com\nhttps://zh.live.91pinse.com\npkey=Iecohquahc5RieQu\npkey=bXorqTB5ZhP5FcpX",
    "sourceGroup": "1",
    "sourceIcon": "https://i.imgs.ovh/2025/12/29/Cwo6eX.png",
    "sourceName": "Strip直播",
    "sourceUrl": "https://zh.topcams.tv"
  },
  {
    "articleStyle": 0,
    "customOrder": 76,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\"User-Agent\":\"Mozilla/5.0\"}",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "shouldOverrideUrlLoading": "java.openUrl(\"https://aifun.ltd/UMEgz\"); return true;",
    "singleUrl": true,
    "sourceGroup": "1",
    "sourceIcon": "",
    "sourceName": "AI风月",
    "sourceUrl": "https://aifun.ltd/UMEgz"
  },
  {
    "articleStyle": 0,
    "customOrder": 77,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 1779221084729,
    "loadWithBaseUrl": true,
    "ruleArticles": "class.video-img-box",
    "ruleContent": "<js>\nvar hlsMatch = result.match(/var hlsUrl\\s*=\\s*'([^']+)'/);\nvar posterMatch = result.match(/poster=\"([^\"]+)\"/);\nvar titleMatch = result.match(/<h4>([^<]+)<\\/h4>/);\n\nvar videoUrl = hlsMatch ? hlsMatch[1] : '';\nvar poster = posterMatch ? posterMatch[1] : '';\nvar title = titleMatch ? titleMatch[1] : (java.getString('h4@text') || 'Jable.TV');\n\nif (!videoUrl) {\n    result = '<html><body><h2 style=\"text-align:center;color:#fff;background:#000;padding:40px;\">视频链接获取失败</h2></body></html>';\n} else {\n    result = '<!DOCTYPE html>\\n<html>\\n<head>\\n<meta charset=\"utf-8\">\\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\">\\n<title>'+title+'</title>\\n<style>\\n*{margin:0;padding:0;box-sizing:border-box}\\nbody{background:#000;font-family:-apple-system,sans-serif}\\n.header{padding:12px 16px;background:#1a1a1a;color:#fff;font-size:14px;line-height:1.4;border-bottom:1px solid #333}\\n.video-wrap{position:relative;width:100%;background:#000}\\nvideo{width:100%;display:block;max-height:100vh}\\n</style>\\n</head>\\n<body>\\n<div class=\"header\">'+title+'</div>\\n<div class=\"video-wrap\">\\n<video id=\"player\" controls playsinline poster=\"'+poster+'\"></video>\\n</div>\\n<script src=\"https://cdn.jsdelivr.net/npm/hls.js@1.5.17/dist/hls.min.js\"></script>\\n<script>\\nvar video = document.getElementById(\"player\");\\nif (Hls.isSupported()) {\\n    var hls = new Hls({ maxBufferSize: 1*1000*1000 });\\n    hls.loadSource(\"'+videoUrl+'\");\\n    hls.attachMedia(video);\\n} else if (video.canPlayType(\"application/vnd.apple.mpegurl\")) {\\n    video.src = \"'+videoUrl+'\";\\n}\\n</script>\\n</body>\\n</html>';\n}\n</js>",
    "ruleImage": "img@data-src",
    "ruleLink": "a@href",
    "ruleNextPage": "page",
    "rulePubDate": "class.sub-title@text",
    "ruleTitle": "h6.title@text",
    "singleUrl": false,
    "sortUrl": "🔥 熱度優先::/hot/{{page}}/\n🔍 搜索::/search/{{source.getVariable()}}/{{page}}/\n--- 熱門分類（Categories） ---\n角色劇情::/categories/roleplay/{{page}}/\n中文字幕::/categories/chinese-subtitle/{{page}}/\n制服誘惑::/categories/uniform/{{page}}/\n絲襪美腿::/categories/pantyhose/{{page}}/\n直接開啪::/categories/sex-only/{{page}}/\n多P群交::/categories/groupsex/{{page}}/\n主奴調教::/categories/bdsm/{{page}}/\n男友視角::/categories/pov/{{page}}/\n凌辱快感::/categories/insult/{{page}}/\n盜攝偷拍::/categories/private-cam/{{page}}/\n\n--- 熱門標籤（Tags） ---\n巨乳::/tags/big-tits/{{page}}/\n少女::/tags/girl/{{page}}/\n熟女::/tags/mature-woman/{{page}}/\n人妻::/tags/wife/{{page}}/\n中出::/tags/creampie/{{page}}/\n口交::/tags/blowjob/{{page}}/\nNTR::/tags/ntr/{{page}}/\n女僕::/tags/maid/{{page}}/\nOL::/tags/ol/{{page}}/\n護士::/tags/nurse/{{page}}/\n老師::/tags/teacher/{{page}}/\n溫泉::/tags/hot-spring/{{page}}/\n偷拍::/tags/private-cam/{{page}}/\n按摩::/tags/massage/{{page}}/\n黑人::/tags/black/{{page}}/\n風俗娘::/tags/club-hostess-and-sex-worker/{{page}}/\n痴漢::/tags/chikan/{{page}}/\n處女::/tags/first-night/{{page}}/",
    "sourceComment": "jable.tv - 修复版。ai编写",
    "sourceGroup": "视频",
    "sourceIcon": "https://jable.tv/favicon.ico",
    "sourceName": "Jable.TV",
    "sourceUrl": "https://jable.tv"
  },
  {
    "articleStyle": 0,
    "customOrder": 78,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceIcon": "",
    "sourceName": "壁纸",
    "sourceUrl": "http://www.hjtaotu.com/he/jitu/20280521/207277.html"
  },
  {
    "articleStyle": 3,
    "customOrder": 79,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 1774018195635,
    "loadWithBaseUrl": true,
    "ruleArticles": "class.ucontent@li",
    "ruleContent": "<js>\n// 提取m3u8链接\nvar m3u8Match = result.match(/\"([^\"]*?index\\.m3u8[^\"]*)\"/i) \n             || result.match(/'([^']*?index\\.m3u8[^']*)'/i);\n\nvar p = '';\nif (m3u8Match) {\n    var u = m3u8Match[1]\n        .replace(/\\\\\\//g, '/')      // \\/ → /\n        .replace(/\\\\\\\\/g, '\\\\')      // \\\\ → \\\n        .trim();\n    \n    // 补全协议\n    if (u.startsWith('//')) {\n        u = 'https:' + u;\n    } else if (!u.startsWith('http')) {\n        // 需要基础URL，这里假设当前页面URL在result中或需要传入\n        u = 'https://' + u;  // 简化处理，或根据实际需求调整\n    }\n    p = u;\n}\n\n// 标题：从 span.tx-flex-sh > a 的 title 属性获取\nvar t = java.getString('.single-strong @text') || '未知标题';\n\n// 标签：从 meta[name=\"description\"] 的 content 获取  \nvar b = java.getString('meta[name=\"description\"]@content') || '';\nvar updateIndex = b.indexOf('更新时间');\nif (updateIndex !== -1) {\nvar d = b.substring(updateIndex);  // 保留\"更新时间\"及之后的内容\n}\n\n`<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>${t}</title>\n<style>\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,sans-serif;background:#f0f9ff;padding:10px}\n.v-box{max-width:800px;margin:0 auto;background:white;border-radius:12px;box-shadow:0 5px 15px rgba(0,0,0,0.1);overflow:hidden}\n.header{padding:12px;border-bottom:1px solid #eee;display:flex;flex-wrap:wrap;justify-content:space-between}\n.title{font-size:18px;font-weight:600;margin-bottom:8px;width:100%}\n.tags{color:#5f6368;font-size:14px;flex:1;min-width:60%;word-break:break-all}\n.time{color:#5f6368;font-size:14px;text-align:right;flex-basis:35%}\n.v-wrap{position:relative;padding-top:56.25%;background:#000}\n.video{position:absolute;top:0;left:0;width:100%;height:100%}\n.footer{padding:8px;text-align:center;color:#5f6368;font-size:13px}\n.info-box{padding:15px;font-size:14px;line-height:1.6}\n.info-box p{margin:8px 0}\n.hint{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background:rgba(0,0,0,0.7);color:#fff;padding:12px 20px;border-radius:20px;font-size:1.1rem;z-index:10;display:none}\n.controls{position:absolute;top:0;left:0;width:100%;height:4px;background:rgba(255,255,255,0.3);z-index:5;transition:opacity 0.3s}\n.progress{height:100%;background:#4a9eff;width:0}\n</style>\n</head>\n<body>\n<div class=\"v-box\">\n<div class=\"header\">\n<div class=\"title\">${t}</div>\n<div class=\"tags\">${d}</div>\n<div class=\"time\" id=\"timeDisplay\">00:00/00:00</div></div>\n<div class=\"v-wrap\">\n<div class=\"controls\"><div class=\"progress\" id=\"progressBar\"></div></div>\n<div class=\"hint\" id=\"hint\">快进中 &gt;&gt;</div>\n<video class=\"video\" id=\"v\" controls playsinline>\n<source src=\"${p}\" type=\"application/x-mpegURL\">您的浏览器不支持HTML5视频\n</video>\n</div>\n<div class=\"footer\">滑动调整进度 | 长按2倍速</div>\n</div>\n<script>\nvar v = document.getElementById('v');\nvar tDisplay = document.getElementById('timeDisplay');\nvar pBar = document.getElementById('progressBar');\nvar hint = document.getElementById('hint');\nvar startX = 0, startTime = 0;\nvar longPressTimer;\nvar sensitivity = 0.1;\nvar longPressTime = 500;\nvar hintDuration = 2000;\nfunction updateTime() {\nif (!v.duration) return;\nvar m1 = Math.floor(v.currentTime / 60);\nvar s1 = Math.floor(v.currentTime % 60);\nvar m2 = Math.floor(v.duration / 60);\nvar s2 = Math.floor(v.duration % 60);\ntDisplay.textContent = m1 + ':' + (s1 < 10 ? '0' : '') + s1 + '/' + m2 + ':' + (s2 < 10 ? '0' : '') + s2;\npBar.style.width = (v.currentTime / v.duration) * 100 + '%';}\nv.addEventListener('timeupdate', updateTime);\nv.addEventListener('loadedmetadata', updateTime);\nv.addEventListener('touchstart', function(e) {\nstartX = e.touches[0].clientX;\nstartTime = Date.now();\nif (longPressTimer) clearTimeout(longPressTimer);\nhint.style.display = 'none';\nlongPressTimer = setTimeout(function() {\nv.playbackRate = 2.0;\nhint.style.display = 'block';\nsetTimeout(function() { hint.style.display = 'none'; }, hintDuration);}, longPressTime);});\nv.addEventListener('touchmove', function(e) {\ne.preventDefault();\nclearTimeout(longPressTimer);\nvar diffX = e.touches[0].clientX - startX;\nvar change = diffX * sensitivity * v.duration / 100;\nv.currentTime = Math.max(0, Math.min(v.currentTime + change, v.duration));\nstartX = e.touches[0].clientX;updateTime();});\nv.addEventListener('touchend', function() {\nv.playbackRate = 1.0;\nclearTimeout(longPressTimer);});\n</script>\n</body>\n</html>`\n</js>\n",
    "ruleImage": "class.cover@style\n<js>\nvar img=\"\";\nvar pics = result.split(\"background-image:url('\")[1];\nvar picc = pics.split(\"')\")[0];\n\nimg= picc;\n</js>",
    "ruleLink": "a@href",
    "ruleNextPage": ".text-center@a.-2 @href",
    "rulePubDate": "class.time@text",
    "ruleTitle": "class.ctitle@text",
    "singleUrl": false,
    "sortUrl": "情侣::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-SwmVnh7DhV5fti8rANEOnA%3D%3D.html\n真实自拍::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-sxFQ8fIfXNi%2F7h%2FTa%2BVqaQ%3D%3D-2.html?k=%E7%9C%9F%E5%AE%9E%E8%87%AA%E6%8B%8D{{page}}\n艳照门::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-sWJNZL81qog%2FV0kqE7K4xg%3D%3D.html\n韩国::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-qYmLQw%2Bg9uPbbhsqBrcq2Q%3D%3D.html\n水滴::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-WuIS%2BITZ25HLRd6XZW%2FOxA%3D%3D.html\r\n91大神::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-QOe0y05XimbXo8PhBayueA%3D%3D.html\r\n重口::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-DEbPb09hbgP9k6scQg63sw%3D%3D.html\r\n国产3P::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-GWLkyuIEPQDeXCqVFoTAyA%3D%3D.html\r\n寻花::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-rKKopyjdoS20rSOUxh3zJQ%3D%3D.html\r\n探花::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-hgzJx3zpIIxdOEMcWHz2Tg%3D%3D.html\r\n百度云泄密::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-2lC5aEeJd1u2dqQ%2FmdRIVQ%3D%3D.html\r\n叫爸爸::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-y8uZo8HwYsn8SvxL1UCb0g%3D%3D.html\r\n人妖::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-%2BbRZ5xmyn24x0B7zvVH51A%3D%3D.html\r\n双飞::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-5thccQpFuzxfZnnatss5wQ%3D%3D.html\r\n援交::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-eYLQqyMZKX0naw7R9aFiUQ%3D%3D.html\n高潮::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-vxgb5Mhrcm45%2BvJ3jR%2FK5w%3D%3D.html\n云盘泄密::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-Uk8R2RDqogK686unextaRA%3D%3D.html\n百度云::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-5ZDf525skrVIknBGx5lmFQ%3D%3D.html\n母狗::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-6%2BdjspHsB86vEMDYR8vX0g%3D%3D.html\nSWAG::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-dth6EA%2B8L38m3Nca%2FQFL2Q%3D%3D.html\n灌醉::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-CgBbOg15Du4JraAsWNBNjQ%3D%3D.html\n乱伦::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-62iSChVBLwn9fxJe4R2eFw%3D%3D.html\n台湾::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-SxxaH9csNSivTS3P7gZoFg%3D%3D.html\n双洞::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-PsCugwsYtwmQ4ClpO%2FoDjg%3D%3D.html\n黑人::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-Jo0QDMWSz9h5NGQAE9Q6VQ%3D%3D.html\n模特::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-rkt3PZIjjsRwGyupHFDGaA%3D%3D.html\n明星::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-QYz3d2N9zvH04hLT6JKzUQ%3D%3D.html\n外围::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-IMWBtdaYv%2Fjxugi4%2BHhZ4A%3D%3D.html\n平胸::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-6KvMA5igEDec1T31X3GJzw%3D%3D.html\n萝莉::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-z90Pw6%2BPlSZL6DsNDa3HDw%3D%3D.html\n偷拍::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-kA%2FTlS7qmOLRGkgF%2Fn0INQ%3D%3D.html\n强奸::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-rkfTz9iRzCZ2YZ9BgpLQPQ%3D%3D.html\n孕妇::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-T5nxv4JMS0RuKayEmUskBg%3D%3D.html\n露出::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-cWH28OVOk5XusdgQlQ42DA%3D%3D.html\n学生::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-S4a6Y3Jh0ahrOuC%2BnPWraw%3D%3D.html\n厕所::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-OBoF9jSv3ssvCWLzi0ZUow%3D%3D.html\n丝袜::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-HZAcWdDll929vjXxi%2Fis9Q%3D%3D.html\n麻豆::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-AAzZLiir3JVotigCPt5yyw%3D%3D.html\n剧情::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-vX2kdY6Bji%2BZDgJC3Uom8Q%3D%3D.html\n少妇::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-WvRQ3zJ6x0Iddtyv%2F3kQ7Q%3D%3D.html\n初中::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-7zlfwQmL2OCGlwAMuO9PkQ%3D%3D.html\n户外::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-P5xjiQfnsJ62f4Hz3RGbVg%3D%3D.html\n巨乳::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-B5Vt3CkBgs3beFwmKholzg%3D%3D.html\n按摩师::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-JM5fp9rXtfWRGHxSh8zS5w%3D%3D.html\n抖音::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-zFa%2FHlIv9P7FSIj1wrTPLw%3D%3D.html\n极品::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-IuN82Iai2xUOVHMMANfnOA%3D%3D.html\n勾引::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-vh64QmiM3Mo2OcKdxDQdsQ%3D%3D.html\n调教::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-%2BQeUgBv85wKceg%2FDI5Ak0w%3D%3D.html\n对白::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-%2B9ccuxdMZa3%2FJ8LzxMB6qg%3D%3D.html\n喷水::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-1oRbUL2Xn9xhEmXGx6GsQA%3D%3D.html\n白虎::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-UKNntcz6aNUmZxjkxJCFPQ%3D%3D.html\n肛交::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-nWw6UIl046QAjrvoKFS2Rw%3D%3D.html\n双洞::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-PsCugwsYtwmQ4ClpO%2FoDjg%3D%3D.html\n宿舍::https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com/search-0-1-12%2BMLChLTiqIX3cSShXxtg%3D%3D.html",
    "sourceComment": "搜索被加密了，不加搜索\n永久地址：https://jfgso.xyz\n\n260320修复",
    "sourceIcon": "http://img5.adesk.com/68d0f78fab9725cae3c22331?imageMogr2/thumbnail/!1080x1920r/gravity/Center/crop/1080x1920&sign=ec76e92a65142f3c04f056faeaa9c918&t=69bd67e1",
    "sourceName": "集芳阁云搜",
    "sourceUrl": "https://xn---jifanggecom-ud8sv658aesydp6a.xn--9kq80g37uthu.com",
    "style": ".dz {\nwidth:100%; \npadding:5px 0;\nborder:solid; \nborder-radius:5px;\noverflow:scroll;\nbackground-color:#dddddd\n}"
  },
  {
    "articleStyle": 0,
    "customOrder": 80,
    "enableJs": true,
    "enabled": true,
    "enabledCookieJar": true,
    "injectJs": "//$(\"div.layui-panel\").eq(0).remove();\nsetInterval(function () {\n    $(\"div.layui-hide-md\").css(\"display\",\"none\");\n},100)",
    "lastUpdateTime": 1774678267975,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "1",
    "sourceIcon": "https://www.yck2026.top/favicon.ico",
    "sourceName": "改—源仓库(去底部广告)",
    "sourceUrl": "https://www.yck2026.top/yuedu/index/index.html"
  },
  {
    "articleStyle": 0,
    "customOrder": 81,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "header": "{\"User-Agent\":\"Mozilla/5.0 (Symbian/3; Series60/5.2 NokiaN8-00/012.002; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.3.0 Mobile Safari/533.4 3gpp-gba\"}",
    "lastUpdateTime": 1774456899623,
    "loadWithBaseUrl": true,
    "loginUrl": "https://yckceo.vip/",
    "ruleArticles": "class.ylist",
    "ruleContent": "head@all&&class.m-top@all",
    "ruleLink": "a@href",
    "rulePubDate": "{{@@h2@p@text}} {{@@tag.span@text&&tag.span.2@title}}\n@js:result.replace(/\\n/g,'  ').replace(/\\s+[23]\\.X/,'').replace(/用户[: ：]+/,'👤').replace(/ 下载[: ：](\\d+)\\s*UID[:：](\\d+)/,'(UID: $2)  📥$1').replace(/下载[：: ]+/,'📥').replace(/源数量[：:](\\d+)/,'📝$1个源')",
    "ruleTitle": "名称：{{//h2/a[1]/text()##http.*}}\n网址：{{//h2/a[1]/text()##.*(http)##$1}}\n@js:result.replace(/([\\s\\S]{4,}?)(?:\\s+)?\\1/g, '$1')",
    "singleUrl": false,
    "sortUrl": "📖书源::/yuedu/shuyuan/index.html?page={{page - 1 == 0 ? \"\": page}}\n🔰订阅源::/yuedu/rss/index.html?page={{page}}\n📖书源合集::/yuedu/shuyuans/index.html?page={{page}}\n🔰订阅源合集::/yuedu/rsss/index.html?page={{page}}\n\n🔎搜书源::/yuedu/shuyuan/index.html?keys={{svg=String(java.base64Encode(`<svg width=\"1190\" height=\"300\" xmlns=\"http://www.w3.org/2000/svg\"><rect width=\"100%\" height=\"100%\" fill=\"#ffffff\"/><text x=\"200\" y=\"100\" font-family=\"Arial, sans-serif\" font-size=\"70\" fill=\"#333\" font-weight=\"bold\">请输入关键词</text></svg>`));if(page==1){let a=\"\";try{a=java.getVerificationCode('data:image/svg+xml;base64,'+svg);}catch(e){java.log(e)};if(a==\"\"){a=source.getVariable()}source.setVariable(a);a}else{source.getVariable()};}}&uid=&order1=time&order2=1&ver=&faxian=&sousuo=&x18=<,&page={{page}}>\n🔎搜订阅::/yuedu/rss/index.html?keys={{svg=String(java.base64Encode(`<svg width=\"1190\" height=\"300\" xmlns=\"http://www.w3.org/2000/svg\"><rect width=\"100%\" height=\"100%\" fill=\"#ffffff\"/><text x=\"200\" y=\"100\" font-family=\"Arial, sans-serif\" font-size=\"70\" fill=\"#333\" font-weight=\"bold\">请输入关键词</text></svg>`));if(page==1){let a=\"\";try{a=java.getVerificationCode('data:image/svg+xml;base64,'+svg);}catch(e){java.log(e)};if(a==\"\"){a=source.getVariable()}source.setVariable(a);a}else{source.getVariable()};}}&uid=&order1=time&order2=1&ver=&faxian=&sousuo=&x18=<,&page={{page}}>\n👤搜书源(UID)::/yuedu/shuyuan/index.html?keys=&uid={{svg=String(java.base64Encode(`<svg width=\"1190\" height=\"300\" xmlns=\"http://www.w3.org/2000/svg\"><rect width=\"100%\" height=\"100%\" fill=\"#ffffff\"/><text x=\"200\" y=\"100\" font-family=\"Arial, sans-serif\" font-size=\"70\" fill=\"#333\" font-weight=\"bold\">请输入UID</text></svg>`));if(page==1){let a=\"\";try{a=java.getVerificationCode('data:image/svg+xml;base64,'+svg);}catch(e){java.log(e)};if(a==\"\"){a=source.getVariable()}source.setVariable(a);a}else{source.getVariable()};}}&order1=time&order2=1&ver=&faxian=&sousuo=&x18=<,&page={{page}}>\n👤搜订阅(UID)::/yuedu/rss/index.html?keys=&uid={{svg=String(java.base64Encode(`<svg width=\"1190\" height=\"300\" xmlns=\"http://www.w3.org/2000/svg\"><rect width=\"100%\" height=\"100%\" fill=\"#ffffff\"/><text x=\"200\" y=\"100\" font-family=\"Arial, sans-serif\" font-size=\"70\" fill=\"#333\" font-weight=\"bold\">请输入UID</text></svg>`));if(page==1){let a=\"\";try{a=java.getVerificationCode('data:image/svg+xml;base64,'+svg);}catch(e){java.log(e)};if(a==\"\"){a=source.getVariable()}source.setVariable(a);a}else{source.getVariable()};}}&order1=time&order2=1&ver=&faxian=&sousuo=&x18=<,&page={{page}}>",
    "sourceComment": "by：旅途\n改：歌行灯\n弹窗搜索的代码是从关耳大大那抄的\n————————————\n【地址失效的解决方法】\n若地址失效导致订阅源失效，可于登录处进入源仓库最新地址发布页，从发布页复制最新可用地址粘贴到源URL处，然后退出重进即可。\n————————————\n【如何搜索】\n点击（或下拉）标有🔎或👤的列表，会弹出提示框，填写关键词或UID即可。也可直接在源变量处填写关键词/UID（记得保存并刷新分类）\n（昵称后面的括号里那串数字就是UID，注意不要填“UID:”这几个字符，只用填数字）\n如果你填的是源名称，那么结果在🔎处查看；如果你填的是源作者的UID，那么结果在👤处查看。\n阅读Sigma版可点击右上角搜索按钮，输入关键词搜索书源。\n————————————\n修复源URL与源名称一样时重复显示4遍的问题（2026.2.3@歌行灯）",
    "sourceGroup": "默认",
    "sourceIcon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAWEAAAFhBAMAAABT0QbkAAAAAXNSR0IArs4c6QAAACRQTFRFLzY8R3BMLTQ6LjU7oMxJm8dElsI/kb05jLg0hrMvb446T2M71eCsLgAAAAR0Uk5T/wBQxEskO5YAAA+JSURBVHja1NXBbdswFMbxT5KLIOlFlRaQ0AWoegEfyMCoLz0wG2SEDtARfA168cED9NABq9KMbMsSE+gRzHt/2D4+/PQsgvgSrForhZQVxboNikqEuAofU9GGxARvcnNYvMbHtg6IQwtmtOawuAaHuveLv4JH3wLiMZgbOSxuwKf8PeIanOreFlfgVfuWuFJgRw6LFbhVhMUl+JWFxBU41gbEChwr5sU1eNbNisG1OXEJrnUzYvBtWlyCb9mkGJybEpfgXDYhVmDdrbgG77obsQLvirG4AvfakbgB9/KRGPy7FpfgX3YlbsC//FJcQULthbiGhLoLcQMJ5RdiyOgsriGjbhCXkFE2iCGlV3EFKbVeXENKnRc3kFLuxQpSKrwYcjqJa8ipc+IScsqcuIGccidWEJQTQ5q4gqTaXlxDUlkvLsWJG0gq78UKkip6MWQlUVxBVg1qzPb5ZbrfiNTDy3R7zKdQBsR6ukdEaqWn2yDQErH+gzgdk4kPiJNOJt6AEHl+s2DiDlG6WyZWC8QaUVqJEx8Tin8hRs/LxFgi3sQ5eAnF3xGh+5TiLSK0SiCOe+sdk4oPoGeTijcxDl5S8Q7k7tKKH0FulVasQe6YWLwHtefE4g394KUV02+9+9TiLYh9Siym33rH5OIDaD0lFhv9A7R08h3vqDee0Ta+eGamNdpqE+HGM9N/nyXt2Pa88SfGrXc0Dnw73BB3bOd2bO0elH5q09ts9B073mgJ/imMG0t74ez/6dfzDW3Hp3HjV8K4aEfvwT268fOuXglrKTu2ZmrHDm63tIPnpxinHoaf9MvFw5RLsNH+MUDo70n5Ot3xh+1QduyH6LPXo622pFvPnnfsztowP8aO+6/PDT5vhnL0tB3Ome0b5hv3VhPEPif3x7rP/VhDOHr3fpK3Dht+or7Hboz/ng+d37b9R2wZ48YNQ0G0C5C91wApXfyhsXDjhoWRJk2O4CPsUXK/wMPPT8u7sKH/19CINCkZGIyfNKAfK/9qDitfTItPoNw8zY2r4y6deOulbfdmleYZYYSmFDdmZkS+ehcSlIscjWsPEA/5xJ+qgkL1DWFJqIuJBdhph8TkKX3iGYev+aLVXDXGdDdpRR/PfqVPPArwCuvyJxXGDB8sDIt71vgfiA3ksNZaSLzMKLMYY0mfet0ZMOqmTawlxkJAYDHQ0Ew7AzRGWKcce2OBsbk8txZpPEtW76dybcwYRKrf8ZSRVGQX9OwxeeLRSPC9mRHa6hcVxgyeBGSKIerbZrJ4HtgpO4nBmGCdMRZjYMPYctV71VesyBJG47S1ImMzCsFibFyMaQ85EMpquhQRnM4ig3xi+SzGTiAYG1PVO5Eemb7MrMO0xBjxriKrEXOQ53TxaOaThKzDFFZjbEZMENqHjGCyeCJJaGosY7D6HUtYjCfigSNTvb9uqcvk7QD8DhXGMopvOSAH4+eELc1oQZizgPdh/KWeMsX7XN+c+Jwo3rGJmSjewYn3V+9yQOKaOQ9IXKre6ejEL3tNfxydmIniHZC4Ur3XoxP3P7Xi3T9xY78afumOv3cW79rRx7i0LSTunddqmlPnexWva5YZX8MIZ7/re4t3m/DE0KuMb8JomrnqXRpvq7FrVhl/JNHYg3Fvb7fteZdnJ2XSN769ibEnLzCWR19D0otrLXfqndhbUPUh6e8QkhrjgXH9lCjjNvWys3juI8v/tJaxchQxEESVeMHwfZ6E5AKmjX05VWRExI6IL+HiS9jvo7Y127NVSzCLuClrNVaVWq0njWXnt0f/80Pdf3esq8DWP9Eyt0OFt0wKVWOvhMF8hHH45IF5fNJ2bOhy7F/NcEWoFFEiPAOMdRuYbFNTeujV45yU6nw9IoSHGMdN0Cm6OHi284HCI9pgHN1W1IcZd8tdjDkF2dL4gdJ7oN8gILHkG4jGGYuBQGz3YAcKr4slWffPV4sT1CJDjLd3lmq/tgca+aVeeN4ln7oe3f9OEpEM3GOHw8y8B/PJls7BLvL6q4c1Vj3Hl2npqGY9gQSPO6YMpSMcj66ARXIuF54rhOJ1kraWGmDcObALrB+xktUyKJfeO209sZ5mHZlOc4AxurJDBNpXd2iwr4Oq4LxaQkBw2NvMdKMKOw0wDsvJpV11T7QQqqX3EwZGnpG32ZjK8hjj8JtEvU3QVRGc70VBiHEqttk9b8Vo5Tkgy9G1R5jGVsbnauHBImTvExm7XPsgY/nS5Vu2kX4D2mtNb4KhhwN9Mk7JOGQxfo+TscFa469gg/f2VC08mCImX5ZRrFvHMGOGs7EztDbnkKE33OqFp+Bku7Urwj01GQOOO1y4y3NrkwsujKNWhAJA5x+TX5IAz44fG2UMo2enXmuPUAjLuVR4K8KM5bm8OnxljFHGFOKPzHGU42YwJ2jYt4rce2R0xL54u4JB8sOOt/LO1FprP3IHazyXCk+Ocu7b4jgR27hjXrxQItQWUFQqTCuvnmBuXcewFvpPjFllucTELWjUyKog9ySGCjr2HeRhx9tzvLH0TCORnktqti+8RO8SG3asCMcN+yi8eg+GXZzkWHFvx4pK4e3jwnfl/o7nv4/XCy9n3Z/x80Jlwi4Krx728dLuy1jn+AGFRSpiZzq+N2ON73BVXry9s/sz5iJ/qi9jpdaNKAwfYCaWTIPgBWDyApCXSUtz0UzSUFnLdeMqWkGjKlcyjapc6FzF3LeLo2jWRP/Z9drWSqt/3O3K++nzOXuAeZXDGs898ZdK00RfzK3HP1Mv/OGQWA23Cbewf+PFfRDHNVj4gJkf2Hg065R41k6jEhd2Tb0JPjK7d0CMWWhOiR/ImJ90jUcPbolnNbFx6tlPPHJOHCvHnLFH0ob/7Z9cEAPyrOYyTj37xnNHjCbVCirjE3Jf5YA4xjTH/DmDJMbGizEV1fkVVzrtvEeyaj37xjt37ljrzDj1ZhjRLMWYTidIQxziUjzf690f5uoQyBGOH1pRjolZMky9CVdfeEiToxxDHrU/80NiaDymUSsnjiHK8d+4ZGi9v2IMHOKkjreTbcL6t2+8+In6qONPjqd25ac8wvSck4s6TiBbjwlG23phglmoQzCPBxPPINsv+xZj9I2HqdQhmMOJE0NTrPFtZrrW+x5jTIcc4dhQFZO4vRbHOfFJME/UZIqHdOt4rk5Cx8n9Id/TrWOMOolijKb1AlOpTrutY8yWeJZgCMIXUCKqrWOMI8frGLPiG28GSWgAx5MEw7deyl3dJseOiKfa+YKNh1/TG/Hsd8OdFdfqbCbeLIdVZ46/ksq3BJnZxktQctUf8TOprMEcP/W+I3BCrohjyFcyt57txBukKqZMId9bfcvnbUGPxBQzy7Z/aqpMXBP/Bj83X6BGpNkKlvtxvE4wK6bxMDSIY/6whdXEc02MXW4/rvjBOZRj0leN+bXyYRzzU0/A/3gJpuqTOCO71jM33mCOA4upJ7nvGMYxX6OifRoH1L9j+9bjJ16fxAKI2dYzA60GdLxOIYpH23iidZekbh2LHQaFyAkuQFPdTFLnju1bzzzxlGO3xKkgi9Yzv1JOvdaxpF0/+pNd4ynHolPiVLQ/Lcdr3PI/orWADQm1HOOWw4nxu1q3GwXMloq2SXH5a4tY4JYjHOO3tYinsEUk97SN2ClwkvbrmGBLkj5/nnhYFHm7KtJeHVOKjjNSCRjHK6iKfh2vwdDn1vqeokAa2HEAhkSSf7r82suq8baOe67jqRBtx9sDz4WA5Rdw3OVdIXY7pvbvLkTyvL1JUljOnTqWmIxaKQx7JhKjGs+wZ3E4sYCA4w+BWVGzlmKoTZxiDidOMeA4TCGyatakgDwDscAc4RgDjqcSoupQu2SuCseOSWDmev25jWO3dUwMlqA6gWRK3HEdSwg6/oA9QjQrQkKIBr8rKEDHzW9fpJBn8sAxtl4qF80Loz2GuFPHUqStDxITbJJi2bwKrORILFPYtuh25kHeNLsCiVk5r+N2TyExtl7akH1IDEGCjqtCpi1khjiUmIr/i+OZWMeiyzq2qApsPSEfYeLpUAKZdukYwnUeyXZ/SfnCjm+Zk+s6lgDDERegWD7pGw/ruO+7omYDZLbxMrJ07J4YkuVc4y25h4cgPmcP5Un8cMzBzaeceE8c81Mv5BrPE8d8k71JDHnjOOQ2chPPG8dTaZWFP45JWiX3xTFOPT7ZyiPHgRUxDeK4JMvWwyw1L1tAenB8jsdict5xNohjkhB24rmv4yJrfzJi8wYb4ZOteMfM3j4c49TDUC+OCzBAbMKdilXjgWM843DiTMr2uRrH0128qvEYx7C3D8dU7ACWstIQZ5t06DizdEyF2fEmK53jQkqXjnXEgdkxPOjKcWbtONjleK591c3qEHV8nhmBZZFrXzWDY3pxTOY5ncmqF8cZYmiJ3zJj5Epfx3BMfnhVtI81EH8UxpSkd1xkrRzuuGRCmoSlIUXxSnrHsP1wx/u4mpYZxEZbmBWQw4kZCC0xlaaaKCt9VeApRzguIQbizFAV5crgGHb35Dg0OiZDHcPunhyHJscveuKyzHp3jH2K1nx0TKU+sjIUU6eODQWJec+0KVeGqoDLojyCGJIZiH+U+pDBMR5yTB3vdbYe+JUMjjG52ymN2zELw3sOSEyZlrgyOC4GJNYCF+SNY7yo2E9J/tWxufVeTA8xb+iK2L71cl8dk7bxfK1jei/5kH+OzVOvIG8dh5qJ56Fjc+vl/jomTeN56NjceuSx44An9thxyDaex475J/KOHd92SUxs43nsmG898trxj72fCAcmnjKN5zEx/0jeNfF1p8TENF7XdXzRLfH7vg+EromX+wIs+yY+Wtmr58T4TN458VW3xASN1zHxLV3uIH7ffpZYlnzrLf97bolvyBOrByyIrynq2HF41P5lTW4ivnBN/ErHVgUS39KYcrYhvqYx5XRDfEFjysmG+IrGlLsN8SWNKTcb4ojGlOhf4tuxEY/qsjitiS/GdFXUxFdjuipq4mhMZVwTj6j1zmriMbXeaU08pkK+a4gvxzPxGuJoRI3XEF+MpYwV8dVYylgRR6MpCkV8PY6iUMRjKYsTRTyW++1GEY9kUJ9Fingk99uJIh7LbREp4pHcFqct4iv/x0eLOLr1v+8U8Th67wSIfZccIfGF54qROPJbMRB7LvkUiH2XHPHEV55XMRJH/t7FQOy55DsgVrn1XDESX5KPuUFiv2+4kwiI/a6LswiIPa+LGyAGZA+BkdjfK+4uQmLItV9/TyAx5mfyJb9EHLFvyAiMxJgrv2oYiTGXnt0SSIy59aznkBg1D8l8BoKBeGBm5NUS/wMtJQR5NY0DewAAAABJRU5ErkJggg==",
    "sourceName": "源仓库\n(看注释)",
    "sourceUrl": "https://www.yck2026.top",
    "variableComment": "请填写搜索关键词或UID\n若列表没有刷新请手动 右上三个点【刷新分类】\n"
  },
  {
    "articleStyle": 0,
    "customOrder": 82,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "legado",
    "sourceIcon": "https://cdn.jsdelivr.net/gh/gedoor/legado@master/app/src/main/res/mipmap-hdpi/ic_launcher.png",
    "sourceName": "使用说明",
    "sourceUrl": "https://www.yuque.com/legado"
  },
  {
    "articleStyle": 0,
    "coverDecodeJs": "java.createSymmetricCrypto(\"AES/CBC/NoPadding\",\"f5d965df75336270\",\"97b60394abc2fbe1\").decrypt(result)",
    "customOrder": 83,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\"User-Agent\":\"Mozilla/5.0 (Linux; U; Android 13; zh-Hans-CN; PFJM10 Build/TP1A.220905.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/135.0.4896.58 Quark/6.13.6.581 Mobile Safari/537.36\",\n\"Accept-Language\":\"zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7\"}",
    "lastUpdateTime": 1775584744388,
    "loadWithBaseUrl": true,
    "ruleArticles": "#body>.container>.row>div[role=\"main\"]>article:not(:has(meta[content=\"广告\"]))>a",
    "ruleContent": "@js:\nlet urls = [];\nlet resultStr = String(result);\n\nlet getM3u8 = (html = resultStr) => {\n    let url = /(https?:[^'\"\\s]*?\\.m3u8[^'\"\\s]*)/g;\n    let urlSet = new Set();\n    for (let match of (html.matchAll(url) || [])) {\n  \t   let ul = match[1].replace(/\\\\/g, \"\");\n  \t   urlSet.add(ul);\n    \t};\n    return Array.from(urlSet);\n};\n\n let updateProgress = (current, total) => {\n    let percentage = Math.round(current / total * 10000)/100;\n    let blocks = Math.floor(percentage / 10);\n    let progressBar = \"█\".repeat(blocks) + \"░\".repeat(10 - blocks);\n    java.longToast(`【加载进度】\\n${progressBar} \\n${percentage}%`);\n};\n\nif (/点我/.test(result) && /查看详情/.test(result)) {\n    let list = java.getElements('@@#post>article>.post-content>p>a');\n    let links = Array.from(list).slice(0,-1);\n    let tempUrls = []; \n    links.forEach((link, index) => {\n        updateProgress(index + 1, links.length);\n        \n        let href = String(link.attr('href'));\n        let fullUrl = `${source.key}${href}`;\n        let doc = String(java.ajax(fullUrl));\n        let pageUrls = getM3u8(doc);\n        if (pageUrls.length > 0) {\n            tempUrls = tempUrls.concat(pageUrls);\n        }\n        if (index === links.length - 1) {\n            urls = tempUrls;\n        }\n    })\n} else {\n    urls = getM3u8();\n};\n\n`<html>\n    <head>\n        <meta name=\"viewport\" content=\"width=device-width\">\n        <style>\n            body {\n                margin: 0;\n                font-family: Arial, sans-serif;\n                background: linear-gradient(135deg, #ece9e6, #ffffff);\n                display: flex;\n                flex-direction: column;\n                align-items: center;\n                justify-content: flex-start;\n                padding: 20px;\n            }\n            .container {\n                width: 100%;\n                max-width: 800px;\n                background: #fff;\n                border-radius: 10px;\n                box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n                overflow: hidden;\n                margin-bottom: 20px;\n            }\n            h3 {\n            \t    text-align: center;\n                margin: 0;\n                padding: 10px 20px;\n                font-size: 0.9em;\n                background: #333;\n                color: #fff;\n                border-radius: 10px 10px 0 0;\n            }\n            .video-container {\n                width: 100%;\n                background: #000;\n                position: relative;\n            }\n            video {\n                width: 100%;\n                height: auto;\n                display: block;\n            }\n            .info-container {\n                padding: 20px;\n            }\n            .info-container p {\n                margin: 10px 0;\n                color: #555;\n            }\n            .info-container p span {\n                font-weight: bold;\n                color: #000;\n            }\n            .nav-container {\n                display: flex;\n                justify-content: space-between;\n                align-items: center;\n                padding: 15px 20px;\n                background: #f5f5f5;\n                border-top: 1px solid #ddd;\n            }\n            .nav-button {\n                padding: 10px 20px;\n                background: #007bff;\n                color: white;\n                border: none;\n                border-radius: 5px;\n                cursor: pointer;\n                font-size: 14px;\n            }\n            .nav-button:disabled {\n                background: #6c757d;\n                cursor: not-allowed;\n            }\n            .page-select {\n                padding: 10px 15px;\n                border: 1px solid #ddd;\n                border-radius: 5px;\n                font-size: 14px;\n                background: white;\n                min-width: 120px;\n            }\n            .video-info {\n                text-align: center;\n                padding: 10px;\n                background: #f8f9fa;\n                border-bottom: 1px solid #ddd;\n                font-size: 14px;\n                color: #666;\n            }\n        </style>\n    </head>\n    <body>\n        <div class=\"container\">\n        <h3>当前播放: 第<span id=\"currentVideo\">1</span>集 / 共${urls.length}集</h3>\n            <div class=\"video-container\">\n                <video controls autoplay name=\"media\" id=\"videoPlayer\">\n                    <source src=\"${urls[0] || ''}\" type=\"application/x-mpegURL\">\n                </video>\n            </div>\n            <div class=\"nav-container\">\n                <button class=\"nav-button\" id=\"prevBtn\" onclick=\"changeVideo(-1)\">上一集</button>\n                <select class=\"page-select\" id=\"pageSelect\">\n                    <!-- 选项将通过JavaScript动态生成 -->\n                </select>\n                <button class=\"nav-button\" id=\"nextBtn\" onclick=\"changeVideo(1)\">下一集</button>\n            </div>\n            <div class=\"info-container\">\n            </div>\n        </div>\n\n        <script>\n            // 视频地址数组和当前索引\n            const videoUrls = ${JSON.stringify(urls)};\n            let currentVideoIndex = 0;\n            \n            // 获取DOM元素\n            const video = document.getElementById('videoPlayer');\n            const prevBtn = document.getElementById('prevBtn');\n            const nextBtn = document.getElementById('nextBtn');\n            const pageSelect = document.getElementById('pageSelect');\n            const currentVideoSpan = document.getElementById('currentVideo');\n            \n            // 生成下拉菜单选项\n            function generateSelectOptions() {\n                let optionsHtml = '';\n                for (let i = 0; i < videoUrls.length; i++) {\n                   optionsHtml += '<option value=\"' + i + '\">第' + (i + 1) + '集</option>';\n    };\n                pageSelect.innerHTML = optionsHtml;\n             }\n            \n            // 更新按钮状态和显示\n            function updateButtons() {\n                prevBtn.disabled = currentVideoIndex === 0;\n                nextBtn.disabled = currentVideoIndex === videoUrls.length - 1;\n                pageSelect.value = currentVideoIndex;\n                currentVideoSpan.textContent = currentVideoIndex + 1;\n            }\n            \n            // 切换视频\n            function changeVideo(direction) {\n                const newIndex = currentVideoIndex + direction;\n                if (newIndex >= 0 && newIndex < videoUrls.length) {\n                    currentVideoIndex = newIndex;\n                    video.src = videoUrls[currentVideoIndex];\n                    video.load();\n                    updateButtons();\n                }\n            }\n            \n            // 选择特定视频\n            function selectVideo(index) {\n                const newIndex = parseInt(index);\n                if (newIndex >= 0 && newIndex < videoUrls.length) {\n                    currentVideoIndex = newIndex;\n                    video.src = videoUrls[currentVideoIndex];\n                    video.load();\n                    updateButtons();\n                }\n            }\n            \n            // 初始化按钮状态\n            generateSelectOptions();\n            updateButtons();\n            \n            // 绑定下拉菜单事件\n            pageSelect.addEventListener('change',function() {\n               selectVideo(this.value);\n             });\n            \n            // 触摸控制相关代码\n            let touchStartX = 0;\n            let touchStartY = 0;\n            let touchStartTime = 0;\n            let isLongPress = false;\n\n            // 滑动快进\n            video.addEventListener('touchstart', (e) => {\n                touchStartX = e.touches[0].clientX;\n                touchStartY = e.touches[0].clientY;\n                touchStartTime = Date.now();\n                isLongPress = false;\n            });\n\n            video.addEventListener('touchmove', (e) => {\n                const deltaX = e.touches[0].clientX - touchStartX;\n                const deltaY = e.touches[0].clientY - touchStartY;\n\n                // 如果是水平滑动，且未进入长按状态\n                if (Math.abs(deltaX) > Math.abs(deltaY) && !isLongPress) {\n                    const duration = video.duration;\n                    const seekTime = video.currentTime + (deltaX / 100); // 每滑动100px快进1秒\n                    video.currentTime = Math.min(Math.max(seekTime, 0), duration);\n                }\n            });\n\n            // 长按快进\n            video.addEventListener('touchend', (e) => {\n                const touchEndTime = Date.now();\n                const touchDuration = touchEndTime - touchStartTime;\n\n                // 如果长按时间超过500ms，进入长按快进状态\n                if (touchDuration > 500) {\n                    isLongPress = true;\n                    // 在长按状态下，根据滑动距离快进\n                    const deltaX = e.changedTouches[0].clientX - touchStartX;\n                    const duration = video.duration;\n                    const seekTime = video.currentTime + (deltaX / 100); // 每滑动100px快进1秒\n                    video.currentTime = Math.min(Math.max(seekTime, 0), duration);\n                } else {\n                    isLongPress = false;\n                }\n            });\n\n            // 防止默认行为（如页面滚动）\n            video.addEventListener('touchmove', (e) => {\n                e.preventDefault();\n            });\n        </script>\n    </body>\n</html>`",
    "ruleImage": "@js:\nvar text = java.getString('script@html');\nvar match = text.match(/loadBannerDirect\\('([^']+)'/);\nvar img = match ? match[1] : '';\nimg;",
    "ruleLink": "href",
    "ruleNextPage": "page",
    "rulePubDate": "{{@@.wraps@text}}{{@@.post-card-info span@text##\\n}}",
    "ruleTitle": "h2@text",
    "singleUrl": false,
    "sortUrl": "首页::/page/{{page}}/\n每日大赛::/category/mrds/{{page}}/\n搜索::/search/{{source.getVariable()}}/{{page}}/\n主题大赛::/category/ztds/{{page}}/\n热搜吃瓜::/category/rstt/{{page}}/\n校园学生::/category/xazd/{{page}}/\n必撸大赛::/category/blyp/{{page}}/\n反差泄密::/category/fctg/{{page}}/\n网红黑料::/category/mhds/{{page}}/\n猎奇重口::/category/lqdp/{{page}}/\nAV看片::/category/jdsj/{{page}}/\n明星大赛::/category/mxwh/{{page}}/\n动漫之家::/category/smdh/{{page}}/\n影视国漫::/category/dypd/{{page}}/\ncos写真::/category/mtds/{{page}}/\n声控ASMR::/category/ysds/{{page}}/\n寸止挑战::/category/czds/{{page}}/\n混剪PMV::/category/hjds/{{page}}/\n原创投稿::/category/tgds/{{page}}/\n欧美精品::/category/omjp/{{page}}/\n全网参赛::/category/qwcs/{{page}}/",
    "sourceComment": "发布页: https://www.njttvylz.cc\n最新网址: https://mrds72.com\n永久地址: https://mrds.com\n备用网址: https://mrdsx5.com\n备用线路1: big.ktgchwz.xyz\n备用线路2: adjust.ktgchwz.xyz\n备用线路3: borrow.ktgchwz.xyz\n备用线路4: black.ktgchwz.xyz\n获取地址: mrds.club@gmail.com",
    "sourceGroup": "美涩",
    "sourceIcon": "https://img2.baidu.com/it/u=2497591018,1494490685&fm=253&fmt=auto&app=138&f=JPEG?w=375&h=500",
    "sourceName": "每日大赛",
    "sourceUrl": "https://d3fzqoxno61m61.rnxuiofe.com/",
    "style": "iframe{\n\theight:600px\n}\ntitle{\n\tdisplay:block\n}"
  },
  {
    "articleStyle": 0,
    "customOrder": 84,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "legado",
    "sourceIcon": "http://mmbiz.qpic.cn/mmbiz_png/hpfMV8hEuL2eS6vnCxvTzoOiaCAibV6exBzJWq9xMic9xDg3YXAick87tsfafic0icRwkQ5ibV0bJ84JtSuxhPuEDVquA/0?wx_fmt=png",
    "sourceName": "小说拾遗",
    "sourceUrl": "snssdk1128://user/profile/562564899806367"
  },
  {
    "articleStyle": 0,
    "customOrder": 85,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "legado",
    "sourceIcon": "https://cdn.jsdelivr.net/gh/mgz0227/meowcloud/icon.png",
    "sourceName": "Meow云",
    "sourceUrl": "https://pan.miaogongzi.net"
  },
  {
    "articleStyle": 0,
    "customOrder": 86,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 1774456739906,
    "loadWithBaseUrl": true,
    "ruleArticles": ".vod[2:23]",
    "ruleContent": "<js>\n// 提取m3u8链接\nvar m3u8Match = result.match(/\"([^\"]*?index\\.m3u8[^\"]*)\"/i) \n             || result.match(/'([^']*?index\\.m3u8[^']*)'/i);\n\nvar p = '';\nif (m3u8Match) {\n    var u = m3u8Match[1]\n        .replace(/\\\\\\//g, '/')      // \\/ → /\n        .replace(/\\\\\\\\/g, '\\\\')      // \\\\ → \\\n        .trim();\n    \n    // 补全协议\n    if (u.startsWith('//')) {\n        u = 'https:' + u;\n    } else if (!u.startsWith('http')) {\n        // 需要基础URL，这里假设当前页面URL在result中或需要传入\n        u = 'https://' + u;  // 简化处理，或根据实际需求调整\n    }\n    p = u;\n}\n\n// 标题：从 span.tx-flex-sh > a 的 title 属性获取\nvar t = java.getString('.title.1 @text') || '未知标题';\n\n// 标签：从 meta[name=\"description\"] 的 content 获取  \nvar b = java.getString('meta[name=\"description\"]@content') || '';\nvar updateIndex = b.indexOf('更新时间');\nif (updateIndex !== -1) {\nvar d = b.substring(updateIndex);  // 保留\"更新时间\"及之后的内容\n}\n\n`<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>${t}</title>\n<style>\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,sans-serif;background:#f0f9ff;padding:10px}\n.v-box{max-width:800px;margin:0 auto;background:white;border-radius:12px;box-shadow:0 5px 15px rgba(0,0,0,0.1);overflow:hidden}\n.header{padding:12px;border-bottom:1px solid #eee;display:flex;flex-wrap:wrap;justify-content:space-between}\n.title{font-size:18px;font-weight:600;margin-bottom:8px;width:100%}\n.tags{color:#5f6368;font-size:14px;flex:1;min-width:60%;word-break:break-all}\n.time{color:#5f6368;font-size:14px;text-align:right;flex-basis:35%}\n.v-wrap{position:relative;padding-top:56.25%;background:#000}\n.video{position:absolute;top:0;left:0;width:100%;height:100%}\n.footer{padding:8px;text-align:center;color:#5f6368;font-size:13px}\n.info-box{padding:15px;font-size:14px;line-height:1.6}\n.info-box p{margin:8px 0}\n.hint{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background:rgba(0,0,0,0.7);color:#fff;padding:12px 20px;border-radius:20px;font-size:1.1rem;z-index:10;display:none}\n.controls{position:absolute;top:0;left:0;width:100%;height:4px;background:rgba(255,255,255,0.3);z-index:5;transition:opacity 0.3s}\n.progress{height:100%;background:#4a9eff;width:0}\n</style>\n</head>\n<body>\n<div class=\"v-box\">\n<div class=\"header\">\n<div class=\"title\">${t}</div>\n<div class=\"tags\">${d}</div>\n<div class=\"time\" id=\"timeDisplay\">00:00/00:00</div></div>\n<div class=\"v-wrap\">\n<div class=\"controls\"><div class=\"progress\" id=\"progressBar\"></div></div>\n<div class=\"hint\" id=\"hint\">快进中 &gt;&gt;</div>\n<video class=\"video\" id=\"v\" controls playsinline>\n<source src=\"${p}\" type=\"application/x-mpegURL\">您的浏览器不支持HTML5视频\n</video>\n</div>\n<div class=\"footer\">滑动调整进度 | 长按2倍速</div>\n</div>\n<script>\nvar v = document.getElementById('v');\nvar tDisplay = document.getElementById('timeDisplay');\nvar pBar = document.getElementById('progressBar');\nvar hint = document.getElementById('hint');\nvar startX = 0, startTime = 0;\nvar longPressTimer;\nvar sensitivity = 0.1;\nvar longPressTime = 500;\nvar hintDuration = 2000;\nfunction updateTime() {\nif (!v.duration) return;\nvar m1 = Math.floor(v.currentTime / 60);\nvar s1 = Math.floor(v.currentTime % 60);\nvar m2 = Math.floor(v.duration / 60);\nvar s2 = Math.floor(v.duration % 60);\ntDisplay.textContent = m1 + ':' + (s1 < 10 ? '0' : '') + s1 + '/' + m2 + ':' + (s2 < 10 ? '0' : '') + s2;\npBar.style.width = (v.currentTime / v.duration) * 100 + '%';}\nv.addEventListener('timeupdate', updateTime);\nv.addEventListener('loadedmetadata', updateTime);\nv.addEventListener('touchstart', function(e) {\nstartX = e.touches[0].clientX;\nstartTime = Date.now();\nif (longPressTimer) clearTimeout(longPressTimer);\nhint.style.display = 'none';\nlongPressTimer = setTimeout(function() {\nv.playbackRate = 2.0;\nhint.style.display = 'block';\nsetTimeout(function() { hint.style.display = 'none'; }, hintDuration);}, longPressTime);});\nv.addEventListener('touchmove', function(e) {\ne.preventDefault();\nclearTimeout(longPressTimer);\nvar diffX = e.touches[0].clientX - startX;\nvar change = diffX * sensitivity * v.duration / 100;\nv.currentTime = Math.max(0, Math.min(v.currentTime + change, v.duration));\nstartX = e.touches[0].clientX;updateTime();});\nv.addEventListener('touchend', function() {\nv.playbackRate = 1.0;\nclearTimeout(longPressTimer);});\n</script>\n</body>\n</html>`\n</js>\n",
    "ruleImage": "img@data-original",
    "ruleLink": "a@href",
    "ruleNextPage": ".pageitem.-1@href",
    "ruleTitle": "a@text",
    "singleUrl": false,
    "sortUrl": "自拍::https://eeoopinkyy.cc/pink/index.php/vod/type/id/198/page/{{page}}.html\n搜索::https://eeoopinkyy.cc/pink/index.php/vod/search/page/{{page}}/wd/{{source.getVariable()}}.html\n吃瓜::https://eeoopinkyy.cc/pink/index.php/vod/search/page/{{page}}/wd/吃瓜.html\n国产::https://eeoopinkyy.cc/pink/index.php/vod/type/id/197/page/{{page}}.html\n国产视频::https://eeoopinkyy.cc/pink/index.php/vod/type/id/199.html\n国产传媒::https://eeoopinkyy.cc/pink/index.php/vod/type/id/200.html\n国产裸聊::https://eeoopinkyy.cc/pink/index.php/vod/type/id/201.html\n国产直播::https://eeoopinkyy.cc/pink/index.php/vod/type/id/202.html\n国产偷拍::https://eeoopinkyy.cc/pink/index.php/vod/type/id/203.html\n国产大制作::https://eeoopinkyy.cc/pink/index.php/vod/type/id/204.html\n国产主播::https://eeoopinkyy.cc/pink/index.php/vod/type/id/205.html\n蜜桃传媒::https://eeoopinkyy.cc/pink/index.php/vod/type/id/217.html\n天美传媒::https://eeoopinkyy.cc/pink/index.php/vod/type/id/218.html\n乌鸦传媒::https://eeoopinkyy.cc/pink/index.php/vod/type/id/219.html\n星空传媒::https://eeoopinkyy.cc/pink/index.php/vod/type/id/220.html\n乐播传媒::https://eeoopinkyy.cc/pink/index.php/vod/type/id/221.html\n大象传媒::https://eeoopinkyy.cc/pink/index.php/vod/type/id/222.html\n映画传媒::https://eeoopinkyy.cc/pink/index.php/vod/type/id/223.html\n皇家华人::https://eeoopinkyy.cc/pink/index.php/vod/type/id/208.html\n精东影业::https://eeoopinkyy.cc/pink/index.php/vod/type/id/209.html\n成人头条::https://eeoopinkyy.cc/pink/index.php/vod/type/id/210.html\n免子先生::https://eeoopinkyy.cc/pink/index.php/vod/type/id/211.html\n杏吧原创::https://eeoopinkyy.cc/pink/index.php/vod/type/id/212.html\n91制片厂::https://eeoopinkyy.cc/pink/index.php/vod/type/id/213.html\n开心鬼传媒::https://eeoopinkyy.cc/pink/index.php/vod/type/id/214.html\n黑料网曝::https://eeoopinkyy.cc/pink/index.php/vod/type/id/181.html\n会所技师::https://eeoopinkyy.cc/pink/index.php/vod/type/id/182.html\n探花约炮::https://eeoopinkyy.cc/pink/index.php/vod/type/id/183.html\n淫妻绿帽::https://eeoopinkyy.cc/pink/index.php/vod/type/id/184.html\n制服诱惑::https://eeoopinkyy.cc/pink/index.php/vod/type/id/185.html\n重口猎奇::https://eeoopinkyy.cc/pink/index.php/vod/type/id/186.html\n强奸乱伦::https://eeoopinkyy.cc/pink/index.php/vod/type/id/187.html\n精品甄之::https://eeoopinkyy.cc/pink/index.php/vod/type/id/190.html\n网曝黑料::https://eeoopinkyy.cc/pink/index.php/vod/type/id/191.html\n明星换脸::https://eeoopinkyy.cc/pink/index.php/vod/type/id/192.html\n女优明星::https://eeoopinkyy.cc/pink/index.php/vod/type/id/193.html\n韩国主播::https://eeoopinkyy.cc/pink/index.php/vod/type/id/194.html\n网红主播::https://eeoopinkyy.cc/pink/index.php/vod/type/id/195.html\n群交淫乱::https://eeoopinkyy.cc/pink/index.php/vod/type/id/196.html\n巨乳美乳::https://eeoopinkyy.cc/pink/index.php/vod/type/id/244.html\n高清名优::https://eeoopinkyy.cc/pink/index.php/vod/type/id/245.html\n人妻熟女::https://eeoopinkyy.cc/pink/index.php/vod/type/id/246.html\n中文字幕::https://eeoopinkyy.cc/pink/index.php/vod/type/id/247.html\nSM调教::https://eeoopinkyy.cc/pink/index.php/vod/type/id/248.html\nVR视角::https://eeoopinkyy.cc/pink/index.php/vod/type/id/249.html\nAV解说::https://eeoopinkyy.cc/pink/index.php/vod/type/id/250.html\n日本无码::https://eeoopinkyy.cc/pink/index.php/vod/type/id/235.html\n欧美性爱::https://eeoopinkyy.cc/pink/index.php/vod/type/id/236.html\n欧美无码::https://eeoopinkyy.cc/pink/index.php/vod/type/id/237.html\n高清有码::https://eeoopinkyy.cc/pink/index.php/vod/type/id/238.html\n日本素人::https://eeoopinkyy.cc/pink/index.php/vod/type/id/239.html\n伦理三级::https://eeoopinkyy.cc/pink/index.php/vod/type/id/240.html\n动漫精选::https://eeoopinkyy.cc/pink/index.php/vod/type/id/241.html\n乱伦毁三观::https://eeoopinkyy.cc/pink/index.php/vod/type/id/226.html\n淫乱学生妹::https://eeoopinkyy.cc/pink/index.php/vod/type/id/227.html\n玩偶姐姐::https://eeoopinkyy.cc/pink/index.php/vod/type/id/228.html\n糖心Vlog::https://eeoopinkyy.cc/pink/index.php/vod/type/id/229.html\n萝莉社::https://eeoopinkyy.cc/pink/index.php/vod/type/id/230.html\n性视界::https://eeoopinkyy.cc/pink/index.php/vod/type/id/231.html\nPsychoPorn::https://eeoopinkyy.cc/pink/index.php/vod/type/id/232.html",
    "sourceComment": "┍   　  　书源作者：闻君三月　　  　┒\n├───┬────────────┤\n│！免责│本书源只提供代码进行技术│\n│！声明│交流，请于２４小时后删除│\n└────────────────┘",
    "sourceGroup": "美涩",
    "sourceIcon": "https://ico.img12345.com/jt/favicon.png",
    "sourceName": "粉粉",
    "sourceUrl": "https://eeoopinkyy.cc/pink/index.php/vod/type/id/197.html"
  },
  {
    "articleStyle": 1,
    "customOrder": 87,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 1774475223761,
    "loadWithBaseUrl": true,
    "ruleArticles": "class.col-xs-12 col-sm-4 col-md-3 col-lg-3",
    "ruleContent": "<js>\nresult=decodeURIComponent(result.match(/strencode2\\(\"(.*?)\"\\)/)[1]).match(/src='(.*?)'/)[1];\n`<html>\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no\" />\n</head>\n<body>\n<video src=\"${result}\" width=\"100%\" height=\"auto\" controls=\"controls\" ></video>\n</body>\n</html>`\n</js>",
    "ruleImage": "img@src",
    "ruleLink": "a@href",
    "ruleNextPage": "page",
    "rulePubDate": "class.duration@text",
    "ruleTitle": "class.video-title title-truncate m-t-5@text",
    "singleUrl": false,
    "sortUrl": "主页::/v.php?category=rf&viewtype=basic&page={{page}},{'webView': true}\n91原创::/v.php?category=ori&viewtype=basic&page={{page}},{'webView': true}\n当前最热::/v.php?category=hot&viewtype=basic&page={{page}},{'webView': true}\n本月最热::/v.php?category=top&viewtype=basic&page={{page}},{'webView': true}\n10分钟以上 ::/v.php?category=long&viewtype=basic&page={{page}},{'webView': true}\n20分钟以上 ::/v.php?category=longer&viewtype=basic&page={{page}},{'webView': true}\n本月收藏::/v.php?category=tf&viewtype=basic&page={{page}},{'webView': true}\n 收藏最多::/v.php?category=mf&viewtype=basic&page={{page}},{'webView': true}\n高清::/v.php?category=hd&viewtype=basic&page={{page}},{'webView': true}\n上月最热::/v.php?category=top&m=-1&viewtype=basic&page={{page}},{'webView': true}\n本月讨论::/v.php?category=md&viewtype=basic&page={{page}},{'webView': true}\n",
    "sourceGroup": "美涩",
    "sourceIcon": "https://z3.ax1x.com/2021/05/04/gnLfmD.png",
    "sourceName": "©91porn",
    "sourceUrl": "https://91porn.com/",
    "style": "body{background-color:black;margin:0;padding:0;width:100%;}"
  },
  {
    "articleStyle": 0,
    "customOrder": 88,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "class.ucontent@li",
    "ruleContent": "class.s-tab-main@html",
    "ruleImage": "@js:\"https://i.postimg.cc/htVZ5jk1/1665570814797.png\"",
    "ruleLink": "tag.a@href",
    "ruleNextPage": "text.下一页@href",
    "rulePubDate": "class.time@text",
    "ruleTitle": "class.ctitle@text",
    "singleUrl": true,
    "sortUrl": "情侣::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=SwmVnh7DhV5fti8rANEOnA%3D%3D\n真实自拍::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=sxFQ8fIfXNi%2F7h%2FTa%2BVqaQ%3D%3D\n艳照门::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=sWJNZL81qog%2FV0kqE7K4xg%3D%3D\n韩国::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=qYmLQw%2Bg9uPbbhsqBrcq2Q%3D%3D\n91大神::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=WuIS%2BITZ25HLRd6XZW%2FOxA%3D%3D\n重口::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=DEbPb09hbgP9k6scQg63sw%3D%3D\n国产3P::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=GWLkyuIEPQDeXCqVFoTAyA%3D%3D\n寻花::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=rKKopyjdoS20rSOUxh3zJQ%3D%3D\n探花::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=hgzJx3zpIIxdOEMcWHz2Tg%3D%3D\n百度云泄露::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=2lC5aEeJd1u2dqQ%2FmdRIVQ%3D%3D\n叫爸爸::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=y8uZo8HwYsn8SvxL1UCb0g%3D%3D\n双飞::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=5thccQpFuzxfZnnatss5wQ%3D%3D\n援交::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=eYLQqyMZKX0naw7R9aFiUQ%3D%3D\n高潮::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=vxgb5Mhrcm45%2BvJ3jR%2FK5w%3D%3D\n云盘泄密::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=Uk8R2RDqogK686unextaRA%3D%3D\n百度云::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=5ZDf525skrVIknBGx5lmFQ%3D%3D\n母狗::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=6%2BdjspHsB86vEMDYR8vX0g%3D%3D\nSWAG::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=dth6EA%2B8L38m3Nca%2FQFL2Q%3D%3D\n灌醉::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=CgBbOg15Du4JraAsWNBNjQ%3D%3D\n乱伦::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=62iSChVBLwn9fxJe4R2eFw%3D%3D\n台湾::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=SxxaH9csNSivTS3P7gZoFg%3D%3D\n双洞::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=PsCugwsYtwmQ4ClpO%2FoDjg%3D%3D\n黑人::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=Jo0QDMWSz9h5NGQAE9Q6VQ%3D%3D\n模特::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=rkt3PZIjjsRwGyupHFDGaA%3D%3D\n明星::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=QYz3d2N9zvH04hLT6JKzUQ%3D%3D\n外围::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=IMWBtdaYv%2Fjxugi4%2BHhZ4A%3D%3D\nE罩::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=est3SVEmdTex%2Fvm3L4vYPw%3D%3D\n平胸::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=6KvMA5igEDec1T31X3GJzw%3D%3D\n萝莉::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=z90Pw6%2BPlSZL6DsNDa3HDw%3D%3D\n偷拍::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=kA%2FTlS7qmOLRGkgF%2Fn0INQ%3D%3D\n强奸::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=rkfTz9iRzCZ2YZ9BgpLQPQ%3D%3D\n孕妇::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=T5nxv4JMS0RuKayEmUskBg%3D%3D\n露出::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=cWH28OVOk5XusdgQlQ42DA%3D%3D\n学生::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=S4a6Y3Jh0ahrOuC%2BnPWraw%3D%3D\n厕所::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=OBoF9jSv3ssvCWLzi0ZUow%3D%3D\n丝袜::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=HZAcWdDll929vjXxi%2Fis9Q%3D%3D\n麻豆::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=AAzZLiir3JVotigCPt5yyw%3D%3D\n剧情::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=vX2kdY6Bji%2BZDgJC3Uom8Q%3D%3D\n少妇::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=WvRQ3zJ6x0Iddtyv%2F3kQ7Q%3D%3D\n初中::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=7zlfwQmL2OCGlwAMuO9PkQ%3D%3D\n户外::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=P5xjiQfnsJ62f4Hz3RGbVg%3D%3D\n巨乳::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=B5Vt3CkBgs3beFwmKholzg%3D%3D\n按摩师::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=JM5fp9rXtfWRGHxSh8zS5w%3D%3D\n抖音::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=zFa%2FHlIv9P7FSIj1wrTPLw%3D%3D\n极品::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=IuN82Iai2xUOVHMMANfnOA%3D%3D\n勾引::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=vh64QmiM3Mo2OcKdxDQdsQ%3D%3D\n调教::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=%2BQeUgBv85wKceg%2FDI5Ak0w%3D%3D\n对白::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=%2B9ccuxdMZa3%2FJ8LzxMB6qg%3D%3D\n喷水::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=1oRbUL2Xn9xhEmXGx6GsQA%3D%3D\n白虎::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=UKNntcz6aNUmZxjkxJCFPQ%3D%3D\n肛交::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=nWw6UIl046QAjrvoKFS2Rw%3D%3D\n宿舍::https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/search.php?k=12%2BMLChLTiqIX3cSShXxtg%3D%3D",
    "sourceComment": "",
    "sourceGroup": "🔞 18禁,R18",
    "sourceIcon": "https://i.postimg.cc/tCs5Fb8F/1664101587780.png",
    "sourceName": "©集芳阁®",
    "sourceUrl": "https://xn---jfgsoucom-xo3rt4olv7g07mz39a.jifangge-club.com/"
  },
  {
    "articleStyle": 2,
    "customOrder": 89,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\"User-Agent\": \"Mozilla/5.0 (Linux; Android 12; 22041211AC Build/SP1A.210812.016) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.104 Mobile Safari/537.36\"}",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": ".inside-article",
    "ruleContent": "@js:\nlet pics = java.getString('p@a@img@src'); \nlet p = String(pics).split(\"\\n\").map(i => `<img src=\"${i}\">`).join(\"\\n\");\np = '<title>🏄Mengteen</title>\\n' +  \n'<style>\\n' +\n'  * {margin: 0; padding: 0}\\n' +  \n'  img {width: 100%;height: auto}\\n' +\n'  /* Mengteen阅图基础UI */\\n' +\n'  /* 返回按钮基础 */\\n' +\n'  #backToTopBtn {\\n' +\n'    display: none;\\n' + \n'    position: fixed;\\n' +\n'    bottom: 36px;\\n' +\n'    right: 18px;\\n' +\n'    z-index: 999;\\n' +\n'    border: none;\\n' +\n'    outline: none;\\n' +\n'    background: linear-gradient(135deg, #ADD8E6, #FFF8DC);\\n' +  \n'    color: white;\\n' +\n'    cursor: pointer;\\n' +\n'    padding: 2px;\\n' +\n'    border-radius: 10%;\\n' +\n'    font-size: 18px;\\n' +\n'    box-shadow: 0 8px 32px rgba(70, 130, 180, 0.3);\\n' +  \n'    transition: all 0.3s ease;\\n' +  \n'    backdrop-filter: blur(4px);\\n' +  \n'    border: 1px solid rgba(255, 255, 255, 0.3);\\n' +  \n'  }\\n' +\n'  \\n' +\n'  #backToTopBtn:hover {\\n' +\n'    background: linear-gradient(135deg, #ADD8E6, #FFF8DC);\\n' +  \n'    transform: scale(1.08);\\n' +  \n'    box-shadow: 0 8px 25px rgba(70, 130, 180, 0.4);\\n' +  \n'  }\\n' +\n'  \\n' +\n'  #backToTopBtn:active {\\n' +\n'    transform: scale(0.95);\\n' +  \n'  }\\n' +\n'  \\n' +\n'  /* 图片加载完成提示基础 */\\n' +\n'  #image-loaded-toast {\\n' +\n'    position: fixed;\\n' +\n'    bottom: 33px;\\n' +\n'    left: 50%;\\n' +\n'    transform: translateX(-50%);\\n' +\n'    background: rgba(0, 0, 0, 0.7);\\n' +\n'    color: white;\\n' +\n'    padding: 10px 20px;\\n' +\n'    border-radius: 20px;\\n' +\n'    font-size: 14px;\\n' +\n'    z-index: 998;\\n' +\n'    backdrop-filter: blur(4px);\\n' +\n'    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);\\n' +\n'    opacity: 0;\\n' +\n'    transition: opacity 0.3s;\\n' +\n'    pointer-events: none;\\n' +\n'  }\\n' +\n'  \\n' +\n'  /* 标题卡片基础 */\\n' +\t\n'  #image-loaded-toast.show {\\n' +\n'    opacity: 1;\\n' +\n'  }\\n' +\n'</style>\\n' +\n'<div style=\"' +  \n  'text-align:center;' +      \n  'padding:50px 20px 20px;' + \n  'margin:0 0 0px;' +        \n  'position:relative;' +      \n  'background:linear-gradient(135deg, #f0f7ff, #e6f0ff);' +   \n'\">\\n' +\n'  <!-- 标题卡片 -->\\n' +\n'  <div style=\"' +  \n    'position:relative;' +   \n    'z-index:10;' +          \n    'display:inline-block;' + \n    'transform:translateY(-20px);' + \n    'filter: drop-shadow(0 15px 25px rgba(70,130,180,0.25));' + \n  '\">\\n' +\n  \n  '    <div style=\"' +  \n    'background:rgba(255,255,255,0.75);' + \n    'backdrop-filter:blur(12px);' +        \n    'padding:16px 48px;' +                 \n    'border-radius:18px;' +               \n    'border:1px solid rgba(255,255,255,0.5);' + \n    'box-shadow:0 8px 32px rgba(70,130,180,0.2), inset 0 0 12px rgba(255,255,255,0.6);' + \n    'position:relative;' +  \n    'overflow:hidden;' +    \n  '\">\\n' +\n  \n  '      <!-- 顶部高光 -->\\n' +\n  '      <div style=\"' +  \n    'position:absolute;' + \n    'top:0; left:0; right:0;' + \n    'height:40%;' +        \n    'background:linear-gradient(to bottom, rgba(255,255,255,0.4), transparent);' + \n    'pointer-events:none;' + \n  '\"></div>\\n' +\n  \n  '      \\n' +\n  '      <h3 style=\"' +  \n    'background:linear-gradient(135deg, #4a7bd0, #00a2b8);' + \n    '-webkit-background-clip:text;' + \n    'background-clip:text;' +         \n    'color:transparent;' +            \n    'font-size:1.3rem;' +             \n    'font-weight:700;' +              \n    'margin:0;' +                     \n    'letter-spacing:-0.5px;' +        \n    'position:relative;' +            \n    'z-index:2;' +                    \n  '\">{{@@title@text## – Cos波蕾}}</h3>\\n' +  //主标题   \n  \n  '      <!-- 左下装饰点 -->\\n' +\n  '      <div style=\"' +  \n    'position:absolute;' +  \n    'bottom:12px;' +        \n    'left:20px;' +          \n    'width:6px;' +          \n    'height:6px;' +         \n    'background:#00a2b8;' + \n    'border-radius:50%;' +  \n    'opacity:0.7;' +        \n  '\"></div>\\n' +\n  \n  '      <!-- 右下装饰点 -->\\n' +\n  '      <div style=\"' +  \n    'position:absolute;' +\n    'bottom:12px;' +\n    'right:20px;' +       \n    'width:6px;' +\n    'height:6px;' +\n    'background:#4a7bd0;' + \n    'border-radius:50%;' +\n    'opacity:0.7;' +\n  '\"></div>\\n' +\n  \n  '    </div>\\n' +  \n  '  </div>\\n' +    \n  \n  '  \\n' +\n  '  <!-- 时间信息 -->\\n' +\n  '  <div style=\"' +  \n    'margin-top:0px;' +   \n    'padding:0px 20px;' + \n  '\">\\n' +\n  \n  '    <h5 style=\"' +  \n    'color:#6c757d;' +       \n    'font-weight:400;' +      \n    'font-size:1rem;' +    \n    'margin:0;' +             \n    'line-height:1.6;' +      \n    'letter-spacing:0.3px;' + \n    'position:relative;' +    \n    'display:inline-block;' + \n    'max-width:700px;' +      \n  '\">\\n' +\n  \n  '      {{@@.posted-on@.entry-date@text}} 收录 \\n' +  //副标题\n  \n  '      <!-- 下划线装饰 -->\\n' +\n  '      <div style=\"' +  \n    'position:absolute;' + \n    'bottom:-5px;' +       \n    'left:0;' +            \n    'width:100%;' +        \n    'height:1px;' +        \n    'background:linear-gradient(90deg, transparent, rgba(70,130,180,0.3), transparent);' + \n  '\"></div>\\n' +\n  \n  '    </h5>\\n' +  \n  '  </div>\\n' +   \n  \n  '  \\n' +\n  '  <!-- 左上装饰圆 -->\\n' +\n  '  <div style=\"' +  \n    'position:absolute;' + \n    'top:10%;' +           \n    'left:15%;' +          \n    'width:40px;' +        \n    'height:40px;' +       \n    'border-radius:50%;' + \n    'background:linear-gradient(135deg, rgba(74,123,208,0.1), transparent);' + \n    'filter:blur(2px);' +  \n  '\"></div>\\n' +\n  \n  '  <!-- 右下装饰圆 -->\\n' +\n  '  <div style=\"' +  \n    'position:absolute;' +\n    'bottom:15%;' +      \n    'right:10%;' +       \n    'width:60px;' +      \n    'height:60px;' +     \n    'border-radius:50%;' +\n    'background:linear-gradient(135deg, rgba(0,162,184,0.1), transparent);' + \n    'filter:blur(4px);' + \n    'transform:rotate(30deg);' + \n  '\"></div>\\n' +\n  \n'</div>\\n' +  \np +  \n// 图片加载完成提示\n'\\n<div id=\"image-loaded-toast\">✅ 全部图片已完成加载</div>\\n' +\n// 原有返回顶部按钮和功能脚本保持不变\n'\\n<button id=\"backToTopBtn\" title=\"回到顶部\">🔝</button>\\n' +\n'<script>\\n' +\n'(function() {\\n' +\n'  const backToTopBtn = document.getElementById(\"backToTopBtn\");\\n' +\n'  const toast = document.getElementById(\"image-loaded-toast\");\\n' +\n'  \\n' +\n'  // 图片加载完成检测\\n' +\n'  const images = document.querySelectorAll(\"img\");\\n' +\n'  let loadedCount = 0;\\n' +\n'  const totalImages = images.length;\\n' +\n'  \\n' +\n'  // 如果页面没有图片，直接隐藏提示\\n' +\n'  if(totalImages === 0) {\\n' +\n'    toast.style.display = \"none\";\\n' +\n'  }\\n' +\n'  \\n' +\n'  // 检测图片加载完成\\n' +\n'  images.forEach(img => {\\n' +\n'    if(img.complete) {\\n' +\n'      checkAllLoaded();\\n' +\n'    } else {\\n' +\n'      img.addEventListener(\"load\", checkAllLoaded);\\n' +\n'      img.addEventListener(\"error\", checkAllLoaded);\\n' +\n'    }\\n' +\n'  });\\n' +\n'  \\n' +\n'  function checkAllLoaded() {\\n' +\n'    loadedCount++;\\n' +\n'    if(loadedCount >= totalImages) {\\n' +\n'      showToast();\\n' +\n'    }\\n' +\n'  }\\n' +\n'  \\n' +\n'  function showToast() {\\n' +\n'    toast.classList.add(\"show\");\\n' +\n'    setTimeout(() => {\\n' +\n'      toast.classList.remove(\"show\");\\n' +\n'    }, 2000);\\n' +\n'  }\\n' +\n'  \\n' +\n'  // 监听页面滚动事件\\n' +\n'  window.addEventListener(\"scroll\", () => {\\n' +\n'    const scrollPosition = window.scrollY || document.documentElement.scrollTop;\\n' +\n'    \\n' +\n'    if (scrollPosition > 288) {\\n' +\n'      backToTopBtn.style.display = \"block\";\\n' +\n'      backToTopBtn.style.opacity = \"1\";\\n' + \n'    } else {\\n' +\n'      backToTopBtn.style.display = \"none\";\\n' +\n'    }\\n' +\n'  });\\n' +\n'  \\n' +\n'  // 点击事件监听器\\n' +\n'  backToTopBtn.addEventListener(\"click\", () => {\\n' +\n'    window.scrollTo({\\n' +\n'      top: 0,\\n' +\n'      behavior: \"smooth\"\\n' +\n'    });\\n' +\n'  });\\n' +\n'})();\\n' +\n'</script>';",
    "ruleImage": "img@src",
    "ruleLink": "h2@a@href",
    "ruleNextPage": "page",
    "rulePubDate": "🔖{{@@.cat-links@a@text}}｜📆{{@@time@text}}",
    "ruleTitle": "h2@a@text",
    "singleUrl": false,
    "sortUrl": "首页::/page/{{page}}\n搜索::/page/{{page}}?s={{(source.getVariable()==''||source.getVariable()==null)?source.setVariable('大尺度'):source.getVariable()}}\n角色扮演::/category/cosplay/page/{{page}}\n纯情写真::/category/chunqing/page/{{page}}\n欧美套图::/category/oumei/page/{{page}}",
    "sourceComment": "源社区：@Mengteen  2025.7.3更新\n二传二创或者是其它问题请联系我。\n我邮箱:[xxxmgqxxx@vip.qq.com]\n我QQ:99737563(备注来意)\n1.不需要挂🪜,个别网络加载可能有点慢，别急！\n2.设计了全新看图UI,自适应全屏,增加一键返回顶上按钮,增加图片加载完成提示。\n3.搜索和分类是按我自己个人喜欢的,你也可以放一些你自己喜欢的。",
    "sourceGroup": "🔞,R18",
    "sourceIcon": "https://cdn.sshs.rip/7b/ef/7b521fec7f16375cdae775707e1c63ef.webp",
    "sourceName": "👙cos波蕾",
    "sourceUrl": "https://cn.cosblay.com/##@Mengteen",
    "variableComment": "🏄Mengteen提示：在此输入关键词搜索！"
  },
  {
    "articleStyle": 0,
    "customOrder": 91,
    "enableJs": false,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": false,
    "ruleArticles": "class.clearfix@tag.li",
    "ruleContent": "id.post@all",
    "ruleImage": "class.image-list-item-image@a@img@src",
    "ruleLink": "a@href",
    "ruleNextPage": "class.nextpostslink@href",
    "rulePubDate": "class.image-list-item-regist-date@text",
    "ruleTitle": "class.image-list-item-title@text",
    "singleUrl": false,
    "sortUrl": "搜索::https://zh.hentai-img.com/search/keyword/Genshin/\n排行::https://zh.hentai-img.com/ranking/\n萝莉::https://zh.hentai-img.com/search/tag/lolita",
    "sourceGroup": "R18",
    "sourceIcon": "https://avatars.githubusercontent.com/u/49548316",
    "sourceName": "hentai-img",
    "sourceUrl": "https://zh.hentai-img.com/"
  },
  {
    "articleStyle": 2,
    "customOrder": 92,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36",
    "injectJs": "(function() {\n    console.log('验证码脚本启动');\n    \n    // 延迟执行，确保页面加载完成\n    setTimeout(function() {\n        // 查找所有文本节点，寻找数学问题\n        const walker = document.createTreeWalker(\n            document.body,\n            NodeFilter.SHOW_TEXT,\n            null,\n            false\n        );\n        \n        let node;\n        while (node = walker.nextNode()) {\n            const text = node.textContent.trim();\n            // 简单的数字运算匹配\n            if (text.match(/\\d+\\s*[\\+\\-\\*/]\\s*\\d+/)) {\n                console.log('发现数学问题:', text);\n                \n                // 尝试填写\n                const inputs = document.getElementsByTagName('input');\n                for (let input of inputs) {\n                    if (input.type === 'text') {\n                        // 简单计算 1+1 作为测试\n                        input.value = '2';\n                        input.dispatchEvent(new Event('input'));\n                        console.log('已尝试填写验证码');\n                        break;\n                    }\n                }\n            }\n        }\n    }, 2000);\n})();",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "li:has(img)||ul@li||div@li",
    "ruleContent": "<!DOCTYPE html>\r\n<html>\r\n\r\n<head>\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0\">\r\n    <link rel=\"stylesheet\" href=\"https://cdn.bootcdn.net/ajax/libs/viewerjs/1.10.1/viewer.min.css\">\r\n    <script src=\"https://cdn.bootcdn.net/ajax/libs/viewerjs/1.10.1/viewer.min.js\"></script>\r\n    <script src=\"http://libs.baidu.com/jquery/2.0.0/jquery.min.js\"></script>\n    {{@@tag.title@html}}\r\n</head>\r\n\r\n<body>\r\n    <h3>{{@@.h@tag.h1@text}}</h3>\r\n    <div id=\"box\">{{@@id.picg@tag.img@html}}</div>\r\n    <div id=\"loads\">加载中...</div>\r\n    <script>\r\n        var loads;\r\n        $(document).ready(function () {\r\n            var box = document.getElementById(\"box\");\r\n            loads = document.getElementById(\"loads\");\r\n            new Viewer(box, { title: false, interval: 3000 })\r\n            var i = 2;\r\n            // 尝试获取总页数，如果获取失败默认给个大一点的数字或者1\r\n            var pageStr = \"{{@@class.pagelist.0@tag.a.-2@textNodes##\\\\n}}\";\r\n            var page = parseInt(pageStr);\r\n            if(isNaN(page)) page = 100; // 容错处理\r\n            \r\n            var url = \"{{baseUrl.replace('.html','_')}}\";\r\n            \r\n            new IntersectionObserver(entries => {\r\n                if (entries[0].intersectionRatio) {\r\n                    if (entries[0].intersectionRatio <= 0) return;\r\n                    if (i <= page) {\r\n                        fetchHtml(i, page, url);\r\n                        i += 1;\r\n                    } else {\r\n                        $('#loads').html(\"已显示全部\");\r\n                    }\r\n                }\r\n            }).observe(loads)\r\n        });\r\n\r\n\r\n        function fetchHtml(i, page, url) {\n            nurl = url + i + '.html';\r\n            $.ajax({\r\n                url: nurl,\r\n                dataType: 'html',\r\n                success: function (html) {\r\n                    $('#box').append('<h5>' + (i) + '/' + (page) + '</h5>');\r\n                    // 修正：使用 #picg img 选择器，与主规则一致\r\n                    var newImg = $(html).find('#picg img');\r\n                    if(newImg.length === 0) {\r\n                        // 备用选择器，防止ID变化\r\n                        newImg = $(html).find('.content img, img');\r\n                    }\r\n                    $('#box').append(newImg);\r\n                    box.viewer.update();\r\n                },\r\n                error: function (xhr) { \r\n                    $('#loads').html(\"加载失败\");\r\n                }\r\n            });\r\n        }\r\n    </script>\r\n</body>\r\n\r\n</html>",
    "ruleImage": "img@lazy-src",
    "ruleLink": "a@href",
    "ruleNextPage": "page",
    "ruleTitle": "class.title@text",
    "singleUrl": false,
    "sortUrl": "\n搜索::/s.asp?keyword={{source.getVariable()}}&page={{page}}\n\n今日更新::/\n\n套图::/shey/yingtiiurm/1_{{page}}.html\n\n日韩::/shey/yingtiiurm/2_{{page}}.html\n\n内衣::/shey/yingtiiurm/9_{{page}}.html\n\n萌妹::/shey/yingtiiurm/11_{{page}}.html\n\n精品::/shey/yingtiiurm/18_{{page}}.html\n\n高清::/shey/yingtiiurm/24_{{page}}.html\n\n无圣光::/shey/yingtiiurm/25_{{page}}.html",
    "sourceComment": "可以换着看，大部分不一样\n摄影图库：http://www.sytuk.com\n精品美女图:http://www.akywt.com\n私房妹子图:http://www.gqsft.com\n高清尤物图:http://www.flsft.com\n私拍尤物图:http://www.mtgqt.com\n性感尤物图:http://www.akxzt.com\n私拍美女图:http://www.sfsnt.com\n极品尤物图:http://www.mtsyt.com\n高清私房图:http://www.jpnst.com\n漂亮网红图:http://www.sfwht.com\n尤物嫩模图:http://www.ywnmt.com\n经典网红图:http://www.jcmeinv.com\n模特网红图:http://www.mtmnw.com\n特色写真图:http://www.jpsft.com.com\n高清网红图:http://www.jpmnt.com\n福利网红图:http://www.sfmtw.com\n高清妹子图:http://www.gqtuku.com\n少女私房图:http://www.sntaotu.com\n极品美女图:http://www.xzmeinv.com\n免费私房图:http://www.mtflt.com\n私房网红图:http://www.gqsft.com",
    "sourceGroup": "图",
    "sourceIcon": "http://www.sytuk.com/favicon.ico",
    "sourceName": "摄影图库",
    "sourceUrl": "http://www.sytuk.com",
    "style": "/*标题相关*/\r\nh3{text-align:center}\r\nh6{margin-bottom:0}\r\nimg{width:100%}\nh5{margin-bottom:0;padding-left:5;text-align:center;color:#666;font-size:12px;}"
  },
  {
    "articleStyle": 1,
    "customOrder": 93,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "header": "",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "",
    "ruleContent": "",
    "ruleDescription": "",
    "ruleImage": "",
    "ruleLink": "",
    "rulePubDate": "",
    "ruleTitle": "",
    "singleUrl": true,
    "sourceGroup": "🌐 媒体,R18",
    "sourceIcon": "https://cdn.aixifan.com/dotnet/20130418/umeditor/dialogs/emotion/images/ac/47.gif",
    "sourceName": "AC正义",
    "sourceUrl": "https://m.acfun.cn"
  },
  {
    "articleStyle": 2,
    "customOrder": 94,
    "enableJs": false,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": false,
    "ruleArticles": "$.[*]",
    "ruleContent": "class.wookmark-initialised@img@html##src.*data-",
    "ruleImage": "t_url",
    "ruleLink": "g_url",
    "ruleNextPage": "page",
    "ruleTitle": "desc",
    "singleUrl": false,
    "sortUrl": "热门::https://www.pornpics.com/search/srch.php?q=popular&limit=20&offset={{(page-1)*20}}\n搜索::https://www.pornpics.com/search/srch.php?q=关键字&limit=20&offset={{(page-1)*20}}\n丝袜::https://www.pornpics.com/search/srch.php?q=stocking&limit=20&offset={{(page-1)*20}}\r\n亚洲::https://www.pornpics.com/search/srch.php?q=asians&limit=20&offset={{(page-1)*20}}\r\n萝莉::https://www.pornpics.com/search/srch.php?q=lolita&limit=20&offset={{(page-1)*20}}\r\n青少年::https://www.pornpics.com/search/srch.php?q=teenager&limit=20&offset={{(page-1)*20}}\r\n白::https://www.pornpics.com/search/srch.php?q=white&limit=20&offset={{(page-1)*20}}\r\n自拍::https://www.pornpics.com/search/srch.php?q=Selfie&limit=20&offset={{(page-1)*20}}\r\n公开场合::https://www.pornpics.com/getchank2.php?rid=1&cat=102&limit=20&offset={{(page-1)*20}}\r\n肛::https://www.pornpics.com/search/srch.php?q=anus&limit=20&offset={{(page-1)*20}}\n",
    "sourceComment": "需VPN\n搜索自行替换关键字，只支持英文搜索\n<js>github@ifwlzs</js>",
    "sourceGroup": "R18",
    "sourceIcon": "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F5a93370d-5604-4420-82cb-dea9f6bf5573%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1681571427&t=bd6d35c7eeb261f7d2cf98747331db22",
    "sourceName": "pornpics",
    "sourceUrl": "https://www.pornpics.com/",
    "style": "img{\n\twidth:100%;\n\theight:auto;\n\t}##github@ifwlzs"
  },
  {
    "articleStyle": 0,
    "customOrder": 95,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "R18",
    "sourceIcon": "",
    "sourceName": "韩漫书源",
    "sourceUrl": "legado://import/bookSource?src=https://jt12.de/SYV2_4/2024/03/04/20/48/54/170955653465e5c33680046.json"
  },
  {
    "articleStyle": 0,
    "customOrder": 96,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "class.pb@tag.div",
    "ruleDescription": "",
    "ruleImage": "class.focus@tag.span@tag.img@src",
    "ruleNextPage": "class.pagination pagination-multi@class.next-page@tag.a@href",
    "rulePubDate": "class.text-muted time.0@text##发布于:",
    "ruleTitle": "class.excerpt excerpt-one.0@tag.header@tag.a@text",
    "singleUrl": true,
    "sourceGroup": "R18",
    "sourceIcon": "https://www.xx3004.vip/wp-content/themes/xiu/images/wap-logo.png",
    "sourceName": "美女写真",
    "sourceUrl": "https://www.san449.com/meinv"
  },
  {
    "articleStyle": 1,
    "customOrder": 97,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "li",
    "ruleContent": "class.stui-player__left@script.0@all##url\":\"([^\"]+.m3u8)##$1##\n<js>\nresult=result.replace(/\\\\/g,\"\")\r\nresult = \"<video src=\\\"\" + result + \"\\\" width=\\\"100%\\\" height=\\\"auto\\\" controls=\\\"controls\\\" ></video>\";\r\nresult = \"<html><head><meta charset=\\\"utf-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no\\\" /><style>html,body{margin:0;padding:0;width:100%;}</style></head><body>\" + result + \"</body></html>\"\n result\n</js>",
    "ruleDescription": "",
    "ruleImage": "a@data-original",
    "ruleLink": "a@href##.html##/sid/1/nid/1.html<js>##detail##play</js>",
    "ruleNextPage": "class.stui-page__item@tag.li.-2@a@href",
    "rulePubDate": "",
    "ruleTitle": "h4@text",
    "singleUrl": false,
    "sortUrl": "国产传媒::https://www.douyg.cc/index.php/vod/type/id/24.html\n\n無碼搜索::https://www.douyg.cc/index.php/vod/search/page/1/wd/%E7%84%A1%E7%A2%BC.html\n\n无码动漫搜索::https://www.douyg.cc/index.php/vod/search/page/1/wd/%E6%97%A0%E7%A0%81.html\n\n日本无码::https://www.douyg.cc/index.php/vod/type/id/28/page/1.html\n\n少女萝莉::https://www.douyg.cc/index.php/vod/type/id/35.html\n\n\n动漫::https://www.douyg.cc/index.php/vod/type/id/23.html\n",
    "sourceComment": "",
    "sourceGroup": "R18",
    "sourceIcon": "https://z3.ax1x.com/2021/06/30/RDkSyR.png",
    "sourceName": "逗阴馆(已补全)",
    "sourceUrl": "https://www.douyg.cc/",
    "style": ""
  },
  {
    "articleStyle": 1,
    "customOrder": 98,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "class.line_bottom@tr",
    "ruleContent": "class.entry@html",
    "ruleLink": "tag.a.0@href",
    "ruleNextPage": "page",
    "rulePubDate": "text",
    "ruleTitle": "a@title",
    "singleUrl": false,
    "sortUrl": "最新::https://3sdfs.enpeta.com/e/action/ListInfo/?classid=1",
    "sourceComment": "https://3sdfs.enpeta.com/e/action/ListInfo/?classid=1\n最新::https://31.enpeta.com/e/action/ListInfo/index.php?page={{page}}&classid=1",
    "sourceGroup": "202",
    "sourceIcon": "https://avatars.githubusercontent.com/u/49548316",
    "sourceName": "性趣套图",
    "sourceUrl": "https://enpeta.com"
  },
  {
    "articleStyle": 1,
    "customOrder": 99,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": ".aspect-ratio",
    "ruleContent": "class.max-width-md margin-x-auto margin-bottom-lg@all",
    "ruleImage": "img@data-src",
    "ruleLink": "a@href",
    "ruleNextPage": "",
    "rulePubDate": ".card-video__duration@text",
    "ruleTitle": "img@alt",
    "singleUrl": false,
    "sortUrl": "中國AV::https://ppp.porn/categories/china-av/\n日本片商::https://ppp.porn/categories/japan-producer/\n素人自拍::https://ppp.porn/categories/amateur/\n中國::https://ppp.porn/categories/china/\n台灣::https://ppp.porn/categories/taiwan/\n日本::https://ppp.porn/categories/japan/\n東南亞::https://ppp.porn/categories/se-asia/\n韓國::https://ppp.porn/categories/korea/\n香港::https://ppp.porn/categories/hongkong/\nCosplay::https://ppp.porn/categories/cosplay/\n主播::https://ppp.porn/categories/streamer/\n主觀視角::https://ppp.porn/categories/first-person-pov/\n凌辱::https://ppp.porn/categories/bdsm/\n劇情::https://ppp.porn/categories/drama/\n多P::https://ppp.porn/categories/threesome/\n探花::https://ppp.porn/categories/91-tanhua/\n流出::https://ppp.porn/categories/leaked/\n無碼::https://ppp.porn/categories/uncensored/\n野外露出::https://ppp.porn/categories/exhibitionists/\nOL::https://ppp.porn/categories/office-lady/\n動漫::https://ppp.porn/categories/acg/\n古裝::https://ppp.porn/categories/costume/\n女僕::https://ppp.porn/categories/maid/\n學生::https://ppp.porn/categories/student/\n旗袍::https://ppp.porn/categories/cheongsam/\n獸耳::https://ppp.porn/categories/kemonomimi/\n瑜伽褲::https://ppp.porn/categories/yoga-pants/\n真理褲::https://ppp.porn/categories/dolfin-shorts/\n絲襪::https://ppp.porn/categories/pantyhose/\n護士::https://ppp.porn/categories/nurse/\n過膝襪::https://ppp.porn/categories/knee-socks/",
    "sourceGroup": "1,18🚫禁",
    "sourceIcon": "https://i.postimg.cc/q7MH2x2p/IMG-20220716-132525.jpg",
    "sourceName": "P站",
    "sourceUrl": "https://ppp.porn/",
    "style": "video{width:100%}img{width:100%}"
  },
  {
    "articleStyle": 1,
    "customOrder": 100,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "ul",
    "ruleContent": "title@text&&id.video@all",
    "ruleImage": ".lazy@img",
    "ruleLink": "a@href",
    "ruleNextPage": "text.Next@href",
    "rulePubDate": "日期: {{@@.view@span@text}}      时长:{{@@class.image@text}}",
    "ruleTitle": "class.title@text",
    "singleUrl": false,
    "sortUrl": "最新视频::https://www.tasexy.com/new.html\n偷拍自拍::https://www.tasexy.com/list/129.html\n国产情侣::https://www.tasexy.com/list/180.html\n国产偷拍::https://www.tasexy.com/list/353.html\n自拍偷拍::https://www.tasexy.com/list/456.html\n国产色情::https://www.tasexy.com/list/455.html\n素人自拍::https://www.tasexy.com/list/454.html\n国产色情::https://www.tasexy.com/list/210.html\n国产色情:https://www.tasexy.com/list/222.html\n\n国产精品::https://www.tasexy.com/list/187.html\n国产自拍::https://www.tasexy.com/list/234.html\n国产自拍::https://www.tasexy.com/list/198.html\n短视频::https://www.tasexy.com/list/319.html\n女神学生::https://www.tasexy.com/list/243.html\n自慰群交::https://www.tasexy.com/list/248.html\n抖阴视频::https://www.tasexy.com/list/254.html\n小鸟酱::https://www.tasexy.com/list/260.html\n网曝门::https://www.tasexy.com/list/261.html\n水果派::https://www.tasexy.com/list/322.html\n颜射::https://www.tasexy.com/list/324.html\n韩国明星::https://www.tasexy.com/list/173.html\n国产女奴::https://www.tasexy.com/list/177.html\n网曝门::https://www.tasexy.com/list/466.html\n网红流出::https://www.tasexy.com/list/465.html\nCosplay::https://www.tasexy.com/list/463.html\n过膝袜::https://www.tasexy.com/list/462.html\n瑜伽裤::https://www.tasexy.com/list/461.html\n兽耳系列::https://www.tasexy.com/list/460.html\n91探花::https://www.tasexy.com/list/425.html\n",
    "sourceComment": "✪一夜爆裤制作✪\n✪名称后带\"@/封面VPN\"要翻墙✪\n✪更多分类自行添加✪\n 发布地址→https://www.662222.one/",
    "sourceGroup": "成人视频,@造,❤️",
    "sourceIcon": "https://img2.baidu.com/it/u=1877943053,1292683255&fm=253&fmt=auto&app=138&f=PNG?w=319&h=296",
    "sourceName": "百万视频@VPN",
    "sourceUrl": "https://www.tasexy.com/#dialog",
    "style": "iframe{\n\theight:420px\n}\ntitle{\n\tdisplay:block\n}"
  },
  {
    "articleStyle": 1,
    "customOrder": 101,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": ".item",
    "ruleContent": "id.kt_player@all&&script@all",
    "ruleImage": "img@data-original",
    "ruleLink": "a@href",
    "ruleNextPage": "",
    "rulePubDate": ".duration@text",
    "ruleTitle": "img@alt",
    "singleUrl": false,
    "sortUrl": "台灣::https://www.85po.com/tags/tai-wan/\n\t搜索::https://www.85po.com/search/{{(source.getVariable()==''||source.getVariable()==null)?source.setVariable('初中'):\"\"}}{{source.getVariable()}}.html\n\t巨乳::https://www.85po.com/tags/ju-ru/\n泰國::https://www.85po.com/tags/tai-guo/\n自拍::https://www.85po.com/tags/zi-pai/\n越南::https://www.85po.com/tags/yue-nan/\n近拍::https://www.85po.com/tags/jin-pai/\n日本::https://www.85po.com/tags/ri-ben/\n中國::https://www.85po.com/tags/zhong-guo/\n偷拍::https://www.85po.com/tags/tou-pai/\n韓國::https://www.85po.com/tags//han-guo/\n香港::https://www.85po.com/tags/xiang-gang/\n新馬::https://www.85po.com/tags/xin-ma/\n街拍::https://www.85po.com/tags/jie-pai/",
    "sourceGroup": "成人视频,@造,❤️",
    "sourceIcon": "https://85tube.com/favicon.ico",
    "sourceName": "85Tube梯子可用",
    "sourceUrl": "https://www.85po.com"
  },
  {
    "articleStyle": 0,
    "customOrder": 101,
    "enableJs": true,
    "enabled": true,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "版本",
    "sourceIcon": "",
    "sourceName": "每日大赛",
    "sourceUrl": "https://www.njttvylz.cc"
  },
  {
    "articleStyle": 2,
    "customOrder": 102,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "loginUrl": "",
    "ruleArticles": "id.masonry.0@class.item",
    "ruleContent": ".content@tag.img@data-original##\\n##\\$\n\n<js>\nli='\\n'\njava.log(result)\nlist=result.split('$')\nfor(i in list){\n\t     if(list[i].length<20) break;\n\t\tli += '<li><img src=\"/static/thumbnail.gif\" data-src=\"'+list[i]+'\"></li>\\n';\n\t}\nli\n</js>\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0\">\n\n\n<ul id=\"box\">\n{{result}}\n</ul>\n<h3>{{@@.song-info@h3@text}}</h3>\r\n<h6>{{@@id.myList@h4@text}}</h6>\n\n<link rel=\"stylesheet\" href=\"https://cdn.bootcdn.net/ajax/libs/viewerjs/1.10.1/viewer.min.css\">\r\n<script src=\"https://cdn.bootcdn.net/ajax/libs/viewerjs/1.10.1/viewer.min.js\"></script>\n<script>\n\troot = document.getElementById('box')\n\tlazy = new IntersectionObserver(entires => {\n\t\tentires.forEach(item => {\n\t\t\tif(item.isIntersecting){\n\t\t\t\titem=item.target\n\t\t\t\titem.src=item.getAttribute('data-src')\n\t\t\t\tlazy.unobserve(item)\n\t\t\t}\n\t\t})\n\t}, {\n\t\troot: root,\n\t\tthreshold: [0],\n\t\trootMargin:\"0px 0px 500px 0px\"\n\t})\n\nimgs = document.getElementsByTagName('img')\nArray.from(imgs).forEach(item => {\n\t\tlazy.observe(item)\n\t})\n\n//查看大图插件\nnew Viewer(root,{title:false,interval:3000})\n</script>",
    "ruleImage": "tag.img.0@data-original",
    "ruleLink": "tag.a.0@href",
    "ruleNextPage": "page",
    "rulePubDate": "class.item-sort.0@text",
    "ruleTitle": "class.item-link-text.0@text",
    "singleUrl": false,
    "sortUrl": "搜索::https://www.hentaiclub.net/search/{{source.getVariable()}}\nR15::/sort/r15.html/{{page}}/\nR18::/sort/r18.html/{{page}}/\n随机R15::/sort/r15.html/{{ Math.ceil(Math.random()*690) }}/\n随机R18::/sort/r18.html/{{ Math.ceil(Math.random()*309) }}/",
    "sourceGroup": "h",
    "sourceIcon": "",
    "sourceName": "绅士会所",
    "sourceUrl": "https://www.hentaiclub.net/",
    "style": "* {\n\tmargin: 0;\n\tpadding: 0\n}\nul {\n\tfont-size: 0;\n\theight: 100%;\n\toverflow-y: scroll\n}\nli {\n\tlist-style: none;\n\ttext-align: center\n}\nimg {\n\twidth: 100%;\n\theight: auto\n}"
  },
  {
    "articleStyle": 1,
    "customOrder": 103,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\"User-Agent\": \"Mozilla/5.0 (Linux; Android 13; 2211133C Build/TKQ1.220905.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Mobile Safari/537.36\"}",
    "lastUpdateTime": 1775586071363,
    "loadWithBaseUrl": true,
    "ruleArticles": ".grid_post-box",
    "ruleContent": "@js:\nlet images = [];\nlet regex = /<a\\s[^>]*?href\\s*=\\s*['\"]([^'\"]+\\.(?:jpe?g|png|gif|webp|bmp))['\"][^>]*>\\s*<img[^>]*>/gi;\nlet match;\nwhile ((match = regex.exec(result)) !== null) {\n    let realUrl = match[1];\n    images.push(`<img src=\"${realUrl}\" style=\"max-width:100%;display:block;margin:0px auto;\">`);\n}\nlet imageContent = images.join('');\nlet p = `\n<title>🏄Mengteen</title>\n<style>\n  * {margin: 0; padding: 0}\n  img {width: 100%;height: auto}\n  /* Mengteen阅图基础UI */\n  /* 返回按钮基础 */\n  #backToTopBtn {\n    display: none;\n    position: fixed;\n    bottom: 36px;\n    right: 18px;\n    z-index: 999;\n    border: none;\n    outline: none;\n    background: linear-gradient(135deg, #ADD8E6, #FFF8DC);\n    color: white;\n    cursor: pointer;\n    padding: 2px;\n    border-radius: 10%;\n    font-size: 18px;\n    box-shadow: 0 8px 32px rgba(70, 130, 180, 0.3);\n    transition: all 0.3s ease;\n    backdrop-filter: blur(4px);\n    border: 1px solid rgba(255, 255, 255, 0.3);\n  }\n  \n  #backToTopBtn:hover {\n    background: linear-gradient(135deg, #ADD8E6, #FFF8DC);\n    transform: scale(1.08);\n    box-shadow: 0 8px 25px rgba(70, 130, 180, 0.4);\n  }\n  \n  #backToTopBtn:active {\n    transform: scale(0.95);\n  }\n  \n  /* 图片加载完成提示基础 */\n  #image-loaded-toast {\n    position: fixed;\n    bottom: 33px;\n    left: 50%;\n    transform: translateX(-50%);\n    background: rgba(0, 0, 0, 0.7);\n    color: white;\n    padding: 10px 20px;\n    border-radius: 20px;\n    font-size: 14px;\n    z-index: 998;\n    backdrop-filter: blur(4px);\n    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);\n    opacity: 0;\n    transition: opacity 0.3s;\n    pointer-events: none;\n  }\n  \n  /* 标题卡片基础 */\n  #image-loaded-toast.show {\n    opacity: 1;\n  }\n</style>\n<div style=\"\n  text-align:center;\n  padding:50px 20px 20px;\n  margin:0 0 0px;\n  position:relative;\n  background:linear-gradient(135deg, #f0f7ff, #e6f0ff);\n\">\n  <!-- 标题卡片 -->\n  <div style=\"\n    position:relative;\n    z-index:10;\n    display:inline-block;\n    transform:translateY(-20px);\n    filter: drop-shadow(0 15px 25px rgba(70,130,180,0.25));\n  \">\n    <div style=\"\n      background:rgba(255,255,255,0.75);\n      backdrop-filter:blur(12px);\n      padding:16px 48px;\n      border-radius:18px;\n      border:1px solid rgba(255,255,255,0.5);\n      box-shadow:0 8px 32px rgba(70,130,180,0.2), inset 0 0 12px rgba(255,255,255,0.6);\n      position:relative;\n      overflow:hidden;\n    \">\n      <!-- 顶部高光 -->\n      <div style=\"\n        position:absolute;\n        top:0; left:0; right:0;\n        height:40%;\n        background:linear-gradient(to bottom, rgba(255,255,255,0.4), transparent);\n        pointer-events:none;\n      \"></div>\n      \n      <h3 style=\"\n        background:linear-gradient(135deg, #4a7bd0, #00a2b8);\n        -webkit-background-clip:text;\n        background-clip:text;\n        color:transparent;\n        font-size:1.3rem;\n        font-weight:700;\n        margin:0;\n        letter-spacing:-0.5px;\n        position:relative;\n        z-index:2;\n      \">{{@@h1@text}}</h3>\n      \n      <!-- 左下装饰点 -->\n      <div style=\"\n        position:absolute;\n        bottom:12px;\n        left:20px;\n        width:6px;\n        height:6px;\n        background:#00a2b8;\n        border-radius:50%;\n        opacity:0.7;\n      \"></div>\n      \n      <!-- 右下装饰点 -->\n      <div style=\"\n        position:absolute;\n        bottom:12px;\n        right:20px;\n        width:6px;\n        height:6px;\n        background:#4a7bd0;\n        border-radius:50%;\n        opacity:0.7;\n      \"></div>\n    </div>\n  </div>\n  \n  <!-- 时间信息 -->\n  <div style=\"\n    margin-top:0px;\n    padding:0px 20px;\n  \">\n    <h5 style=\"\n      color:#6c757d;\n      font-weight:400;\n      font-size:1rem;\n      margin:0;\n      line-height:1.6;\n      letter-spacing:0.3px;\n      position:relative;\n      display:inline-block;\n      max-width:700px;\n    \">\n      {{@@.post-meta-bottom@time.0@text}}\n      <!-- 下划线装饰 -->\n      <div style=\"\n        position:absolute;\n        bottom:-5px;\n        left:0;\n        width:100%;\n        height:1px;\n        background:linear-gradient(90deg, transparent, rgba(70,130,180,0.3), transparent);\n      \"></div>\n    </h5>\n  </div>\n  \n  <!-- 左上装饰圆 -->\n  <div style=\"\n    position:absolute;\n    top:10%;\n    left:15%;\n    width:40px;\n    height:40px;\n    border-radius:50%;\n    background:linear-gradient(135deg, rgba(74,123,208,0.1), transparent);\n    filter:blur(2px);\n  \"></div>\n  \n  <!-- 右下装饰圆 -->\n  <div style=\"\n    position:absolute;\n    bottom:15%;\n    right:10%;\n    width:60px;\n    height:60px;\n    border-radius:50%;\n    background:linear-gradient(135deg, rgba(0,162,184,0.1), transparent);\n    filter:blur(4px);\n    transform:rotate(30deg);\n  \"></div>\n</div>\n${imageContent}  <!-- 这里是图片内容 -->\n<div id=\"image-loaded-toast\">✅ 全部图片已完成加载</div>\n<button id=\"backToTopBtn\" title=\"回到顶部\">🔝</button>\n<script>\n(function() {\n  const backToTopBtn = document.getElementById(\"backToTopBtn\");\n  const toast = document.getElementById(\"image-loaded-toast\");\n  \n  // 图片加载完成检测\n  const images = document.querySelectorAll(\"img\");\n  let loadedCount = 0;\n  const totalImages = images.length;\n  \n  // 如果页面没有图片，直接隐藏提示\n  if(totalImages === 0) {\n    toast.style.display = \"none\";\n  }\n  \n  // 检测图片加载完成\n  images.forEach(img => {\n    if(img.complete) {\n      checkAllLoaded();\n    } else {\n      img.addEventListener(\"load\", checkAllLoaded);\n      img.addEventListener(\"error\", checkAllLoaded);\n    }\n  });\n  \n  function checkAllLoaded() {\n    loadedCount++;\n    if(loadedCount >= totalImages) {\n      showToast();\n    }\n  }\n  \n  function showToast() {\n    toast.classList.add(\"show\");\n    setTimeout(() => {\n      toast.classList.remove(\"show\");\n    }, 2000);\n  }\n  \n  // 监听页面滚动事件\n  window.addEventListener(\"scroll\", () => {\n    const scrollPosition = window.scrollY || document.documentElement.scrollTop;\n    \n    if (scrollPosition > 288) {\n      backToTopBtn.style.display = \"block\";\n      backToTopBtn.style.opacity = \"1\";\n    } else {\n      backToTopBtn.style.display = \"none\";\n    }\n  });\n  \n  // 点击事件监听器\n  backToTopBtn.addEventListener(\"click\", () => {\n    window.scrollTo({\n      top: 0,\n      behavior: \"smooth\"\n    });\n  });\n})();\n</script>\n`;\np;",
    "ruleImage": "img@data-src",
    "ruleLink": ".clearfix@data-href",
    "ruleNextPage": "page",
    "rulePubDate": "🏄Mengteen｜🔖{{@@.post-cat@text}}",
    "ruleTitle": "img@alt",
    "singleUrl": false,
    "sortUrl": "首页::/page/{{page}}/\n搜索::/page/{{page}}/?s={{(source.getVariable()==''||source.getVariable()==null)?source.setVariable('美女'):source.getVariable()}}\n女優画像::/category/avjoyuu/page/{{page}}/\n女高画像::/category/josikousei/page/{{page}}/\nおっぱい画像[美乳]::/category/oppai/page/{{page}}/\n太もも画像[美腿]::/category/hutomomo/page/{{page}}/\nオナニー画像[自慰]::/category/onani/page/{{page}}/\n野外セックス[野外啪啪]::/category/yagaisekkusu/page/{{page}}/\n乱交画像[群P]::/category/rankougazou/page/{{page}}/\nフェラ画像[口交]::/category/fera/page/{{page}}/\nクンニ画像[口交]::/category/kunnni/page/{{page}}/\nパイズリ画像[乳交]::/category/paizurigazou/page/{{page}}/\nレズ[女同]::/category/rezugazou/page/{{page}}/\nキス画像[接吻]::/category/kisugazou/page/{{page}}/\nSM::/category/smgazou/page/{{page}}/\n露出::/category/rosyutsugazou/page/{{page}}/\n偷拍::/category/tousatsugazou/page/{{page}}/\n素人::/category/sirouto/page/{{page}}/\n欧美::/category/gaizinerogazou/page/{{page}}/\n制服::/category/olgazou/page/{{page}}/\n泳衣::/category/mizugi/page/{{page}}/\n网袜::/category/amitaitsu/page/{{page}}/\n黑丝::/category/pannsuto/page/{{page}}/\n吊带::/category/ga-ta-beruto/page/{{page}}/\n浴衣::/category/yukatakimono/page/{{page}}/\n女仆::/category/meido/page/{{page}}/\n眼镜娘::/category/megane/page/{{page}}/",
    "sourceComment": "源社区：@Mengteen  2025.7.16\n二传二创或者是其它问题请联系我。\n我邮箱:[xxxmgqxxx@vip.qq.com]\n我QQ:99737563(备注来意)\n1.不需要挂🪜子,个别地方网络加载可能有点慢或者是需要挂🪜子才能访问，别急！\n2.使用了我自己的看图UI,卡片式标题,自适应全屏,一键返回顶上按钮,图片加载完成提示等。\n3.搜索和分类是按我自己个人喜欢的,你也可以放一些你自己喜欢的。",
    "sourceGroup": "涩图",
    "sourceIcon": "https://pashalism.com/wp-content/uploads/2022/03/2341-33.jpg",
    "sourceName": "👙工口画像",
    "sourceUrl": "https://pashalism.com/##@Mengteen",
    "variableComment": "🏄Mengteen提示：在此输入关键词搜索！"
  },
  {
    "articleStyle": 2,
    "customOrder": 104,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 1665869775181,
    "loadWithBaseUrl": true,
    "ruleArticles": "class.row justify-content-md-center@class.col-6 col-sm-4 col-lg-3 col-xl-2",
    "ruleContent": "[itemprop=\"thumbnailUrl\"]@content\n<js>\nresult=result.match(/hh\\/.+(?=\\/poster)/);\nresult=\"https://mymaster-uk.cyou/api/v3/\"+result+\"/master.m3u8\"\n</js>\n<link href=\"https://unpkg.com/video.js/dist/video-js.css\" rel=\"stylesheet\">\n<script src=\"https://unpkg.com/video.js/dist/video.js\"></script>\n<script src=\"https://unpkg.com/videojs-contrib-hls/dist/videojs-contrib-hls.js\"></script>\n<video src=\"{{result}}\" controls preload=\"auto\"  style='width: 100%;height: auto'></video>",
    "ruleImage": "tag.img@src",
    "ruleLink": "a@href\n<js>\nresult+=\"episode-\"+((source.getVariable==null||source.getVariable=='')?source.setVariable(\"1\"):source.getVariable()+\"/\")\n</js>",
    "ruleTitle": "tag.img@alt",
    "singleUrl": false,
    "sortUrl": "全部最新::https://hanime.xxx/hentai/<,page/{{page}}>/\n全部评分::https://hanime.xxx/hentai/<,page/{{page}}>/?m_orderby=rating\n全部热门::https://hanime.xxx/hentai/<,page/{{page}}>/?m_orderby=views\n\n无修最新::https://hanime.xxx/category/uncensored-hentai<,/page/{{page}}>\n无修评分::https://hanime.xxx/category/uncensored-hentai/<,page/{{page}}>/?m_orderby=rating\n无修热门::https://hanime.xxx/category/uncensored-hentai<,page/{{page}}>/?m_orderby=views\n百合最新::https://hanime.xxx/category/yuri/{{page}}/\n百合评分::https://hanime.xxx/category/yuri/{{page}}/?m_orderby=rating\n百合热门::https://hanime.xxx/category/yuri/{{page}}/?m_orderby=views\n\n触手最新::https://hanime.xxx/category/tentacle<,/page/{{page}}/>\n触手评分::https://hanime.xxx/category/tentacle<,page/{{page}}>/?m_orderby=rating\n触手热门::https://hanime.xxx/category/tentacle<,page/{{page}}>/?m_orderby=views\n\n熟女最新::https://hanime.xxx/category/milf/<,page/{{page}}/>\n熟女评分::https://hanime.xxx/category/milf/<,page/{{page}}>/?m_orderby=rating\n熟女热门::https://hanime.xxx/category/milf/<,page/{{page}}>/?m_orderby=views",
    "sourceGroup": "R18",
    "sourceIcon": "https://hanime.xxx/wp-content/uploads/2019/10/Logo-Hanime.png",
    "sourceName": "hanime.xxx",
    "sourceUrl": "https://hanime.xxx/hentai/",
    "style": "<style>.video-js .vjs-tech {position: relative !important;}</style>"
  },
  {
    "articleStyle": 2,
    "customOrder": 109,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "ul@li",
    "ruleContent": "<!DOCTYPE html>\r\n<html>\r\n\r\n<head>\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0\">\r\n    <link rel=\"stylesheet\" href=\"https://cdn.bootcdn.net/ajax/libs/viewerjs/1.10.1/viewer.min.css\">\r\n    <script src=\"https://cdn.bootcdn.net/ajax/libs/viewerjs/1.10.1/viewer.min.js\"></script>\r\n    <script src=\"http://libs.baidu.com/jquery/2.0.0/jquery.min.js\"></script>\n    {{@@tag.title@html}}\r\n</head>\r\n\r\n<body>\r\n    <h3>{{@@.h@tag.h1@text}}</h3>\r\n    <div id=\"box\">{{@@id.picg@tag.img@html}}</div>\r\n    <div id=\"loads\">加载中 </div>\r\n    <script>\r\n        var loads;\r\n        $(document).ready(function () {\r\n            var box = document.getElementById(\"box\");\r\n            loads = document.getElementById(\"loads\");\r\n            new Viewer(box, { title: false, interval: 3000 })\r\n            var i = 2;\r\n            var page = {{@@class.pagelist.0@tag.a.-2@textNodes##\\n}};\r\n            var url = \"{{baseUrl.replace('.html','_')}}\";\r\n            new IntersectionObserver(entries => {\r\n                if (entries[0].intersectionRatio) {\r\n                    if (entries[0].intersectionRatio <= 0) return;\r\n                    for (var j = 0; j < 1; j++) {\r\n                        fetchHtml(i, page, url);\r\n                        i += 1;\r\n                    }\r\n                }\r\n            }).observe(loads)\r\n        });\r\n\r\n\r\n        function fetchHtml(i, page, url) {\n        \t\r\n            if (i <= page) {\r\n                nurl = url + i + '.html';\r\n                $.ajax({\r\n                    url: nurl,\r\n                    dataType: 'html',\r\n                    success: function (html) {\r\n                        $('#box').append('<h5>' + (i) + '->' + (page) + '</h5>');\r\n                        $('#box').append($(html).find('p a img'));\r\n                        box.viewer.update();\r\n                    },\r\n                    error: function (xhr) { }\r\n                });\r\n            } else {\r\n                $('#loads').html(\"\");\r\n            }\r\n        }\r\n    </script>\r\n</body>\r\n\r\n</html>",
    "ruleImage": "img@src",
    "ruleLink": "a@href",
    "ruleNextPage": "page",
    "ruleTitle": "class.title@text",
    "singleUrl": true,
    "sortUrl": "套图::http://www.sytuk.com/shey/yingtiiurm/1_{{page}}.html\n\n日韩::http://www.sytuk.com/shey/yingtiiurm/2_{{page}}.html\n\n内衣::http://www.sytuk.com/shey/yingtiiurm/9_{{page}}.html\n\n萌妹::http://www.sytuk.com/shey/yingtiiurm/11_{{page}}.html\n\n精品::http://www.sytuk.com/shey/yingtiiurm/18_{{page}}.html\n\n高清::http://www.sytuk.com/shey/yingtiiurm/24_{{page}}.html\n\n无圣光::http://www.sytuk.com/shey/yingtiiurm/25_{{page}}.html",
    "sourceComment": "斧头帮全体同仁恭迎火云邪神，来根华子波",
    "sourceGroup": "版本",
    "sourceIcon": "天",
    "sourceName": "图",
    "sourceUrl": "http://www.sytuk.com/",
    "style": "/*标题相关*/\r\nh3{text-align:center}\r\nh6{margin-bottom:0}\r\nimg{width:100%}\nh5{margin-bottom:0;padding-left:5;}"
  },
  {
    "articleStyle": 2,
    "customOrder": 110,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "ul@li",
    "ruleContent": "   <h3>{{@@.h@tag.h1@text}}</h3>\r\n    <div id=\"box\">{{@@id.picg@tag.img@html}}</div>\r\n",
    "ruleImage": "img@src",
    "ruleLink": "a@href",
    "ruleNextPage": "page",
    "ruleTitle": "class.title@text",
    "singleUrl": false,
    "sortUrl": "摄影图库::http://www.sytuk.com/shey/yingtiiurm/11_1.html\n经典套图::http://www.jdtaotu.com/s.asp?keyword=%CD%F8%C2%B7\n女神美图::http://www.nsmeitu.com/s.asp?keyword=%CD%F8%C2%B7\n极品美女图::http://www.jpmnt.com/s.asp?keyword=%CD%F8%C2%B7\n高清网红图::http://www.gqwht.com/s.asp?keyword=%CD%F8%C2%B7\n漂亮网红图::http://www.plwht.com/s.asp?keyword=%CD%F8%C2%B7\n模特摄影图::http://www.mtsyt.com/s.asp?keyword=%CD%F8%C2%B7\n漂亮美图::http://www.plmeitu.com/s.asp?keyword=%CD%F8%C2%B7\n私房写真图::http://www.sfxzt.com/s.asp?keyword=%CD%F8%C2%B7\n极品女神图::http://www.jpnst.com/s.asp?keyword=%CD%F8%C2%B7\n国产写真图::http://www.gcxzt.com/s.asp?keyword=%CD%F8%C2%B7\n少女套图::http://www.sntaotu.com/s.asp?keyword=%CD%F8%C2%B7\n模特写真图::http://www.mtxzt.com/chis/wangluo/1.html",
    "sourceComment": "分类无法显示下一页",
    "sourceGroup": "版本",
    "sourceIcon": "天",
    "sourceName": "2.7",
    "sourceUrl": "http://www.mtxzt.com",
    "style": "/*标题相关*/\r\nh3{text-align:center}\r\nh6{margin-bottom:0}\r\nimg{width:100%}\nh5{margin-bottom:0;padding-left:5;}"
  },
  {
    "articleStyle": 0,
    "customOrder": 111,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": " {\n\"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36\",\"Cookie\":\"__cfduid=d150f32feeec7048d35993a8a642d2c0e1600348724; AVS=k29ctap8qhbuncoijpdkckr5v7\"\n}",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "class.left@class.row@class.game-item&&class.left@class.row@class.video-item",
    "ruleContent": "@js:\nheader={\"Referer\":baseUrl};\nheaders={\"headers\":JSON.stringify(header)}\nif(baseUrl.match(/gif/)){\nvar doc = org.jsoup.Jsoup.parse(result);\nvar gif = String(doc).match(/gif.{5,10}.webm/);\nvar preview = 'https://www.hentaicloud.com/media/'+gif;\n\nif(String(doc).match(/From Video/)){\nvar url = doc.select(\"div.fromvideo\").select(\"a\").attr(\"href\");\nvar allUrl = 'https://www.hentaicloud.com'+url;\nvar doc = org.jsoup.Jsoup.connect(allUrl).get();\nvar spt = doc.select(\"source\").toString();\nvar src = spt.match(/https.{36}hd.{5,10}mp4/);\nresult = '<body><div><video controls=\"true\" width=\"100%\" autoplay=\"true\" src ='+preview+'></div><div><a href='+src+' >点击看全片</a></div></body>'\n}else{  \nresult = '<body><div><video controls=\"true\" width=\"100%\" autoplay=\"true\" src ='+preview+'></div><div><a>此片暂无出处</a></div></body>'\n}\n\n}else{\nvar doc = org.jsoup.Jsoup.parse(result);\nvar spt = doc.select(\"source\").toString();\nvar src = spt.match(/https.{36}hd.{5,10}mp4/);\nvar video='<iframe src='+src+' width=\"100%\" height=\"560\" frameborder=\"no\" allowfullscreen=\"true\">'  \nresult = video}",
    "ruleImage": "tag.img@src",
    "ruleLink": "tag.a@href",
    "ruleNextPage": "page",
    "rulePubDate": "@js:\nvar doc = org.jsoup.Jsoup.parse(result)\nvar text = doc.select(\"div.info\").select(\"span\").textNodes();\nif(text.size()==3){\nvar view = text.get(2).toString();\nif(view==\" \"){view =\"无\";}\nvar episode =text.get(0).toString();\nif(episode ==\" \"|| episode ==\"-\"){episode =\"无\";}\nresult = episode+\"   观看:\"+view}else if(text.size()==4){\nvar view = text.get(3).toString();\nif(view==\" \"){view =\"无\";}\nvar episode =text.get(0).toString();\nif(episode ==\" \"|| episode ==\"-\"){episode =\"无\";}\nresult = episode+\"   观看:\"+view\n}else{result = \"可通过动图预览查找动画\"}\n",
    "ruleTitle": "tag.div@id&&class.name@text",
    "singleUrl": false,
    "sortUrl": "搜索::https://www.hentaicloud.com/search?search_type=videos&search_query=&search_type=videos&page={{page}}\n\n\n动图::https://www.hentaicloud.com/gifs?page={{page}}\n3D::https://www.hentaicloud.com/videos/3d-hentai?page={{page}}\n口交::https://www.hentaicloud.com/tags/Blowjob?page={{page}}\n无码::https://www.hentaicloud.com/tags/Uncensored?page={{page}}\n触手::https://www.hentaicloud.com/tags/Tentacle?page={{page}}\n扶她::https://www.hentaicloud.com/videos/futanari?page={{page}}\n恶魔::https://www.hentaicloud.com/tags/Demon?page={{page}}\n自慰::https://www.hentaicloud.com/tags/Masturbation?page={{page}}\n后宫::https://www.hentaicloud.com/tags/Harem?page={{page}}",
    "sourceGroup": "版本",
    "sourceIcon": "天",
    "sourceName": "2.8",
    "sourceUrl": "https://www.hentaicloud.com",
    "style": ""
  },
  {
    "articleStyle": 0,
    "contentBlacklist": "https://lupic.cdn.bcebos.com/,\nhttps://cpro.baidu.com/,\nhttps://eclick.baidu.com/,\nhttps://sofire.baidu.com/,\nhttps://analytics.woozooo.com/,\nhttps://statics.woozooo.com/",
    "customOrder": 112,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\n    'User-Agent': 'Mozilla/5.0 (Linux; Android 11; Pixel 3 XL Build/RQ3A.211001.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/102.0.4988.0 Mobile Safari/537.36 SearchCraft/3.9.2 (Baidu; P1 11) '\n}",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "<js>\njson=[];\nif(baseUrl.match(/★/)){\nlist=baseUrl.replace(/http.*?wd=\\s*/,'').split('★');\nfor(i in list){\nhref=list[i].match(/【(.*?)】/)[1];\ntext=list[i].match(/《(.*?)》/)[1];\nintro=list[i].match(/◎(.*?)◎/)[1];\nindex=list[i].match(/^(\\d+、\\d+、)/)?list[i].match(/^(\\d+、\\d+、)/)[1]:list[i].match(/^(.*?)【/)[1]\njson.push({text:text,src:href,intro:intro,index:index})\n}\n}\nJSON.stringify(json)</js>\n$.[*]",
    "ruleContent": "",
    "ruleImage": "$.src",
    "ruleLink": "$.index",
    "ruleNextPage": "",
    "rulePubDate": "$.intro",
    "ruleTitle": "$.text",
    "singleUrl": false,
    "sortUrl": "📲 导航::https://www.smdhb.com/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/smdy.png?ref=master】《神马电影导航吧》◎收集高清在线资源网站◎★https://anee.cc/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/ayys.png?ref=master】《安逸影视导航》◎一家集合全网影视专业导航网站◎★https://www.baicp.com/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/dydhw.png?ref=master】《电影导航网》◎电影网站大全◎★http://www.2cydh.com/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/ecydh.png?ref=master】《二次元导航》◎动漫、漫画网站大全◎★https://acgjj.cc/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/acgjj.png?ref=master】《ACG聚集》◎二次元宝藏资源聚合https://acgjj.org/◎★https://www.acgbox.link/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/acghz.png?ref=master】《ACG盒子》◎🚀VPN｜专注ACG的导航盒子◎★https://www.shangwaiwang.com/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/sww.png?ref=master】《上外网》◎🚀VPN｜外网网址导航◎\n\n\n📺 影视::https://www.btnull.net/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/wmxz.png?ref=master】《无名小站》◎fun,in,nu,org,to,si,com,net◎★https://www.66s6.net/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/xb6vdy.png?ref=master】《新版6V电影》◎6V电影网◎★https://www.appmovie.cc/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/appyy.png?ref=master】《APP影院》◎全网最全视频库◎★https://www.555dyy5.com/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/555dy.png?ref=master】《555电影》◎发布页地址：https://www.gtbyw.com/◎★https://cupfox.app/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/cbh.png?ref=master】《茶杯狐》◎中国最大的影视资源聚合搜索引擎◎★https://www.bdys10.com/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/bdys.png?ref=master】《哔嘀影视》◎发布页地址：https://www.bdys.me/◎★https://www.ikanbot.com/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/akjqr.png?ref=master】《爱看机器人》◎影视资源◎★https://www.nen9.com/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/qnys.png?ref=master】《青柠影视》◎最新电影在线观看◎★https://www.400blzx.com/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/dzm.png?ref=master】《谍战迷》◎抗日电视剧大全◎★https://ddys.pro/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/ddys.png?ref=master】《低端影视》◎超清在线视频｜https://ddys.info/◎★http://vi5kwix.gaku56.com/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/jjyy.png?ref=master】《竞技影院》◎免费高清电影院◎★https://www.libvio.fun/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/libvio.png?ref=master】《LIBVIO》◎海内外优质影视｜https://libvio.app/◎★https://www.wandou.la/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/wdpro.png?ref=master】《豌豆PRO》◎专业的电影搜索引擎◎★https://www.bttwo.net/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/lgbt.png?ref=master】《两个BT》◎发布地址：https://www.bttwo.vip/◎★https://www.fuju1.tv/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/fjtv.png?ref=master】《腐剧TV》◎腐剧、BL动漫、同性电影、百合◎★https://www.bl210.top/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/sgys.png?ref=master】《曙光影视》◎腐剧、耽美、泰剧暖光影视官网◎★https://www.tj8.top/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/ftjw.png?ref=master】《泰剧网》◎腐剧、耽美、泰剧暖光影视官网◎\n\n\n🎬 外影::https://wap.meijutt.tv/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/mjtt.png?ref=master】《美剧天堂》◎美剧天堂◎★https://www.mjutv.cn/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/mjw.png?ref=master】《美剧网》◎美剧网◎★http://www.tjtt.cc/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/tjtt.png?ref=master】《泰剧天堂》◎泰剧天堂◎★https://www.chaospace.xyz/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/chaospace.png?ref=master】《CHAOSPACE》◎外国影视资源站◎★https://www.hjutv.cn/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/hjw.png?ref=master】《韩剧网》◎韩剧网站◎★https://www.han-ju.cc/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/xhjw.png?ref=master】《新韩剧网》◎97韩剧网◎\n\n\n🐻‍ 动漫::http://m.yinghuavideo.com/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/yhdm.png?ref=master】《樱花动漫》◎专注动漫的门户网站◎★http://www.mxdm9.com/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/mxdm.png?ref=master】《MX动漫》◎专注在线动漫的樱花动漫备用网站◎★https://dm530.org/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/fcdm.png?ref=master】《风车动漫》◎拥有上万集高清晰画质的在线动漫◎★http://www.nicotv.club/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/nkdm.png?ref=master】《妮可动漫》◎追番补番的集中营，宅男腐女的秘密基地◎\n\n\n✔️ 解析::https://www.strerr.com/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/spfmxz.png?ref=master】《视频封面下载》◎油管、B站、N站、西瓜封面下载◎★https://www.m4411.com/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/syjx.png?ref=master】《鲨鱼解析》◎发布地址：https://www.ikan.club/◎★https://vip.yeyulingfeng.com/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/yylf.png?ref=master】《夜雨聆风》◎视频解析◎★https://superparse.com/【https://www.gitlink.org.cn/api/yi-c/tc/raw/dy/ys/superparse.png?ref=master】《超级解析》◎国内外知名视频网站解析◎",
    "sourceComment": "",
    "sourceGroup": "版本",
    "sourceIcon": "天",
    "sourceName": "2.9",
    "sourceUrl": "影视合集"
  },
  {
    "articleStyle": 0,
    "customOrder": 113,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "@js:\njson=[];\nif(baseUrl.match(/•/)){\nlist=baseUrl.replace(/http.*?wd=\\s*/,'').split('•');\nfor(i in list){\nhref=list[i].match(/【(.*?)】/)[1];\ntext=list[i].match(/《(.*?)》/)[1];\njson.push({text:text,href:href})\n}\n}else{\nlist=baseUrl.replace(/http.*?wd=/,'');\nhref=list.match(/【(.*?)】/)[1];\ntext=list.match(/《(.*?)》/)[1];\njson.push({text:text,href:href})\n}\njson",
    "ruleLink": "href",
    "rulePubDate": "href",
    "ruleTitle": "text",
    "singleUrl": false,
    "sortUrl": "说明:\n\n⓪ 不要相信网站广告!!!\n错信广告照成的金钱损失本人概不负责。\n\n\n① [Pro]的诞生\n全靠@关耳大佬的模板，感谢大佬\n\n② 网站来源:\n大部分来自 源仓库分享\n小部分来自 酷安评论区\n\n③ 关于启用和未启用:\n[保证能打开，不保证能看]\n启用 发布时会确认能打开网站\n未启用 没检查网站可能不能用\n\n④ 如何增加网站?:[网站格式]\n[7.0前]\n你喜欢的名字   两个\":\"   http://+网站  保存后就可以找到添加的网站了-大部分网站都适用\n\n[7.0(Pro)后]\n分类名称 两个\":\" http://www.baidu.com?wd=【网址1】《网站名称1》•【网址2】《网站名称2》\n新分类格式如上\n\n⑤ 关于导航:[互相套娃]\n顺着一个导航网站你能找到十个导航网站\n12个导航能让你找到100⁺的网站(迷路警告)\n\n\n──────已──启──用──────\n\n\n🔎 常用[10]::http://www.baidu.com?wd=【https://m.baidu.com】《🔎 | 百度一下》•【http://www.huapuzi.com】《💰 | 花铺子》•【https://huaban.com/favorite/beauty】《📸 | 花瓣网》•【https://a7a7.net/meitu】《📸 | 阿七美图》•【http://pic.sogou.com/pic/searchList.jsp?uID=&v=5&statref=index_form_1&spver=0&rcer=&keyword=%E7%BE%8E%E5%A5%B3】《📸 | 搜狗》•【https://vt.sm.cn/api/commonPage/index?type=pic&source=sc&scname=life_show_general_image&uc_param_str=dnntnwvepffrgibijbprsvdsdicheiniut#/%E7%BE%8E%E5%A5%B3//latest:1】《📸 | 夸克》•【https://m.baidu.com/sf/vsearch?pd=image_content&atn=page&fr=alawise&tn=vsearch&sa=tb&oq=%E5%85%85%E6%B0%94%E5%A8%83%E5%A8%83&word=%E7%BE%8E%E5%A5%B3&vs_req_t=1612074463274】《📸 | 百度》•【https://cn.bing.com/images/search?q=%E7%BE%8E%E5%A5%B3&form=QBIR】《📸 | 必应》•【https://www.feixuew.com】《🔞🗂️📥》•【http://m.u9h.com/top.html】《🔞🎮📥》\n\n\n📸 美图[12]::http://www.baidu.com?wd=【http://bzgif.com】《动图 | 暴走动图》•【http://www.qmsgif.com】《动图 | 秋名动图》•【https://www.ikmjx.com】《📸 | 买家秀》•【https://mmz.moe】《📸 | 萌妹子》•【https://m.appjpg.com】《📸 | 美女写真》•【https://www.f4mm.com】《📸 | F4mm》•【https://openys.cn/category/znns】《📸 | 宅男女神》•【https://www.1bie.com】《📸 | 娇妻美图》•【http://www.630h.com】《📸 | 630美图》•【https://www.ameitu.com】《📸 | 爱美图库》•【https://m.24tupian.org】《📸 | 爱死美图》•【http://www.skinnyeroticteens.com】《欧美 | 少女美图》\n\n\n🎨 漫画[12]::http://www.baidu.com?wd=【http://mm.vvvv.网址】《爱你 | 网站合集》•【https://www.mh-mh.com】《A | 看漫画》•【https://manhua.zsh8.com】《A | 芝士豪八》•【https://18comic.bet】《A⁻ | 禁漫天堂》•【https://www.ikanwzd.top】《A⁻ | 久久漫画》•【http://wzdhm.cc】《A⁻ | 韩国漫画》•【https://m.svipmh.com】《B⁺ | svip漫画》•【http://m.kmh8.net】《B | 看漫画吧》•【http://m.zwenquan.com】《B | 邪恶集》•【http://m.bancangyang.com】《B | 邪恶道》•【http://m.lifanbzk.org】《B | 里番本子库》•【http://m.che43.com】《B | 邪琉璃神社》\n\n\n📺 视频[21]::http://www.baidu.com?wd=【http://sp.vvvv.网址】《爱你 | 网站合集》•【http://h.zy40.cn/gjdq/dh/inde.html】《智云 | 网站合集》•【http://h.zy40.cn/z/sejso.php】《智云 | 智云视频》•【https://pwa.litchihouse.cn】《📺 | 鲁兔》•【https://lutu.club】《📺 | 鲁兔②》•【http://sese7218.com】《📺 | 色色碰》•【http://sese7888.com】《📺 | 色色碰②》•【https://5gtsc5.xyz】《📺 | 5G影院》•【https://www.770dy.com】《📺 | 七七影院》•【http://www.shejj.ga】《📺 | 射姐姐》•【https://www.66se14.com】《📺 | 66色》•【https://8x5098x.com/html/category/video】《📺 | 八X》•【https://yuanqi06.com/category/lunli】《📺 | 艾尔》•【https://www.myq6m1yx64y5uq88bph.xyz:59980】《📺 | 密芽》•【http://niugua04.com】《📺 | 牛瓜》•【https://qq.com.tieniu06.xyz】《📺 | 铁牛》•【https://www.kdtjq.com】《📺 | 宅男俱乐部》•【https://nckk58.com】《难加载 | 📺 | 嫩草》•【https://ny012.xyz】《难加载 | 📺 | 嫩芽》•【https://www.62362734c46affbd.com/index/home.html】《难加载 | 屏蔽移动 | 四色》•【https://www.e0fe9e2b1da0.com/index/home.html】《难加载 | 屏蔽移动 | 猫咪》\n\n\n🔞 小说[14]::http://www.baidu.com?wd=【http://www.5je.net】《发布 | 版主》•【http://www.jiuai1.top】《发布 | 久爱》•【https://xvlog.xyz】《A | 闲暇》•【https://bk301.xyz】《A | 锁狼》•【https://xrw6.xyz】《A⁻ | 夏日》•【https://crazyfiction.xyz】《A⁻ | 瘋情》•【http://www.krxs.xyz】《A⁻ | 狂人》•【http://www.xiusexx.xyz】《B⁺ | 羞涩》•【http://www.pqz999.top】《B⁺ | 茄子》•【http://www.xqxs.xyz】《B⁺ | 胸器》•【http://www.692653.com】《B⁺ | 渣男》•【http://www.zwxs.buzz】《B⁺ | 宅污》•【http://www.833179.com】《B | 色虎》•【http://www.hxsxs1.xyz】《B | H小说吧》\n\n\n🌐 导航[23]::http://www.baidu.com?wd=【https://www.moefuns.vip】《导航 | 萌翻》•【http://app.sgj168.com】《导航 | 哇我家》•【http://zjh.wtf】《导航 | 宅聚合》•【https://zhaijuhe.com/?tj】《导航 | 宅聚合②》》•【https://www.hxsb.org】《导航 | 小说吧》•【http://buliang7.com】《导航 | 不良研究所》•【https://mimi-70.com】《导航 | 秘密入口》•【http://mmtd.fun】《导航 | 秘密通道》》•【http://yy-b.ppyaya.com:8880】《导航 | YY》•【https://i7dios.cn】《导航 | 蜜桃》•【http://lemon1.info/】《导航 | 柠檬》•【http://www.du373.top】《导航 | 多多》•【http://jimeng.org】《导航 | 激萌》•【http://qrpnvcjndkfjha--012517.cdnmd0113.mdoudh.com:8880】《导航 |麻豆》•【https://uvbobo.xyz】《导航 | 波波》•【http://lwdh.in】《导航 |老王》•【https://xinbiao.info】《导航 | 信标》•【https://www.xingdh.com】《导航 | 杏导航》•【http://lang81.com】《导航 | 狼导航》•【https://www.xlldh.space】《导航 | 小萝莉》•【http://yuenuge.cc】《导航 | 阅女阁》•【http://laosj666.xyz】《导航 |老司机》•【https://www.tommaodh.me】《导航 | Tom猫》\n\n\n📱 发布页[8]::http://www.baidu.com?wd=【https://mmrk.neocities.org】《导航 | 秘密入口》•【https://buliang.neocities.org】《导航 | 不良研究所》•【http://403mh.com】《🎨 | 可乐漫画》•【https://www.404hm.com】《🎨 | SVIP漫画》•【https://github.com/8x8xkpian/8x8x-love/wiki】《📺 | 八x》•【https://lutu.fun】《📺 | 鲁兔》•【https://lutu.me】《📺 | 鲁兔②》•【https://www.ebay.com/usr/seseporn】《📺 | 色色碰》",
    "sourceGroup": "版本",
    "sourceIcon": "http://47.105.79.245/anitama.jpg",
    "sourceName": "3.0",
    "sourceUrl": "特殊整合Pro[8.0 | 100/100]"
  },
  {
    "articleStyle": 2,
    "customOrder": 117,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\n  \"User-Agent\": \"Mozilla/5.0 (Linux; Android 13; SM-S918B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36\",\n  \"Referer\": \"https://qikzj.com/\"\n}",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": ".bricks-layout-item.repeater-item",
    "ruleContent": "@js:\nvar doc = org.jsoup.Jsoup.parse(result);\nvar myImgs = [];\n\n// 1. 严格锁定正文 ID，彻底避开 Related Posts 等外部组件\nvar contentHtml = \"\";\nvar mainBox = doc.getElementById(\"brxe-qoenez\");\nif (mainBox) {\n    contentHtml = mainBox.html();\n} else {\n    contentHtml = doc.select(\".brxe-post-content\").html();\n}\n\nif (contentHtml) {\n    // 2. 在限定范围内扫描高清图片链接\n    var regex = /https?:\\/\\/qikzj\\.com\\/wp-content\\/uploads\\/[^\"'\\s<>]*?\\.(?:jpg|jpeg|png|webp|gif)/gi;\n    var matches;\n    while ((matches = regex.exec(contentHtml)) !== null) {\n        var s = matches[0];\n        // 过滤 Logo 和头像\n        if (s.indexOf(\"logo\") === -1 && s.indexOf(\"avatar\") === -1) {\n            // 还原高清原图路径，去掉尺寸和缩放后缀\n            var cleanUrl = s.replace(/-\\d+x\\d+\\./i, \".\").replace(/-scaled\\./i, \".\");\n            if (myImgs.indexOf(cleanUrl) === -1) {\n                myImgs.push(cleanUrl);\n            }\n        }\n    }\n}\n\nvar displayTitle = (typeof title !== 'undefined' && title) ? title : \"QikZ Visuals\";\n\nvar h = \"<!DOCTYPE html><html><head><style>body{margin:0;background:#050505;color:#eee;font-family:sans-serif;padding-bottom:100px} .top{background:#111;color:#888;text-align:center;padding:15px;font-size:10px;text-transform:uppercase;letter-spacing:3px;border-bottom:1px solid #222} .header{padding:40px 25px;text-align:center} .img-list{padding:0 10px} .img-box{position:relative;margin-bottom:18px;background:#000;border-radius:2px;overflow:hidden;box-shadow:0 10px 30px rgba(0,0,0,0.5)} .img-box img{width:100%;display:block;height:auto} .img-num{position:absolute;bottom:10px;right:15px;background:rgba(0,0,0,0.6);color:#fff;padding:2px 8px;border-radius:2px;font-size:10px;font-family:monospace;font-weight:bold}</style></head><body>\";\nh += \"<div class='top'>HD VISUAL SHOWCASE</div>\";\nh += \"<div class='header'><h1 style='font-size:20px;margin:0;font-weight:300;color:#fff;line-height:1.4'>\" + displayTitle + \"</h1></div>\";\nh += \"<div class='img-list'>\";\nfor(var k=0; k<myImgs.length; k++){\n    h += \"<div class='img-box'><img src='\" + myImgs[k] + \"'><span class='img-num'>\" + (k+1) + \" / \" + myImgs.length + \"</span></div>\";\n}\nh += \"</div><p style='text-align:center;color:#333;font-size:10px;margin-top:60px;letter-spacing:2px'>QIKZ PHOTOGRAPHY GALLERY</p></body></html>\";\nresult = h;",
    "ruleImage": "@js:\nvar img = result.select(\"img\").first();\nif (img) {\n    var s = img.attr(\"data-src\") || img.attr(\"data-srcset\") || img.attr(\"src\");\n    if (s && s.indexOf(\" \") > 0) s = s.split(\" \")[0];\n    result = s;\n} else {\n    result = \"https://qikzj.com/favicon.ico\";\n}\nresult;",
    "ruleLink": "h3.dynamic a@href",
    "ruleNextPage": ".page-numbers.next@href",
    "ruleTitle": "h3.dynamic a@text",
    "singleUrl": false,
    "sortUrl": "",
    "sourceGroup": "版本",
    "sourceIcon": "https://qikzj.com/favicon.ico",
    "sourceName": "图",
    "sourceUrl": "https://qikzj.com"
  },
  {
    "articleStyle": 0,
    "customOrder": 119,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "版本",
    "sourceIcon": "天",
    "sourceName": "图",
    "sourceUrl": "http://www.sytuk.com/shey/yingtiiurm/1_{{page}}.html"
  },
  {
    "articleStyle": 0,
    "customOrder": 121,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "版本",
    "sourceIcon": "",
    "sourceName": "漫",
    "sourceUrl": "http://www.mxshm.top"
  },
  {
    "articleStyle": 0,
    "customOrder": 123,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "singleUrl": true,
    "sourceGroup": "版本",
    "sourceIcon": "天",
    "sourceName": "图",
    "sourceUrl": "http://www.hjtaotu.com/chis/gufeng/1.html"
  },
  {
    "articleStyle": 2,
    "customOrder": 140,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "class.item",
    "ruleContent": "<js>\n\nfunction getNext(){\n\n//下一页url，链接不全请补全\nnextUrl = java.getString('class.next@href')\n\n\n\n\t\tif(nextUrl!=\"\"){\n\t\t\t\tp++\n\t\tjava.toast('p'+p+'加载中...')\n\t\t\t\treturn getHtml()\n\t\t\t}\n\njava.toast('加载完成')\n\t\treturn result\n\t}\n\n\n\n\n\nfunction getHtml(){\ntry{\n\t\tajax = java.ajax(nextUrl)\n\t\tjava.setContent(ajax)\n\t\tresult += ajax\n\t\treturn getNext()\n\t}\n\n//ajax下一页报错时，会重新尝试两次。\n//超过三次失败就不再加载。\ncatch (err){\n\t\tif(e<4){\n\t\t\t\te++\n\t\t\tjava.toast('p'+p+'加载中...')\n\t\t\t\treturn getHtml()\n\t\t\t}\n\t\treturn result\n\t}\n}\n\np = e = 1\ngetNext()\n</js>\n\n\ntag.noscript@tag.img@src\n<js>\nli='\\n'\nlist=result.split('\\n')\nfor(i in list){\n\t\tli += '<li><img src=\"https://www.q10drfc.com/wp-content/themes/justnews/images/logo.png\" data-src=\"'+list[i]+'\"></li>\\n'\n\t}\nli\n</js>\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0\">\n\n\n<ul id=\"box\">\n{{result}}\n</ul>\n\n\n<link rel=\"stylesheet\" href=\"https://cdn.bootcdn.net/ajax/libs/viewerjs/1.10.1/viewer.min.css\">\r\n<script src=\"https://cdn.bootcdn.net/ajax/libs/viewerjs/1.10.1/viewer.min.js\"></script>\n<script>\n\troot = document.getElementById('box')\n\tlazy = new IntersectionObserver(entires => {\n\t\tentires.forEach(item => {\n\t\t\tif(item.isIntersecting){\n\t\t\t\titem=item.target\n\t\t\t\titem.src=item.getAttribute('data-src')\n\t\t\t\tlazy.unobserve(item)\n\t\t\t}\n\t\t})\n\t}, {\n\t\troot: root,\n\t\tthreshold: [0],\n\t\trootMargin:\"0px\"\n\t})\n\nimgs = document.getElementsByTagName('img')\nArray.from(imgs).forEach(item => {\n\t\tlazy.observe(item)\n\t})\n\n//查看大图插件\nnew Viewer(root,{title:false,interval:3000})\n</script>",
    "ruleDescription": "",
    "ruleImage": "tag.img@src##.*src=|&.*",
    "ruleLink": "tag.a.0@href",
    "ruleNextPage": "class.next@href",
    "rulePubDate": "{{@@class.item-category@text}} &nbsp; {{@@class.item-meta-left@text}}",
    "ruleTitle": "class.item-title@text",
    "singleUrl": false,
    "sortUrl": "美女图片::https://www.q10drfc.com/category/mntp\n三度_69::https://www.q10drfc.com/tag/%e4%b8%89%e5%ba%a6_69\n\n变量搜索::https://www.q10drfc.com/?s={{v=source.getVariable();(v!='',v!=null)?v:(source.setVariable('青春'),source.getVariable())}}\n\n秀人网::https://www.q10drfc.com/category/mntp/%e7%a7%80%e4%ba%ba%e7%bd%91\n爱尤物::https://www.q10drfc.com/category/mntp/%e7%88%b1%e5%b0%a4%e7%89%a9\n语画界::https://www.q10drfc.com/category/mntp/%e8%af%ad%e7%94%bb%e7%95%8c\n花漾show::https://www.q10drfc.com/category/mntp/%e8%8a%b1%e6%bc%beshow\n模范学院::https://www.q10drfc.com/category/mntp/%e6%a8%a1%e8%8c%83%e5%ad%a6%e9%99%a2\n美媛馆::https://www.q10drfc.com/category/mntp/%e7%be%8e%e5%aa%9b%e9%a6%86\n喵糖映画::https://www.q10drfc.com/category/mntp/%e5%96%b5%e7%b3%96%e6%98%a0%e7%94%bb\n雅拉伊::https://www.q10drfc.com/category/mntp/%e9%9b%85%e6%8b%89%e4%bc%8a\n爱蜜社::https://www.q10drfc.com/category/mntp/%e7%88%b1%e8%9c%9c%e7%a4%be\n嗲囡囡::https://www.q10drfc.com/category/mntp/%e5%97%b2%e5%9b%a1%e5%9b%a1\n星颜社::https://www.q10drfc.com/category/mntp/%e6%98%9f%e9%a2%9c%e7%a4%be\n尤美::https://www.q10drfc.com/category/mntp/%e5%b0%a4%e7%be%8e\n尤蜜荟::https://www.q10drfc.com/category/mntp/%e5%b0%a4%e8%9c%9c%e8%8d%9f\n头条女神::https://www.q10drfc.com/category/mntp/%e5%a4%b4%e6%9d%a1%e5%a5%b3%e7%a5%9e\n糖果画报::https://www.q10drfc.com/category/mntp/%e7%b3%96%e6%9e%9c%e7%94%bb%e6%8a%a5\n魅妍社::https://www.q10drfc.com/category/mntp/%e9%ad%85%e5%a6%8d%e7%a4%be\n尤物馆::https://www.q10drfc.com/category/mntp/%e5%b0%a4%e7%89%a9%e9%a6%86\n蜜桃社::https://www.q10drfc.com/category/mntp/%e8%9c%9c%e6%a1%83%e7%a4%be\n花の颜::https://www.q10drfc.com/category/mntp/%e8%8a%b1%e3%81%ae%e9%a2%9c\nDK御女郎::https://www.q10drfc.com/category/mntp/dk%e5%be%a1%e5%a5%b3%e9%83%8e\n猫萌榜::https://www.q10drfc.com/category/mntp/%e7%8c%ab%e8%90%8c%e6%a6%9c\n尤果网::https://www.q10drfc.com/category/mntp/%e5%b0%a4%e6%9e%9c%e7%bd%91\n星乐园::https://www.q10drfc.com/category/mntp/%e6%98%9f%e4%b9%90%e5%9b%ad\n猎女神::https://www.q10drfc.com/category/mntp/%e7%8c%8e%e5%a5%b3%e7%a5%9e\n克拉女神::https://www.q10drfc.com/category/mntp/%e5%85%8b%e6%8b%89%e5%a5%b3%e7%a5%9e\n熊川纪信::https://www.q10drfc.com/category/mntp/%e7%86%8a%e5%b7%9d%e7%ba%aa%e4%bf%a1\n果团网::https://www.q10drfc.com/category/mntp/%e6%9e%9c%e5%9b%a2%e7%bd%91\n轰趴猫::https://www.q10drfc.com/category/mntp/%e8%bd%b0%e8%b6%b4%e7%8c%ab\n兔几盟::https://www.q10drfc.com/category/mntp/%e5%85%94%e5%87%a0%e7%9b%9f\n波萝社::https://www.q10drfc.com/category/mntp/%e6%b3%a2%e8%90%9d%e7%a4%be\n美腿宝贝::https://www.q10drfc.com/category/mntp/%e7%be%8e%e8%85%bf%e5%ae%9d%e8%b4%9d\n推女神::https://www.q10drfc.com/category/mntp/%e6%8e%a8%e5%a5%b3%e7%a5%9e\n模特联盟::https://www.q10drfc.com/category/mntp/%e6%a8%a1%e7%89%b9%e8%81%94%e7%9b%9f\n激萌文化::https://www.q10drfc.com/category/mntp/%e6%bf%80%e8%90%8c%e6%96%87%e5%8c%96\n优星馆::https://www.q10drfc.com/category/mntp/%e4%bc%98%e6%98%9f%e9%a6%86\n薄荷叶::https://www.q10drfc.com/category/mntp/%e8%96%84%e8%8d%b7%e5%8f%b6\n萌缚::https://www.q10drfc.com/category/mntp/%e8%90%8c%e7%bc%9a\n推女郎::https://www.q10drfc.com/category/mntp/%e6%8e%a8%e5%a5%b3%e9%83%8e\n爱丝::https://www.q10drfc.com/category/mntp/%e7%88%b1%e4%b8%9d\n影私荟::https://www.q10drfc.com/category/mntp/%e5%bd%b1%e7%a7%81%e8%8d%9f\n村长的宝物::https://www.q10drfc.com/category/mntp/%e6%9d%91%e9%95%bf%e7%9a%84%e5%ae%9d%e7%89%a9\nDDY::https://www.q10drfc.com/category/mntp/ddy\n顽味生活::https://www.q10drfc.com/category/mntp/%e9%a1%bd%e5%91%b3%e7%94%9f%e6%b4%bb\n51Modo::https://www.q10drfc.com/category/mntp/51modo\nRosi::https://www.q10drfc.com/category/mntp/rosi\nDisi::https://www.q10drfc.com/category/mntp/disi\nIShow::https://www.q10drfc.com/category/mntp/ishow\nPans::https://www.q10drfc.com/category/mntp/pans\n中国腿模::https://www.q10drfc.com/category/mntp/%e4%b8%ad%e5%9b%bd%e8%85%bf%e6%a8%a1\nVGirl::https://www.q10drfc.com/category/mntp/vgirl\nRu1mm::https://www.q10drfc.com/category/mntp/ru1mm\nSityle::https://www.q10drfc.com/category/mntp/sityle\n美女写真杂烩::https://www.q10drfc.com/category/mntp/%e7%be%8e%e5%a5%b3%e5%86%99%e7%9c%9f%e6%9d%82%e7%83%a9\n中国美女写真::https://www.q10drfc.com/category/mntp/%e4%b8%ad%e5%9b%bd%e7%be%8e%e5%a5%b3%e5%86%99%e7%9c%9f\n台湾美女写真::https://www.q10drfc.com/category/mntp/%e5%8f%b0%e6%b9%be%e7%be%8e%e5%a5%b3%e5%86%99%e7%9c%9f\n韩国美女写真::https://www.q10drfc.com/category/mntp/%e9%9f%a9%e5%9b%bd%e7%be%8e%e5%a5%b3%e5%86%99%e7%9c%9f\n日本美女写真::https://www.q10drfc.com/category/mntp/%e6%97%a5%e6%9c%ac%e7%be%8e%e5%a5%b3%e5%86%99%e7%9c%9f",
    "sourceComment": "原图标\nhttps://www.q10drfc.com/wp-includes/images/w-logo-blue-white-bg.png",
    "sourceGroup": "版本",
    "sourceIcon": "天",
    "sourceName": "5.3网页还能用",
    "sourceUrl": "https://www.q10drfc.com/category/mntp",
    "style": "*{\n\tmargin: 0;\n\tpadding: 0\n}\nul{\n\tfont-size: 0;\n\theight: 100%;\n\toverflow-y: scroll\n}\nli{\n\tlist-style: none;\n\ttext-align: center\n}\nimg{\n\twidth:100%;\n\theight:auto\n}",
    "variableComment": ""
  },
  {
    "articleStyle": 0,
    "customOrder": 145,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "header": "{\"User-Agent\": \"Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1\"}",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "article.masonry-post",
    "ruleContent": "@js:\nvar img_list=\"\";\ndata=java.getElements('.dynamic-entry-content@img')\nfor(i in data){\n\turl=data[i].attr('src')\n\timg_list+=`<img src=\"${url}\"/>\\n`\n}\nresult=`<html>\n<head>\n <title>${java.get('title')}</title>\n <meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no\">\n</head>\n<body>\n <div class=\"img_container\">\n   ${img_list}\n </div>\n</body>\n</html>`",
    "ruleImage": ".gb-block-image img@src",
    "ruleLink": "a@href##$##,{\"webView\":true}",
    "ruleNextPage": "a.next@href",
    "rulePubDate": "",
    "ruleTitle": ".gb-headline a@text\n<js>\njava.put('title',result)\n</js>",
    "singleUrl": false,
    "sortUrl": "最新::https://danryoku.com/\nNSFW::https://danryoku.com/category/nsfw/\nCOSPLAY::https://danryoku.com/category/cosplay/\n日本::https://danryoku.com/category/country/japan/\n中国::https://danryoku.com/category/country/china/{{page}}/\n韩国::https://danryoku.com/category/country/korea/\n台湾::https://danryoku.com/category/country/taiwan/\n西方::https://danryoku.com/category/country/western/\n搜索::https://danryoku.com/?s={{source.getVariable()}}/",
    "sourceComment": "DANRYOKU - Idol & Cosplay Photobook gallery\n网站：https://danryoku.com",
    "sourceGroup": "版本",
    "sourceIcon": "https://danryoku.com/favicon.ico",
    "sourceName": "5.8",
    "sourceUrl": "https://danryoku.com",
    "style": "*{margin:0;padding:0;}\nhtml,body{width:100%;height:100%;}\nh2{text-align:center;}\nimg{width:100%;height:auto;}"
  },
  {
    "articleStyle": 2,
    "customOrder": 156,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\n  \"User-Agent\": \"Mozilla/5.0 (Linux; Android 13; SM-S918B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36\",\n  \"Referer\": \"https://hksexdoll.com/\"\n}",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "@js:\n// 1. 列表规则分流\nif (baseUrl.includes(\"hksexdoll.com\")) {\n    // 娃娃：原版规则不动\n    result = org.jsoup.Jsoup.parse(result).select(\".brxe-ivopbr\");\n} else {\n    // 【关键修改】影视：只抓取 class=\"my-movie-grid\" 下面的 li\n    // 这样可以避开 WordPress 顶部的菜单栏干扰\n    result = org.jsoup.Jsoup.parse(result).select(\".my-movie-grid li\");\n}\nresult;",
    "ruleContent": "@js:\n// 5. 详情页跳转逻辑（原版逻辑保持不变）\nif (!baseUrl.includes(\"hksexdoll.com\")) {\n    // 只要不是娃娃官网，直接跳浏览器\n    java.startBrowser(baseUrl, \"正在前往...\");\n    result = \"正在跳转到外部浏览器播放...<br>\" + baseUrl;\n} else {\n    // 娃娃详情页解析（原版代码不动）\n    var doc = org.jsoup.Jsoup.parse(result);\n    var myImgs = [];\n    var rawList = doc.select(\".brxe-image-gallery img, .bricks-image-gallery img, noscript img, .entry-content img\");\n    for (var i = 0; i < rawList.size(); i++) {\n        var s = rawList.get(i).attr(\"data-src\") || rawList.get(i).attr(\"src\");\n        if (s && s.startsWith(\"http\") && !s.toLowerCase().includes(\".svg\") && !s.includes(\"100x100\") && !myImgs.includes(s)) {\n            myImgs.push(s);\n        }\n    }\n    var displayTitle = (typeof title !== 'undefined' && title && title !== \"null\") ? title : (doc.select(\"h1\").text() || \"1:1 Show\");\n    var h = \"<!DOCTYPE html><html><head><style>body{margin:0;background:#000;color:#eee;font-family:sans-serif;padding-bottom:50px} .top{background:#1a1a1a;color:#888;text-align:center;padding:12px;font-size:11px;position:sticky;top:0;z-index:99;letter-spacing:2px;border-bottom:1px solid #222} .header{padding:35px 20px 20px;background:#000;text-align:center} .img-wrap{padding:0 8px} .img-item{position:relative;margin-bottom:10px;border-radius:2px;overflow:hidden} .img-item img{width:100%;display:block;background:#111} .img-count{position:absolute;bottom:8px;right:10px;background:rgba(0,0,0,0.4);color:#999;padding:2px 6px;border-radius:2px;font-size:10px;font-family:monospace}</style></head><body>\";\n    h += \"<div class='top'>HD VISUAL SHOWCASE</div>\";\n    h += \"<div class='header'><h1 style='font-size:19px;margin:0;font-weight:400;color:#fff;letter-spacing:0.5px'>\" + displayTitle + \"</h1></div>\";\n    h += \"<div class='img-wrap'>\";\n    for(var k=0; k<myImgs.length; k++){\n        h += \"<div class='img-item'><img src='\" + myImgs[k] + \"'><span class='img-count'>\" + (k+1) + \" / \" + myImgs.length + \"</span></div>\";\n    }\n    h += \"</div><p style='text-align:center;color:#222;font-size:9px;margin-top:30px;letter-spacing:1px'>EXHIBITION ONLY</p></body></html>\";\n    result = h;\n}\nresult;",
    "ruleImage": "@js:\n// 4. 图片分流\nif (baseUrl.includes(\"hksexdoll.com\")) {\n    // 娃娃：原版规则不动\n    var img = result.select(\"img\").first();\n    result = img ? (img.attr(\"data-src\") || img.attr(\"src\")) : \"\";\n} else {\n    // 【关键修改】影视：抓取你代码里的 Google API 图标\n    var img = result.select(\"img\").first();\n    // 如果抓到了图就用图，抓不到就用默认图标兜底\n    result = img ? img.attr(\"src\") : \"https://goradioai.com/favicon.ico\";\n}\nresult;",
    "ruleLink": "@js:\n// 3. 链接分流\nif (baseUrl.includes(\"hksexdoll.com\")) {\n    var el = result.select(\"a.brxe-sfypzq\").first();\n    result = el ? el.attr(\"href\") : \"\";\n} else {\n    var el = result.select(\"a\").first();\n    result = el ? el.attr(\"href\") : \"\";\n}\nresult;",
    "ruleNextPage": "text.Next@href || .next.page-numbers@href",
    "ruleTitle": "@js:\n// 2. 标题分流\nif (baseUrl.includes(\"hksexdoll.com\")) {\n    result = result.select(\".product-title a\").text();\n} else {\n    // 影视：直接获取文本（会自动忽略掉 img 标签，只留文字）\n    result = result.text();\n}\nresult;",
    "singleUrl": false,
    "sortUrl": "全部展示::/shop/\n🎬 影视大全::https://goradioai.com/share/",
    "sourceGroup": "版本",
    "sourceIcon": "https://hksexdoll.com/favicon.ico",
    "sourceName": "7.0",
    "sourceUrl": "https://hksexdoll.com"
  },
  {
    "articleStyle": 1,
    "customOrder": 158,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "{\"User-Agent\":\"Mozilla/5.0 (Linux; Android 11; PCAM10 Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4103.106 Mobile Safari/537.36\"} ",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "[class=\"H5__content\"]@[class=\"video__wrap\"]@a",
    "ruleContent": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<title>内容提取-双模版</title>\n\n<script src=\"https://code.jquery.com/jquery-3.6.0.min.js\"></script>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.3/viewer.min.css\" />\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.3/viewer.min.js\"></script>\n<style>\n    body {font-family: Arial, sans-serif;font-size: 16px;}\n    #title, #page, #loading-status {margin: 0 auto;font-size: 20px;text-align: center;}\n    #description, #urls, #video-url, #video-sources, #messages {width: 100%;max-width: 800px;margin: 1.5px auto;font-size: 14px;text-align: left;word-wrap: break-word;white-space: pre-wrap;}\n    #text, #text :not(img), #text img + * {text-indent: 2em;width: 100%;font-size: 16px;line-height: 1.5em;margin-top: 0;margin-bottom: 0;word-wrap: break-word;white-space: pre-wrap;}\n    img, #text img {width: 100%;height: auto;display: block;margin-bottom: 1.5px;}\n    .flex-container {display: flex;justify-content: center;align-items: center;gap: 10px;margin: 1.5px 0;font-size: 14px;}\n    button, select {flex: 1 1 31%; padding: 3px;border: 1px solid #ccc;border-radius: 5px;box-sizing: border-box;cursor: pointer;background-color: #f9f9f9;transition: background-color 0.3s ease;margin: 1.5px;min-width: 0;font-size: 14px;}\n    #url-select, #video-source-select {flex: 1 1 100%; margin-left: 0;margin-right: 0;text-align: center;}\n    #video-element {width: 100%;height: auto;}\n    textarea {width: 100%;height: auto;min-height: 100px;box-sizing: border-box;resize: vertical;}\n    .error, .warn {color: red;}\n    #urls,#messages,#debug-info,#video-url,#video-container,#video-source-select,#images,#text {display:none;}\n</style>\n</head>\n<body>\n    <h3 id=\"title\">{{@@title@text||h1.0@text||h2.0@text||.title.0@text##高清在线观看|-国产剧| - 专享影视| - 热门高清|影视大全|海外华人|高清1080p|无广告影院|\\|}}</h3>\n    <p id=\"description\">{{@@.info.0@html||.jianjie@html}}</p>\n    <p id=\"page\">共<span id=\"total-pages\">1</span>页</p>\n    <p id=\"loading-status\" style=\"display:none;\"></p>\n    <div class=\"flex-container\" id=\"loading-buttons\" style=\"display:none;\">\n        <button id=\"prev-page-btn\">上一页</button>\n        <button id=\"next-page-btn\">下一页</button>\n        <button id=\"auto-load-btn\">自&nbsp;&nbsp;动</button>\n    </div>\n    <div class=\"flex-container\">\n        <select id=\"url-select\" style=\"display:none;\"></select>\n    </div>\n    <div class=\"flex-container\">\n        <button id=\"toggle-urls-btn\">显/隐网址</button>\n        <button id=\"toggle-messages-btn\">显/隐信息</button>\n        <button id=\"toggle-debug-btn\">显/隐调试</button>\n    </div>\n    <div id=\"urls\"></div>\n    <div id=\"messages\"></div>\n    <div id=\"debug-info\"></div>\n    <div id=\"video-url\"></div>\n    <div id=\"video-container\">\n        <video id=\"video-element\" controls preload=\"auto\" width=\"640\" height=\"264\">\n            <source id=\"video-source\" src=\"\" type=\"\">\n            您的浏览器不支持 video 标签。\n        </video>\n    </div>\n    <div class=\"flex-container\">\n        <select id=\"video-source-select\" onchange=\"updateVideoSource()\"></select>\n    </div>\n    <div id=\"images\"></div>\n    <div id=\"text\"></div>\n    <script>\nconst config = {    \n    videoSelector: 'body', // 视频选择器\n    imgSelector: '.gridlane-box-inside img', // 图片选择器\n    textSelector: '#content', // 文本选择器\n    debugSelector: '.player-wrapper', // 调试信息选择器\n    swapImageAttributes: false, // 是否交换图片属性\n    delayTime: 1500, // 延迟提取时间\n    retryDelayTime: 1500, // 重试加载延迟时间\n    maxLoadAttempts: 3, // 最大加载次数\n    autoLoading: false, // true自动模式，false单页模式\n    debugOnce: 0, // 只在特定索引输出一次调试信息\n         /* -网页拼接-*/    \n    totalPagesText: '{{@@.pager@li.-3@a@textNodes}}', // 总页码\n    urlSuffixToRemove: /\\.aspx$/, // 移除url后缀\n    pageUrlText: '{urlPrefix}p{i}.aspx', // 拼接URL模板        \n        /* -以上拼接模式（网址需要拼接）-*/\n        /* -上下分割线-*/\n        /* -以下列表模式（地址与目录对应，比如视频、漫画）-*/   \n    ListMode: true, // true网址列表模式，false网址拼接模式    \n    initialUrls: `{{@@#sort-item-5.0@a@href}}`, // 网址\n    initialUrlsName: `{{@@#sort-item-5.0@a@span@text}}`, // 网址名称\n    sourceurl: '', // 来源URL前缀\n};\n\nlet videoSources = [];\nlet loadAttempts = {};\nlet urls = [];\nlet imageBox;\nlet textBox;\nlet currentPageIndex = 0;\nlet canLoadNextPage = true;\nlet autoLoadInProgress = false;\n\n// 构建URL列表\nfunction buildUrls(totalPages, baseUrl) {\n    let initialUrlsArray = config.initialUrls.trim().split('\\n').filter(url => url.trim() !== '');\n    let initialUrlsNameArray = config.initialUrlsName.trim().split('\\n').filter(name => name.trim() !== '');\n\n    if (config.ListMode && initialUrlsArray.length > 0) {\n        if (initialUrlsArray.length !== initialUrlsNameArray.length) {\n            $('#messages').append(`<span class=\"warn\">警告：initialUrls 和 initialUrlsName 的长度不匹配。</span><br>`);\n        }\n\n        urls = initialUrlsArray.map(url => {\n            if (config.sourceurl && url.startsWith('/') && !/^https?:\\/\\//i.test(url)) {\n                return config.sourceurl.replace(/\\/$/, '') + url;\n            } else {\n                return url;\n            }\n        });\n\n        urls.forEach((url, index) => {\n            const name = initialUrlsNameArray[index] || `第 ${index + 1} 页`;\n            $('#url-select').append(`<option value=\"${index}\">${name}</option>`);\n            $('#urls').append(`<div>${name}: ${url}</div>`);\n        });\n    } else {\n        if (totalPages === 1) {\n            urls.push(baseUrl);\n        } else {\n            urls.push(baseUrl);\n            for (let i = 2; i <= totalPages; i++) {\n                urls.push(config.pageUrlText.replace('{urlPrefix}', baseUrl.replace(config.urlSuffixToRemove, '').replace(/\\/$/, '')).replace('{i}', i));\n            }\n        }\n\n        urls.forEach((url, index) => {\n            const name = `第 ${index + 1} 页`;\n            $('#url-select').append(`<option value=\"${index}\">${name}</option>`);\n            $('#urls').append(`<div>${name}: ${url}</div>`);\n        });\n    }\n\n    $('#total-pages').text(urls.length);\n    toggleNavigationButtons();\n}\n\nfunction normalizeUrl(url) {\n    if (typeof url!== 'string' ||!url.trim()) return '';\n    url = url.replace(/\\\\u[\\dA-F]{4}/gi, (match) => String.fromCharCode(parseInt(match.replace(/\\\\u/g, ''), 16)));\n    url = decodeURIComponent(url);\n    url = url.replace(/^http:\\/([^/])/, 'http://$1'); // 修正 http:/ 协议部分\n    url = url.replace(/^https:\\/([^/])/, 'https://$1'); // 修正 https:/ 协议部分\n    return url;\n}\n\n// 清空容器\nfunction clearContainers() {\n    $('#messages').empty();\n    $('#images').empty();\n    $('#text').empty();\n}\n\n// 更新图片的src属性\nfunction updateImageSrc(elements, shouldSwap) {\n    elements.each(function () {\n        const $this = $(this);\n        const attrsToUpdate = {};\n        if (shouldSwap) {\n            ['data-original', 'data-src', 'data-url'].forEach(attr => {\n                if ($this.attr(attr)) {\n                    attrsToUpdate['src'] = $this.attr(attr);\n                }\n            });\n        }\n        $this.attr(attrsToUpdate);\n    });\n    return elements;\n}\n\n// 切换导航按钮和选择框的显示\nfunction toggleNavigationButtons() {\n    if ($('#url-select option').length > 1  && !config.autoLoading) {\n        $('#loading-buttons').show();\n        $('#url-select').show();\n    } else {\n        $('#loading-buttons').hide();\n        $('#url-select').hide();\n    }\n}\n\n// 显示加载状态\nfunction showLoadingStatus(pageNumber) {\n    const selectedOption = $('#url-select option:selected').text();\n    $('#loading-status').text(`正在加载：${selectedOption}`).show();\n}\n\n// 隐藏加载状态\nfunction hideLoadingStatus() {\n    $('#loading-status').hide();\n}\n\n// 内容提取函数内容\nfunction loadContent(index) {\n    if (index < 0 || index >= urls.length || !canLoadNextPage) return;\n    canLoadNextPage = false;\n    currentPageIndex = index;\n    $('#url-select').val(index);\n    $('#messages').append(`<div>当前地址: <span class=\"warn\">${urls[index]}</span> </div>`);\n    if (autoLoadInProgress) {\n        showLoadingStatus(index + 1);\n    }\n    $.ajax({\n        url: urls[index],\n        type: 'GET',\n        success: function (data) {\n            try {\n                const $data = $(data);\n                let updatedHtmlContent = data.replace(/(['\"])(\\/\\/)(?!\\/)/g, '$1https://')\n                    .replace(/src=\"upload/gi, 'src=\"/upload')\n                    .replace(/style=[\"'][^'\"]+[\"']/gi, '')\n                    .replace(/\\\\\\//g, '/');\n                const parser = new DOMParser();\n                const doc = parser.parseFromString(updatedHtmlContent, \"text/html\");\n\n                  // 添加调试标签输出信息\n                if (config.debugOnce === index) {\n                    const debugElements = $(doc).find(config.debugSelector);\n                    if (debugElements.length > 0) {\n                        const debugContents = $('<pre>').html(debugElements.clone().wrapAll('<div/>').parent().html()).html();\n                        $('#debug-info').html(`<span class=\"warn\">调试信息: <textarea rows=\"10\" cols=\"80\">${debugContents}</textarea></span>`);\n                    } else {\n                        $('#debug-info').html(`<span class=\"warn\">调试信息: <textarea rows=\"10\" cols=\"80\">调试信息未提取到内容，请检查选择器！</textarea></span>`);\n                    }\n                }\n\n                // 方法1：video标签获取视频地址\n                const videoContents = $(doc).find(config.videoSelector);\n                const videoTags = $(videoContents).find('video');\n                videoTags.each(function () {\n                    const videosrc = $(this).attr('src') || $(this).attr('data-src') || $(this).attr('data-original') || '';\n                    if (videosrc) {\n                        videoSources.push(videosrc);\n                    }\n                });\n                \n                // 方法2：source标签获取视频地址\n                const sources = $(videoContents).find('source');\n                sources.each(function () {\n                    const sourceSrc = $(this).attr('src') || $(this).attr('data-src') || $(this).attr('data-original') || '';\n                    if (sourceSrc) {\n                        videoSources.push(sourceSrc);\n                    }\n                });\n                \n                // 方法3：正则表达式获取视频地址\n                const regex = /['\"]https?[^'<>\"]+\\.(m3u8|mp4|webm|ogg|flv|mp3|m4a|wav|ape|flac)['\"]/ig;\n                const matches = data.match(regex);\n                if (matches) {\n                    const uniqueMatches = matches.filter((value, idx, self) => self.indexOf(value) === idx);\n    videoSources = videoSources.concat(uniqueMatches.map((match) => {\n        // 使用replace删除引号\n                const urlWithoutQuotes = match.replace(/['\"]/g, '');\n                return normalizeUrl(urlWithoutQuotes);\n                          }));\n                }\n\n                videoSources = videoSources.map(src => normalizeUrl(src.replace(/\\\\+/g, '')));\n                videoSources = [...new Set(videoSources)];\n\n                if (videoSources.length > 0) {\n                    $('#messages').append(`<span>成功提取到视频，找到 ${videoSources.length} 个视频。</span><br>`);\n                    videoSources.forEach((src, idx) => {\n                        $('#messages').append(`<div>视频地址:<span class=\"warn\"> ${src}</span><br></div>`);\n                        $('#video-source-select').append(`<option value=\"${idx}\">视频源 ${idx + 1}</option>`);\n                    });\n                    \n                    if (videoSources.length == 1) {\n                        $('#video-container').show();\n                        $('#video-url').show();\n                        $('#video-source-select').hide();\n                        updateVideoSource(); // 自动更新视频源\n                    } else if (videoSources.length > 1) {\n                        $('#video-container').show();\n                        $('#video-url').show();\n                        $('#video-source-select').show();\n                        updateVideoSource(); // 默认选择第一个视频源\n                    } else {\n                        $('#video-container').hide();\n                        $('#video-url').hide();\n                        $('#video-source-select').hide();\n                    }\n                } else {\n                    $('#messages').append(`<span class=\"warn\">未找到视频源。</span><br>`);\n                    $('#video-container').hide();\n                    $('#video-url').hide();\n                    $('#video-source-select').hide();\n                }\n\n                // 标签获图片\n                const $imgContents = $(doc).find(config.imgSelector);\n                const shouldSwap = config.swapImageAttributes;\n                const newContents = updateImageSrc($imgContents.clone(), shouldSwap);\n                $('#images').append(newContents).show();\n                if (newContents.length > 0) {\n                    $('#messages').append(`<span>成功提取图片，共 ${newContents.length} 张。</span><br>`);\n                    newContents.each(function () {\n                        const imgSrc =$(this).attr('src') || $(this).attr('data-original') || $(this).attr('data-src') || $(this).attr('data-url');\n                        $('#messages').append(`<div>地址:<span class=\"warn\"> ${imgSrc}</span><br></div>`);\n                    });\n                } else {\n                    $('#messages').append(`<span class=\"warn\">未提取到图片。</span><br>`);\n                }\n\n                // 标签获图文\n                const textContents = $(doc).find(config.textSelector).map(function () {\n                    const $currentContents = $(this);\n                    $currentContents.find('img + br, script, video, source').remove();\n                    $currentContents.html($currentContents.html().replace(/>\\s+/gi, '>').replace(/<\\/?br\\s*([^>]*)\\s*\\/?>/gi, '\\n').replace(/\\n+/g, '\\n'));\n                    return $currentContents.html();\n                }).get().join('');\n                if (textContents.trim()) {\n                    $('#text').append(`<span>${textContents}</span><br>`).show();\n                    $('#messages').append(`<span>成功提取图文。</span><br>`);\n                } else {\n                    $('#messages').append(`<span class=\"warn\">未提取到图文。</span><br>`);\n                }\n                \n                \n                if (autoLoadInProgress && currentPageIndex < urls.length - 1) {\n                    setTimeout(() => { \n                        canLoadNextPage = true;\n                        loadContent(currentPageIndex + 1); \n                    }, config.delayTime);\n                } else {\n                    canLoadNextPage = true;\n                    if (autoLoadInProgress) {\n                        hideLoadingStatus();\n                    }\n                }\n            } catch (parseError) {\n                $('#messages').append(`<span class=\"error\">解析页面内容时发生错误: ${parseError.message}</span><br>`);\n                handleLoadFailure(urls, index);\n            } finally {\n                if (imageBox) imageBox.viewer.update();\n                if (textBox) textBox.viewer.update();\n            }\n        },\n        error: function (jqXHR, textStatus, errorThrown) {\n            let errorMessage = `内容加载失败: ${urls[index]}`;\n            switch (textStatus) {\n                case 'timeout':\n                    errorMessage += ', 请求超时';\n                    break;\n                case 'abort':\n                    errorMessage += ', 请求被取消';\n                    break;\n                case 'parsererror':\n                    errorMessage += ', 解析响应出错';\n                    break;\n                default:\n                    errorMessage += `, 状态码: ${jqXHR.status}, 错误信息: ${errorThrown}`;\n                    break;\n            }\n            $('#messages').append(`<span class=\"error\">${errorMessage}</span><br>`);\n            handleLoadFailure(urls, index);\n        }\n    });\n}\n\n// 处理加载失败的情况\nfunction handleLoadFailure(urls, index) {\n    if (!loadAttempts[urls[index]]) {\n        loadAttempts[urls[index]] = 1;\n    } else {\n        loadAttempts[urls[index]]++;\n    }\n    if (loadAttempts[urls[index]] <= config.maxLoadAttempts) {\n        const retryMessage = `第${index + 1}页加载失败，正在进行第${loadAttempts[urls[index]]}次加载！`;\n        $('#messages').append(`<span class=\"error\">${retryMessage}</span><br>`);\n        setTimeout(() => { \n            canLoadNextPage = true;\n            loadContent(index); \n        }, config.retryDelayTime);\n    } else {\n        const finalErrorMessage = `第${index + 1}页加载失败，已达到最大尝试次数(${config.maxLoadAttempts})！`;\n        $('#messages').append(`<span class=\"error\">${finalErrorMessage}</span><br>`);\n        if (autoLoadInProgress && currentPageIndex < urls.length - 1) {\n            setTimeout(() => { \n                canLoadNextPage = true;\n                loadContent(currentPageIndex + 1); \n            }, config.delayTime);\n        } else {\n            canLoadNextPage = true;\n            if (autoLoadInProgress) {\n                hideLoadingStatus();\n            }\n        }\n    }\n}\n\n// 更新视频源\nfunction updateVideoSource() {\n    const selectedIndex = parseInt(document.getElementById('video-source-select').value);\n    const selectedSource = videoSources[selectedIndex];\n    document.getElementById('video-url').textContent = `视频地址:\\n ${selectedSource}`;\n\n    // 设置 video-source 的 src 属性\n    const videoSourceElement = document.getElementById('video-source');\n    videoSourceElement.src = selectedSource;\n\n    // 更新 video 元素的 src 属性\n    const videoElement = document.getElementById('video-element');\n    videoElement.load();\n\n    // 添加调试信息\n    $('#messages').append(`<span>更新视频源为: ${selectedSource}</span><br>`);\n}\n\n// 函数执行主体\n$(document).ready(function () {\n    imageBox = document.getElementById('images');\n    textBox = document.getElementById('text');\n    if (imageBox && textBox) {\n        new Viewer(imageBox, { title: true, interval: 2000 });\n        new Viewer(textBox, { title: true, interval: 2000 });\n    }\n\n    const totalPagesText = config.totalPagesText;\n    const totalPages = parseInt(totalPagesText, 10) || 1;\n    const baseUrl = '{{baseUrl}}';\n    \n    clearContainers();\n    $('#urls').empty();\n    $('#debug-info textarea').empty();   \n    $('#video-url').empty().hide();\n    $('#video-container').hide();\n    $('#video-source-select').empty().hide();\n    \n    buildUrls(totalPages, baseUrl);\n\n    const urlSelect = document.getElementById('url-select');\n    if (urlSelect.options.length > 0) {\n        urlSelect.value = '0'; \n        \n        if (config.autoLoading) {\n            autoLoadInProgress = true;\n            for (let i = 0; i < urls.length; i++) {\n                loadContent(i);\n            }\n        } else {\n            loadContent(0);\n        }\n    } else {\n        loadContent(0);\n    }\n\n    $('#url-select').change(function () {\n        clearContainers();\n        const selectedIndex = parseInt($(this).val());\n        loadContent(selectedIndex);\n    });\n    $('#prev-page-btn').click(function () {\n        clearContainers();\n        if (currentPageIndex > 0) {\n            loadContent(currentPageIndex - 1);\n        }\n    });\n    $('#next-page-btn').click(function () {\n        clearContainers();\n        if (currentPageIndex < urls.length - 1) {\n            loadContent(currentPageIndex + 1);\n        }\n    });\n    $('#auto-load-btn').click(function () {\n        autoLoadInProgress = true;\n        showLoadingStatus(1); \n        for (let i = currentPageIndex + 1; i < urls.length; i++) {\n            loadContent(i);\n        }\n    });\n    $('#toggle-messages-btn').click(function () { $('#messages').toggle(); });\n    $('#toggle-urls-btn').click(function () { $('#urls').toggle(); });\n    $('#toggle-debug-btn').click(function () { $('#debug-info').toggle(); });\n});\n    </script>\n</body>\n</html>",
    "ruleImage": "img@src",
    "ruleLink": "a@href",
    "ruleNextPage": "page||text.下一页@href",
    "rulePubDate": "p.-1@text\n",
    "ruleTitle": "h3.-1@text",
    "singleUrl": false,
    "sortUrl": "搜索::https://czy.yzfnb6.help/cn/home/web/index.php/vod/search.html?wd={{source.getVariable()}}\n最新上传::/cn/home/web/index.php/label/new/page/{{page}}.html\n熟母少妇::/cn/home/web/index.php/vod/type/id/20/page/{{page}}.html\n网红直播::/cn/home/web/index.php/vod/type/id/21/page/{{page}}.html\n自拍偷拍::/cn/home/web/index.php/vod/type/id/22/page/{{page}}.html\n强奸乱伦::/cn/home/web/index.php/vod/type/id/23/page/{{page}}.html\n高清国产::/cn/home/web/index.php/vod/type/id/24/page/{{page}}.html\n韩国专区::/cn/home/web/index.php/vod/type/id/25/page/{{page}}.html\n日本有码::/cn/home/web/index.php/vod/type/id/26/page/{{page}}.html\n日本无码::/cn/home/web/index.php/vod/type/id/27/page/{{page}}.html\n欧美情色::/cn/home/web/index.php/vod/type/id/28/page/{{page}}.html\n动漫卡通::/cn/home/web/index.php/vod/type/id/29/page/{{page}}.html\n三级伦理::/cn/home/web/index.php/vod/type/id/30/page/{{page}}.html",
    "sourceComment": "By小新\n永久地址：https://bqm.avds8.com/g/",
    "sourceGroup": "版本",
    "sourceIcon": "",
    "sourceName": "7.3需要网页",
    "sourceUrl": "https://rlblsm.yzfnb4.lat/cn/home/web/"
  },
  {
    "articleStyle": 2,
    "customOrder": 186,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "class.list",
    "ruleContent": ".pic_center@html",
    "ruleImage": "img@src",
    "ruleLink": "a@href",
    "ruleNextPage": "page",
    "ruleTitle": "@text",
    "singleUrl": false,
    "sortUrl": "网友自拍::/category.php?cid=1&page={{page}}\n\n影视作品::/category.php?cid=2&page={{page}}\n\n搜索::/public/api.php?app=search&q={{(source.getVariable()==''||source.getVariable()==null)?source.setVariable('少妇'):source.getVariable()}}&page={{page}}",
    "sourceComment": "源社区：@Mengteen\n不要传的太泛滥，请不要二次上传，如要二次分享请@Mengteen",
    "sourceGroup": "h",
    "sourceIcon": "https://www.qpic.ws/images/2025/01/01/blzvXu.jpg",
    "sourceName": "👙网友自拍",
    "sourceUrl": "https://3zx4.023vcc.com/#@Mengteen",
    "style": ""
  },
  {
    "articleStyle": 1,
    "concurrentRate": "20/10000",
    "contentBlacklist": "",
    "customOrder": 187,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "header": "<js>\nheaders={\n    \"User-Agent\": \"Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Mobile Safari/537.36 EdgA/127.0.0.0\",\n    \"Referer\": String(source.getKey()).replace(/(.*\\/\\/[a-z0-9.-]+).*/, '$1')\n}\nJSON.stringify(headers);\n</js>",
    "injectJs": "",
    "jsLib": "function get(tag,num) {\n    sort = ['today_views','weekly_views','monthly_views','views','released_at','published_at','saved'];\n    filters = ['','individual','multiple','chinese-subtitle'];\n    filters1 = ['','individual','jav','uncensored-leak','uncensored','chinese-subtitle'];\n    var e = eval(tag + '[' + num + ']');\n    return e;\n}\nfunction Get(e) {\n    const { java, source, cookie, cache } = this;\n    var get = JSON.parse(source.getLoginHeader());\n    return get[e];\n}\nfunction Map(e) {\n    const { java, source, cookie, cache } = this;\n    var infomap = source.getLoginInfoMap();\n    var map = (infomap !== null && infomap.get(e)) ? infomap.get(e) : '';\n    return String(map);\n}\nfunction formatSeconds(seconds) {\n    var hours = Math.floor(seconds / 3600);\n    var minutes = Math.floor((seconds % 3600) / 60);\n    var secs = Math.floor(seconds % 60);\n\n    var formattedHours = hours.toString().padStart(2, '0');\n    var formattedMinutes = minutes.toString().padStart(2, '0');\n    var formattedSeconds = secs.toString().padStart(2, '0');\n\n    return `${formattedHours}:${formattedMinutes}:${formattedSeconds}`;\n}",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "loginCheckJs": "",
    "loginUi": "[\n  { name: \"  查看当前  \", type: \"button\", action: \"look(0)\" },\n  { name: \"   查看历史   \", type: \"button\", action: \"look(1)\" },\n  { name: \"  恢复默认  \", type: \"button\", action: \"test(0)\" },\n\n  {\n    name: \"            💡　　 源　　 站　　 更　　 新　　 💡            \",\n    type: \"button\",\n    action: \"update()\"\n  },\n\n  { name: \"                      ༺ˇ»`ʚ  点击切换源站  ɞ´«ˇ༻                    \", type: \"button\" },\n  { name: \"       ①国际网址✈️       \", type: \"button\", action: \"$(1)\"},\n  { name: \"       ②国内网址🐰       \", type: \"button\", action: \"$(2)\"},\n\n  { name: \"                      ༺ˇ»`ʚ  点击切换分类  ɞ´«ˇ༻                    \", type: \"button\" },\n  { name: \"           类型标签           \", type: \"button\", action: \"o(0)\" },\n  { name: \"           女优一览           \", type: \"button\", action: \"o(1)\" },\n\n  { name: \"                      ༺ˇ»`ʚ  影片浏览排序  ɞ´«ˇ༻                    \", type: \"button\" },\n  { name: \" 今 日   \", type: \"button\", action: \"q(0)\" },\n  { name: \" 本 周   \", type: \"button\", action: \"q(1)\" },\n  { name: \" 本 月   \", type: \"button\", action: \"q(2)\" },\n  { name: \" 全 部 \", type: \"button\", action: \"q(3)\" },\n  { name: \"                      ༺ˇ»`ʚ  影片其他排序  ɞ´«ˇ༻                    \", type: \"button\" },\n  { name: \"  发行日期  \", type: \"button\", action: \"q(4)\" },\n  { name: \"   最近更新   \", type: \"button\", action: \"q(5)\" },\n  { name: \"  收藏数量  \", type: \"button\", action: \"q(6)\" },\n\n  { name: \"                      ༺ˇ»`ʚ  分类影片过滤  ɞ´«ˇ༻                    \", type: \"button\" },\n  { name: \" 所 有   \", type: \"button\", action: \"r(0)\" },\n  { name: \" 单 人   \", type: \"button\", action: \"r(1)\" },\n  { name: \" 多 人   \", type: \"button\", action: \"r(2)\" },\n  { name: \" 中 文 \", type: \"button\", action: \"r(3)\" },\n\n  { name: \"                      ༺ˇ»`ʚ  搜索影片过滤  ɞ´«ˇ༻                    \", type: \"button\" },\n  { name: \"  所有影片  \", type: \"button\", action: \"s(0)\" },\n  { name: \"   单人作品   \", type: \"button\", action: \"s(1)\" },\n  { name: \"   日本AV    \", type: \"button\", action: \"s(2)\" },\n  { name: \"  无码流出  \", type: \"button\", action: \"s(3)\" },\n  { name: \"   无码影片   \", type: \"button\", action: \"s(4)\" },\n  { name: \"  中文字幕  \", type: \"button\", action: \"s(5)\" },\n\n  { name: \"                      ༺ˇ»`ʚ  分类女优排序  ɞ´«ˇ༻                    \", type: \"button\" },\n  { name: \"           影片数量           \", type: \"button\", action: \"p(0)\" },\n  { name: \"           出道时间           \", type: \"button\", action: \"p(1)\" },\n\n  { name: \"                      ༺ˇ»`ʚ  女优加载过滤  ɞ´«ˇ༻                    \", type: \"button\" },\n  { name: \" 身 高   \", type: \"button\", action: \"login('【身高参数】' + n(2) + '[0]131-135 [1]136-140 [2]141-145 [3]146-150 [4]151-155 [5]156-160 [6]161-165 [7]166-170 [8]171-175 [9]176-180 [10]181-185 [11]186-190\\\\n\\\\n填写对应身高序号')\" },\n  { name: \" 年 龄   \", type: \"button\", action: \"login('【年龄参数】' + n(2) + '[0]0-20 [1]20-30 [2]30-40\\\\n[3]40-50 [4]50-60 [5]60-99\\\\n\\\\n填写对应年龄序号')\" },\n  { name: \" 罩 杯   \", type: \"button\", action: \"login('【罩杯参数】' + n(2) + '可选罩杯范围：A~Q\\\\n只能填写一个大写字母')\" },\n  { name: \" 出 道 \", type: \"button\", action: \"login('【出道年份】' + n(2) + '填写年份，如：2024\\\\n只能填写一个')\" },\n  { name: \"身高：\", type: \"text\" },\n  { name: \"年龄：\", type: \"text\" },\n  { name: \"罩杯：\", type: \"text\" },\n  { name: \"出道：\", type: \"text\" },\n\n  { name: \"                      ༺ˇ»`ʚ  女优加载页数  ɞ´«ˇ༻                    \", type: \"button\", action: \"login('【加载页数】' + n(2) + '填写数字或范围，如：15或10-20')\" },\n  { name: \"页数：\", type: \"text\" },\n\n  { name: \"                      ༺ˇ»`ʚ  填写收藏词条  ɞ´«ˇ༻                    \", type: \"button\", action: \"login('【收藏词条】' + n(2) + '填写搜索关键词\\\\n多个关键词用英文逗号”,“隔开')\" },\n  { name: \"收藏：\", type: \"text\" },\n\n  {\n    name: \"            💡　　 源　　 站　　 打　　 印　　 💡            \",\n    type: \"button\",\n    action: \"test()\"\n  }\n]",
    "loginUrl": "var fburl = 'https://missav.live';\noriginal = {\n    'o': 0,\n    'p': 0,\n    'q': 0,\n    'r': 0,\n    's': 0,\n    'url': 'https://missav.com',\n    'urls': [\n        'https://missav.com',\n        'https://missav.com'\n    ]\n};\ntry {\n    $$$ = JSON.parse(source.getLoginHeader());\n    if ($$$ == null) {\n        error;\n    } else {\n        '';\n    };\n} catch (e) {\n    $$$ = original;\n    put($$$);\n}\nx = '⓪①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳㉑㉒㉓㉔㉕㉖㉗㉘㉙㉚';\nvar Headers = String(cache.get(java.md5Encode16(Get('url') + \"headers\")));\nvar Option = {\n    \"method\": \"GET\",\n    \"headers\": Headers\n};\nfunction test(e) {\n    if (e == undefined) {\n        return java.log('\\n' + JSON.stringify($$$['urls'], null, '\\t')) + login('【源站输出提示】' + n(2) + '源站已打印完毕，请到日志查看');\n    }\n    if (e == 0) {\n        login('【初始化提示】' + n(2) + '已恢复默认设置');\n        return put(original);\n    }\n    date1 = new Date().getTime();\n    html = java.ajax($$$.urls[e]+'/dm10/cn');\n    if(html.includes('no-js')){\n        cookie.removeCookie(Get('url'));\n        java.startBrowserAwait($$$.urls[e],\"验证\").body();\n        date1 = new Date().getTime();\n        html = java.ajax($$$.urls[e]+'/dm10/cn');\n    }\n    date2 = new Date().getTime();\n    t = date2 - date1;\n    time = t / 1000 + 's';\n    c = String(html).indexOf('日本');\n    logTime = '【' + name(e) + '】\\n┋┋\\n' + '解析时间：' + time;\n    if (c == -1 || t > 5000) {\n        return login('【访问失败提示】' + n(2) + '┏┅━┅━┅━┅━┅━┅━┅━┅━┅┓\\n┋┋\\n' + logTime + '\\n┋┋\\n♣️源站已失效(可能被墙)♣️\\n┋┋\\n请更新网址/切换源站/切换网络环境\\n┋┋' + '\\n┗┅━┅━┅━┅━┅━┅━┅━┅━┅┛');\n    } else if (t < 1000) {\n        return login('【网络环境优良】' + n(2) + '┏┅━┅━┅━┅━┅━┅━┅━┅━┅┓\\n┋┋\\n' + logTime + '\\n┋┋\\n❤️延迟低，推荐使用此站❤️\\n┋┋\\n网络环境优良，请继续保持状态\\n┋┋' + '\\n┗┅━┅━┅━┅━┅━┅━┅━┅━┅┛');\n    } else if (t >= 1000 && t < 2000) {\n        return login('【网络环境一般】' + n(2) + '┏┅━┅━┅━┅━┅━┅━┅━┅━┅┓\\n┋┋\\n' + logTime + '\\n┋┋\\n♦️延迟一般，勉强可使用♦️\\n┋┋\\n请切换其他源站或切换网络环境\\n┋┋' + '\\n┗┅━┅━┅━┅━┅━┅━┅━┅━┅┛');\n    } else if (t >= 2000 && t < 5000) {\n        return login('【网络环境堪忧】' + n(2) + '┏┅━┅━┅━┅━┅━┅━┅━┅━┅┓\\n┋┋\\n' + logTime + '\\n┋┋\\n♠延迟过高，不建议使用♠\\n┋┋\\n请切换其他源站或切换网络环境\\n┋┋' + '\\n┗┅━┅━┅━┅━┅━┅━┅━┅━┅┛');\n    }\n}\nfunction put(data) {\n    return source.putLoginHeader(JSON.stringify(data, null, '\\t'));\n}\nfunction update() {\n    $$$['urls'].splice(original['urls'].length);\n    time = new Date().getTime();\n    html = java.webViewGetOverrideUrl(null, fburl + '?t=' + time, null, '');\n    J = org.jsoup.Jsoup.parse(html);\n    u = J.select('button');\n    for (i in u) {\n        host = eval(String(String(u[i].attr('onclick')).replace(/^.*=\\s*/,''))).replace(/(.*\\/\\/[a-z0-9.-]+).*/, '$1');\n        if (String($$$['urls']).indexOf(host) === -1) {\n            java.log('\\n✅已添加源站：\\n' + host);\n            $$$['urls'].push(host);\n            put($$$);\n        }\n    }\n    return login('【源站更新提示】' + n(2) + '源站更新完毕，请到日志查看');\n}\nfunction name(e) {\n    if (e == undefined) {\n        e = 0;\n    }\n    return x[e] + $$$.urls[e];\n}\nfunction login(e) {\n    if (e == undefined) {\n        return;\n    }\n    java.longToast(e);\n}\nfunction n(e) {\n    n = '\\n';\n    for (m = 1; m < e; m++) {\n        n = n + '\\n';\n    }\n    return n;\n}\nfunction k(e) {\n    k = ' ';\n    for (q = 1; q < e; q++) {\n        k = k + ' ';\n    }\n    return k;\n}\nfunction l(e) {\n    l = '';\n    for (o = 1; o < e; o++) {\n        l = l + '';\n    }\n    return l;\n}\nfunction look(e) {\n    if (e == 0) {\n        return login('【查看当前源站】\\n\\n┏┅━┅━┅━┅━┅━┅━┅━┅━┅┓\\n┋┋' + ('\\n ' + '📌' + name($$$.ci0)) + '\\n┋┋' + ('\\n' + '🗳订阅分类：' + typeO($$$.o)) + '\\n┋┋' + ('\\n' + '👩‍🎤女优排序：' + typeP($$$.p)) + '\\n┋┋' + ('\\n' + '📚影片排序：' + typeQ($$$.q)) + '\\n┋┋' + ('\\n' + '🔎分类过滤：' + typeR($$$.r)) + '\\n┋┋' + ('\\n' + '🔍搜索过滤：' + typeS($$$.s)) + '\\n┋┋' + '\\n┗┅━┅━┅━┅━┅━┅━┅━┅━┅┛');\n    } else {\n        return login('【查看历史接口】\\n\\n┏┅━┅━┅━┅━┅━┅━┅━┅━┅┓\\n┋┋' + ('\\n ci1：' + name($$$.ci1)) + '\\n┋┋' + ('\\n ci2：' + name($$$.ci2)) + '\\n┋┋' + ('\\n ci3：' + name($$$.ci3)) + '\\n┋┋' + '\\n┗┅━┅━┅━┅━┅━┅━┅━┅━┅┛');\n    }\n}\nfunction $(e) {\n    if (e == undefined) {\n        e = result['序号：'];\n        e = e > 0 ? e : '0';\n    }\n    if (/^ci[123]$/.test(e)) {\n        eval('i=$$$.' + e);\n    }\n    if (/\\D|^$/.test(e) || e < 0 || e >= $$$['urls'].length) {\n        return login('【源站错误提示】' + n(2) + '已选择的源站无效，请重新选择');\n    }\n    $$$['url'] = $$$['urls'][e];\n    $$$['ci3'] = $$$['ci2'];\n    $$$['ci2'] = $$$['ci1'];\n    $$$['ci1'] = $$$['ci0'];\n    $$$['ci0'] = e;\n    put($$$);\n    test(e);\n}\nO = ['主题标签','全部女优'];\nfunction typeO(e) {\n    if (e == undefined) {\n        e = 0;\n    }\n    return O[e];\n}\nfunction o(e) {\n    if (o == undefined) {\n        o = result.o;\n    }\n    if (e == $$$.o) {\n        return login('【分类切换提示】' + n(2) + '已经选择此分类，无需更换');\n    }\n    login('【分类切换提示】' + n(2) + '已经切换到[' + typeO(e) + ']分类，请刷新分类');\n    $$$.o = e;\n    return put($$$);\n}\nP = ['影片数量','出道时间'];\nfunction typeP(e) {\n    if (e == undefined) {\n        e = 0;\n    }\n    return P[e];\n}\nfunction p(e) {\n    if (p == undefined) {\n        p = result.p;\n    }\n    if (e == $$$.p) {\n        return login('【女优排序提示】' + n(2) + '已经选择此排序，无需更换');\n    }\n    login('【女优排序提示】' + n(2) + '已经切换到[' + typeP(e) + ']排序，请刷新分类');\n    $$$.p = e;\n    return put($$$);\n}\nQ = ['今日浏览','本周浏览','本月浏览','全部浏览','发行日期','最近更新','收藏数量'];\nfunction typeQ(e) {\n    if (e == undefined) {\n        e = 0;\n    }\n    return Q[e];\n}\nfunction q(e) {\n    if (q == undefined) {\n        q = result.q;\n    }\n    if (e == $$$.q) {\n        return login('【切换影片排序】' + n(2) + '已经选择此排序，无需更换');\n    }\n    login('【切换影片排序】' + n(2) + '已经切换到[' + typeQ(e) + ']排序');\n    $$$.q = e;\n    return put($$$);\n}\nR = ['所有影片','单人作品','多人作品','中文字幕'];\nfunction typeR(e) {\n    if (e == undefined) {\n        e = 0;\n    }\n    return R[e];\n}\nfunction r(e) {\n    if (r == undefined) {\n        r = result.r;\n    }\n    if (e == $$$.r) {\n        return login('【列表影片过滤】' + n(2) + '已经选择此过滤，无需更换');\n    }\n    login('【列表影片过滤】' + n(2) + '已经切换到[' + typeR(e) + ']过滤');\n    $$$.r = e;\n    return put($$$);\n}\nS = ['所有影片','单人作品','日本AV','无码流出','无码影片','中文字幕'];\nfunction typeS(e) {\n    if (e == undefined) {\n        e = 0;\n    }\n    return S[e];\n}\nfunction s(e) {\n    if (r == undefined) {\n        r = result.s;\n    }\n    if (e == $$$.s) {\n        return login('【搜索影片过滤】' + n(2) + '已经选择此过滤，无需更换');\n    }\n    login('【搜索影片过滤】' + n(2) + '已经切换到[' + typeS(e) + ']过滤');\n    $$$.s = e;\n    return put($$$);\n}",
    "ruleArticles": ".thumbnail.group",
    "ruleContent": "<js>\n//获取集数\nvar n = /-chinese-subtitle/.test(baseUrl) ? 2 : (/-uncensored-leak/.test(baseUrl) ? 1 : 0);\nvar names = ['原版视频', '无码流出', '中文字幕'];\nvar fhs = ['', '-uncensored-leak', '-chinese-subtitle'];\nvar list = [];\nURL = baseUrl.replace(/-uncensored-leak|-chinese-subtitle/,'');\nFH = String(java.getElements('[property=\"og:title\"]').attr('content')).replace(/^(.*?)\\s.*/, '$1');\nlist.push(URL);\nlist.push(URL+'-uncensored-leak');\nlist.push(URL+'-chinese-subtitle');\nvar url = '';\njishu = list.map(($, i)=>{\n    var value = '',name = '',bt = '',fm = '',fh = '',lx = '';\n    var style = ' style=\"display:none;\"';\n    html = $ == baseUrl ? result : java.ajax($);\n    J = org.jsoup.Jsoup.parse(html);\n    if (i < 1 || String(J.select('[hreflang=\"zh-Hans\"]').attr('href')) !== list[0] || i < 1) {\n        name = names[i];\n        var Value = [];\n        url = /找不到页面/.test(html) ? '' : eval(html.match(/(eval.*video.*\\)\\))/m)[1]);\n        if (url !== '') {\n            url1 = String(url).replace(/\\/[^\\/]+\\/[^\\/]+$/, '/');\n            res = String(java.ajax(String(url).replace(/\\/[^\\/]+\\/[^\\/]+$/, '/playlist.m3u8')));\n            sizes = res.match(/RESOLUTION=\\d+x\\d+/g).map(e => e.split('x')[1]);\n            srcs = res.match(/(.*\\/video\\.m3u8)/g);\n            for (j in srcs) {\n                Value.push({src:url1+srcs[j],size:sizes[j]});\n            }\n            Value.sort((a, b) => parseInt(b.size) - parseInt(a.size));\n            value = JSON.stringify(Value);\n        }\n        bt = J.select('[property=\"og:title\"]').attr('content');\n        fh = '🎬 番号：' + FH + fhs[i];\n        lx = '📦 类型：' + String(/找不到页面/.test(html) ? '' : J.select('.text-secondary:contains(类型:)').text()).replace(/类型:/,'');\n        fm = J.select('video').attr('data-poster');\n        style = /找不到页面/.test(html) ? ' style=\"display:none;\"' : '';\n    }\n    return `<button onclick=\"jishu(this)\" value=${value} data-bt=\"${bt}\" data-fh=\"${fh}\" data-lx=\"${lx}\"  data-fm=\"${fm}\"${style}><b>${name}</b></button>`;\n}).join('\\n');\n\nstyle = /none.*none/s.test(jishu) ? ' style=\"display:none;\"' : '';\njishu = `<div class=\"jishu\" data-n=\"${n}\"${style}>\\n<p>🎥 视频版本：&lrm;</p>\\n<p>${jishu}</p>\\n</div>\\n`;\n\n//返回json\nJSON.stringify({\n    jishu: jishu\n})\n</js>\n<!DOCTYPE html>\n<html lang=\"zh-Hans\">\n<head>\n<title></title>\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no\">\n<link rel=\"stylesheet\" href=\"https://cdn.plyr.io/3.6.12/plyr.css\">\n<style>\n* {\n    z-index: 0;\n    margin: 0;\n    padding: 0;\n}\n\nbody {\n    margin: auto;\n    background: #ccc;\n    width: 100%;\n}\n\nbody>p:first-of-type {\n    width: 100%;\n    position: sticky;\n    top: 0px;\n    text-indent: 0px;\n    height: 16px;\n    font-size: 0.7rem;\n    border-radius: 0px 0px 0px 0px;\n    background: #000;\n    color: #fff;\n    white-space: nowrap;\n    overflow: auto;\n    z-index: 4;\n}\n\nvideo {\n    visibility: hidden;\n}\n\n.video-container {\n    position: relative;\n    min-height: 56.25vw;\n    z-index: 3;\n}\n\n#player {\n    position: relative;\n    top: 0;\n    left: 0;\n    width: 100%;\n    height: 100%;\n}\n\n:root {\n    --plyr-color-main: #00aaff;/* 播放器主要颜色 */\n    --plyr-control-color: #fff;/* 播放器控件图标颜色 */\n    --plyr-control-background: transparent;/* 播放器控件背景颜色 */\n    --plyr-video-background: transparent;/* 视频背景颜色 */\n    --plyr-range-fill-background: #0099ee;/* 进度条已填充部分的颜色 */\n    --plyr-range-thumb-background: #fff;/* 进度条滑块的颜色 */\n}\n\n.plyr__control--overlaid {\n    background: transparent;\n    border: 0;\n    border-radius: 100%;\n    color: #fff;\n    left: calc(50% - 30px);\n    top: calc(50% - 45px);\n    transform: none;\n    width: 60px;\n    height: 60px;\n    padding: 0;\n    z-index: 2;\n}\n\n.plyr__control--overlaid svg {\n    width: 50px;\n    height: 50px;\n    left: calc(50% - 25px);\n    top: calc(50% - 25px);\n    transform: none;\n    fill: #fff;/* 大播放器控件图标颜色 */\n}\n\n.plyr--video .plyr__control.plyr__tab-focus,.plyr--video .plyr__control:hover,.plyr--video .plyr__control[aria-expanded=true] {\n    background: transparent;/* 播放器控件悬停/点击背景颜色 */\n    color: #00aaff;/* 播放器控件悬停/点击图标颜色 */\n}\n\n.plyr__controls .plyr__controls__item {\n    margin-left: auto;\n    margin: calc(var(--plyr-control-spacing,10px)/4);\n}\n\n.plyr__time--duration {\n    display: inline-block!important;\n}\n\n.plyr__time+.plyr__time:before {\n    margin-right: 8px!important\n}\n\n@media (max-width: 640px) {\n    .plyr__captions {\n        margin-bottom:-8px\n    }\n\n    .plyr__progress__container {\n        margin-right: 5px\n    }\n\n    .plyr__time {\n        position: absolute;\n        bottom: 29px;\n    }\n\n    .plyr__time--current {\n        left: 108px\n    }\n\n    .plyr__time+.plyr__time:before {\n        content: \"\"!important\n    }\n\n    .plyr__time--duration {\n        right: 110px;\n    }\n\n    .plyr__volume {\n        width: auto;\n        max-width: 32px!important;\n        min-width: 32px!important\n    }\n\n    input[id^=plyr-volume-] {\n        display: none!important;\n    }\n\n    .plyr--airplay-supported [data-plyr=airplay],.plyr--captions-enabled [data-plyr=captions],.plyr--pip-supported [data-plyr=pip] {\n        display: none!important;\n    }\n}\n\n.all-info {\n    position: absolute;\n    background: #ccc;/* 详情信息背景颜色 */\n    margin: auto;\n    width: 100%;\n    height: auto;\n}\n\n.all-info>div {\n    width: 100%;\n    margin: auto;\n}\n\n.all-info>p {\n    text-indent: 0px;\n}\n\n.all-info>div>p {\n    width: 90%;\n    margin: 5px 5%;\n    outline: none;\n    text-align: left;\n    word-wrap: break-word;\n}\n\ndetails {\n    width: 100%;\n    height: auto;\n    margin: auto;\n    padding: 0;\n    border-bottom: 0.5px solid #333;\n}\n\ndetails>img {\n    width: 100%;\n}\n\ndetails[open] {\n    border-bottom: none;\n}\n\nsummary {\n    width: 90%;\n    margin: 5px 3%;\n    outline: none;\n    line-height: 1.5;\n    text-align: left;\n    word-wrap: break-word;\n}\n\nsummary::-webkit-details-marker {\n    display: none;\n}\n\nbutton {\n    width: 29.5%;\n    margin: 1.25%;\n    padding: 5px;\n    outline: none;\n    border-radius: 8px;\n    font-size: 0.7rem;\n    text-overflow: ellipsis;\n    overflow: hidden;\n}\n\nbutton.active {\n    color: #166188;\n    position: sticky;\n    left: 0;\n    right: 0;\n}\n</style>\n</head>\n<body>\n<p></p>\n<div class=\"video-container\">\n  <video id=\"player\" playsinline controls preload=\"auto\" poster=\"https://qyyuapi.com/img/noposter.png\">\n  </video>\n</div>\n<div class=\"all-info\">\n<details>\n  <summary>\n    <h3></h3>\n  </summary>\n  <img>\n</details>\n{{JSON.parse(result).jishu}}\n<div>\n    <p>📆 发行：{{@css:.text-secondary:contains(发行日期:)@text##发行日期:|}}</p>\n    <p></p>\n    <p>👩‍🎤 女优：{{@css:.text-secondary:contains(女优:)@text##女优:}}</p>\n    <p>👨‍🎤 男优：{{@css:.text-secondary:contains(男优:)@text##男优:}}</p>\n    <p>🎦 片商：{{@css:.text-secondary:contains(发行商:)@text##发行商:}}</p>\n    <p>🕵️‍♀️ 导演：{{@css:.text-secondary:contains(导演:)@text##导演:}}</p>\n    <p>🔖 标签：{{@css:.text-secondary:contains(标籤:)@text##标籤:}}</p>\n    <p>🏷 系列：{{@css:.text-secondary:contains(系列:)@text##系列:}}</p>\n    <p></p>\n    <p>✏️ 标题：{{@css:.text-secondary:contains(标题:)@text##标题:}}</p>\n    <p>📋 简介：{{@@[property=\"og:description\"]@content##.*免费加入会员.*}}</p>\n</div>\n</div>\n\n<script src=\"https://cdn.plyr.io/3.6.12/plyr.js\"></script>\n<script src=\"https://cdn.jsdelivr.net/npm/hls.js@latest\"></script>\n\n<script>\n// 选中标签\nfunction $(rule) {\n    return document.querySelectorAll(rule);\n}\n\n// 删除选中标签的class\nfunction omit(items) {\n    return Array.from(items, (item) => {\n        item.className = \"\";\n    });\n}\n\n// 选中标签的class增加active\nfunction active(items, index) {\n    items[index].className = \"active\";\n}\n\n// 播放器实例\nlet player = null;\n\n// 获取视频URL并更新视频源\nfunction geturl() {\n    let zyurl = $(\".jishu button.active\")[0].value;\n    let img = $('img')[0];\n    let bt = $(\".jishu button.active\")[0].dataset.bt;\n    let fh = $(\".jishu button.active\")[0].dataset.fh;\n    let lx = $(\".jishu button.active\")[0].dataset.lx;\n    let fm = $(\".jishu button.active\")[0].dataset.fm;\n\n    // 更新页面信息\n    $(\"title\")[0].innerText = bt;\n    $(\".all-info>details>summary>h3\")[0].innerText = bt;\n    $(\".all-info>div>p\")[3].innerText = fh;\n    $(\".all-info>div>p\")[10].innerText = lx;\n    $(\".all-info>div>p\")[3].style = /：\\s*$/.test(fh) ? \"display:none;\" : \"\";\n    $(\".all-info>div>p\")[10].style = /：\\s*$/.test(lx) ? \"display:none;\" : \"\";\n\n    // 更新详情封面\n    img.src = fm;\n\n    // 更新视频封面\n    $(\".video-container\")[0].style.background = `#000 url('${fm}') no-repeat center center / cover`;\n\n    // 设置不同分辨率的视频源\n    let sources = JSON.parse(zyurl);\n\n    return { sources: sources };\n}\n\n// 初始化播放器\nfunction initializePlayer(sources) {\n    const video = $('video')[0];\n    const qualityOptions = sources.map(source => parseInt(source.size));\n\n    // 立即重新初始化 Plyr 实例\n    player = new Plyr(video, {\n        controls: [\n            'play-large',   // 大播放按钮\n            'rewind',       // 倒退\n            'play',         // 播放\n            'fast-forward', // 快进\n            'progress',     // 进度条\n            'current-time', // 当前时间\n            'duration',     // 总时长\n            'mute',         // 静音\n            'volume',       // 音量\n            'captions',     // 字幕\n            'settings',     // 设置\n            'pip',          // 画中画\n            'airplay',      // Airplay\n            'fullscreen'    // 全屏\n        ],\n        settings: ['quality', 'speed'],\n        quality: {\n            default: qualityOptions[0],\n            options: qualityOptions,\n            forced: true,\n            onChange: (newQuality) => {\n                changeVideoQuality(newQuality, sources);\n            }\n        },\n        fullscreen: {\n            enabled: true,\n            fallback: true,\n            iosNative: true,\n            container: null,\n        },\n        speed: {\n            selected: 1, // 设置默认播放倍数\n            options: [0.25, 0.5, 1, 1.5, 2],\n        },\n        i18n: {\n            restart: '重新开始',\n            rewind: '倒退 {seektime} 秒',\n            play: '播放',\n            pause: '暂停',\n            fastForward: '快进 {seektime} 秒',\n            seek: '进度',\n            seekLabel: '{currentTime} / {duration}',\n            played: '播放',\n            buffered: '缓冲',\n            currentTime: '当前时间',\n            duration: '持续时间',\n            volume: '音量',\n            mute: '静音',\n            unmute: '取消静音',\n            enableCaptions: '启用字幕',\n            disableCaptions: '禁用字幕',\n            enterFullscreen: '进入全屏',\n            exitFullscreen: '退出全屏',\n            frameTitle: '播放器',\n            captions: '字幕',\n            settings: '设置',\n            speed: '速度',\n            normal: '正常',\n            quality: '画质',\n            qualityLabel: {\n                0: '自动',\n            },\n            pip: '画中画',\n            loop: '循环',\n            start: '开始',\n            end: '结束',\n            all: '全部',\n            reset: '重置',\n            disabled: '禁用',\n            advertisement: '广告'\n        },\n        keyboard: {\n            focused: true,\n            global: true,\n        },\n        tooltips: {\n            controls: true,\n            seek: true\n        },\n        captions: {\n            active: true,\n            update: true,\n            language: 'auto',\n        },\n    });\n\n    player.on('ready', () => {\n        video.style.visibility = 'visible';\n\n        // 添加长按倍速播放功能\n        let longPressTimeout = null;\n        let initialSpeed = 1;\n        let isLongPress = false;\n        const controls = document.querySelector('.plyr__controls');\n        const overlaid = document.querySelector('.plyr__control--overlaid');\n\n        const startLongPress = (e) => {\n            e.stopPropagation();\n            initialSpeed = player.speed;\n            longPressTimeout = setTimeout(() => {\n                setTimeout(() => {\n                    controls.style.display = 'none';\n                    overlaid.style.display = 'none';\n                }, 1000);\n                isLongPress = true;\n                player.speed = 2; // 长按时设置2倍速播放\n            }, 500);\n        };\n\n        const endLongPress = (e) => {\n            e.stopPropagation();\n            clearTimeout(longPressTimeout);\n            if (isLongPress) {\n                player.speed = initialSpeed;\n                isLongPress = false;\n                setTimeout(() => {\n                    controls.style.display = 'flex';\n                    overlaid.style.display = 'flex';\n                }, 2000);\n            }\n        };\n\n        // 监听播放器区域的pointerdown和pointerup事件\n        const playerContainer = document.querySelector('.plyr__video-wrapper');\n\n        playerContainer.addEventListener('pointerdown', startLongPress, true);\n        playerContainer.addEventListener('pointerup', endLongPress, true);\n        playerContainer.addEventListener('pointerleave', endLongPress, true);\n\n        // 处理全屏模式下的特殊情况\n        document.addEventListener('fullscreenchange', () => {\n            if (!document.fullscreenElement) {\n                endLongPress();\n            }\n        });\n    });\n}\n\n// 切换视频质量的函数\nfunction changeVideoQuality(quality, sources) {\n    const video = $('video')[0];\n    const selectedSource = sources.find(source => source.size === quality.toString());\n    const currentTime = video.currentTime;\n    const wasPlaying = !video.paused;\n\n    if (wasPlaying) {\n        $(\".video-container\")[0].style.background = '#000';\n    }\n    $(\"body>p\")[0].innerText = selectedSource.src;\n\n    if (selectedSource) {\n        if (Hls.isSupported() && selectedSource.src.endsWith('.m3u8')) {\n            const hls = new Hls();\n            hls.loadSource(selectedSource.src);\n            hls.attachMedia(video);\n            hls.on(Hls.Events.MANIFEST_PARSED, () => {\n                video.currentTime = currentTime;\n                if (wasPlaying) {\n                    video.play();\n                }\n            });\n        } else {\n            video.pause();\n            video.src = selectedSource.src;\n            video.load();\n            video.currentTime = currentTime;\n            if (wasPlaying) {\n                video.play();\n            }\n        }\n    }\n}\n\n// 点击集数按钮时调用的函数\nfunction jishu(item) {\n    if (player && typeof player.destroy === 'function') {\n        player.destroy();\n        player = null;\n    }\n    omit($('.jishu button.active'));\n    item.className = \"active\";\n    const { sources } = geturl();\n    initializePlayer(sources);\n}\n\n// 页面加载时初始化播放器\n(() => {\n    let n = $(\".jishu\")[0].dataset.n;\n    active($('.jishu button'), n);\n    const { sources } = geturl();\n    initializePlayer(sources);\n})();\n</script>\n</body>\n</html>\n@js:result\n.replace(/：\\s*/g,'：')\n.replace(/<p>(.+)：<\\/p>/gm, '<p style=\"display:none;\">$1：</p>')",
    "ruleDescription": "",
    "ruleImage": "img@data-src",
    "ruleLink": "a.0@href",
    "ruleNextPage": "page",
    "rulePubDate": "⌚️ {{@@.right-1@text}}    📦 {{@@.left-1@text}}\n@js:result.replace(/📦\\s*$/,'')",
    "ruleTitle": ".text-secondary@text",
    "singleUrl": false,
    "sortUrl": "@js:\neval(String(source.loginUrl));\nvar exploreUrl = [];\nvar Sort = `{{get('sort',Get('q'))}}`;\nvar Filters = `{{get('filters',Get('r'))}}`;\nvar Filters1 = `{{get('filters1',Get('s'))}}`;\nfunction explore(e, f, g) {\n    if (g=='类别') {\n        style = `${e}::${f}\\n`;\n    } else if (g=='收藏') {\n        style = `${e}::@js:\\`${f}\\`\\n`;\n    } else if (g=='分类') {\n        style = `${e}::@js:\\`${f}?page={{page}}&filters=${Filters}&sort=${Sort}\\`\\n`;\n    } else if (g=='日本') {\n        style = `${e}::@js:\\`${f}?page={{page}}&filters=${Filters}\\`\\n`;\n    } else {//女优\n        style = `${e}::@js:\\`${f}?page={{page}}&filters=${Filters}&sort=${Sort}\\`\\n`;\n    }\n    return style;\n}\n\nsc = Map('收藏：');\nscs = sc !== '' ? sc.split(\",\") : [];\nif (scs.length > 0) {\n    scs.forEach((sc) => {\n        let scHref = `{{Get('url')}}/cn/search/${sc}?page={{page}}&filters=${Filters1}&sort=${Sort}`;\n        exploreUrl.push(explore(sc, scHref, '收藏'));\n    });\n}\n\nhtml = java.ajax(Get('url')+'/dm10/cn');\nif(String(html).includes('no-js')){\n    cookie.removeCookie(Get('url'));\n    java.startBrowserAwait(Get('url'),'验证');\n}\n\nJ = org.jsoup.Jsoup.parse(html);\n\nif (Get('o') == 0) {\n    java.toast(\"正在获取分类标签数据，请耐心等待！\")\n    gcs = J.select('.right-0.mt-2.w-56 span')[7].select('a');\n    exploreUrl.push(explore('中文字幕', `{{Get('url')}}/dm265/cn/chinese-subtitle?page={{page}}&filters=${Filters}&sort=${Sort}`, '分类'));\n    exploreUrl.push(explore('国产▶', null, '类别'));\n    for (i in gcs) {\n        exploreUrl.push(explore(gcs[i].text(), `{{Get('url')}}${String(gcs[i].attr('href')).replace(/.*\\/\\/[a-z0-9.-]+/, '')}`, '分类'));\n    }\n    rbs = J.select('.right-0.mt-2.w-56 span')[1].select('a');\n    exploreUrl.push(explore('日本▶', null, '类别'));\n    for (i in rbs) {\n        if (i < 3 || i > 6) {\n            exploreUrl.push(explore(rbs[i].text(), `{{Get('url')}}${String(rbs[i].attr('href')).replace(/.*\\/\\/[a-z0-9.-]+/, '')}`, '日本'));\n        }\n    }\n    srs = J.select('.right-0.mt-2.w-56 span')[3].select('a');\n    exploreUrl.push(explore('素人▶', null, '类别'));\n    for (i in srs) {\n        exploreUrl.push(explore(srs[i].text(), `{{Get('url')}}${String(srs[i].attr('href')).replace(/.*\\/\\/[a-z0-9.-]+/, '')}`, '分类'));\n    }\n    wms = J.select('.right-0.mt-2.w-56 span')[5].select('a');\n    exploreUrl.push(explore('无码▶', null, '类别'));\n    for (i in wms) {\n        exploreUrl.push(explore(wms[i].text(), `{{Get('url')}}${String(wms[i].attr('href')).replace(/.*\\/\\/[a-z0-9.-]+/, '')}`, '分类'));\n    }\n}\n\nif (Get('o') == 0) {\n    exploreUrl.push(explore('标签▶', null, '类别'));\n    J0 = org.jsoup.Jsoup.parse(java.ajax(Get('url')+'/cn/genres'));\n    Page = String(J0.select('#price-currency')[0].text()).match(/(\\d+)/)[1];\n    var murl = [];\n    for (i = 1; i <= Page; i++) {\n        murl.push(Get('url')+'/cn/genres?page='+i); \n    }\n    htmls = java.ajaxAll(murl);\n    for (let i = 0; i < htmls.length; i++) {\n        let models = org.jsoup.Jsoup.parse(htmls[i].body()).select('.gap-4 div');\n        models.forEach((model) => {\n            let modelName = model.select('.text-nord13').text();\n            let modelSpanText = model.select('.text-nord10').text();\n            let modelVideosCount = String(modelSpanText).replace(/(\\d+).*$/, '$1');\n            let modelHref = `{{Get('url')}}${String(model.select('a').attr('href')).replace(/.*\\/\\/[a-z0-9.-]+/, '')}`;\n            exploreUrl.push(explore(`${modelName}(${modelVideosCount})`, modelHref, '分类'));\n        });\n    }\n}\n\nnsort = ['videos','debut'];\nNsort = /\\d+/.test(Map('出道：')) ? 'debut' : nsort[Get('p')]\nheight = ['131-135', '136-140', '141-145', '146-150', '151-155', '156-160', '161-165', '166-170', '171-175', '176-180', '181-185', '186-190'];\nage = ['0-20','20-30','30-40','40-50','50-60','60-99'];\nHeight= /\\d+/.test(Map('身高：')) ? height[Map('身高：')] : '';\nAge= /\\d+/.test(Map('年龄：')) ? age[Map('年龄：')] : '';\nif (Get('o') == 1) {\n    java.toast(\"正在获取女优数据，请耐心等待！\");\n    Fpage = /-/.test(Map('页数：')) ? Map('页数：').match(/(\\d+)/g)[0] : '1';\n    Lpage = /-/.test(Map('页数：')) ? Map('页数：').match(/(\\d+)/g)[1] : (/\\d+/.test(Map('页数：')) ? Map('页数：') : '5');\n    var murl = [];\n    for (let i = Fpage; i <= Lpage; i++) {\n        murl.push(Get('url')+'/cn/actresses?sort='+Nsort+'&height='+Height+'&cup='+Map('罩杯：')+'&age='+Age+'&debut='+Map('出道：')+'&page='+i);\n    }\n    htmls = java.ajaxAll(murl);\n    for (let i = 0; i < htmls.length; i++) {\n        let models = org.jsoup.Jsoup.parse(htmls[i].body()).select('.max-w-full .space-y-4');\n        models.forEach((model) => {\n            let modelName = model.select('h4').text();\n            let modelP0Text = model.select('p')[0].text();\n            let modelVideosCount = String(modelP0Text).replace(/(\\d+).*$/, '$1');\n            let modelP1Text = model.select('p')[1].text();\n            let modelDebutYear = String(modelP1Text).replace(/(\\d+).*$/, '$1');\n            let modelHref = `{{Get('url')}}${String(model.select('a').attr('href')).replace(/.*\\/\\/[a-z0-9.-]+/, '')}`;\n            exploreUrl.push(explore(`${modelName}(${modelVideosCount} • ${modelDebutYear})`, modelHref, '女优'));\n        });\n    }\n}\n\n`变量搜索::@js:\\`{{Get('url')}}/cn/search/{{v=source.getVariable();if(/^\\s*$/.test(v)||v==null)source.setVariable('秘密');source.getVariable()}}?page={{page}}&filters=${Filters1}&sort=${Sort}\\`\\n\n${exploreUrl.join('\\n')}`",
    "sourceComment": "修改：1、优化页面样式；by：xiaohan231-2024/08/25\n\n修改：1、优化长按倍速播放功能；2、增加分辨率切换功能；by：xiaohan231-2024/08/24\n\n修改：1、优化播放器样式；2、选择播放倍速后，点击屏幕不再恢复成正常；3、添加长按2倍速播放功能，想要设置成其他的可以在内容规则根据注释修改；by：xiaohan231-2024/08/21\n\n修改：1、调用Plyr插件搭建网页播放器；2、设置播放器默认比例为16/9，以防止加载时播放器高度变动；3、优化播放器样式；by：xiaohan231-2024/08/20\n\n修改：1、修复部分视频无法播放的bug；2、增加收藏关键词；3、视频不再采用第三方解析，改为调用原生播放器；4、添加视频封面；by：xiaohan231-2024/08/18\n\nby：xiaohan231-2024/08/17",
    "sourceGroup": "h",
    "sourceIcon": "https://krseoul.imgtbl.com/i/2024/08/17/66bfb74a9b088.png",
    "sourceName": "MISSAV",
    "sourceUrl": "https://missav.com/#xh",
    "style": ""
  },
  {
    "articleStyle": 2,
    "customOrder": 188,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "header": "{\"User-Agent\": \"Mozilla/5.0 (Linux; Android 13; 2211133C Build/TKQ1.220905.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Mobile Safari/537.36\"}",
    "lastUpdateTime": 1768532090341,
    "loadWithBaseUrl": true,
    "ruleArticles": ".img@li@a||ul@li",
    "ruleContent": "<js>\n(() => {\n    urlt = baseUrl.match(/(.+)\\.html/)[1];\n    aTags = org.jsoup.Jsoup.parse(result).select('[class=\"pagelist\"] a');\n    if (aTags.length >= 3) {\n        text = aTags.get(aTags.length - 2).text();\n    } else {\n        text = \"1\";\n    }\n    maxpage = Number(text);\n    textI = \"\";\n    var loadedCount = 0;\n    var htmlContent = `<!DOCTYPE html>\n    <html>\n    <head>\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0\">\n        <link rel=\"stylesheet\" href=\"https://cdn.bootcdn.net/ajax/libs/viewerjs/1.10.1/viewer.min.css\">\n        <script src=\"https://cdn.bootcdn.net/ajax/libs/viewerjs/1.10.1/viewer.min.js\"></script>\n        <script src=\"http://lib.sinaapp.com/js/jquery/2.0.2/jquery-2.0.2.min.js\"></script>\n    <title>🏄Mengteen</title>\n    <!-- 阅图UI ©2025-->\n    \n        <style>\n            #backToTopBtn {\n                display: none;\n                position: fixed;\n                bottom: 36px;\n                right: 18px;\n                z-index: 999;\n                border: none;\n                outline: none;\n                background: rgba(0, 0, 0, 0.5);\n                color: white;\n                cursor: pointer;\n                padding: 9px;\n                border-radius: 10%;\n                font-size: 9px;\n                box-shadow: 0 8px 32px rgba(0, 0, 0, 0.8);\n                transition: all 0.3s ease;\n                backdrop-filter: blur(4px);\n                border: 1px solid rgba(255, 255, 255, 0.2);\n            }\n            #backToTopBtn:hover {\n                background: rgba(0, 0, 0, 0.5);\n                transform: scale(1.08);\n                box-shadow: 0 8px 25px rgba(0, 0, 0, 0.7);}\n            #backToTopBtn:active {\n                transform: scale(0.95);}\n            #image-loaded-toast {\n                position: fixed;\n                bottom: 33px;\n                left: 50%;\n                transform: translateX(-50%);\n                background: rgba(0, 0, 0, 0.5);\n                color: white;\n                padding: 10px 20px;\n                border-radius: 20px;\n                font-size: 14px;\n                z-index: 998;\n                backdrop-filter: blur(4px);\n                box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);\n                opacity: 0;\n                transition: opacity 0.3s;\n                pointer-events: none;\n                white-space: nowrap;\n            }\n            #image-loaded-toast.show {\n                opacity: 1;\n            }\n            .header-container {\n                text-align:center;\n                padding:50px 20px 20px;\n                margin:0 0 0px;\n                position:relative;\n                background:linear-gradient(135deg, #f0f7ff, #e6f0ff);\n            }\n            .header-card {\n                position:relative;\n                z-index:10;\n                display:inline-block;\n                transform:translateY(-20px);\n                filter: drop-shadow(0 15px 25px rgba(70,130,180,0.25));\n            }\n            .header-content {\n                background:rgba(255,255,255,0.75);\n                backdrop-filter:blur(12px);\n                padding:16px 48px;\n                border-radius:18px;\n                border:1px solid rgba(255,255,255,0.5);\n                box-shadow:0 8px 32px rgba(70,130,180,0.2), inset 0 0 12px rgba(255,255,255,0.6);\n                position:relative;\n                overflow:hidden;\n            }\n            .header-highlight {\n                position:absolute;\n                top:0; left:0; right:0;\n                height:40%;\n                background:linear-gradient(to bottom, rgba(255,255,255,0.4), transparent);\n                pointer-events:none;\n            }\n            .header-title {\n                background:linear-gradient(135deg, #4a7bd0, #00a2b8);\n                -webkit-background-clip:text;\n                background-clip:text;\n                color:transparent;\n                font-size:1.3rem;\n                font-weight:700;\n                margin:0;\n                letter-spacing:-0.5px;\n                position:relative;\n                z-index:2;\n            }\n            \n            * {margin: 0; padding: 0}\n            img {width: 100%;height: auto}\n            ul {font-size: 0; padding: 0}\n            li {list-style: none;\n                text-align: center;\n                margin-bottom: 0px;\n                border-radius: 0px;}\n            .loading-indicator {\n                text-align: center;\n                width: 100%;\n                padding: 0px 0;\n                font-size: 0.9rem;\n                color: #4682B4;\n                font-weight: 500;\n                letter-spacing: 2px;\n                background: linear-gradient(135deg, #f0f7ff, #e6f0ff);\n                backdrop-filter: blur(4px);\n                border-radius: 0px;\n                margin: 0px 0;}\n        </style>\n    </head>\n    <body>\n        <div class=\"header-container\">\n            <div class=\"header-card\">\n                <div class=\"header-content\">\n                    <div class=\"header-highlight\"></div>\n                    <h3 class=\"header-title\">{{@h1@text##P.1}}</h3>\n                </div>\n            </div>\n            \n            <div style=\"margin-top:0px; padding:0px 20px;\">\n                <h5 style=\"color:#6c757d; font-weight:400; font-size:1rem; margin:0; line-height:1.6; letter-spacing:0.3px; position:relative; display:inline-block; max-width:700px;\">✨永远相信美好的事情即将发生!\n                    <div style=\"position:absolute; bottom:-5px; left:0; width:100%; height:1px; background:linear-gradient(90deg, transparent, rgba(70,130,180,0.3), transparent);\"></div>\n                </h5>\n            </div>\n        </div>\n        \n        <ul>`;\n    \n    for (var i = 1; i <= maxpage; i++) {\n        urli = urlt + \"_\" + i + \".html\";\n        htmli = java.ajax(urli);\n        var imgs = org.jsoup.Jsoup.parse(htmli).select('[class=\"slide\"] img');\n        var pageImgCount = imgs.size();  \n        \n        htmlContent += `<li class=\"loading-indicator\">第${i}页图片</li>`;\n        \n        for (var j = 0; j < pageImgCount; j++) {\n            var imgTag = imgs.get(j).toString();\n            htmlContent += '<li>' + imgTag + '</li>';\n        }\n        \n        loadedCount += pageImgCount;  \n        \n        var progressBar = \"\";\n        var progress = Math.round((i / maxpage) * 10);\n        for (var k = 0; k < 10; k++) {\n            progressBar += (k < progress) ? \"♥️\" : \"♡\";\n        }\n        \n        var toastMsg = \"\\n载入第\" + i + \"页\";\n        toastMsg += \"/\" + loadedCount + \"张图片中\\n\";\n        toastMsg += progressBar + \" \" + Math.round((i / maxpage) * 100) + \"%\";\n        java.toast(toastMsg);\n    }\n    \n    java.toast(\"\\n载入图片已完成\\n共有\" + maxpage + \"页/\" + loadedCount + \"张图片\");\n    \n    htmlContent += `</ul>\n        \n        <div id=\"image-loaded-toast\">加载提示</div>\n        \n        <button id=\"backToTopBtn\" title=\"回到顶部\">△</button>\n        \n        <script>\n            (function() {\n                const backToTopBtn = document.getElementById(\"backToTopBtn\");\n                const toast = document.getElementById(\"image-loaded-toast\");\n                const images = document.querySelectorAll(\"img\");\n                \n                let loadedCount = 0;\n                const totalImages = images.length;\n                \n                function updateToast() {\n                    toast.innerHTML = \"⏳ 图片加载中(\" + loadedCount + \"/\" + totalImages + \")\";\n                    toast.classList.add(\"show\");\n                }\n                \n                if(totalImages === 0) {\n                    toast.style.display = \"none\";\n                } else {\n                    updateToast();\n                }\n                \n                function checkAllLoaded() {\n                    loadedCount++;\n                    updateToast();\n                    \n                    if(loadedCount >= totalImages) {\n                        toast.innerHTML =\"✅ 全部图片载入完成(共\" + totalImages + \"张)\";\n                        setTimeout(() => {\n                            toast.classList.remove(\"show\");\n                        }, 3000);                    \n                        initImageViewer();\n                    }\n                }\n                \n                window.addEventListener(\"scroll\", () => {\n                    const scrollPosition = window.scrollY || document.documentElement.scrollTop;\n                    if (scrollPosition > 288) {\n                        backToTopBtn.style.display = \"block\";\n                        backToTopBtn.style.opacity = \"1\";\n                    } else {\n                        backToTopBtn.style.display = \"none\";\n                    }\n                });\n                \n                backToTopBtn.addEventListener(\"click\", () => {\n                    window.scrollTo({\n                        top: 0,\n                        behavior: \"smooth\"\n                    });\n                });\n                \n                function initImageViewer() {\n                    const container = document.querySelector('ul');\n                    if (container && typeof Viewer !== 'undefined') {\n                        const viewer = new Viewer(container, {\n                            title: false, \n                            navbar: true, \n                            toolbar: {\n                                zoomIn: true,\n                                zoomOut: true,\n                                oneToOne: true,\n                                reset: true,\n                                rotateLeft: true,\n                                rotateRight: true,\n                                flipHorizontal: true,\n                                flipVertical: true,\n                            },\n                            viewed() {\n                                backToTopBtn.style.display = 'none';\n                            },\n                            hidden() {\n                                if (window.scrollY > 288) {\n                                    backToTopBtn.style.display = 'block';\n                                }\n                            }\n                        });\n                        \n                        container.querySelectorAll('img').forEach(img => {\n                            img.addEventListener('click', function() {\n                                viewer.show();\n                            });\n                        });\n                    }\n                }\n                \n                images.forEach(img => {\n                    if(img.complete) {\n                        checkAllLoaded();\n                    } else {\n                        img.addEventListener(\"load\", checkAllLoaded);\n                        img.addEventListener(\"error\", checkAllLoaded);\n                    }\n                });\n                \n                if (typeof Viewer !== 'undefined') {\n                    \n                } else {\n                    const viewerScript = document.createElement('script');\n                    viewerScript.src = 'https://cdn.bootcdn.net/ajax/libs/viewerjs/1.10.1/viewer.min.js';\n                    viewerScript.onload = function() {\n                       };\n                    document.head.appendChild(viewerScript);\n                }\n            })();\n        </script>\n    </body>\n    </html>`;\n    \n    return htmlContent;\n})()\n</js>",
    "ruleImage": "@js:\"https://cdn.sshs.rip/d1/e2/d14c0de2dbc537f09349f78ede233ce2.webp\"",
    "ruleLink": "a@href",
    "ruleNextPage": "page",
    "rulePubDate": "@js:\"🏄Mengteen ©2025\"",
    "ruleTitle": "a@title",
    "singleUrl": false,
    "sortUrl": "首页::/\n无圣光::/sif/fangtukum/25_{{page}}.html\n性感美女::/sif/fangtukum/1_{{page}}.html\n日韩套图::/sif/fangtukum/2_{{page}}.html\n内衣丝袜::/sif/fangtukum/9_{{page}}.html\n萌妹萝莉::/sif/fangtukum/11_{{page}}.html\n精品套图::/sif/fangtukum/18_{{page}}.html\n高清套图::/sif/fangtukum/24_{{page}}.html\n搜索::/chis/{{(source.getVariable()==''||source.getVariable()==null)?source.setVariable('meinv'):source.getVariable()}}/{{page}}.html",
    "sourceComment": "源社区@Mengteen 2025.8.2原创\n二传二创或者是其它问题请联系我。\n我邮箱:[xxxmgqxxx@vip.qq.com]\n我QQ:99737563(备注来意)\n1.不需要挂🪜子,不排除个别地方网络加载可能有点慢或者是需要挂🪜子才能访问，别急！\n2.使用了我自己的看图UI：卡片式标题,自适应全屏,查看大图浏览,返回顶上按钮,图片加载完成提示等。\n3.分类是按我自己个人喜欢的,你也可以放一些你自己喜欢的。\n4.只能用拼音搜索，例如:美女要用meinv来搜，用中文不生效！",
    "sourceGroup": "h",
    "sourceIcon": "https://cdn.sshs.rip/d0/df/d01dca8fdf5ffdf82c96203b73aa4ddf.webp",
    "sourceName": "👙私房图库",
    "sourceUrl": "http://www.sftuku.com/##@Mengteen",
    "variableComment": "🏄Mengteen提示：在此输入拼音关搜索！\n⚠️只能用拼音搜索，例如:美女要用meinv来搜，用中文不生效！"
  },
  {
    "articleStyle": 2,
    "concurrentRate": "5",
    "customOrder": 191,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "id.content.0@tag.article",
    "ruleContent": "id.msacwl-slider-1@tag.img@data-lazy##(.*)\n<pre>\n    <js>\n        imgList = result.split(\"\\n\");\n        imgDom = \"\";\n        for (let i = 0; i < imgList.length; i++) {\n          imgDom += `<img src=\"http://iph.href.lu/375x400?text=AiKan\" data-src=\"${imgList[i]}\" />`;\n        }\n      </js>\n</pre>\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0\" />\n<h3>{{@@class.entry-title.0@text}}</h3>\n<p>时间：{{@@class.updated.0@text}}</p>\n<p>{{@@class.entry-content@tag.p.[0:4]@text}}</p>\n<div id=\"imgbox\">{{result}}</div>\n<!-- tag.iframe.0@data-src -->\n<iframe src=\"{{@@tag.iframe.0@data-src}}\"></iframe>\n<link rel=\"stylesheet\" href=\"https://cdn.bootcdn.net/ajax/libs/viewerjs/1.10.1/viewer.min.css\" />\n<script src=\"https://cdn.bootcdn.net/ajax/libs/viewerjs/1.10.1/viewer.min.js\"></script>\n<script>\n  root = document.getElementById(\"imgbox\");\n  //查看大图插件\n  new Viewer(root, {\n    title: false,\n    interval: 3000,\n  });\n  lazy = new IntersectionObserver(\n    (entires) => {\n      console.log(\"entires\", entires);\n      entires.forEach((item) => {\n        if (item.isIntersecting) {\n          item = item.target;\n          item.src = item.getAttribute(\"data-src\");\n          lazy.unobserve(item);\n        }\n      });\n    },\n    {\n      root: root,\n      threshold: [0],\n      rootMargin: \"0px 0px 500px 0px\",\n    }\n  );\n\n  imgs = document.getElementsByTagName(\"img\");\n  Array.from(imgs).forEach((item) => {\n    lazy.observe(item);\n  });\n</script>\n",
    "ruleDescription": "",
    "ruleImage": "class.featured-image.0@tag.a.0@tag.img@data-src",
    "ruleLink": "class.featured-image.0@tag.a.0@href",
    "ruleNextPage": "page",
    "rulePubDate": "class.updated.0@text",
    "ruleTitle": "class.featured-image.0@tag.a.0@title",
    "shouldOverrideUrlLoading": "1",
    "singleUrl": false,
    "sortUrl": "首页::/\n搜索::/page/{{page}}?s={{(source.getVariable()==''||source.getVariable()==null)?source.setVariable('hokage'):source.getVariable()}}\n角色扮演::/category/ero-cosplay/page/{{page}}\n性感::/category/sexy-set/page/{{page}}\n在线视频::/category/online-video/page/{{page}}\nnude::/category/nude/page/{{page}}",
    "sourceComment": "首页只有10条",
    "sourceGroup": "呦呦鹿鸣",
    "sourceIcon": "https://mitaku.net/wp-content/uploads/2020/05/cropped-Mitaku-Logo-1-32x32.jpg",
    "sourceName": "Mitaku动漫Coser",
    "sourceUrl": "https://mitaku.net",
    "style": " body {\n    padding: 30rpx;\n  }\n  img {\n    display: block;\n    width: 100%;\n  }\n  iframe {\n    margin-top: 30rpx;\n    display: block;\n    width: 100%;\n    min-height: 200px;\n    border: 0;\n    outline: 0;\n    background: url(\"http://iph.href.lu/375x200?text=Video\") contian/center no-repeat;\n  }"
  },
  {
    "articleStyle": 1,
    "customOrder": 192,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "header": "{\"User-Agent\": \"Mozilla/5.0 (Linux; Android 12; 22041211AC Build/SP1A.210812.016) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.104 Mobile Safari/537.36\"}",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": ".list@li",
    "ruleContent": "<js>\nvar v = result.match(/source\\s*=\\s*[\"']([^\"']*?\\.(m3u8|mp4)\\b[^\"']*)[\"']/i);\nvar p = v ? v[1].replace(/\\\\/g,'') : '';\nvar t = '@get:{t}';\nvar d = java.getString('[property=\"video:tag\"]@content');\nvar sign1 = java.base64Decode('44CQ5aSc5piO56m644CR55qE5pKt5pS+5Zmo');\nvar sign2 = java.base64Decode('5LuF5L6b5Liq5Lq65a2m5Lmg5L2/55So77yM5Lil56aB5YiG5Lqr44CB5YCS5Y2W5Y+K5Lu75L2V6L+d5rOV6KGM5Li677yB');\nvar sign3 = java.base64Decode('5L2/55So6ICF6Ieq6KGM5om/5ouF6aOO6Zmp5LiO6LSj5Lu7');\n`<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>${t}</title>\n<style>\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,sans-serif;background:#f0f9ff;padding:10px}\n.v-box{max-width:800px;margin:0 auto;background:white;border-radius:12px;box-shadow:0 5px 15px rgba(0,0,0,0.1);overflow:hidden}\n.header{padding:12px;border-bottom:1px solid #eee;display:flex;flex-wrap:wrap;justify-content:space-between}\n.sign{background:#e9f7ff;padding:6px;border-radius:6px;margin-bottom:8px;font-size:14px;color:#1a73e8;width:100%}\n.title{font-size:18px;font-weight:600;margin-bottom:8px;width:100%}\n.tags{color:#5f6368;font-size:14px;flex:1;min-width:60%;word-break:break-all}\n.time{color:#5f6368;font-size:14px;text-align:right;flex-basis:35%}\n.v-wrap{position:relative;padding-top:56.25%;background:#000}\n.video{position:absolute;top:0;left:0;width:100%;height:100%}\n.footer{padding:8px;text-align:center;color:#5f6368;font-size:13px}\n.info-box{padding:15px;font-size:14px;line-height:1.6}\n.info-box p{margin:8px 0}\n.hint{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background:rgba(0,0,0,0.7);color:#fff;padding:12px 20px;border-radius:20px;font-size:1.1rem;z-index:10;display:none}\n.controls{position:absolute;top:0;left:0;width:100%;height:4px;background:rgba(255,255,255,0.3);z-index:5;transition:opacity 0.3s}\n.progress{height:100%;background:#4a9eff;width:0}\n</style>\n</head>\n<body>\n<div class=\"v-box\">\n<div class=\"header\">\n<div class=\"sign\" style=\"text-align:center;padding:5px 0\">\n<div>${sign1}</div>\n<div style=\"text-align:left; padding-top:4px\">\n${sign2}<br>${sign3}</div>\n</div>\n<div class=\"title\">${t}</div>\n<div class=\"tags\">${d}</div>\n<div class=\"time\" id=\"timeDisplay\">00:00/00:00</div></div>\n<div class=\"v-wrap\">\n<div class=\"controls\"><div class=\"progress\" id=\"progressBar\"></div></div>\n<div class=\"hint\" id=\"hint\">快进中 &gt;&gt;</div>\n<video class=\"video\" id=\"v\" controls playsinline>\n<source src=\"${p}\" type=\"video/mp4\">您的浏览器不支持HTML5视频\n</video>\n</div>\n<div class=\"footer\">滑动调整进度 | 长按2倍速</div>\n</div>\n<script>\nvar v = document.getElementById('v');\nvar tDisplay = document.getElementById('timeDisplay');\nvar pBar = document.getElementById('progressBar');\nvar hint = document.getElementById('hint');\nvar startX = 0, startTime = 0;\nvar longPressTimer;\nvar sensitivity = 0.1;\nvar longPressTime = 500;\nvar hintDuration = 2000;\nfunction updateTime() {\nif (!v.duration) return;\nvar m1 = Math.floor(v.currentTime / 60);\nvar s1 = Math.floor(v.currentTime % 60);\nvar m2 = Math.floor(v.duration / 60);\nvar s2 = Math.floor(v.duration % 60);\ntDisplay.textContent = m1 + ':' + (s1 < 10 ? '0' : '') + s1 + '/' + m2 + ':' + (s2 < 10 ? '0' : '') + s2;\npBar.style.width = (v.currentTime / v.duration) * 100 + '%';}\nv.addEventListener('timeupdate', updateTime);\nv.addEventListener('loadedmetadata', updateTime);\nv.addEventListener('touchstart', function(e) {\nstartX = e.touches[0].clientX;\nstartTime = Date.now();\nif (longPressTimer) clearTimeout(longPressTimer);\nhint.style.display = 'none';\nlongPressTimer = setTimeout(function() {\nv.playbackRate = 2.0;\nhint.style.display = 'block';\nsetTimeout(function() { hint.style.display = 'none'; }, hintDuration);}, longPressTime);});\nv.addEventListener('touchmove', function(e) {\ne.preventDefault();\nclearTimeout(longPressTimer);\nvar diffX = e.touches[0].clientX - startX;\nvar change = diffX * sensitivity * v.duration / 100;\nv.currentTime = Math.max(0, Math.min(v.currentTime + change, v.duration));\nstartX = e.touches[0].clientX;updateTime();});\nv.addEventListener('touchend', function() {\nv.playbackRate = 1.0;\nclearTimeout(longPressTimer);});\n</script>\n</body>\n</html>`\n</js>",
    "ruleImage": "img@data-original",
    "ruleLink": "a.0@href",
    "ruleNextPage": "page",
    "rulePubDate": "{{@@.vodlist_img@html##(\\d+)-(\\d+)-(\\d+)##$0###}} | {{@@.vodlist_img@span.0@text}}",
    "ruleTitle": ".title@text@put:{\"t\":\"@@.title@text\"}",
    "singleUrl": false,
    "sortUrl": "搜索 🔍::/s/page/{{page}}/wd/{{source.getVariable()}}/\n最新::/label/hot/by/time/page/{{page}}/\n日榜::/label/hot/by/hits_day/page/{{page}}/\n周榜::/label/hot/by/hits_week/page/{{page}}/\n月榜::/label/hot/by/hits_month/page/{{page}}/\n国产 🎞::/t/1-{{page}}/\n自拍::/t/5-{{page}}/\n主播大秀::/t/6-{{page}}/\n主播诱惑::/t/36-{{page}}/\n探花::/t/7-{{page}}/\n偷拍::/t/8-{{page}}/\n乱伦::/t/8-{{page}}/\n吃瓜::/t/10-{{page}}/\n抖阴::/t/11-{{page}}/\nAV::/t/12-{{page}}/\n福利姬::/t/20-{{page}}/\n侵犯::/t/37-{{page}}/\n日韩 🎞::/t/2-{{page}}/\n日韩自拍::/t/13-{{page}}/\n日本无码::/t/14-{{page}}/\n字幕::/t/15-{{page}}/\n解说::/t/17-{{page}}/\n换脸::/t/18-{{page}}/\n欧美 🎞::/t/3-{{page}}/\n自拍::/t/21-{{page}}/\n字幕::/t/22-{{page}}/\n伦理 🎞::/t/4-{{page}}/\n三级::/t/29-{{page}}/\n日韩::/t/30-{{page}}/\n动漫 🎞::/t/16-{{page}}/\n剧集::/t/26-{{page}}/\n3D::/t/27-{{page}}/\n次元::/t/28-{{page}}/\n另类 🎞::/t/39-{{page}}/\n同性恋::/t/38-{{page}}/\n变性::/t/40-{{page}}/\n重口味::/t/23-{{page}}/",
    "sourceComment": "<声明>\n//2025.8.10 作者：夜明空\n//源社区：https://taoba.cf\n//仅供个人学习使用，严禁分享、倒卖及任何违法行为！使用者自行承担风险与责任\n</声明>\n\n//网址更新频繁，有需要请到发布页自行更新\n//发布页：\nhttps://18j.18hu.link/mdce\n18j.vip\n18zy.vip\n51zy.vip",
    "sourceGroup": "呦呦鹿鸣",
    "sourceIcon": "https://18oc.life/18link/18j/images/favicon.ico",
    "sourceName": "18J-夜明空",
    "sourceUrl": "https://18oj.life/label/"
  },
  {
    "articleStyle": 3,
    "customOrder": 197,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 1775591744706,
    "loadWithBaseUrl": true,
    "ruleArticles": "ul@li",
    "ruleContent": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<title>内容提取</title>\n<!-- v2025.05.10 -->\n\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<script src=\"https://code.jquery.com/jquery-3.6.0.min.js\"></script>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.3/viewer.min.css\" />\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.3/viewer.min.js\"></script>\n<style>\n    body { font-family: Arial, sans-serif; font-size: 16px; }\n    #title, #page, #loading-status { margin: 0 auto; font-size: 20px; text-align: center; }\n    #description, #urls, #video-url, #video-sources, #messages { width: 100%; max-width: 800px; margin: 1.5px auto; font-size: 14px; text-align: left; word-wrap: break-word; white-space: pre-wrap; }\n    #text, #text :not(img), #text img + * { text-indent: 2em; width: 100%; font-size: 16px; line-height: 1.5em; margin-top: 0; margin-bottom: 0; word-wrap: break-word; white-space: pre-wrap; }\n    img, #text img { width: 100%; height: auto; display: block; margin-bottom: 1.5px; }\n    .flex-container { display: flex; justify-content: center; align-items: center; gap: 10px; margin: 1.5px 0; font-size: 14px; }\n    button, select { flex: 1 1 31%; padding: 3px; border: 1px solid #ccc; border-radius: 5px; box-sizing: border-box; cursor: pointer; background-color: #f9f9f9; transition: background-color 0.3s ease; margin: 1.5px; min-width: 0; font-size: 14px; }\n    #url-select, #video-source-select { flex: 1 1 100%; margin-left: 0; margin-right: 0; text-align: center; }\n    #video-element { width: 100%; height: auto; }\n    textarea { width: 100%; height: auto; min-height: 100px; box-sizing: border-box; resize: vertical; }\n    .error, .warn { color: red; }\n</style>\n</head>\n<body>\n    <h3 id=\"title\">{{@@title@text||h1.0@text||h2.0@text||.title.0@text}}</h3>\n    <p id=\"description\">{{@@.info.0@html||.jianjie@html}}</p>\n    <p id=\"page\" style=\"display:none;\">共<span id=\"total-pages\">1</span>页</p>\n    <p id=\"loading-status\" style=\"display:none;\"></p>\n\n    <div class=\"flex-container\" id=\"loading-buttons\" style=\"display:none;\">\n        <button id=\"prev-page-btn\">上一页</button>\n        <button id=\"next-page-btn\">下一页</button>\n        <button id=\"auto-load-btn\">自&nbsp;&nbsp;动</button>\n    </div>\n    \n    <div class=\"flex-container\">\n        <select id=\"url-select\" style=\"display:none;\"></select>\n    </div>\n    \n    <div class=\"flex-container\">\n        <button id=\"toggle-urls-btn\">显/隐网址</button>\n        <button id=\"toggle-messages-btn\">显/隐信息</button>\n        <button id=\"toggle-debug-btn\">显/隐调试</button>\n    </div>\n    <div id=\"urls\"></div>\n    <div id=\"messages\"></div>\n    <div id=\"debug-info\"></div>\n    <div id=\"video-url\"></div>\n    <div id=\"video-container\" style=\"display: none;\">\n        <video id=\"video-element\" controls preload=\"auto\" width=\"640\" height=\"264\">\n            <source id=\"video-source\" src=\"\" type=\"\">您的浏览器不支持 video 标签。\n        </video>\n    </div>\n    <div class=\"flex-container\" id=\"video-source-container\" style=\"display: none;\">\n        <select id=\"video-source-select\" onchange=\"updateVideoSource()\"></select>\n    </div>\n    <div id=\"images\"></div>\n    <div id=\"text\"></div>\n\n    <script>\n        // 配置对象，包含各种选择器、延迟时间等配置项\n        const config = {    \n            videoSelector: 'body', // 视频选择器\n            imgSelector: '.gridlane-box-inside img,.photos figure img,.content p img', // 图片选择器\n            textSelector: '#content', // 文本选择器\n            debugSelector: '#content, .page, .pager, .content, script', // 调试信息选择器\n            swapImageAttributes: false, // 是否交换图片属性\n            delayTime: 1500, // 延迟提取时间\n            retryDelayTime: 1500, // 重试加载延迟时间\n            maxLoadAttempts: 3, // 最大加载次数\n            autoLoading: false, // true自动模式，false单页模式\n            debugOnce: 0, // 只在特定索引输出一次调试信息\n            totalPagesText: '{{@@.page.0@a.-2@textNodes}}', // 总页码\n            urlSuffixToRemove: /\\.html$/, // 移除url后缀\n            pageUrlText: '{urlPrefix}_{i}.html', // 拼接URL模板        \n            ListMode: true, // true网址列表模式，false网址拼接模式    \n            initialUrls: `{{@@#sort-item-5.0@a@href}}`, // 网址\n            initialUrlsName: `{{@@#sort-item-5.0@a@span@text}}`, // 网址名称\n            sourceurl: '', // 来源URL前缀\n        };\n\n        let videoSources = []; // 存储视频源数组\n        let loadAttempts = {}; // 记录每个URL的加载尝试次数\n        let urls = []; // 存储所有页面的URL\n        let imageBox;\n        let textBox;\n        let currentPageIndex = 0; // 当前页面索引\n        let canLoadNextPage = true; // 控制是否可以加载下一页\n        let autoLoadInProgress = false; // 自动加载状态\n\n        // 构建URL列表\n        function buildUrls(totalPages, baseUrl) {\n            let initialUrlsArray = config.initialUrls.trim().split('\\n').filter(url => url.trim() !== '');\n            let initialUrlsNameArray = config.initialUrlsName.trim().split('\\n').filter(name => name.trim() !== '');\n\n            if (config.ListMode && initialUrlsArray.length > 0) {\n                if (initialUrlsArray.length !== initialUrlsNameArray.length) {\n                    $('#messages').append(`<span class=\"warn\">警告：initialUrls 和 initialUrlsName 的长度不匹配。</span><br>`);\n                }\n\n                urls = initialUrlsArray.map(url => {\n                    if (config.sourceurl && url.startsWith('/') && !/^https?:\\/\\//i.test(url)) {\n                        return config.sourceurl.replace(/\\/$/, '') + url;\n                    } else {\n                        return url;\n                    }\n                });\n\n                urls.forEach((url, index) => {\n                    const name = initialUrlsNameArray[index] || `第 ${index + 1} 页`;\n                    $('#url-select').append(`<option value=\"${index}\">${name}</option>`);\n                    $('#urls').append(`<div>${name}: ${url}</div>`);\n                });\n            } else {\n                if (totalPages === 1) {\n                    urls.push(baseUrl);\n                } else {\n                    urls.push(baseUrl);\n                    for (let i = 2; i <= totalPages; i++) {\n                        urls.push(config.pageUrlText.replace('{urlPrefix}', baseUrl.replace(config.urlSuffixToRemove, '').replace(/\\/$/, '')).replace('{i}', i));\n                    }\n                }\n\n                urls.forEach((url, index) => {\n                    const name = `第 ${index + 1} 页`;\n                    $('#url-select').append(`<option value=\"${index}\">${name}</option>`);\n                    $('#urls').append(`<div>${name}: ${url}</div>`);\n                });\n            }\n\n            $('#total-pages').text(urls.length);\n            toggleNavigationButtons();\n            toggleTotalPagesDisplay();\n        }\n\n        // 规范化URL\n        function normalizeUrl(url) {\n            if (typeof url !== 'string' || !url.trim()) {\n                return '';\n            }\n            const match = url.match(/['\"](.*?)['\"]/);\n            if (match && match[1]) {\n                url = match[1];\n            }\n\n            function processUrl(str) {\n                str = str.trim();\n                str = str.replace(/\\\\u[\\dA-F]{4}/gi, match => String.fromCharCode(parseInt(match.replace(/\\\\u/g, ''), 16)));\n                str = decodeURIComponent(str);\n                str = str.replace(/^http:\\/([^/])/, 'http://$1');\n                str = str.replace(/^https:\\/([^/])/, 'https://$1');\n                return str;\n            }\n            return processUrl(url);\n        }\n\n        // 清空容器内容\n        function clearContainers() {\n            $('#messages').empty();\n            $('#images').empty();\n            $('#text').empty();\n        }\n\n        // 更新图像源\n        function updateImageSrc(elements, shouldSwap) {\n            elements.each(function () {\n                const $this = $(this);\n                const attrsToUpdate = {};\n                if (shouldSwap) {\n                    ['data-original', 'data-src', 'data-url'].forEach(attr => {\n                        if ($this.attr(attr)) {\n                            attrsToUpdate['src'] = $this.attr(attr);\n                        }\n                    });\n                }\n                $this.attr(attrsToUpdate);\n            });\n            return elements;\n        }\n\n        // 切换导航按钮显示状态\n        function toggleNavigationButtons() {\n            if ($('#url-select option').length > 1 && !config.autoLoading) {\n                $('#loading-buttons').show();\n                $('#url-select').show();\n            } else {\n                $('#loading-buttons').hide();\n                $('#url-select').hide();\n            }\n        }\n\n        // 显示加载状态\n        function showLoadingStatus(pageNumber) {\n            const selectedOption = $('#url-select option:selected').text();\n            $('#loading-status').text(`正在加载：${selectedOption}`).show();\n        }\n\n        // 隐藏加载状态\n        function hideLoadingStatus() {\n            $('#loading-status').hide();\n        }\n\n        // 加载指定索引的内容\n        function loadContent(index) {\n            if (index < 0 || index >= urls.length || !canLoadNextPage) return;\n            canLoadNextPage = false;\n            currentPageIndex = index;\n            $('#url-select').val(index);\n            $('#messages').append(`<div>当前地址: <span class=\"warn\">${urls[index]}</span></div>`);\n            if (autoLoadInProgress) {\n                showLoadingStatus(index + 1);\n            }\n            $.ajax({\n                url: urls[index],\n                type: 'GET',\n                success: function (data) {\n                    try {\n                    const $data = $(data);\n                    let updatedHtmlContent = data.replace(/(['\"])(\\/\\/)(?!\\/)/g, '$1https://')\n                        .replace(/src=\"upload/gi, 'src=\"/upload')\n                        .replace(/style=[\"'][^'\"]+[\"']/gi, '')\n                        .replace(/\\\\\\//g, '/');\n                    const parser = new DOMParser();\n                    const doc = parser.parseFromString(updatedHtmlContent, \"text/html\");\n\n                    if (config.debugOnce === index) {\n                        const debugElements = $(doc).find(config.debugSelector);\n                        if (debugElements.length > 0) {\n                            const debugContents = $('<pre>').html(debugElements.clone().wrapAll('<div/>').parent().html()).html();\n                            $('#debug-info').html(`<span class=\"warn\">调试信息: <textarea rows=\"10\" cols=\"80\">${debugContents}</textarea></span>`);\n                        } else {\n                            $('#debug-info').html(`<span class=\"warn\">调试信息: <textarea rows=\"10\" cols=\"80\">调试信息未提取到内容，请检查选择器！</textarea></span>`);\n                        }\n                    }\n                    // 方法1：提取视频\n                    const videoSources1 = [];\n                    const videoContents = $(doc).find(config.videoSelector);\n                    const videoTags = $(videoContents).find('video, source');\n                    videoTags.each(function() {\n                        const videosrc = $(this).attr('src') || \n                                     $(this).attr('data-src') || \n                                     $(this).attr('data-original') || '';\n                        \n                        if (videosrc) {\n                            videoSources1.push(videosrc);\n                        }\n                    });\n                    //反馈\n                    if (videoSources1.length > 0) {\n                        $('#messages').append(`<span>方法1，找到 ${videoSources1.length} 个视频。</span><br>`);\n                    }\n\n                    // 方法2：正则提取视频\n                    const regex = /['\"]https?[^'<>\"]+(m3u8|mp4|webm|ogg|flv|mp3|m4a|wav|ape|flac)([^'<>\"]+)?['\"]/gi;\n                    const matches = data.match(regex);\n                    const videoSources2 = [];\n\n                    if (matches) {\n                        const uniqueMatches = [...new Set(matches)];\n                    \n                        uniqueMatches.forEach(match => {\n                            const normalizedSrc = normalizeUrl(match.replace(/['\"]/g, ''));\n                            videoSources2.push(normalizedSrc);\n                        });\n                    }\n                    //反馈\n                    if (videoSources2.length > 0) {\n                        $('#messages').append(`<span>方法2，找到 ${videoSources2.length} 个视频。</span><br>`);\n                    }\n\n                    // 合并两种方法的结果\n                    videoSources = [...videoSources1, ...videoSources2];\n\n                    // 去重并标准化 URL\n                    const imageExtensions = /\\.(jpg|jpeg|png|gif|bmp|svg)$/i;\n\n                    videoSources = videoSources\n                                  .map(src => normalizeUrl(src.replace(/\\\\+/g, '')))\n                                  .filter(src => src) // 过滤空值\n                                  .filter(src => !imageExtensions.test(src)); // 移除图片地址\n                        \n                    videoSources = [...new Set(videoSources)];// 去重\n\n                    // 显示最终结果\n                    $('#messages').append(`<span>总共找到 ${videoSources.length} 个视频。</span><br>`);\n\n                    if (videoSources.length > 0) {\n                        $('#messages').append(`<span>成功提取到视频，找到 ${videoSources.length} 个视频。</span><br>`);\n                        videoSources.forEach((src, idx) => {\n                            $('#messages').append(`<div>视频地址:<span class=\"warn\"> ${src}</span><br></div>`);\n                            $('#video-source-select').append(`<option value=\"${idx}\">视频源 ${idx + 1}</option>`);\n                        });\n                    \n                        if (videoSources.length == 1) {\n                            $('#video-container').show();\n                            $('#video-url').show();\n                            $('#video-source-container').hide();\n                            updateVideoSource();\n                        } else if (videoSources.length > 1) {\n                            $('#video-container').show();\n                            $('#video-url').show();\n                            $('#video-source-container').show();\n                            updateVideoSource();\n                        } else {\n                            $('#video-container').hide();\n                            $('#video-url').hide();\n                            $('#video-source-container').hide();\n                        }\n                    } else {\n                        $('#messages').append(`<span class=\"warn\">未找到视频源。</span><br>`);\n                        $('#video-container').hide();\n                        $('#video-url').hide();\n                        $('#video-source-container').hide();\n                    }\n\n                    //提取图片\n                    const $imgContents = $(doc).find(config.imgSelector);\n                    const shouldSwap = config.swapImageAttributes;\n                    const newContents = updateImageSrc($imgContents.clone(), shouldSwap);\n                    $('#images').append(newContents).show();\n                    if (newContents.length > 0) {\n                        $('#messages').append(`<span>成功提取图片，共 ${newContents.length} 张。</span><br>`);\n                        newContents.each(function () {\n                            const imgSrc = $(this).attr('src') || $(this).attr('data-original') || $(this).attr('data-src') || $(this).attr('data-url');\n                            $('#messages').append(`<div>地址:<span class=\"warn\"> ${imgSrc}</span><br></div>`);\n                        });\n                    } else {\n                        $('#messages').append(`<span class=\"warn\">未提取到图片。</span><br>`);\n                    }\n\n                    //提取图片和文本\n                    const textContents = $(doc).find(config.textSelector).map(function () {\n                        const $currentContents = $(this);\n                        $currentContents.find('img + br, script, video, source, iframe').remove();\n                        $currentContents.html($currentContents.html().replace(/>\\s+/gi, '>').replace(/<\\/?br\\s*([^>]*)\\s*\\/?>/gi, '\\n').replace(/\\n+/g, '\\n'));\n                        return $currentContents.html();\n                    }).get().join('');\n                    if (textContents.trim()) {\n                        $('#text').append(`<span>${textContents}</span><br>`).show();\n                        $('#messages').append(`<span>成功提取图文。</span><br>`);\n                    } else {\n                        $('#messages').append(`<span class=\"warn\">未提取到图文。</span><br>`);\n                    }\n\n                    if (autoLoadInProgress && currentPageIndex < urls.length - 1) {\n                        setTimeout(() => { \n                            canLoadNextPage = true;\n                            loadContent(currentPageIndex + 1); \n                        }, config.delayTime);\n                    } else {\n                        canLoadNextPage = true;\n                        if (autoLoadInProgress) {\n                            hideLoadingStatus();\n                        }\n                    }\n                } catch (parseError) {\n                    $('#messages').append(`<span class=\"error\">解析页面内容时发生错误: ${parseError.message}</span><br>`);\n                    handleLoadFailure(urls, index);\n                } finally {\n                    if (imageBox) imageBox.viewer.update();\n                    if (textBox) textBox.viewer.update();\n                }\n            },\n            error: function (jqXHR, textStatus, errorThrown) {\n                let errorMessage = `内容加载失败: ${urls[index]}`;\n                switch (textStatus) {\n                    case 'timeout':\n                        errorMessage += ', 请求超时';\n                        break;\n                    case 'abort':\n                        errorMessage += ', 请求被取消';\n                        break;\n                    case 'parsererror':\n                        errorMessage += ', 解析响应出错';\n                        break;\n                    default:\n                        errorMessage += `, 状态码: ${jqXHR.status}, 错误信息: ${errorThrown}`;\n                        break;\n                }\n                $('#messages').append(`<span class=\"error\">${errorMessage}</span><br>`);\n                handleLoadFailure(urls, index);\n                }\n            });\n        }\n\n        // 处理加载失败的情况\n        function handleLoadFailure(urls, index) {\n            if (!loadAttempts[urls[index]]) {\n                loadAttempts[urls[index]] = 1;\n            } else {\n                loadAttempts[urls[index]]++;\n            }\n            if (loadAttempts[urls[index]] <= config.maxLoadAttempts) {\n                const retryMessage = `第${index + 1}页加载失败，正在进行第${loadAttempts[urls[index]]}次加载！`;\n                $('#messages').append(`<span class=\"error\">${retryMessage}</span><br>`);\n                setTimeout(() => { \n                    canLoadNextPage = true;\n                    loadContent(index); \n                }, config.retryDelayTime);\n            } else {\n                const finalErrorMessage = `第${index + 1}页加载失败，已达到最大尝试次数(${config.maxLoadAttempts})！`;\n                $('#messages').append(`<span class=\"error\">${finalErrorMessage}</span><br>`);\n                if (autoLoadInProgress && currentPageIndex < urls.length - 1) {\n                    setTimeout(() => { \n                        canLoadNextPage = true;\n                        loadContent(currentPageIndex + 1); \n                    }, config.delayTime);\n                } else {\n                    canLoadNextPage = true;\n                    if (autoLoadInProgress) {\n                        hideLoadingStatus();\n                    }\n                }\n            }\n        }\n\n        // 更新视频源\n        function updateVideoSource() {\n            const selectedIndex = parseInt(document.getElementById('video-source-select').value);\n            if (isNaN(selectedIndex) || !videoSources[selectedIndex]) {\n                $('#messages').append(`<span class=\"warn\">未找到有效的视频源。</span><br>`);\n                console.warn(\"Invalid or undefined video source:\", selectedIndex, videoSources);\n                return;\n            }\n\n            const selectedSource = videoSources[selectedIndex];\n            document.getElementById('video-url').textContent = `视频地址:\\n ${selectedSource}`;\n\n            const videoSourceElement = document.getElementById('video-source');\n            videoSourceElement.src = selectedSource;\n\n            const videoElement = document.getElementById('video-element');\n            videoElement.load();\n\n            $('#messages').append(`<span>更新视频源为: ${selectedSource}</span><br>`);\n            console.log(\"Updated video source to:\", selectedSource);\n        }\n\n        // 切换总页数显示状态\n        function toggleTotalPagesDisplay() {\n            if (urls.length > 1) {\n                $('#page').show();\n            } else {\n                $('#page').hide();\n            }\n        }\n\n        // 页面加载完成后执行的主要逻辑\n        $(document).ready(function () {\n            imageBox = document.getElementById('images');\n            textBox = document.getElementById('text');\n            if (imageBox && textBox) {\n                new Viewer(imageBox, { title: true, interval: 2000 });\n                new Viewer(textBox, { title: true, interval: 2000 });\n            }\n\n            const totalPagesText = config.totalPagesText;\n            const totalPages = parseInt(totalPagesText, 10) || 1;\n            const baseUrl = '{{baseUrl}}';\n\n            clearContainers();\n            $('#urls, #debug-info textarea, #video-url, #video-source-select').empty();\n            $('#urls, #messages, #debug-info, #video-url, #video-container, #video-source-container, #images, #text').hide();\n\n            buildUrls(totalPages, baseUrl);\n\n            const urlSelect = document.getElementById('url-select');\n            if (urlSelect.options.length > 0) {\n                urlSelect.value = '0'; \n\n                if (config.autoLoading) {\n                    autoLoadInProgress = true;\n                    for (let i = 0; i < urls.length; i++) {\n                        loadContent(i);\n                    }\n                } else {\n                    loadContent(0);\n                }\n            } else {\n                loadContent(0);\n            }\n\n            $('#url-select').change(function () {\n                clearContainers();\n                const selectedIndex = parseInt($(this).val());\n                loadContent(selectedIndex);\n            });\n            $('#prev-page-btn').click(function () {\n                clearContainers();\n                if (currentPageIndex > 0) {\n                    loadContent(currentPageIndex - 1);\n                }\n            });\n            $('#next-page-btn').click(function () {\n                clearContainers();\n                if (currentPageIndex < urls.length - 1) {\n                    loadContent(currentPageIndex + 1);\n                }\n            });\n            $('#auto-load-btn').click(function () {\n                autoLoadInProgress = true;\n                showLoadingStatus(1); \n                for (let i = currentPageIndex + 1; i < urls.length; i++) {\n                    loadContent(i);\n                }\n            });\n            $('#toggle-messages-btn').click(function () { $('#messages').toggle(); });\n            $('#toggle-urls-btn').click(function () { $('#urls').toggle(); });\n            $('#toggle-debug-btn').click(function () { $('#debug-info').toggle(); });\n        });\n    </script>\n</body>\n</html>",
    "ruleImage": "a@data-original",
    "ruleLink": "a.0@href",
    "ruleNextPage": "page||text.下一页@href",
    "rulePubDate": "[class=\"pic-text text-right\"]@text",
    "ruleTitle": "h4@text",
    "singleUrl": false,
    "sortUrl": "搜索🔍::/jiejie/index.php/vod/search.html?wd={{source.getVariable()}}\n黄瓜资源::/jiejie/index.php/vod/type/id/87.html\n155资源::/jiejie/index.php/vod/type/id/248.html\n森林资源::/jiejie/index.php/vod/type/id/117.html\n奥斯卡资源::/jiejie/index.php/vod/type/id/86.html\n百万资源::/jiejie/index.php/vod/type/id/237.html\n制服诱惑::/jiejie/index.php/vod/show/id/251.html\n中文字幕::/jiejie/index.php/vod/show/id/254.html\n美乳巨乳::/jiejie/index.php/vod/show/id/262.html\n熟女人妻::/jiejie/index.php/vod/show/id/259.html\n萝莉少女::/jiejie/index.php/vod/show/id/260.html\n强奸乱伦::/jiejie/index.php/vod/show/id/263.html\n无码专区::/jiejie/index.php/vod/show/id/249.html",
    "sourceComment": "jiejiesp.xyz",
    "sourceGroup": "美涩",
    "sourceIcon": "https://img4.tuwandata.com/v2/thumb/jpg/NWFkMywxMTI1LDAsOSwzLDEsLTEsTk9ORSwsLDkw/u/res.tuwan.com/zipgoods/20190508/3b6408c569f8eb687a8dd6eb3578bdb9.jpg",
    "sourceName": "姐姐视频",
    "sourceUrl": "https://wap.jiejiesp19.xyz"
  },
  {
    "articleStyle": 1,
    "customOrder": 218,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "$.rescont.data",
    "ruleContent": "<video src=\"{{$.rescont.videopath}}\" controls width=\"auto\" height=\"auto\"></video>",
    "ruleImage": "$.coverpath",
    "ruleLink": "http://lu3fcm.aksdsrle.com/api/videoplay/{{$.id}}?&uuid=1",
    "ruleNextPage": "page",
    "rulePubDate": "{{$.authername}}",
    "ruleTitle": "$.title",
    "singleUrl": false,
    "sortUrl": "性感佳人::http://lu3fcm.aksdsrle.com/api/videosort/9?orderby=&page={{page}}&uuid=1&device=0\n国产精品::http://lu3fcm.aksdsrle.com/api/videosort/10?orderby=&page={{page}}&uuid=1&device=0\nH动漫::http://lu3fcm.aksdsrle.com/api/videosort/14?orderby=&page={{page}}&uuid=1&device=0\n欧美激情::http://lu3fcm.aksdsrle.com/api/videosort/16?orderby=&page={{page}}&uuid=1&device=0\n三级电影::http://lu3fcm.aksdsrle.com/api/videosort/25?orderby=&page={{page}}&uuid=1&device=0\n高清无码::http://lu3fcm.aksdsrle.com/api/videosort/26?orderby=&page={{page}}&uuid=1&device=0\n美乳巨乳::http://lu3fcm.aksdsrle.com/api/videosort/27?orderby=&page={{page}}&uuid=1&device=0\n少女萝莉::http://lu3fcm.aksdsrle.com/api/videosort/28?orderby=&page={{page}}&uuid=1&device=0\n家庭乱伦::http://lu3fcm.aksdsrle.com/api/videosort/29?orderby=&page={{page}}&uuid=1&device=0\n绝顶潮吹::http://lu3fcm.aksdsrle.com/api/videosort/30?orderby=&page={{page}}&uuid=1&device=0\n痴女淫乱::http://lu3fcm.aksdsrle.com/api/videosort/31?orderby=&page={{page}}&uuid=1&device=0\n强奸凌辱::http://lu3fcm.aksdsrle.com/api/videosort/34?orderby=&page={{page}}&uuid=1&device=0\n制服丝袜::http://lu3fcm.aksdsrle.com/api/videosort/35?orderby=&page={{page}}&uuid=1&device=0\nAV剧情::http://lu3fcm.aksdsrle.com/api/videosort/36?orderby=&page={{page}}&uuid=1&device=0\n人妻熟女::http://lu3fcm.aksdsrle.com/api/videosort/37?orderby=&page={{page}}&uuid=1&device=0\n偷拍盗摄::http://lu3fcm.aksdsrle.com/api/videosort/38?orderby=&page={{page}}&uuid=1&device=0\n风俗沙龙::http://lu3fcm.aksdsrle.com/api/videosort/39?orderby=&page={{page}}&uuid=1&device=0\n国产传媒::http://lu3fcm.aksdsrle.com/api/videosort/40?orderby=&page={{page}}&uuid=1&device=0\n女同性恋::http://lu3fcm.aksdsrle.com/api/videosort/41?orderby=&page={{page}}&uuid=1&device=0\n直播网红::http://lu3fcm.aksdsrle.com/api/videosort/42?orderby=&page={{page}}&uuid=1&device=0\n国产AV::http://lu3fcm.aksdsrle.com/api/videosort/44?orderby=&page={{page}}&uuid=1&device=0\nSM调教::http://lu3fcm.aksdsrle.com/api/videosort/45?orderby=&page={{page}}&uuid=1&device=0\nAV解说::http://lu3fcm.aksdsrle.com/api/videosort/49?orderby=&page={{page}}&uuid=1&device=0\n热门爆料::http://lu3fcm.aksdsrle.com/api/videosort/50?orderby=&page={{page}}&uuid=1&device=0",
    "sourceGroup": "版本",
    "sourceIcon": "",
    "sourceName": "6.9",
    "sourceUrl": "http://lu3fcm.aksdsrle.com/api/videosort/9?orderby=&page=1&uuid=1&device=0"
  },
  {
    "articleStyle": 0,
    "coverDecodeJs": "function toByteArray(input) {\n  var out = new Packages.java.io.ByteArrayOutputStream();\n  var buffer = java.strToBytes('\\0'.repeat(4096));\n  var bytesRead;\n  while ((bytesRead = input.read(buffer)) != -1) {\n    out.write(buffer, 0, bytesRead);\n  }\n  return out.toByteArray();\n}\n\n(function() {\n  if (src.endsWith('.gif')) {\n    return toByteArray(result);\n  }\n\n  // 非GIF文件继续走AES解密逻辑\n  var keyBytes = \"102_53_100_57_54_53_100_102_55_53_51_51_54_50_55_48\"\n    .split('_')\n    .map(c => parseInt(c, 10));\n\n  var ivBytes = \"57_55_98_54_48_51_57_52_97_98_99_50_102_98_101_49\"\n    .split('_')\n    .map(c => parseInt(c, 10));\n\n  return java.createSymmetricCrypto(\n    \"AES/CBC/PKCS5Padding\", \n    keyBytes,\n    ivBytes\n  ).decrypt(result);\n})();",
    "customOrder": 220,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "header": "{\n    \"User-Agent\": \"Mozilla/5.0 (Linux; Android 11; Pixel 3 XL Build/RQ3A.211001.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/102.0.4988.0 Mobile Safari/537.36 SearchCraft/3.9.2 (Baidu; P1 11)\",\n\t\"referer\": \"{{baseUrl}}\"\n}",
    "injectJs": "function setupCustomPlayer(video) {\n  // 手势滑动快进\n  let isDragging = false;\n  let startX = 0;\n  let startTime = 0;\n  \n  // 长按加速相关变量\n  let longPressTimer = null;\n  const LONG_PRESS_DELAY = 300;\n  const NORMAL_SPEED = 1.25;\n  const FAST_SPEED = 3;\n  let wasPaused = false;\n\n  // 触摸事件处理\n  function handleTouchStart(e) {\n    startX = e.touches[0].clientX;\n    startTime = video.currentTime;\n    wasPaused = video.paused;\n    \n    longPressTimer = setTimeout(() => {\n      video.playbackRate = FAST_SPEED;\n      if (wasPaused) video.play();\n    }, LONG_PRESS_DELAY);\n  }\n\n  function handleTouchMove(e) {\n    if (longPressTimer) {\n      clearTimeout(longPressTimer);\n      longPressTimer = null;\n    }\n    \n    const dx = e.touches[0].clientX - startX;\n    if (Math.abs(dx) > 10) {\n      if (!isDragging) {\n        video.pause();\n        isDragging = true;\n      }\n      const change = (dx / video.clientWidth) * video.duration;\n      video.currentTime = Math.max(0, Math.min(startTime + change, video.duration));\n    }\n  }\n\n  function handleTouchEnd() {\n    if (longPressTimer) {\n      clearTimeout(longPressTimer);\n      longPressTimer = null;\n    }\n    \n    if (isDragging) {\n      video.playbackRate = NORMAL_SPEED;\n      video.play();\n      isDragging = false;\n    } else if (video.playbackRate === FAST_SPEED) {\n      video.playbackRate = NORMAL_SPEED;\n      if (wasPaused) video.pause();\n    }\n  }\n\n  // 添加触摸事件监听\n  video.addEventListener('touchstart', handleTouchStart);\n  video.addEventListener('touchmove', handleTouchMove);\n  video.addEventListener('touchend', handleTouchEnd);\n  \n  // 初始播放速度\n  video.playbackRate = NORMAL_SPEED;\n\n  // 创建按钮的通用函数\n  function createButton(text, onClick, position, width = '20px') {\n    const button = document.createElement('button');\n    button.textContent = text;\n    button.style.position = 'absolute';\n    button.style[position.horizontal] = '0';\n    button.style.top = '50%';\n    button.style.transform = 'translateY(-50%)';\n    button.style.zIndex = '999';\n    button.style.padding = '1px';\n    button.style.background = 'rgba(51, 51, 51, 0)';\n    button.style.color = '#fff';\n    button.style.border = 'none';\n    button.style.cursor = 'pointer';\n    button.style.width = width;\n    button.style.height = '30px';\n    button.addEventListener('click', onClick);\n    video.parentNode.appendChild(button);\n    return button;\n  }\n\n  // 旋转按钮（右侧）\n  createButton('⟳', () => {\n    const currentRotation = parseInt(video.getAttribute('data-rotation') || '0');\n    const newRotation = (currentRotation + 90) % 360;\n    video.setAttribute('data-rotation', newRotation);\n    \n    // 保留当前的缩放比例\n    const currentTransform = video.style.transform || '';\n    let currentScale = 1;\n    const scaleMatch = currentTransform.match(/scale\\(([^)]+)\\)/);\n    if (scaleMatch) currentScale = parseFloat(scaleMatch[1]);\n    \n    video.style.transform = `rotate(${newRotation}deg) scale(${currentScale})`;\n  }, { horizontal: 'right' });\n\n  // 缩放按钮（左侧）\n  let zoomCount = 0;\n  createButton('+', () => {\n    const currentRotation = parseInt(video.getAttribute('data-rotation') || '0');\n    \n    // 获取当前缩放比例\n    const currentTransform = video.style.transform || '';\n    let currentScale = 1;\n    const scaleMatch = currentTransform.match(/scale\\(([^)]+)\\)/);\n    if (scaleMatch) currentScale = parseFloat(scaleMatch[1]);\n    \n    if (zoomCount < 4) {\n      const newScale = currentScale * 1.25;\n      video.style.transform = `rotate(${currentRotation}deg) scale(${newScale})`;\n      zoomCount++;\n    } else {\n      video.style.transform = `rotate(${currentRotation}deg) scale(1)`;\n      zoomCount = 0;\n    }\n  }, { horizontal: 'left' });\n\n  // 快速跳转按钮（底部中央）\n  const buttonContainer = document.createElement('div');\n  buttonContainer.style.position = 'absolute';\n  buttonContainer.style.bottom = '0';\n  buttonContainer.style.left = '50%';\n  buttonContainer.style.transform = 'translateX(-50%)';\n  buttonContainer.style.display = 'flex';\n  buttonContainer.style.gap = '10px';\n  buttonContainer.style.zIndex = '999';\n  \n  // 按钮配置\n  const seekButtons = [\n    { text: '-5分', time: -300 },\n    { text: '-1分', time: -60 },\n    { text: '+1分', time: 60 },\n    { text: '+5分', time: 300 }\n  ];\n\n  seekButtons.forEach(({ text, time }) => {\n    const button = document.createElement('button');\n    button.textContent = text;\n    button.style.padding = '1px';\n    button.style.background = 'rgba(51, 51, 51, 0)';\n    button.style.color = '#fff';\n    button.style.border = 'none';\n    button.style.cursor = 'pointer';\n    button.style.width = '60px';\n    button.style.height = '30px';\n    button.addEventListener('click', () => {\n      video.currentTime = Math.max(0, Math.min(video.currentTime + time, video.duration));\n    });\n    buttonContainer.appendChild(button);\n  });\n\n  video.parentNode.appendChild(buttonContainer);\n}\n\n// 修改初始化逻辑，增加重试机制\nfunction initPlayerWithRetry() {\n  const maxRetries = 10;\n  const retryInterval = 500;\n  let retries = 0;\n  const tryInit = () => {\n    const video = document.getElementById('video');\n    if (video) {\n      setupCustomPlayer(video);\n    } else if (retries < maxRetries) {\n      retries++;\n      setTimeout(tryInit, retryInterval);\n    }\n  };\n  tryInit();\n}\n// 使用重试机制初始化播放器\ninitPlayerWithRetry();",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": ".video-item",
    "ruleContent": "{{@@.player-container@script@all}}\n@js:\nvar scriptContent = result.match(/<script>([\\s\\S]*?)<\\/script>/)[1];\nvar decoded = eval(scriptContent.split('eval').join(''));\n\nvar fakeDoc = {write: function(h) { this.h = h; }};\neval(decoded.split('document').join('fakeDoc'));\n\nvar src = fakeDoc.h.match(/src=\"([^\"]*)\"/)[1];\nvar response = java.ajax(source.sourceUrl + src);\n\nif (response && response.indexOf('eval(function(p,a,c,k,e,d)') === 0) {\n    var innerDecoded = eval(response.split('eval').join(''));\n    var fakeDoc2 = {write: function(h) { this.h = h; }};\n    eval(innerDecoded.split('document').join('fakeDoc2'));\n    result = fakeDoc2.h.match(/data-url=\"([^\"]*)\"/)[1];\n} else {\n    result = response;\n}\n\n// 定义所有视频源\n//var sources = [`${result}`,`${play4}`];\nvar sources = [`${result}`];\n\n// 生成源按钮\nvar sourceButtons = \"\";\nif (sources.length > 1) {\n    for (var i = 0; i < sources.length; i++) {\n        sourceButtons += `<button class=\"source-btn\" data-index=\"${i}\">源${i+1}</button>`;\n    }\n}\n\nresult=`\n<html>  \n<head>  \n<meta charset=\"utf-8\">  \n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no\">\n<meta name=\"referrer\" content=\"never\"/>\n<script src=\"https://s4.zstatic.net/ajax/libs/hls.js/1.6.13/hls.min.js\"></script>\n<style>\nhtml, body { text-align: center;margin: 0; padding: 0; width: 100%; overflow: hidden; }\n.source-container { position: absolute; top: 23px; right: 1px; z-index: 10; display: flex; gap: 1px; }\n.source-btn { color: #ff0; background: rgba(0,0,0,0.7); padding: 1px 5px; border-radius: 10px; font-size: 13px; border: none; cursor: pointer; }\n.source-btn.active { color: red !important; }\n</style>\n</head>  \n<body>  \n<div class=\"container\">\n    <div class=\"title\">{{@@h1@text##A片|日本AV}}</div>\n    ${sources.length > 1 ? `<div class=\"source-container\">${sourceButtons}</div>` : ''}\n    <video id=\"video\" width=\"100%\" height=\"91%\" controls autoplay muted loop></video>\n<script>\n    const video = document.getElementById('video');\n    const sources = ${JSON.stringify(sources)};\n    let hls = null;\n    let currentSource = 0;\n    \n    // 初始化HLS播放\n    function playHLS(url) {\n        if (hls) hls.destroy();\n        \n        if (Hls.isSupported()) {\n            hls = new Hls({\nenableSoftwareAES: true, // 强制软件解密\nforceKeyFrameOnDiscontinuity: true, // 关键帧恢复\n\nenableWorker: true, // 启用Web Worker提升性能\nlowLatencyMode: false, // 点播关闭低延迟模式\nbackBufferLength: 90, // 增加后缓冲长度，支持快速回退\n      \nmaxBufferLength: 30,  // 最大缓冲区长度(秒)\nmaxMaxBufferLength: 60,   // 绝对最大缓冲区长度\nmaxBufferSize: 60 * 1000 * 1000,  // 缓冲区大小限制(60MB)\nmaxBufferHole: 0.5, // 减少缓冲区空洞容忍度\n\nabrEwmaFastLive: 3.0,   // 快速ABR响应\nabrEwmaSlowLive: 9.0, // 慢速ABR响应  \nabrEwmaDefaultEstimate: 500000,  // 默认带宽估计(500kbps)\nabrMaxWithRealBitrate: true, // 基于实际码率进行ABR\nmaxFragLookUpTolerance: 0.25, // 片段查找容差\n\nfragLoadingMaxRetry: 6, // 片段加载重试次数\nfragLoadingRetryDelay: 1000, // 片段加载重试延迟\nmanifestLoadingMaxRetry: 3, // 清单加载重试次数\nlevelLoadingMaxRetry: 4, // 级别加载重试次数\n    });\n            hls.loadSource(url);\n            hls.attachMedia(video);\n        } else if (video.canPlayType('application/vnd.apple.mpegurl')) {\n            video.src = url;\n        }\n    }\n    \n    // 切换视频源\n    function switchSource(index) {\n        currentSource = index;\n        playHLS(sources[index]);\n        updateButtons();\n    }\n    \n    // 更新按钮状态\n    function updateButtons() {\n        document.querySelectorAll('.source-btn').forEach((btn, i) => {\n            btn.classList.toggle('active', i === currentSource);\n        });\n    }\n    \n    // 绑定按钮事件\n    document.querySelectorAll('.source-btn').forEach(btn => {\n        btn.addEventListener('click', () => switchSource(parseInt(btn.dataset.index)));\n    });\n    \n    // 播放第一个源\n    if (sources.length > 0) switchSource(0);\n</script>\n<script src=\"https://s4.zstatic.net/ajax/libs/crypto-js/4.1.1/crypto-js.min.js\"></script>\n<script>\n// 密钥配置\nconst KEY_STR = \"102_53_100_57_54_53_100_102_55_53_51_51_54_50_55_48\";\nconst IV_STR = \"57_55_98_54_48_51_57_52_97_98_99_50_102_98_101_49\";\n\nconst key = CryptoJS.enc.Utf8.parse(\n  KEY_STR.split('_').map(c => String.fromCharCode(parseInt(c, 10))).join('')\n);\nconst iv = CryptoJS.enc.Utf8.parse(\n  IV_STR.split('_').map(c => String.fromCharCode(parseInt(c, 10))).join('')\n);\n\n// ArrayBuffer转Base64\nasync function ab2b64(buffer) {\n  return new Promise(resolve => {\n    const reader = new FileReader();\n    reader.onload = () => resolve(reader.result.split(',')[1]);\n    reader.readAsDataURL(new Blob([buffer]));\n  });\n}\n\n// 简化后的解密函数\nasync function decryptImageToBlob(url) {\n  const response = await fetch(url, { mode: 'cors' });\n  const buffer = await response.arrayBuffer();\n  const base64Data = await ab2b64(buffer);\n\n  const decrypted = CryptoJS.AES.decrypt(\n    base64Data,\n    key,\n    { iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }\n  );\n\n  const decryptedBytes = new Uint8Array(\n    decrypted.toString(CryptoJS.enc.Latin1)\n      .split('')\n      .map(c => c.charCodeAt(0))\n  );\n\n  return URL.createObjectURL(new Blob([decryptedBytes], { type: 'image/jpeg' }));\n}\n\n// 直接执行解密设置\nwindow.addEventListener('DOMContentLoaded', () => {\n  const video = document.getElementById('video');\n  const originalPoster = \"${java.get('pic')}\";\n  \n  decryptImageToBlob(originalPoster).then(decryptedUrl => {\n    video.poster = decryptedUrl;\n  });\n});\n</script>\n</div>\n</body>  \n</html>\n`;",
    "ruleImage": "{{@@img@data-src}}\n<js>\njava.put('pic',result)\n</js>",
    "ruleLink": "{{@@a.0@href}}",
    "ruleNextPage": "page",
    "rulePubDate": "{{@@img@data-src##\\/(\\d{8})\\/##$1##}}  ⏱️{{@@.text-sm.0@text}} ",
    "ruleTitle": "@js:\nif (/广告|禁漫/.test(`{{@@.text-sm@text}}`)) {\n    result = \"\";\n} else {\n    result = \"{{@@img@alt##.*屎.*|.*Ts.*|.*TS.*|.*ts.*|.*伪娘.*|.*伪男.*|.*人妖.*|.*男同.*|.*狼狗.*|.*奶狗.*|.*鲜肉.*|.*帅哥.*|.*正装.*|.*猛1.*|.*ZKtop1.*|.*体育生.*|.*大屌.*|.*双性.*|.*男男.*|.*直男.*|.*gv.*|.*父子.*|.*飞机.*|.*撸.*|.*女性向.*|.*骚0.*|.*poop.*|.*娘娘腔.*|.*变性.*|.*TGirls.*|.*鸡巴.*|.*阴茎.*|.*男奴.*|.*奴男.*|.*同志.*|.*苏木.*|.*西装.*|.*骚受.*|.*QS.*|.*Peter.*|.*摔跤社.*|.*基情.*|.*天菜.*|.*大鸡.*|.*肌肉.*|.*薄肌.*|.*G片.*|.*术0.*|.*宏翔.*|.*男蜜.*|.*自制口.*|.*威廉.*|.*骚男.*|.*基友.*|.*美男子.*|.*鸡儿.*|.*口活王子.*|.*融化的冰.*|.*自己射.*|.*運動生.*|.*苏婧薇.*|.*社畜.*|.*纪练深.*|.*性别.*|.*淋尿.*|.*控射.*|.*熟女.*|.*CD.*|.*肥女.*|.*黄金.*|.*厕.*|.*老阿姨.*|.*排泄.*|.*臭脚.*|.*大便.*|.*马眼.*|.*聖水.*|.*尸.*|.*廁.*|.*圣水.*|.*豊満.*|.*黑妹.*|.*坦克.*|.*黑珍珠.*|.*黑屁股.*|.*黑人妹子.*|.*黑逼.*|.*孕妇.*|.*消遣.*|.*伦勃朗.*|.*拉丁裔.*|.*asmr.*|.*GOOD.*|.*奶奶.*|.*老妈.*|.*妈妈.*|.*儿子.*|.*爸爸.*|.*女儿.*|.*母子.*|.*父女.*|.*兄妹.*|.*亲姐.*|.*亲妹.*|.*VR.*|.*都丸富美.*|.*山本かを.*|.*守谷多香子.*|.*波多.*|.*飯岡.*|.*希島.*|.*希岛.*|.*深田.*|.*君島.*|.*君岛.*|.*田中瞳.*|.*向美奈.*|.*美原咲.*|.*华行香.*|.*藤泽丽.*|.*Hitomi.*|.*美乃雀.*|.*若菜奈.*|.*水野朝.*|.*後藤.*|.*明日花.*|.*卯水.*|.*由爱.*|.*JULIA.*|.*风间.*|.*風間.*|.*濑圆.*|.*平冈.*|.*藤樱.*|.*藤泽.*|.*蓮実.*|.*藤沢麗央.*|.*木村玲.*|.*SILK.*|.*afchina.*|.*fway.*|.*rebd.*|.*mbdd.*|.*眼射.*|.*水果派.*|.*解说.*|.*第.*期.*|.*π.*|.*寻花.*|.*尋花.*|.*探花.*|.*偷拍.*|.*偸拍.*|.*抄底.*|.*攝像頭.*|.*摄像头.*|.*第.*话.*|.*番系列.*|.*经典番.*|.*里番.*|.*老番.*|.*国漫.*|.*王者.*|.*斗罗.*|.*穿越.*|.*斗破.*|.*仙剑.*|.*小舞.*|.*MMD.*|.*MODEL.*|.*断雪.*|.*M男.*|.*女王.*|.*老太.*|.*黑肉.*|.*面基.*|.*情侣网黄.*|.*夫妻奴.*|.*田中.*|.*梦梦.*|.*刘玥.*|.*mb.*|.*MB系列.*|.*川怜子.*|.*NINE.*|.*婆婆.*|.*姫野.*|.*肉弹.*|.*L罩杯.*|.*黑木.*|.*爱泽沙罗.*|.*瞳美.*|.*望月绫.*|.*藤森里.*}}\";\n}",
    "singleUrl": false,
    "sortUrl": "\n随机::/av/new/{{ Math.ceil(Math.random()*3160) }}\n最新::/av/new?o=u&page={{page}}\n🔎AV搜::/av/search?search={{v=source.getVariable();if(/^\\s*$/.test(v)||v==null)source.setVariable('奸');source.getVariable()}}&page={{page}}\n🔎视频搜::/video/search?search={{v=source.getVariable();if(/^\\s*$/.test(v)||v==null)source.setVariable('奸');source.getVariable()}}&page={{page}}\n\n丝袜::/av/tag?tag=丝袜\n强奸::/av/tag?tag=强奸\n潮吹::/av/tag?tag=潮吹\n黑人::/av/tag?tag=黑人\n巨汉::/av/tag?tag=巨汉\n\n\n\n",
    "sourceComment": "https://github.com/kissav12/douyin\nhttps://zz.douyin18.com/\nhttps://fbhhnyhm.top/\n备用地址\nhttps://among.oaqoqjep.cc/\n\n\n{{bhost()}}\n@js:\nbhost() + result",
    "sourceGroup": "h",
    "sourceIcon": "https://i1.wp.com/i.postimg.cc/GpvjBZcR/105.gif",
    "sourceName": "🌈抖阴AV   S",
    "sourceUrl": "https://www.jtupsta.cc/",
    "style": ".container {\n    position: relative; /* 相对定位，用于包含视频 */\n    height: 100%; /* 容器高度与视频原始高度相同 */\n    overflow: hidden; /* 隐藏超出容器的部分 */\n}\n.title {\n    position: absolute; /* 绝对定位，相对于容器 */\n    top: 0; \n    width: 100%;\n    overflow: hidden; \n    text-overflow: ellipsis;\n    display: -webkit-box;\n    -webkit-box-orient: vertical; \n    -webkit-line-clamp: 2;\n    z-index: 1; /* 确保标题在视频之上 */\n    background: #000; /* 纯黑色背景 */ \n    padding: 0 0 3px 0;\n}\nvideo {\n    position: absolute; /* 绝对定位，相对于容器 */ \n    top: +20px; /* 视频上移 */\n    left: 0; \n    width: 100%; \n    height: calc(93% + 0px);  /* 调整高度以适应内容 */\n    object-fit: contain; /* 确保视频内容不被裁剪 */\n    z-index: 0; /* 确保视频在标题之下 */\n    controls=\"controls\" autoplay muted; \n} \n"
  },
  {
    "articleStyle": 2,
    "customOrder": 226,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 1775589411655,
    "loadWithBaseUrl": true,
    "ruleArticles": "class.inner_layer@ul@li@a",
    "ruleContent": "text.普通下载@href\n<js>\nresult+=\".m3u8\";\r\nresult = \"<video src=\\\"\" + result + \"\\\" width=\\\"100%\\\" height=\\\"240px\\\" controls=\\\"controls\\\" ></video>\";\r\nresult = \"<html><head><meta charset=\\\"utf-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no\\\" /><style>html,body{margin:0;padding:0;width:100%;}</style></head><body>\" + result + \"</body></html>\"\n</js>",
    "ruleImage": "img@data-original||img@src",
    "ruleLink": "href##$##,\\{\\\"webView\\\": true\\}",
    "ruleNextPage": "page",
    "rulePubDate": "class.timeobxobx@text",
    "ruleTitle": "p.-1@text",
    "singleUrl": false,
    "sortUrl": "三级::/Html/109/{{page - 1 == 0 ? \"\":\"index-\"+page+\".html\"}},{\"webView\": true}\n女优::/Html/100/{{page - 1 == 0 ? \"\":\"index-\"+page+\".html\"}},{\"webView\": true}\n人妻::/Html/111/{{page - 1 == 0 ? \"\": \"index-\"+page+\".html\"}},{\"webView\": true}\n国产::/Html/60/{{page - 1 == 0 ? \"\": \"index-\"+page+\".html\"}},{\"webView\": true}\n欧美::/Html/62/{{page - 1 == 0 ? \"\": \"index-\"+page+\".html\"}},{\"webView\": true}\n无码::/Html/113/{{page - 1 == 0 ? \"\": \"index-\"+page+\".html\"}},{\"webView\": true}\n动漫::https://033yp.com/Html/101/{{page - 1 == 0 ? \"\": \"index-\"+page+\".html\"}}",
    "sourceComment": "发布页https://guochandizhi6.com/\n永久地址https://992kp.com/",
    "sourceGroup": "美涩",
    "sourceIcon": "https://i.postimg.cc/j5ZxW6v7/1657950527553.png",
    "sourceName": "©痴汉",
    "sourceUrl": "https://99imm13.xyz/"
  },
  {
    "articleStyle": 1,
    "customOrder": 236,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "ul@li",
    "ruleContent": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<title>内容提取</title>\n<!-- v2025.05.10 -->\n\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<script src=\"https://code.jquery.com/jquery-3.6.0.min.js\"></script>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.3/viewer.min.css\" />\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.3/viewer.min.js\"></script>\n<style>\n    body { font-family: Arial, sans-serif; font-size: 16px; }\n    #title, #page, #loading-status { margin: 0 auto; font-size: 20px; text-align: center; }\n    #description, #urls, #video-url, #video-sources, #messages { width: 100%; max-width: 800px; margin: 1.5px auto; font-size: 14px; text-align: left; word-wrap: break-word; white-space: pre-wrap; }\n    #text, #text :not(img), #text img + * { text-indent: 2em; width: 100%; font-size: 16px; line-height: 1.5em; margin-top: 0; margin-bottom: 0; word-wrap: break-word; white-space: pre-wrap; }\n    img, #text img { width: 100%; height: auto; display: block; margin-bottom: 1.5px; }\n    .flex-container { display: flex; justify-content: center; align-items: center; gap: 10px; margin: 1.5px 0; font-size: 14px; }\n    button, select { flex: 1 1 31%; padding: 3px; border: 1px solid #ccc; border-radius: 5px; box-sizing: border-box; cursor: pointer; background-color: #f9f9f9; transition: background-color 0.3s ease; margin: 1.5px; min-width: 0; font-size: 14px; }\n    #url-select, #video-source-select { flex: 1 1 100%; margin-left: 0; margin-right: 0; text-align: center; }\n    #video-element { width: 100%; height: auto; }\n    textarea { width: 100%; height: auto; min-height: 100px; box-sizing: border-box; resize: vertical; }\n    .error, .warn { color: red; }\n</style>\n</head>\n<body>\n    <h3 id=\"title\">{{@@title@text||h1.0@text||h2.0@text||.title.0@text}}</h3>\n    <p id=\"description\">{{@@.info.0@html||.jianjie@html}}</p>\n    <p id=\"page\" style=\"display:none;\">共<span id=\"total-pages\">1</span>页</p>\n    <p id=\"loading-status\" style=\"display:none;\"></p>\n\n    <div class=\"flex-container\" id=\"loading-buttons\" style=\"display:none;\">\n        <button id=\"prev-page-btn\">上一页</button>\n        <button id=\"next-page-btn\">下一页</button>\n        <button id=\"auto-load-btn\">自&nbsp;&nbsp;动</button>\n    </div>\n    \n    <div class=\"flex-container\">\n        <select id=\"url-select\" style=\"display:none;\"></select>\n    </div>\n    \n    <div class=\"flex-container\">\n        <button id=\"toggle-urls-btn\">显/隐网址</button>\n        <button id=\"toggle-messages-btn\">显/隐信息</button>\n        <button id=\"toggle-debug-btn\">显/隐调试</button>\n    </div>\n    <div id=\"urls\"></div>\n    <div id=\"messages\"></div>\n    <div id=\"debug-info\"></div>\n    <div id=\"video-url\"></div>\n    <div id=\"video-container\" style=\"display: none;\">\n        <video id=\"video-element\" controls preload=\"auto\" width=\"640\" height=\"264\">\n            <source id=\"video-source\" src=\"\" type=\"\">您的浏览器不支持 video 标签。\n        </video>\n    </div>\n    <div class=\"flex-container\" id=\"video-source-container\" style=\"display: none;\">\n        <select id=\"video-source-select\" onchange=\"updateVideoSource()\"></select>\n    </div>\n    <div id=\"images\"></div>\n    <div id=\"text\"></div>\n\n    <script>\n        // 配置对象，包含各种选择器、延迟时间等配置项\n        const config = {    \n            videoSelector: 'body', // 视频选择器\n            imgSelector: '.gridlane-box-inside img,.photos figure img,.content p img', // 图片选择器\n            textSelector: '#content', // 文本选择器\n            debugSelector: '#content, .page, .pager, .content, script', // 调试信息选择器\n            swapImageAttributes: false, // 是否交换图片属性\n            delayTime: 1500, // 延迟提取时间\n            retryDelayTime: 1500, // 重试加载延迟时间\n            maxLoadAttempts: 3, // 最大加载次数\n            autoLoading: false, // true自动模式，false单页模式\n            debugOnce: 0, // 只在特定索引输出一次调试信息\n            totalPagesText: '{{@@.page.0@a.-2@textNodes}}', // 总页码\n            urlSuffixToRemove: /\\.html$/, // 移除url后缀\n            pageUrlText: '{urlPrefix}_{i}.html', // 拼接URL模板        \n            ListMode: true, // true网址列表模式，false网址拼接模式    \n            initialUrls: `{{@@#sort-item-5.0@a@href}}`, // 网址\n            initialUrlsName: `{{@@#sort-item-5.0@a@span@text}}`, // 网址名称\n            sourceurl: '', // 来源URL前缀\n        };\n\n        let videoSources = []; // 存储视频源数组\n        let loadAttempts = {}; // 记录每个URL的加载尝试次数\n        let urls = []; // 存储所有页面的URL\n        let imageBox;\n        let textBox;\n        let currentPageIndex = 0; // 当前页面索引\n        let canLoadNextPage = true; // 控制是否可以加载下一页\n        let autoLoadInProgress = false; // 自动加载状态\n\n        // 构建URL列表\n        function buildUrls(totalPages, baseUrl) {\n            let initialUrlsArray = config.initialUrls.trim().split('\\n').filter(url => url.trim() !== '');\n            let initialUrlsNameArray = config.initialUrlsName.trim().split('\\n').filter(name => name.trim() !== '');\n\n            if (config.ListMode && initialUrlsArray.length > 0) {\n                if (initialUrlsArray.length !== initialUrlsNameArray.length) {\n                    $('#messages').append(`<span class=\"warn\">警告：initialUrls 和 initialUrlsName 的长度不匹配。</span><br>`);\n                }\n\n                urls = initialUrlsArray.map(url => {\n                    if (config.sourceurl && url.startsWith('/') && !/^https?:\\/\\//i.test(url)) {\n                        return config.sourceurl.replace(/\\/$/, '') + url;\n                    } else {\n                        return url;\n                    }\n                });\n\n                urls.forEach((url, index) => {\n                    const name = initialUrlsNameArray[index] || `第 ${index + 1} 页`;\n                    $('#url-select').append(`<option value=\"${index}\">${name}</option>`);\n                    $('#urls').append(`<div>${name}: ${url}</div>`);\n                });\n            } else {\n                if (totalPages === 1) {\n                    urls.push(baseUrl);\n                } else {\n                    urls.push(baseUrl);\n                    for (let i = 2; i <= totalPages; i++) {\n                        urls.push(config.pageUrlText.replace('{urlPrefix}', baseUrl.replace(config.urlSuffixToRemove, '').replace(/\\/$/, '')).replace('{i}', i));\n                    }\n                }\n\n                urls.forEach((url, index) => {\n                    const name = `第 ${index + 1} 页`;\n                    $('#url-select').append(`<option value=\"${index}\">${name}</option>`);\n                    $('#urls').append(`<div>${name}: ${url}</div>`);\n                });\n            }\n\n            $('#total-pages').text(urls.length);\n            toggleNavigationButtons();\n            toggleTotalPagesDisplay();\n        }\n\n        // 规范化URL\n        function normalizeUrl(url) {\n            if (typeof url !== 'string' || !url.trim()) {\n                return '';\n            }\n            const match = url.match(/['\"](.*?)['\"]/);\n            if (match && match[1]) {\n                url = match[1];\n            }\n\n            function processUrl(str) {\n                str = str.trim();\n                str = str.replace(/\\\\u[\\dA-F]{4}/gi, match => String.fromCharCode(parseInt(match.replace(/\\\\u/g, ''), 16)));\n                str = decodeURIComponent(str);\n                str = str.replace(/^http:\\/([^/])/, 'http://$1');\n                str = str.replace(/^https:\\/([^/])/, 'https://$1');\n                return str;\n            }\n            return processUrl(url);\n        }\n\n        // 清空容器内容\n        function clearContainers() {\n            $('#messages').empty();\n            $('#images').empty();\n            $('#text').empty();\n        }\n\n        // 更新图像源\n        function updateImageSrc(elements, shouldSwap) {\n            elements.each(function () {\n                const $this = $(this);\n                const attrsToUpdate = {};\n                if (shouldSwap) {\n                    ['data-original', 'data-src', 'data-url'].forEach(attr => {\n                        if ($this.attr(attr)) {\n                            attrsToUpdate['src'] = $this.attr(attr);\n                        }\n                    });\n                }\n                $this.attr(attrsToUpdate);\n            });\n            return elements;\n        }\n\n        // 切换导航按钮显示状态\n        function toggleNavigationButtons() {\n            if ($('#url-select option').length > 1 && !config.autoLoading) {\n                $('#loading-buttons').show();\n                $('#url-select').show();\n            } else {\n                $('#loading-buttons').hide();\n                $('#url-select').hide();\n            }\n        }\n\n        // 显示加载状态\n        function showLoadingStatus(pageNumber) {\n            const selectedOption = $('#url-select option:selected').text();\n            $('#loading-status').text(`正在加载：${selectedOption}`).show();\n        }\n\n        // 隐藏加载状态\n        function hideLoadingStatus() {\n            $('#loading-status').hide();\n        }\n\n        // 加载指定索引的内容\n        function loadContent(index) {\n            if (index < 0 || index >= urls.length || !canLoadNextPage) return;\n            canLoadNextPage = false;\n            currentPageIndex = index;\n            $('#url-select').val(index);\n            $('#messages').append(`<div>当前地址: <span class=\"warn\">${urls[index]}</span></div>`);\n            if (autoLoadInProgress) {\n                showLoadingStatus(index + 1);\n            }\n            $.ajax({\n                url: urls[index],\n                type: 'GET',\n                success: function (data) {\n                    try {\n                    const $data = $(data);\n                    let updatedHtmlContent = data.replace(/(['\"])(\\/\\/)(?!\\/)/g, '$1https://')\n                        .replace(/src=\"upload/gi, 'src=\"/upload')\n                        .replace(/style=[\"'][^'\"]+[\"']/gi, '')\n                        .replace(/\\\\\\//g, '/');\n                    const parser = new DOMParser();\n                    const doc = parser.parseFromString(updatedHtmlContent, \"text/html\");\n\n                    if (config.debugOnce === index) {\n                        const debugElements = $(doc).find(config.debugSelector);\n                        if (debugElements.length > 0) {\n                            const debugContents = $('<pre>').html(debugElements.clone().wrapAll('<div/>').parent().html()).html();\n                            $('#debug-info').html(`<span class=\"warn\">调试信息: <textarea rows=\"10\" cols=\"80\">${debugContents}</textarea></span>`);\n                        } else {\n                            $('#debug-info').html(`<span class=\"warn\">调试信息: <textarea rows=\"10\" cols=\"80\">调试信息未提取到内容，请检查选择器！</textarea></span>`);\n                        }\n                    }\n                    // 方法1：提取视频\n                    const videoSources1 = [];\n                    const videoContents = $(doc).find(config.videoSelector);\n                    const videoTags = $(videoContents).find('video, source');\n                    videoTags.each(function() {\n                        const videosrc = $(this).attr('src') || \n                                     $(this).attr('data-src') || \n                                     $(this).attr('data-original') || '';\n                        \n                        if (videosrc) {\n                            videoSources1.push(videosrc);\n                        }\n                    });\n                    //反馈\n                    if (videoSources1.length > 0) {\n                        $('#messages').append(`<span>方法1，找到 ${videoSources1.length} 个视频。</span><br>`);\n                    }\n\n                    // 方法2：正则提取视频\n                    const regex = /['\"]https?[^'<>\"]+(m3u8|mp4|webm|ogg|flv|mp3|m4a|wav|ape|flac)([^'<>\"]+)?['\"]/gi;\n                    const matches = data.match(regex);\n                    const videoSources2 = [];\n\n                    if (matches) {\n                        const uniqueMatches = [...new Set(matches)];\n                    \n                        uniqueMatches.forEach(match => {\n                            const normalizedSrc = normalizeUrl(match.replace(/['\"]/g, ''));\n                            videoSources2.push(normalizedSrc);\n                        });\n                    }\n                    //反馈\n                    if (videoSources2.length > 0) {\n                        $('#messages').append(`<span>方法2，找到 ${videoSources2.length} 个视频。</span><br>`);\n                    }\n\n                    // 合并两种方法的结果\n                    videoSources = [...videoSources1, ...videoSources2];\n\n                    // 去重并标准化 URL\n                    const imageExtensions = /\\.(jpg|jpeg|png|gif|bmp|svg)$/i;\n\n                    videoSources = videoSources\n                                  .map(src => normalizeUrl(src.replace(/\\\\+/g, '')))\n                                  .filter(src => src) // 过滤空值\n                                  .filter(src => !imageExtensions.test(src)); // 移除图片地址\n                        \n                    videoSources = [...new Set(videoSources)];// 去重\n\n                    // 显示最终结果\n                    $('#messages').append(`<span>总共找到 ${videoSources.length} 个视频。</span><br>`);\n\n                    if (videoSources.length > 0) {\n                        $('#messages').append(`<span>成功提取到视频，找到 ${videoSources.length} 个视频。</span><br>`);\n                        videoSources.forEach((src, idx) => {\n                            $('#messages').append(`<div>视频地址:<span class=\"warn\"> ${src}</span><br></div>`);\n                            $('#video-source-select').append(`<option value=\"${idx}\">视频源 ${idx + 1}</option>`);\n                        });\n                    \n                        if (videoSources.length == 1) {\n                            $('#video-container').show();\n                            $('#video-url').show();\n                            $('#video-source-container').hide();\n                            updateVideoSource();\n                        } else if (videoSources.length > 1) {\n                            $('#video-container').show();\n                            $('#video-url').show();\n                            $('#video-source-container').show();\n                            updateVideoSource();\n                        } else {\n                            $('#video-container').hide();\n                            $('#video-url').hide();\n                            $('#video-source-container').hide();\n                        }\n                    } else {\n                        $('#messages').append(`<span class=\"warn\">未找到视频源。</span><br>`);\n                        $('#video-container').hide();\n                        $('#video-url').hide();\n                        $('#video-source-container').hide();\n                    }\n\n                    //提取图片\n                    const $imgContents = $(doc).find(config.imgSelector);\n                    const shouldSwap = config.swapImageAttributes;\n                    const newContents = updateImageSrc($imgContents.clone(), shouldSwap);\n                    $('#images').append(newContents).show();\n                    if (newContents.length > 0) {\n                        $('#messages').append(`<span>成功提取图片，共 ${newContents.length} 张。</span><br>`);\n                        newContents.each(function () {\n                            const imgSrc = $(this).attr('src') || $(this).attr('data-original') || $(this).attr('data-src') || $(this).attr('data-url');\n                            $('#messages').append(`<div>地址:<span class=\"warn\"> ${imgSrc}</span><br></div>`);\n                        });\n                    } else {\n                        $('#messages').append(`<span class=\"warn\">未提取到图片。</span><br>`);\n                    }\n\n                    //提取图片和文本\n                    const textContents = $(doc).find(config.textSelector).map(function () {\n                        const $currentContents = $(this);\n                        $currentContents.find('img + br, script, video, source, iframe').remove();\n                        $currentContents.html($currentContents.html().replace(/>\\s+/gi, '>').replace(/<\\/?br\\s*([^>]*)\\s*\\/?>/gi, '\\n').replace(/\\n+/g, '\\n'));\n                        return $currentContents.html();\n                    }).get().join('');\n                    if (textContents.trim()) {\n                        $('#text').append(`<span>${textContents}</span><br>`).show();\n                        $('#messages').append(`<span>成功提取图文。</span><br>`);\n                    } else {\n                        $('#messages').append(`<span class=\"warn\">未提取到图文。</span><br>`);\n                    }\n\n                    if (autoLoadInProgress && currentPageIndex < urls.length - 1) {\n                        setTimeout(() => { \n                            canLoadNextPage = true;\n                            loadContent(currentPageIndex + 1); \n                        }, config.delayTime);\n                    } else {\n                        canLoadNextPage = true;\n                        if (autoLoadInProgress) {\n                            hideLoadingStatus();\n                        }\n                    }\n                } catch (parseError) {\n                    $('#messages').append(`<span class=\"error\">解析页面内容时发生错误: ${parseError.message}</span><br>`);\n                    handleLoadFailure(urls, index);\n                } finally {\n                    if (imageBox) imageBox.viewer.update();\n                    if (textBox) textBox.viewer.update();\n                }\n            },\n            error: function (jqXHR, textStatus, errorThrown) {\n                let errorMessage = `内容加载失败: ${urls[index]}`;\n                switch (textStatus) {\n                    case 'timeout':\n                        errorMessage += ', 请求超时';\n                        break;\n                    case 'abort':\n                        errorMessage += ', 请求被取消';\n                        break;\n                    case 'parsererror':\n                        errorMessage += ', 解析响应出错';\n                        break;\n                    default:\n                        errorMessage += `, 状态码: ${jqXHR.status}, 错误信息: ${errorThrown}`;\n                        break;\n                }\n                $('#messages').append(`<span class=\"error\">${errorMessage}</span><br>`);\n                handleLoadFailure(urls, index);\n                }\n            });\n        }\n\n        // 处理加载失败的情况\n        function handleLoadFailure(urls, index) {\n            if (!loadAttempts[urls[index]]) {\n                loadAttempts[urls[index]] = 1;\n            } else {\n                loadAttempts[urls[index]]++;\n            }\n            if (loadAttempts[urls[index]] <= config.maxLoadAttempts) {\n                const retryMessage = `第${index + 1}页加载失败，正在进行第${loadAttempts[urls[index]]}次加载！`;\n                $('#messages').append(`<span class=\"error\">${retryMessage}</span><br>`);\n                setTimeout(() => { \n                    canLoadNextPage = true;\n                    loadContent(index); \n                }, config.retryDelayTime);\n            } else {\n                const finalErrorMessage = `第${index + 1}页加载失败，已达到最大尝试次数(${config.maxLoadAttempts})！`;\n                $('#messages').append(`<span class=\"error\">${finalErrorMessage}</span><br>`);\n                if (autoLoadInProgress && currentPageIndex < urls.length - 1) {\n                    setTimeout(() => { \n                        canLoadNextPage = true;\n                        loadContent(currentPageIndex + 1); \n                    }, config.delayTime);\n                } else {\n                    canLoadNextPage = true;\n                    if (autoLoadInProgress) {\n                        hideLoadingStatus();\n                    }\n                }\n            }\n        }\n\n        // 更新视频源\n        function updateVideoSource() {\n            const selectedIndex = parseInt(document.getElementById('video-source-select').value);\n            if (isNaN(selectedIndex) || !videoSources[selectedIndex]) {\n                $('#messages').append(`<span class=\"warn\">未找到有效的视频源。</span><br>`);\n                console.warn(\"Invalid or undefined video source:\", selectedIndex, videoSources);\n                return;\n            }\n\n            const selectedSource = videoSources[selectedIndex];\n            document.getElementById('video-url').textContent = `视频地址:\\n ${selectedSource}`;\n\n            const videoSourceElement = document.getElementById('video-source');\n            videoSourceElement.src = selectedSource;\n\n            const videoElement = document.getElementById('video-element');\n            videoElement.load();\n\n            $('#messages').append(`<span>更新视频源为: ${selectedSource}</span><br>`);\n            console.log(\"Updated video source to:\", selectedSource);\n        }\n\n        // 切换总页数显示状态\n        function toggleTotalPagesDisplay() {\n            if (urls.length > 1) {\n                $('#page').show();\n            } else {\n                $('#page').hide();\n            }\n        }\n\n        // 页面加载完成后执行的主要逻辑\n        $(document).ready(function () {\n            imageBox = document.getElementById('images');\n            textBox = document.getElementById('text');\n            if (imageBox && textBox) {\n                new Viewer(imageBox, { title: true, interval: 2000 });\n                new Viewer(textBox, { title: true, interval: 2000 });\n            }\n\n            const totalPagesText = config.totalPagesText;\n            const totalPages = parseInt(totalPagesText, 10) || 1;\n            const baseUrl = '{{baseUrl}}';\n\n            clearContainers();\n            $('#urls, #debug-info textarea, #video-url, #video-source-select').empty();\n            $('#urls, #messages, #debug-info, #video-url, #video-container, #video-source-container, #images, #text').hide();\n\n            buildUrls(totalPages, baseUrl);\n\n            const urlSelect = document.getElementById('url-select');\n            if (urlSelect.options.length > 0) {\n                urlSelect.value = '0'; \n\n                if (config.autoLoading) {\n                    autoLoadInProgress = true;\n                    for (let i = 0; i < urls.length; i++) {\n                        loadContent(i);\n                    }\n                } else {\n                    loadContent(0);\n                }\n            } else {\n                loadContent(0);\n            }\n\n            $('#url-select').change(function () {\n                clearContainers();\n                const selectedIndex = parseInt($(this).val());\n                loadContent(selectedIndex);\n            });\n            $('#prev-page-btn').click(function () {\n                clearContainers();\n                if (currentPageIndex > 0) {\n                    loadContent(currentPageIndex - 1);\n                }\n            });\n            $('#next-page-btn').click(function () {\n                clearContainers();\n                if (currentPageIndex < urls.length - 1) {\n                    loadContent(currentPageIndex + 1);\n                }\n            });\n            $('#auto-load-btn').click(function () {\n                autoLoadInProgress = true;\n                showLoadingStatus(1); \n                for (let i = currentPageIndex + 1; i < urls.length; i++) {\n                    loadContent(i);\n                }\n            });\n            $('#toggle-messages-btn').click(function () { $('#messages').toggle(); });\n            $('#toggle-urls-btn').click(function () { $('#urls').toggle(); });\n            $('#toggle-debug-btn').click(function () { $('#debug-info').toggle(); });\n        });\n    </script>\n</body>\n</html>",
    "ruleImage": "a@data-original",
    "ruleLink": "a.0@href",
    "ruleNextPage": "page||text.下一页@href",
    "rulePubDate": "[class=\"pic-text text-right\"]@text",
    "ruleTitle": "h4@text",
    "singleUrl": false,
    "sortUrl": "搜索🔍::/jiejie/index.php/vod/search.html?wd={{source.getVariable()}}\n黄瓜资源::/jiejie/index.php/vod/type/id/87.html\n155资源::/jiejie/index.php/vod/type/id/248.html\n森林资源::/jiejie/index.php/vod/type/id/117.html\n奥斯卡资源::/jiejie/index.php/vod/type/id/86.html\n百万资源::/jiejie/index.php/vod/type/id/237.html\n制服诱惑::/jiejie/index.php/vod/show/id/251.html\n中文字幕::/jiejie/index.php/vod/show/id/254.html\n美乳巨乳::/jiejie/index.php/vod/show/id/262.html\n熟女人妻::/jiejie/index.php/vod/show/id/259.html\n萝莉少女::/jiejie/index.php/vod/show/id/260.html\n强奸乱伦::/jiejie/index.php/vod/show/id/263.html\n无码专区::/jiejie/index.php/vod/show/id/249.html",
    "sourceComment": "jiejiesp.xyz",
    "sourceGroup": "呦呦鹿鸣",
    "sourceIcon": "https://8wx27o6v.91gaoqing.rest/upload/vod/20250428-1/cfc014ec16937c7f415afd712b482842.gif",
    "sourceName": "姐姐视频",
    "sourceUrl": "https://wap.jiejiesp27.xyz/"
  },
  {
    "articleStyle": 0,
    "customOrder": 237,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": false,
    "lastUpdateTime": 1773218415285,
    "loadWithBaseUrl": true,
    "ruleArticles": "$.zhubo",
    "ruleContent": "<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n<script src=\"http://bilibili.github.io/flv.js/dist/flv.js\"></script>\n</head>\n<body>\n\t\t\t<video id=\"player1\"  autoplay=\"autoplay\" preload=\"auto\" muted controls=\"controls\">\n\t\t</video>\n\t\t<p>\n    <button onclick=\"enableMute()\" type=\"button\">关闭声音</button>\n\n    <button onclick=\"disableMute()\" type=\"button\">打开声音</button>\n\n</p> \n<div>\n直播链接:{{baseUrl.replace(/zhibo/,\"flv\").replace(/http:\\/\\/api.hclyz.com:81/,\"不可播放rtmp:/\")}}\n</div>\n</body>\n</html>\n<script>\n    if (flvjs.isSupported()) {\n        var videoElement = document.getElementById('player1');\n\t\tvar flvPlayer = flvjs.createPlayer({\n            type: 'flv', \n            url: '{{baseUrl.replace(/zhibo/,\"flv\").replace(/http:\\/\\/api.hclyz.com:81/,\"rtmp://\")}}',\n     });\n\t\tflvPlayer.attachMediaElement(videoElement);\n\t\tflvPlayer.load();\n\t\t//flvPlayer.play();\n    }\n</script>\n <script>\n\nvar myVid = document.getElementById(\"player1\");\n\nfunction enableMute() { \n\n    myVid.muted = true;\n\n} \n\nfunction disableMute() { \n\n    myVid.muted = false;\n\n} \n</script> ",
    "ruleImage": "$.img",
    "ruleLink": "$.address@js:result\n.replace(/\\.flv/,\".zhibo\")\n.replace(/rtmp:\\//,\"\")",
    "ruleTitle": "$.title",
    "singleUrl": false,
    "sortUrl": "偶遇::http://api.hclyz.com:81/mf/jsonouyu.txt\n依依::http://api.hclyz.com:81/mf/jsonyiyi.txt\n夜色::http://api.hclyz.com:81/mf/jsonyese.txt\n亚米::http://api.hclyz.com:81/mf/jsonyami.txt\n色趣::http://api.hclyz.com:81/mf/jsonsequ.txt\n咪狐::http://api.hclyz.com:81/mf/jsonmihu.txt\n夜律::http://api.hclyz.com:81/mf/jsonyelu.txt\n暗语::http://api.hclyz.com:81/mf/jsonanyu.txt\n咪咪::http://api.hclyz.com:81/mf/jsonmimi.txt\n糯米::http://api.hclyz.com:81/mf/jsonnuomi.txt\n苦瓜::http://api.hclyz.com:81/mf/jsonkugua.txt\n蝴蝶::http://api.hclyz.com:81/mf/jsonhudie.txt\n云鹿::http://api.hclyz.com:81/mf/jsonyunlu.txt\n付宝::http://api.hclyz.com:81/mf/jsonfubao.txt\n菠萝::http://api.hclyz.com:81/mf/jsonboluo.txt\n夜艳::http://api.hclyz.com:81/mf/jsonyeyan.txt\n二嫂::http://api.hclyz.com:81/mf/jsonersao.txt\n土豪::http://api.hclyz.com:81/mf/jsontuhao.txt\n盘他::http://api.hclyz.com:81/mf/jsonpanta.txt\n美夕::http://api.hclyz.com:81/mf/jsonmeixi.txt\n坦克::http://api.hclyz.com:81/mf/jsontanke.txt\n蜜桃::http://api.hclyz.com:81/mf/jsonmitao.txt\n她秀::http://api.hclyz.com:81/mf/jsontaxiu.txt\n金鱼::http://api.hclyz.com:81/mf/jsonjinyu.txt\n浴火::http://api.hclyz.com:81/mf/jsonyuhuo.txt\n套路::http://api.hclyz.com:81/mf/jsontaolu.txt\n日出::http://api.hclyz.com:81/mf/jsonrichu.txt\n桃花::http://api.hclyz.com:81/mf/jsontaohua.txt\nLOVE::http://api.hclyz.com:81/mf/jsonLOVE.txt\n久久::http://api.hclyz.com:81/mf/jsonjiujiu.txt\n杏趣::http://api.hclyz.com:81/mf/jsonxingqu.txt\n媚颜::http://api.hclyz.com:81/mf/jsonmeiyan.txt\n灰灰::http://api.hclyz.com:81/mf/jsonhuihui.txt\n爱零::http://api.hclyz.com:81/mf/jsonailing.txt\n爱恋::http://api.hclyz.com:81/mf/jsonailian.txt\n杏播::http://api.hclyz.com:81/mf/jsonxingbo.txt\n金呗::http://api.hclyz.com:81/mf/jsonjinbei.txt\nmoon::http://api.hclyz.com:81/mf/jsonmoon.txt\n夜纯::http://api.hclyz.com:81/mf/jsonyechun.txt\n彩云::http://api.hclyz.com:81/mf/jsoncaiyun.txt\n妞妞::http://api.hclyz.com:81/mf/jsonniuniu.txt\n艳后::http://api.hclyz.com:81/mf/jsonyanhou.txt\n蓝猫::http://api.hclyz.com:81/mf/jsonlanmao.txt\n情趣::http://api.hclyz.com:81/mf/jsonqingqu.txt\n翠鸟::http://api.hclyz.com:81/mf/jsoncuiniao.txt\n糖果::http://api.hclyz.com:81/mf/jsontangguo.txt\n么么哒::http://api.hclyz.com:81/mf/jsonmemeda.txt\n豹娱l::http://api.hclyz.com:81/mf/jsonbaoyul.txt\n卡哇伊::http://api.hclyz.com:81/mf/jsonkawayi.txt\n小妖::http://api.hclyz.com:81/mf/jsonxiaoyao.txt\n幽梦::http://api.hclyz.com:81/mf/jsonyoumeng.txt\n风流::http://api.hclyz.com:81/mf/jsonfengliu.txt\n樱桃::http://api.hclyz.com:81/mf/jsonyingtao.txt\n享色::http://api.hclyz.com:81/mf/jsonxiangse.txt\n娇媚::http://api.hclyz.com:81/mf/jsonjiaomei.txt\n爱爱你::http://api.hclyz.com:81/mf/jsonaiaini.txt\n花房::http://api.hclyz.com:81/mf/jsonhuafang.txt\n卡路里::http://api.hclyz.com:81/mf/jsonkaluli.txt\n名流::http://api.hclyz.com:81/mf/jsonmingliu.txt\n倾心::http://api.hclyz.com:81/mf/jsonqingxin.txt\n樱花::http://api.hclyz.com:81/mf/jsonyinghua.txt\n飘雪::http://api.hclyz.com:81/mf/jsonpiaoxue.txt\n入巷::http://api.hclyz.com:81/mf/jsonruxiang.txt\n蝶恋::http://api.hclyz.com:81/mf/jsondielian.txt\n彩虹::http://api.hclyz.com:81/mf/jsoncaihong.txt\n奥斯卡::http://api.hclyz.com:81/mf/jsonaosika.txt\n皇后::http://api.hclyz.com:81/mf/jsonhuanghou.txt\n牵手::http://api.hclyz.com:81/mf/jsonqianshou.txt\n台妹l::http://api.hclyz.com:81/mf/jsontaimeil.txt\n夜妖姬::http://api.hclyz.com:81/mf/jsonyeyaoji.txt\n一直播::http://api.hclyz.com:81/mf/jsonyizhibo.txt\n玲珑::http://api.hclyz.com:81/mf/jsonlinglong.txt\n橙秀::http://api.hclyz.com:81/mf/jsonchengxiu.txt\n黄瓜::http://api.hclyz.com:81/mf/jsonhuanggua.txt\n颜如玉::http://api.hclyz.com:81/mf/jsonyanruyu.txt\n蛟龙::http://api.hclyz.com:81/mf/jsonjiaolong.txt\n好基友::http://api.hclyz.com:81/mf/jsonhaojiyou.txt\n夜女郎::http://api.hclyz.com:81/mf/jsonyenulang.txt\n娇喘::http://api.hclyz.com:81/mf/jsonjiaochuan.txt\n小妲己::http://api.hclyz.com:81/mf/jsonxiaodaji.txt\n花蝴蝶::http://api.hclyz.com:81/mf/jsonhuahudie.txt\n尤物岛::http://api.hclyz.com:81/mf/jsonyouwudao.txt\n77直播::http://api.hclyz.com:81/mf/json77zhibo.txt\n十八禁::http://api.hclyz.com:81/mf/jsonshibajin.txt\n蝴蝶飞::http://api.hclyz.com:81/mf/jsonhudiefei.txt\n喜欢你::http://api.hclyz.com:81/mf/jsonxihuanni.txt\n兔女郎::http://api.hclyz.com:81/mf/jsontunulang.txt\n双碟::http://api.hclyz.com:81/mf/jsonshuangdie.txt\n约直播::http://api.hclyz.com:81/mf/jsonyuezhibo.txt\n九尾狐::http://api.hclyz.com:81/mf/jsonjiuweihu.txt\n红妆::http://api.hclyz.com:81/mf/jsonhongzhuang.txt\n花仙子::http://api.hclyz.com:81/mf/jsonhuaxianzi.txt\n持久男::http://api.hclyz.com:81/mf/jsonchijiunan.txt\n丽柜厅::http://api.hclyz.com:81/mf/jsonliguiting.txt\n桃花运::http://api.hclyz.com:81/mf/jsontaohuayun.txt\n903娱乐::http://api.hclyz.com:81/mf/json903yule.txt\n视觉秀::http://api.hclyz.com:81/mf/jsonshijuexiu.txt\n芒果派::http://api.hclyz.com:81/mf/jsonmangguopai.txt\n七仙女s::http://api.hclyz.com:81/mf/jsonqixiannus.txt\n夜来香::http://api.hclyz.com:81/mf/jsonyelaixiang.txt\n星宝贝::http://api.hclyz.com:81/mf/jsonxingbaobei.txt\n小蜜蜂::http://api.hclyz.com:81/mf/jsonxiaomifeng.txt\n小棉袄::http://api.hclyz.com:81/mf/jsonxiaomianao.txt\n小辣椒::http://api.hclyz.com:81/mf/jsonxiaolajiao.txt\n小仙女::http://api.hclyz.com:81/mf/jsonxiaoxiannu.txt\n兰桂坊::http://api.hclyz.com:81/mf/jsonlanguifang.txt\n花果山::http://api.hclyz.com:81/mf/jsonhuaguoshan.txt\n招财猫::http://api.hclyz.com:81/mf/jsonzhaocaimao.txt\n心之恋::http://api.hclyz.com:81/mf/jsonxinzhilian.txt\n睡美人::http://api.hclyz.com:81/mf/jsonshuimeiren.txt\n小花螺::http://api.hclyz.com:81/mf/jsonxiaohualuo.txt\n小天使::http://api.hclyz.com:81/mf/jsonxiaotianshi.txt\n小红帽::http://api.hclyz.com:81/mf/jsonxiaohongmao.txt\n樱花雨i::http://api.hclyz.com:81/mf/jsonyinghuayui.txt\n小萌猪::http://api.hclyz.com:81/mf/jsonxiaomengzhu.txt\n小坏蛋::http://api.hclyz.com:81/mf/jsonxiaohuaidan.txt\n小性感::http://api.hclyz.com:81/mf/jsonxiaoxinggan.txt\n红浪漫::http://api.hclyz.com:81/mf/jsonhonglangman.txt\n蚊香社::http://api.hclyz.com:81/mf/jsonwenxiangshe.txt\n蓝月亮::http://api.hclyz.com:81/mf/jsonlanyueliang.txt\n小精灵::http://api.hclyz.com:81/mf/jsonxiaojingling.txt\n红高粱::http://api.hclyz.com:81/mf/jsonhonggaoliang.txt\n小天仙::http://api.hclyz.com:81/mf/jsonxiaotianxian.txt",
    "sourceComment": "某个软件的聚合直播\nrtmp的手机网页应该是无法播放\nmp4的都是广告没管",
    "sourceGroup": "美涩",
    "sourceIcon": "https://img2.baidu.com/it/u=3810767422,2486090729&fm=253&fmt=auto&app=138&f=PNG?w=192&h=192",
    "sourceName": "H直播大全",
    "sourceUrl": "http://api.hclyz.com:81",
    "style": "video{\nwidth:100%;\nheight:auto;}"
  },
  {
    "articleStyle": 0,
    "customOrder": 313,
    "enableJs": true,
    "enabled": false,
    "enabledCookieJar": true,
    "lastUpdateTime": 0,
    "loadWithBaseUrl": true,
    "ruleArticles": "data",
    "ruleImage": "pic",
    "ruleLink": "playlink",
    "ruleNextPage": "page",
    "rulePubDate": "{{$.category}}😊{{$.html5introduce}}",
    "ruleTitle": "title",
    "singleUrl": false,
    "sourceGroup": "678",
    "sourceIcon": "",
    "sourceName": "4399变态版在线玩",
    "sourceUrl": "http://h.4399.com/data/android_s148_{{page}}.js?t=1650965242"
  }
]