Strip直播
https://zh.topcams.tv
分享者: haobai1 (12083)发布时间: 5天前
修复播放器异常裁切
现在双击可以进入全屏
{
"articleStyle": 3,
"cacheFirst": false,
"customOrder": 0,
"enableJs": true,
"enabled": true,
"enabledCookieJar": false,
"header": "{\n\"User-Agent\": \"Mozilla\/5.0 (Android)\"\n}",
"injectJs": "const toggleFull = async () => {\n try {\n if (!document.fullscreenElement) {\n await document.documentElement.requestFullscreen().catch(() => {});\n await screen.orientation.lock('any').catch(() => {});\n } else {\n await document.exitFullscreen();\n }\n } catch (e) {}\n};\n\ndocument.addEventListener('dblclick', (e) => {\n if (e.target.closest('html, body, img, p, span, h1, h2, h3, h4, h5, h6')) {\n toggleFull();\n }\n});\n\nwindow.onload = toggleFull;\nsetTimeout(toggleFull, 50);\n\ndocument.addEventListener('fullscreenchange', () => {\n if (document.fullscreenElement) {\n screen.orientation.lock('any').catch(() => {});\n }\n});",
"lastUpdateTime": 1771211640359,
"loadWithBaseUrl": true,
"preload": false,
"ruleArticles": "$.blocks..models[*]&&$.models[*]",
"ruleContent": "<js>\nconst parts = baseUrl.split(',').map(item => 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?.user || {};\n const 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?.description || \"\";\n responseData.fanClubDescription = 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.strpst.com\/thumbs\/\" + user.snapshotTimestamp + \"\/\" + responseData.modelId;\n }\n if (cam.broadcastSettings?.presets?.pixelated) {\n responseData.pixelatedResolutions = cam.broadcastSettings.presets.pixelated;\n }\n \n responseData.isLive = user.isOnline === true;\n responseData.tipMenuCreatedAt = cam.tipMenu?.createdAt || \"\";\n \n if (cam.tipMenu?.settings) {\n responseData.tipMenuPriceList = cam.tipMenu.settings.map(item => ({\n activity: item.activity || \"\",\n price: item.price || 0\n }));\n }\n}\n\nif (configAjax) {\n const configData = JSON.parse(configAjax);\n const hosts = configData.initial?.common?.hlsStreamHosts || {};\n responseData.hlsLines = [hosts.A, hosts.B, hosts.C, hosts.D, hosts.E, hosts.F].filter(h => h);\n responseData.cdn = responseData.hlsLines[0] || \"\";\n \n const client = configData.initial?.client || {};\n responseData.websocketUrl = client.websocket?.url || \"\";\n responseData.websocketToken = client.websocket?.token || \"\";\n}\n\nif (membersAjax) {\n try {\n const membersData = JSON.parse(membersAjax);\n responseData.membersCount = \n (membersData?.guests || 0) + \n (membersData?.spies || 0) + \n (membersData?.invisibles || 0) + \n (membersData?.greens || 0) + \n (membersData?.golds || 0) + \n (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>StripChat直播<\/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; background: linear-gradient(to top, rgba(0, 0, 0, 0.7), transparent); padding: 12px 15px 6px; display: flex; align-items: center; justify-content: space-between; opacity: 0; transition: opacity 0.2s; z-index: 1000; pointer-events: auto; }\n .player-container:hover .custom-controls, .player-container.loading .custom-controls { opacity: 1; }\n .left-controls, .right-controls { display: flex; align-items: center; gap: 8px; pointer-events: auto; }\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>\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 <!-- 原来的时间信息 移到这里 -->\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=\"floatingTopicSection\">\n <div class=\"floating-info-section-title\">\n <i class=\"fas fa-comment-alt\"><\/i> 直播标题\n <\/div>\n <div class=\"floating-content\" id=\"floatingTopic\"><\/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 };\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 \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 switchStream(url) {\n if (!dp || !dp.video || !url) return;\n \n config.isSwitching = true;\n elements.loadingIndicator.style.display = 'block';\n elements.playerContainer.classList.add('loading');\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 elements.playerContainer.classList.remove('loading');\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 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.topic && config.topic.trim() !== '') {\n elements.floatingTopic.textContent = config.topic;\n elements.floatingTopicSection.style.display = 'block';\n } else {\n elements.floatingTopicSection.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.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.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 } else {\n elements.topicContainer.style.display = 'none';\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 function bindEvents() {\n elements.refreshBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n refreshPlayer();\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 });\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 });\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 });\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 });\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 \n document.addEventListener('DOMContentLoaded', initializeApp);\n <\/script>\n<\/body>\n<\/html>",
"ruleImage": "https:\/\/img.strpst.com\/thumbs\/{$.popularSnapshotTimestamp}\/{$..id}_webp",
"ruleLink": "{$.username}",
"rulePubDate": "观众:{$.viewersCount}人 状态:{$.status} @js:result.replace(\/(状态:)public\/g, \"$1公开\").replace(\/(状态:)(?!公开).+\/g, \"$1付费\")",
"ruleTitle": "$.username",
"showWebLog": false,
"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.mywebcamroom.com\nhttps:\/\/zh.topcams.tv\nhttps:\/\/zh.stripchatgirls.com\nhttps:\/\/zh.stripchat.com\nhttps:\/\/zh.xhamsterlive.com\nhttps:\/\/zh.hotzcam.com\nhttps:\/\/go.tklivechat.com\nhttps:\/\/zh.spankbanglive.com\nhttps:\/\/zh.live.91pinse.com\npkey=Iecohquahc5RieQu\npkey=bXorqTB5ZhP5FcpX\n\n修复播放器异常裁切\n现在双击可以进入全屏",
"sourceIcon": "https:\/\/i.imgs.ovh\/2025\/12\/29\/Cwo6eX.png",
"sourceName": "Strip直播",
"sourceUrl": "https:\/\/zh.topcams.tv",
"type": 0
}