218 lines
29 KiB
HTML
218 lines
29 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no" />
|
||
<title>歪比巴卜 WebHome</title>
|
||
<style>
|
||
:root{--panel-rgb:42,50,58;--panel:rgba(var(--panel-rgb),.62);--panel-soft:rgba(var(--panel-rgb),.44);--panel-strong:rgba(var(--panel-rgb),.86);--line:rgba(255,255,255,.16);--text:#f7fbff;--muted:rgba(247,251,255,.68);--accent:#6c5ce7;--accent2:#a29bfe;--bad:#ff5c7a;--ok:#68e39a;--radius:18px;--shadow:0 18px 50px rgba(0,0,0,.28)}
|
||
*{box-sizing:border-box} html,body{margin:0;min-height:100%;background:transparent;color:var(--text);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",Arial,sans-serif} html:not(.fm-native),html:not(.fm-native) body{background:#222a32}.app{min-height:100vh;background:transparent;padding:10px 10px 28px}.top{position:relative;z-index:1;background:transparent;backdrop-filter:none;padding:8px 0 10px;border-bottom:0}.bar{display:flex;align-items:center;gap:8px}.brand{flex:0 0 auto;font-size:21px;font-weight:900;letter-spacing:.5px;text-shadow:0 2px 14px rgba(0,0,0,.35)}.brand b{color:var(--accent2)}.search{flex:1;display:flex;gap:8px;align-items:center;background:rgba(255,255,255,.10);border:1px solid rgba(255,255,255,.14);border-radius:999px;padding:6px 7px 6px 13px;box-shadow:inset 0 1px 0 rgba(255,255,255,.05)}.search input{flex:1;min-width:0;background:transparent;border:0;outline:0;color:var(--text);font-size:15px}.search input::placeholder{color:var(--muted)}button,.btn{border:1px solid var(--line);background:var(--panel-soft);color:var(--text);border-radius:999px;padding:8px 12px;font-size:14px;cursor:pointer}.btn.primary,button.primary{border-color:rgba(255,107,53,.45);background:linear-gradient(135deg,rgba(255,107,53,.90),rgba(255,184,107,.72));color:#17110d;font-weight:800}.tabs{display:flex;gap:8px;overflow:auto;padding:10px 2px 0;scrollbar-width:none}.tabs::-webkit-scrollbar{display:none}.tab{white-space:nowrap;border-radius:999px;padding:8px 14px;background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.12);color:var(--muted)}.tab.active{background:linear-gradient(135deg,rgba(255,107,53,.55),rgba(255,184,107,.30));color:var(--text);border-color:rgba(255,184,107,.58);font-weight:800}.hero{margin:10px 0 16px;padding:18px;border-radius:var(--radius);background:linear-gradient(135deg,rgba(255,107,53,.28),rgba(42,50,58,.54));border:1px solid var(--line);box-shadow:var(--shadow)}.hero h1{margin:0 0 8px;font-size:24px}.hero p{margin:0;color:var(--muted);line-height:1.6}.status{margin:10px 2px;color:var(--muted);font-size:14px}.grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px}.card{position:relative;min-width:0;border-radius:15px;overflow:hidden;background:linear-gradient(180deg,rgba(255,255,255,.09),rgba(255,255,255,.045));border:1px solid rgba(255,255,255,.12);box-shadow:0 10px 28px rgba(0,0,0,.22);cursor:pointer}.poster{aspect-ratio:3/4;background:rgba(255,255,255,.08);overflow:hidden;position:relative}.poster img{width:100%;height:100%;object-fit:cover;display:block;filter:saturate(1.04) contrast(1.03)}.poster .noimg{height:100%;display:flex;align-items:center;justify-content:center;color:var(--muted);font-size:28px}.meta{padding:8px 8px 10px;background:linear-gradient(180deg,rgba(18,24,30,.15),rgba(18,24,30,.44))}.name{font-weight:800;font-size:13.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.remark{margin-top:4px;color:var(--muted);font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.section{margin:16px 0}.section-title{display:flex;align-items:center;justify-content:space-between;margin:0 2px 10px}.section-title h2{margin:0;font-size:17px;letter-spacing:.3px}.rank{display:grid;gap:8px}.rank-item{display:flex;gap:10px;align-items:center;padding:11px 12px;border-radius:14px;background:var(--panel-soft);border:1px solid var(--line);cursor:pointer}.rank-no{width:32px;height:32px;display:grid;place-items:center;border-radius:10px;background:rgba(255,107,53,.22);font-weight:900;color:var(--accent2)}.rank-title{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.sheet{position:fixed;inset:0;z-index:40;display:none;background:transparent;overflow:hidden}.sheet.active{display:block}.sheet-inner{height:100vh;min-height:100vh;padding:12px;background:transparent;overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;touch-action:pan-y}.detail-panel{background:linear-gradient(135deg,rgba(40,30,64,.68),rgba(24,20,42,.54));border:1px solid rgba(255,255,255,.10);border-radius:22px;box-shadow:var(--shadow);padding:18px 14px 22px;margin-bottom:42px;touch-action:pan-y}.detail-head{display:grid;grid-template-columns:38% 1fr;gap:16px;align-items:start}.detail-pic{width:100%;aspect-ratio:3/4;border-radius:16px;object-fit:cover;background:rgba(255,255,255,.08);box-shadow:0 12px 30px rgba(0,0,0,.32)}.detail-title{font-size:25px;font-weight:500;margin:0 0 9px;line-height:1.25;color:rgba(255,255,255,.94)}.detail-info{color:rgba(255,255,255,.76);line-height:1.85;font-size:18px;font-weight:500}.detail-info b{color:rgba(255,255,255,.68);font-weight:800;margin-right:8px}.detail-date{font-size:20px;color:rgba(255,255,255,.88);margin:2px 0 14px}.intro-pill{display:inline-flex;margin:28px 0 18px;padding:11px 25px;border-radius:999px;background:#25b86b;color:white;font-size:18px;font-weight:700;box-shadow:0 8px 24px rgba(37,184,107,.22)}.desc{margin:0 4px 18px;color:rgba(255,255,255,.66);font-size:20px;line-height:1.95;max-height:none;overflow:visible}.play-title{margin:18px 2px 8px;font-size:18px;font-weight:800;color:rgba(255,255,255,.9)}.line-tabs{display:flex;gap:8px;overflow-x:auto;margin:8px 0 8px;padding-bottom:2px}.line-tab{border-radius:999px;padding:8px 12px;background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.14);white-space:nowrap;color:rgba(255,255,255,.82)}.line-tab.active{background:rgba(255,107,53,.36);border-color:rgba(255,184,107,.55);font-weight:800}.episodes{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px;max-height:none;overflow:visible;touch-action:pan-y}.ep{border-radius:12px;padding:9px 11px;background:rgba(255,255,255,.09);border:1px solid rgba(255,255,255,.14);cursor:pointer;min-width:68px;color:rgba(255,255,255,.86)}.empty{padding:30px 18px;text-align:center;color:var(--muted);background:var(--panel-soft);border:1px dashed var(--line);border-radius:var(--radius)}.loading{opacity:.75}.focusable:focus,.card:focus,.rank-item:focus,.ep:focus,button:focus,.tab:focus,input:focus{outline:2px solid rgba(255,184,107,.76);outline-offset:2px;transform:translateY(-1px)}
|
||
body.detail-active .app{visibility:hidden;pointer-events:none}@media (min-width:720px){.grid{grid-template-columns:repeat(5,minmax(0,1fr))}.app{padding:18px 28px 44px}.hero h1{font-size:30px}.detail-head{grid-template-columns:160px 1fr}.detail-pic{width:160px}}@media (min-width:1100px){.grid{grid-template-columns:repeat(7,minmax(0,1fr))}.app{max-width:1380px;margin:0 auto}.sheet-inner{max-width:1180px;margin:0 auto}}
|
||
@media (max-width:480px){.app{padding:8px 9px 24px}.brand{font-size:20px}.search input{font-size:14px}.search button{padding:7px 10px}.grid{grid-template-columns:repeat(3,minmax(0,1fr));gap:9px}.meta{padding:7px 7px 9px}.name{font-size:13px}.remark{font-size:11px}.detail-head{grid-template-columns:38% 1fr;gap:14px}.detail-title{font-size:24px}.detail-date{font-size:20px}.detail-info{font-size:18px;line-height:1.9}.desc{font-size:20px;line-height:1.92}.sheet-inner{padding:10px}.detail-panel{border-radius:20px;padding:16px 12px}.ep{min-width:64px;padding:8px 9px}}
|
||
|
||
/* detail refine overrides */
|
||
#closeDetail{margin:0 0 18px 0;padding:10px 20px;border-radius:999px;background:rgba(255,255,255,.10);border:1px solid rgba(255,184,107,.55)}
|
||
.detail-head{align-items:start!important;grid-template-columns:38% 1fr!important;gap:16px!important}
|
||
.detail-title{font-size:24px!important;font-weight:600!important;line-height:1.25!important;margin:0 0 10px!important;word-break:break-all}
|
||
.detail-info:empty{display:none!important}
|
||
.detail-info div{margin:4px 0}
|
||
.intro-pill{margin-top:26px!important}
|
||
.episodes{display:grid!important;grid-template-columns:repeat(4,minmax(0,1fr))!important;gap:12px!important;width:100%!important}
|
||
.ep{width:100%!important;min-width:0!important;text-align:center!important;padding:10px 4px!important;border-radius:14px!important}
|
||
@media(max-width:480px){.episodes{grid-template-columns:repeat(4,minmax(0,1fr))!important;gap:10px!important}.ep{font-size:15px!important;padding:9px 2px!important}.detail-title{font-size:23px!important}}
|
||
|
||
/* detail final tune */
|
||
.detail-side{max-height:100%;overflow:hidden}
|
||
.detail-info{font-size:15px!important;line-height:1.55!important;font-weight:500!important;max-height:calc((100vw - 44px) * .38 * 1.333 - 44px);overflow:hidden}
|
||
.detail-info b{font-size:15px!important;margin-right:3px!important}
|
||
.detail-title{font-size:22px!important;margin-bottom:8px!important;font-weight:650!important}
|
||
.desc{font-size:17px!important;line-height:1.75!important;color:rgba(255,255,255,.68)!important}
|
||
.intro-pill{background:rgba(255,255,255,.10)!important;border:1px solid rgba(255,184,107,.55)!important;color:rgba(255,255,255,.94)!important;box-shadow:none!important;padding:10px 22px!important;font-size:17px!important}
|
||
@media(max-width:480px){.detail-info{font-size:15px!important;line-height:1.55!important;max-height:calc((100vw - 44px) * .38 * 1.333 - 42px)}.detail-info b{font-size:15px!important}.detail-title{font-size:22px!important}.desc{font-size:17px!important;line-height:1.75!important}}
|
||
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="app" id="app">
|
||
<div class="top">
|
||
<div class="bar">
|
||
<div class="brand">歪比<b>巴卜</b></div>
|
||
<form class="search" id="searchForm">
|
||
<input id="kw" class="focusable" type="text" placeholder="搜索影片、动漫、剧集…" autocomplete="off" />
|
||
<button class="primary focusable" type="submit">搜索</button>
|
||
</form>
|
||
</div>
|
||
<div class="tabs" id="tabs"></div>
|
||
</div>
|
||
<div class="status" id="status">准备加载…</div>
|
||
<main id="content"></main>
|
||
</div>
|
||
<div class="sheet" id="detailSheet"><div class="sheet-inner"><div class="detail-panel" id="detailPanel"></div></div></div>
|
||
<script>
|
||
(function(){
|
||
'use strict';
|
||
setTimeout(()=>{try{var el=document.getElementById('status');if(el&&el.textContent==='准备加载…')el.textContent='脚本已启动,正在等待 SDK/加载首页…'}catch(e){}},100);
|
||
const BASE='https://wbbb1.com';
|
||
const CATS=[['首页','/'],['电影','/type/1.html'],['剧集','/type/2.html'],['动漫','/type/3.html'],['综艺','/type/4.html'],['今日更新','/label/new.html'],['热搜榜','/label/hot.html']];
|
||
const UA='Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36 Chrome/120 Mobile Safari/537.36';
|
||
let fmReady=false,currentUrl=BASE+'/',lastFocus=null;
|
||
const $=s=>document.querySelector(s), content=$('#content'), status=$('#status'), tabs=$('#tabs');
|
||
function markNative(){ if(window.fongmiBridge||window.fm||window.fongmi) document.documentElement.classList.add('fm-native'); }
|
||
function waitFm(ms=1600){ markNative(); if(window.fm){fmReady=true;return Promise.resolve(window.fm)} return new Promise(r=>{let done=false;const ok=()=>{if(done)return;done=true;markNative();fmReady=!!window.fm;r(window.fm||null)};window.addEventListener('fmsdk',ok,{once:true});setTimeout(ok,ms);});}
|
||
function abs(u){try{return new URL(u,BASE+'/').href}catch(e){return u||''}}
|
||
function esc(s){return String(s||'').replace(/[&<>'"]/g,c=>({'&':'&','<':'<','>':'>',"'":''','"':'"'}[c]))}
|
||
function clean(s){return String(s||'').replace(/\s+/g,' ').replace(/[]/g,'').trim()}
|
||
function imgUrl(u){u=abs(u||''); if(!u) return ''; if(/\.webp(?:\?|$)/i.test(u)) return u; try{return window.fm&&fm.res?fm.res(u,{headers:{Referer:BASE+'/', 'User-Agent':UA}}):u}catch(e){return u}}
|
||
async function reqText(url){url=abs(url);status.textContent='加载:'+url;const headers={'User-Agent':UA,'Referer':BASE+'/','Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8','Accept-Language':'zh-CN,zh;q=0.9','Cache-Control':'no-cache'};try{if(window.fm&&fm.req){let r=await fm.req(url,{method:'GET',headers,responseType:'text',timeout:25,credentials:'include'});if(!r.ok&&String(r.status)==='520'){r=await fm.req(url+(url.includes('?')?'&':'?')+'_t='+Date.now(),{method:'GET',headers:{...headers,Referer:'https://www.baidu.com/'},responseType:'text',timeout:25,credentials:'include'})}if(!r.ok)throw new Error(r.error||('HTTP '+r.status));return r.body||'';}const r=await fetch(url,{headers,cache:'no-store'});if(!r.ok)throw new Error('HTTP '+r.status);return await r.text();}catch(e){status.textContent='加载失败:'+e.message;throw e}}
|
||
function doc(html){return new DOMParser().parseFromString(html,'text/html')}
|
||
function cardFromA(a){const href=abs(a.getAttribute('href')||'');let img=a.querySelector('img');let image=img?(img.getAttribute('data-src')||img.getAttribute('data-original')||img.getAttribute('src')||''):'';let title=a.getAttribute('title')||img?.getAttribute('alt')||'';let text=clean(a.textContent); if(!title) title=text.replace(/^(4K)?(今日更新)?(更新至|已完结|HD|全).*?/,'').slice(0,24)||text;let remark=text.replace(title,'').slice(0,40);return {title:clean(title),remark:clean(remark),href,image:abs(image)}}
|
||
function unique(arr){const m=new Map();arr.forEach(x=>{if(x&&x.href&&x.title&&!m.has(x.href))m.set(x.href,x)});return [...m.values()]}
|
||
function parseList(html,keyword=''){
|
||
const d=doc(html), sections=[];
|
||
const badHost=el=>!!el.closest('.pop-list-body,.search-hot,.history,.footer,.head-more,.slide-time,.banner,.swiper,.large-swiper,.popup');
|
||
const isGood=x=>x&&x.href&&x.title&&x.image&&!/^点击观看$/.test(x.title);
|
||
let heads=[...d.querySelectorAll('.title-a,.module-title,.title')].map(h=>({el:h,title:clean(h.textContent).replace('更多','')})).filter(x=>x.title&&!/搜索|播放记录|搜索历史|热门搜索|更多/.test(x.title));
|
||
for(const h of heads){
|
||
let box=h.el.closest('.box-width,.module,.module-main,.layout-box,.box')||h.el.parentElement;
|
||
let items=[];
|
||
for(let i=0;i<4&&box;i++,box=box.parentElement){
|
||
items=unique([...box.querySelectorAll('a[href*="/detail/"]')].filter(a=>!badHost(a)).map(cardFromA)).filter(isGood).slice(0,24);
|
||
if(items.length>=3)break;
|
||
}
|
||
if(items.length)sections.push({title:h.title,items});
|
||
}
|
||
if(!sections.length){
|
||
let items=unique([...d.querySelectorAll('a[href*="/detail/"]')].filter(a=>!badHost(a)).map(cardFromA)).filter(isGood);
|
||
if(keyword) items=items.filter(x=>x.title.includes(keyword)||x.remark.includes(keyword));
|
||
items=items.slice(0,60);
|
||
sections.push({title:keyword?('搜索:'+keyword):'影片列表',items});
|
||
}
|
||
return sections.filter(s=>s.items.length)
|
||
}
|
||
function parseDetail(html,url){
|
||
const d=doc(html);
|
||
const title=clean(d.querySelector('h1')?.textContent||d.title.replace(/《|》|免费观看.*$/g,'')).replace(/(电视剧|电影|动漫|综艺|短剧|连续剧|国产剧|动画)$/,'');
|
||
let pic=d.querySelector('.module-info-poster .module-item-pic img,.module-poster-bg img,.module-item-pic img[data-original],.detail-pic img,.vod-pic img,.poster img,img[alt]');
|
||
let image=pic?(pic.getAttribute('data-original')||pic.getAttribute('data-src')||pic.getAttribute('src')):'';
|
||
if(image&&/load\.gif|errorpic\.png/i.test(image)){let p2=d.querySelector('img[data-original],img[data-src]');image=p2?(p2.getAttribute('data-original')||p2.getAttribute('data-src')||image):image}
|
||
const raw=(d.body?.innerText||'').replace(/\r/g,'');
|
||
const lines=raw.split('\n').map(x=>clean(x)).filter(Boolean);
|
||
function pickLine(label){
|
||
const labels=['类型','导演','演员','语言','连载','更新'];
|
||
const re=new RegExp('^'+label+'\\s*[::]?\\s*(.*)$');
|
||
const line=lines.find(x=>re.test(x));
|
||
if(!line) return '';
|
||
let v=(line.match(re)||[])[1]||'';
|
||
v=v.replace(/^(:|:)/,'').trim();
|
||
const others=labels.filter(x=>x!==label).join('|');
|
||
v=v.replace(new RegExp('\\s*(?:'+others+')\\s*[::].*$'), '').trim();
|
||
return v.length>120?v.slice(0,120)+'…':v;
|
||
}
|
||
const fields=[
|
||
['类型',pickLine('类型')],
|
||
['导演',pickLine('导演')],
|
||
['演员',pickLine('演员')],
|
||
['连载',pickLine('连载')],
|
||
['更新',pickLine('更新')]
|
||
].filter(x=>x[1]);
|
||
if(!fields.length){
|
||
const text=raw.replace(/\s+/g,' ');
|
||
function pickAny(label,next){const re=new RegExp(label+'\\s*[::]\\s*(.*?)(?='+next+'|简介|播放线路|$)');const m=text.match(re);return m?clean(m[1]).slice(0,120):''}
|
||
const fs=[['类型',pickAny('类型','导演')],['导演',pickAny('导演','演员')],['演员',pickAny('演员','连载')],['连载',pickAny('连载','更新')],['更新',pickAny('更新','简介')]].filter(x=>x[1]);
|
||
fields.push(...fs);
|
||
}
|
||
let desc='';
|
||
const descNode=d.querySelector('.module-info-introduction-content p,.module-info-introduction-content,.video-info-content,.vod_content,.detail-content,.content_desc');
|
||
if(descNode) desc=clean(descNode.textContent).replace(/展开$/,'');
|
||
if(!desc){
|
||
let i=lines.findIndex(x=>x==='简介'||x.startsWith('简介')||x==='剧情介绍'||x.startsWith('剧情介绍'));
|
||
if(i>=0){
|
||
let arr=[];
|
||
for(let j=i+1;j<lines.length;j++){
|
||
if(/^(选集播放|播放线路|资源列表|热播推荐|相关推荐|⚠️|重要提醒|排序|切换节点|至臻|蓝光|自营|推荐\(\d+\))/.test(lines[j])) break;
|
||
if(lines[j] && lines[j] !== '展开') arr.push(lines[j]);
|
||
}
|
||
desc=clean(arr.join(' ')).replace(/展开$/,'');
|
||
}
|
||
}
|
||
if(!desc){
|
||
let m=raw.match(/(?:简介|剧情介绍)\s*([\s\S]*?)(?:选集播放|播放线路|资源列表|热播推荐|相关推荐|⚠️)/);
|
||
desc=m?clean(m[1]).replace(/展开$/,''):'暂无简介';
|
||
}
|
||
desc=desc.replace(/\s*展开\s*$/,''); if(desc.length>360) desc=desc.slice(0,360)+'…';
|
||
let lineNames=[...d.querySelectorAll('.module-tab-item.tab-item')].map(x=>clean(x.getAttribute('data-dropdown-value')||x.querySelector('span')?.textContent||x.textContent.replace(/\d+$/,''))).filter(Boolean);
|
||
if(!lineNames.length) lineNames=[...raw.matchAll(new RegExp('([^\s\n()]{2,12})\((\d+)\)','g'))].map(m=>clean(m[1])).filter(x=>!/提醒|搜索|播放|记录/.test(x));
|
||
lineNames=[...new Set(lineNames)];
|
||
function epNo(ep){let m=(ep.href||'').match(/\/(?:vodplay|vplay|play)\/\d+-\d+-(\d+)\.html/); if(m) return parseInt(m[1],10)||0; let t=(ep.title||'').match(/(\d+)/); return t?parseInt(t[1],10):0;}
|
||
let linesGroup=[];
|
||
const panels=[...d.querySelectorAll('.module-list.sort-list.tab-list.his-tab-list')];
|
||
if(panels.length){
|
||
panels.forEach((pl,i)=>{let arr=unique([...pl.querySelectorAll('a.module-play-list-link,a[href*="/vodplay/"],a[href*="/vplay/"],a[href*="/play/"]')].map(a=>({title:clean(a.querySelector('span')?.textContent||a.textContent)||'播放',href:abs(a.getAttribute('href')),remark:'',image:''}))).sort((a,b)=>epNo(a)-epNo(b));if(arr.length)linesGroup.push({sid:String(i+1),name:lineNames[i]||('线路'+(i+1)),eps:arr})});
|
||
}else{
|
||
const groups={}, lineOrder=[];
|
||
let eps0=unique([...d.querySelectorAll('a.module-play-list-link,a[href*="/vodplay/"],a[href*="/vplay/"],a[href*="/play/"]')].map(a=>({title:clean(a.querySelector('span')?.textContent||a.textContent)||'播放',href:abs(a.getAttribute('href')),remark:'',image:''}))).slice(0,320);
|
||
eps0.forEach(ep=>{let m=ep.href.match(/\/(?:vodplay|vplay|play)\/\d+-(\d+)-\d+\.html/);let sid=m?m[1]:'1';if(!groups[sid]){groups[sid]=[];lineOrder.push(sid)}groups[sid].push(ep)});
|
||
lineOrder.forEach(sid=>groups[sid].sort((a,b)=>epNo(a)-epNo(b)));
|
||
linesGroup=lineOrder.map((sid,i)=>({sid,name:lineNames[i]||('线路'+sid),eps:groups[sid]}));
|
||
}
|
||
let eps=linesGroup[0]?.eps||[];
|
||
return {title,image:abs(image),fields,desc,eps,lines:linesGroup,url}
|
||
}
|
||
function parsePlay(html,playPage){let p=null;const m=html.match(/var\s+player_aaaa\s*=\s*(\{[\s\S]*?\})\s*<\/script>/);if(m){try{p=JSON.parse(m[1].replace(/\\\//g,'/'))}catch(e){}}const d=doc(html);let iframe=d.querySelector('iframe[src]');let src=iframe?abs(iframe.getAttribute('src')):'';let host=new URL(BASE).host;if(!src&&p&&p.url){src=/^https?:\/\//i.test(p.url)?p.url:('https://xn--qvr2v.850088.xyz/player/?url='+encodeURIComponent(p.url)+'&next='+encodeURIComponent(p.link_next?('//'+host+p.link_next):'')+'&title='+encodeURIComponent(p?.vod_data?.vod_name||''))}return{src,token:p&&p.url,title:p?.vod_data?.vod_name||document.title||'歪比播放',from:p?.from||'',page:playPage}}
|
||
function loadCrypto(){return new Promise((ok,err)=>{if(window.CryptoJS)return ok();let s=document.createElement('script');s.src='https://registry.npmmirror.com/crypto-js/4.2.0/files/crypto-js.js';s.onload=ok;s.onerror=err;document.head.appendChild(s)})}
|
||
function rc4b64(key,data){let S=[],j=0,x,res=[];for(let i=0;i<256;i++)S[i]=i;for(let i=0;i<256;i++){j=(j+S[i]+key.charCodeAt(i%key.length))&255;x=S[i];S[i]=S[j];S[j]=x}let i=0;j=0;let bytes=new TextEncoder().encode(data);for(let c of bytes){i=(i+1)&255;j=(j+S[i])&255;x=S[i];S[i]=S[j];S[j]=x;res.push(c^S[(S[i]+S[j])&255])}let bin='';res.forEach(b=>bin+=String.fromCharCode(b));return btoa(bin)}
|
||
async function apiPost(url,data,headers){let body=new URLSearchParams(data).toString();if(window.fm&&fm.req){let r=await fm.req(url,{method:'POST',headers,body,responseType:'text',timeout:25});if(!r.ok)throw new Error(r.error||('HTTP '+r.status));return JSON.parse(r.body||'{}')}let r=await fetch(url,{method:'POST',headers,body});return await r.json()}
|
||
async function directResolve(pp){if(!pp||!pp.token||!pp.src)return'';await loadCrypto();let u=new URL(pp.src),host=u.host,urlParam=pp.token,salt='stray',t=String(Math.floor(Date.now()/1000));let md5=s=>CryptoJS.MD5(String(s)).toString();let rc4key=(md5(urlParam)+' P').slice(-22);let post={url:urlParam,key:rc4b64(rc4key,md5(urlParam+salt)),vkey:rc4b64(rc4key,t+md5(rc4key+salt)),ckey:rc4b64(rc4key,md5(host+salt))};let hs={'User-Agent':UA,'Referer':pp.src,'Origin':'https://'+host,'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8','Accept':'application/json, text/javascript, */*; q=0.01','X-Requested-With':'XMLHttpRequest'};let js=await apiPost('https://'+host+'/player/api.php',post,hs);if(!js||!js.url)return'';let key=CryptoJS.enc.Utf8.parse('OddfJktEbGu7gCv9'),iv=CryptoJS.enc.Utf8.parse('okjutU3RjGpWqB8Z');return CryptoJS.AES.decrypt(js.url,key,{iv,mode:CryptoJS.mode.CBC,padding:CryptoJS.pad.Pkcs7}).toString(CryptoJS.enc.Utf8)}
|
||
function setStatus(t){status.textContent=t||''}
|
||
function renderTabs(active){tabs.innerHTML=CATS.map(([n,p])=>`<button class="tab focusable ${abs(p)===abs(active)?'active':''}" data-url="${esc(abs(p))}">${esc(n)}</button>`).join('');tabs.querySelectorAll('.tab').forEach(b=>b.onclick=()=>loadPage(b.dataset.url))}
|
||
function renderSections(sections){content.innerHTML=sections.map(sec=>`<section class="section"><div class="section-title"><h2>${esc(sec.title)}</h2></div><div class="grid">${sec.items.map(it=>`<article class="card focusable" tabindex="0" data-href="${esc(it.href)}"><div class="poster">${it.image?`<img loading="lazy" referrerpolicy="no-referrer" src="${esc(imgUrl(it.image))}" alt="${esc(it.title)}">`:`<div class="noimg">歪</div>`}</div><div class="meta"><div class="name">${esc(it.title)}</div><div class="remark">${esc(it.remark||'点击查看详情')}</div></div></article>`).join('')}</div></section>`).join('');content.querySelectorAll('.card').forEach(c=>{c.onclick=()=>openDetail(c.dataset.href);c.onkeydown=e=>{if(e.key==='Enter')c.click()}})}
|
||
async function loadPage(url){currentUrl=abs(url);renderTabs(currentUrl);content.innerHTML='<div class="empty loading">正在加载内容…</div>';try{const html=await reqText(currentUrl);const sections=parseList(html);renderSections(sections);setStatus('已加载 '+sections.reduce((n,s)=>n+s.items.length,0)+' 条内容');restoreFocus()}catch(e){content.innerHTML='<div class="empty">加载失败:'+esc(e.message)+'</div>'}}
|
||
async function search(q){
|
||
q=clean(q);if(!q)return;
|
||
renderTabs('');
|
||
content.innerHTML='<div class="empty loading">搜索中…</div>';
|
||
try{
|
||
const searchUrl=BASE+'/search/'+encodeURIComponent(q)+'-------------.html';
|
||
const html=await reqText(searchUrl);
|
||
const sections=parseList(html,q);
|
||
if(!sections.length||!sections[0].items.length){content.innerHTML='<div class="empty">没有找到相关结果</div>';setStatus('无搜索结果:'+q);return;}
|
||
sections[0].title='搜索:'+q;
|
||
renderSections(sections);
|
||
setStatus('搜索完成:'+q);
|
||
}catch(e){content.innerHTML='<div class="empty">搜索失败,请换个关键词重试。</div>';setStatus('搜索失败:'+e.message);}
|
||
}
|
||
async function openDetail(url){lastFocus=document.activeElement;document.body.classList.add('detail-active');$('#detailSheet').classList.add('active');$('#detailPanel').innerHTML='<div class="empty loading">正在读取详情…</div>';history.pushState({route:'detail',url},'', '#detail='+encodeURIComponent(url));try{const html=await reqText(url);const d=parseDetail(html,url);let firstLine=d.lines[0]||{sid:'1',name:'默认线路',eps:d.eps};
|
||
function trimFieldValue(label,value){const labels=['类型','导演','演员','语言','连载','更新'].filter(x=>x!==label).join('|');return String(value||'').replace(new RegExp('\\s*(?:'+labels+')\\s*[::].*$'),'').trim();}
|
||
const shownFields=d.fields.filter(x=>x[0]!=='更新').map(x=>[x[0],trimFieldValue(x[0],x[1])]).filter(x=>x[1]);
|
||
$('#detailPanel').innerHTML=`<button class="focusable" id="closeDetail">返回</button><div class="detail-head"><img class="detail-pic" referrerpolicy="no-referrer" src="${esc(imgUrl(d.image))}" onerror="this.style.display='none'"><div class="detail-side"><div class="detail-title">${esc(d.title)}</div><div class="detail-info">${shownFields.map(x=>`<div><b>${esc(x[0])}:</b>${esc(x[1])}</div>`).join('')||''}</div></div></div><div class="intro-pill">简介</div><p class="desc">${esc(d.desc||'暂无简介')}</p><div class="play-title">播放线路</div><div class="line-tabs">${(d.lines.length?d.lines:[firstLine]).map((ln,i)=>`<button class="line-tab focusable ${i===0?'active':''}" data-sid="${esc(ln.sid)}">${esc(ln.name)}(${ln.eps.length})</button>`).join('')}</div><div class="episodes" id="episodeBox"></div>`;
|
||
function renderLine(sid){const ln=d.lines.find(x=>x.sid==sid)||firstLine;$('#episodeBox').innerHTML=ln.eps.map(ep=>`<button class="ep focusable" data-href="${esc(ep.href)}">${esc(ep.title)}</button>`).join('')||'<div class="empty">暂无分集</div>';$('#episodeBox').querySelectorAll('.ep').forEach(b=>b.onclick=()=>playEpisode(b.dataset.href,d.title+' '+b.textContent));}
|
||
$('#closeDetail').onclick=closeDetail;$('#detailPanel').querySelectorAll('.line-tab').forEach(b=>b.onclick=()=>{$('#detailPanel').querySelectorAll('.line-tab').forEach(x=>x.classList.remove('active'));b.classList.add('active');renderLine(b.dataset.sid)});renderLine(firstLine.sid);$('#closeDetail').focus({preventScroll:true})}catch(e){$('#detailPanel').innerHTML='<button class="focusable" onclick="window.__wbClose()">返回</button><div class="empty">详情加载失败:'+esc(e.message)+'</div>'}}
|
||
async function playEpisode(url,title){
|
||
setStatus('正在解析播放…');
|
||
var playUrl=abs(url);
|
||
try{
|
||
var html=await reqText(playUrl);
|
||
var pp=parsePlay(html,playUrl);
|
||
if(pp.src){
|
||
if(/^https?:\/\//i.test(pp.token||'')&&/\.(m3u8|mp4|mkv)(?:\?|$)/i.test(pp.token)){if(window.fm&&fm.play){await fm.play(pp.token,title,{headers:{'User-Agent':UA,'Referer':BASE+'/','pics':'1'}});setStatus('直连播放:'+title);return}else{location.href=pp.token;return}}
|
||
setStatus('正在直解播放地址…');
|
||
try{let real=await directResolve(pp);if(real&&/\.(m3u8|mp4|mkv)(?:\?|$)/i.test(real)){if(window.fm&&fm.play){await fm.play(real,title,{headers:{'User-Agent':UA,'Referer':new URL(pp.src).origin+'/','pics':'1'}});setStatus('直连播放:'+title);return}else{location.href=real;return}}}catch(e){console.warn('direct resolve failed',e)}
|
||
if(window.fm&&fm.play){await fm.play('push://'+pp.src,title);setStatus('嗅探解析器:'+title);return}
|
||
location.href=pp.src;return;
|
||
}
|
||
}catch(e){console.warn('parse failed',e)}
|
||
try{if(window.fm&&fm.play){await fm.play('push://'+playUrl,title);setStatus('推送播放:'+title);return}}catch(e){}
|
||
setStatus('打开原站播放页…');
|
||
location.href=playUrl;
|
||
}
|
||
function closeDetail(){document.body.classList.remove('detail-active');$('#detailSheet').classList.remove('active');if(location.hash.startsWith('#detail=')) history.back(); if(lastFocus&&lastFocus.focus) setTimeout(()=>lastFocus.focus({preventScroll:true}),50)}window.__wbClose=closeDetail;
|
||
async function nativeSearch(q){q=q||clean($('#kw').value);if(!q)return;if(window.fm&&fm.search){try{await fm.search(q,{direct:true});return}catch(e){}}search(q)}
|
||
function restoreFocus(){setTimeout(()=>{const el=document.querySelector('.card')||document.querySelector('.tab.active'); if(el) el.focus({preventScroll:true})},30)}
|
||
function handleKeys(e){if(e.key==='Escape'||e.key==='Backspace'){if($('#detailSheet').classList.contains('active')){e.preventDefault();closeDetail();return}}if(e.key==='Enter'&&document.activeElement?.classList.contains('focusable')&&document.activeElement.tagName!=='INPUT'){document.activeElement.click();}}
|
||
function boot(){setStatus('正在初始化…');renderTabs(BASE+'/');$('#searchForm').onsubmit=e=>{e.preventDefault();search($('#kw').value)};const ns=$('#nativeSearch'); if(ns) ns.onclick=()=>nativeSearch();document.addEventListener('keydown',handleKeys,true);window.addEventListener('popstate',()=>{if($('#detailSheet').classList.contains('active')){document.body.classList.remove('detail-active');$('#detailSheet').classList.remove('active')}else loadPage(currentUrl)});loadPage(BASE+'/')}
|
||
setTimeout(()=>{try{if(status&&status.textContent==='准备加载…')status.textContent='正在初始化 WebHome…'}catch(e){}},800);
|
||
waitFm().then(()=>{try{boot()}catch(e){status.textContent='启动失败:'+e.message;console.error(e)}});
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html> |