Skip to content

Commit e872464

Browse files
committed
Upload 腾讯视频.html
1 parent 27897f6 commit e872464

1 file changed

Lines changed: 53 additions & 0 deletions

File tree

‎腾讯视频.html‎

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<!doctype html>
2+
<html lang="zh-CN">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
6+
<title>腾讯视频 WebHome</title>
7+
<style>
8+
*{box-sizing:border-box}body{margin:0;color:#fff;background:transparent;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Noto Sans SC',sans-serif}.app{padding:18px 18px 30px;min-height:100vh;background:linear-gradient(135deg,rgba(5,12,25,.82),rgba(9,42,42,.72))}.top-title{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px}.brand{display:flex;align-items:center;gap:10px;font-size:22px;font-weight:800}.logo{width:36px;height:36px;border-radius:12px;background:linear-gradient(135deg,#00f5a0,#00d9f5);display:grid;place-items:center;color:#001;font-weight:900}.icon-btn,.tab,.card,.ep,.line-tab,.cfg-btn{border:1px solid rgba(255,255,255,.14);background:rgba(255,255,255,.09);color:#fff;border-radius:14px}.icon-btn,.cfg-btn{height:38px;padding:0 14px}.search-row{display:grid;grid-template-columns:auto 1fr auto;gap:10px;margin-bottom:12px}input,textarea{width:100%;border:1px solid rgba(255,255,255,.16);background:rgba(0,0,0,.24);color:#fff;border-radius:14px;padding:11px 12px;outline:none}textarea{min-height:112px;resize:vertical;font-family:ui-monospace,Consolas,monospace;font-size:12px}.tabs,.line-tabs{display:flex;gap:8px;overflow:auto;padding:4px 0 12px}.tab,.line-tab{white-space:nowrap;padding:9px 13px}.tab.active,.line-tab.active{background:linear-gradient(135deg,#00d9f5,#00f5a0);color:#001;font-weight:800}.section-head{display:flex;justify-content:space-between;align-items:center;margin:8px 0 12px}h2{font-size:18px;margin:0}.hint{font-size:12px;color:rgba(255,255,255,.62)}#content{display:grid;grid-template-columns:repeat(auto-fill,minmax(116px,1fr));gap:12px}.card{overflow:hidden;text-align:left;padding:0}.poster{width:100%;aspect-ratio:2/3;background:rgba(255,255,255,.08);object-fit:cover;display:block}.card-info{padding:8px}.name{font-size:14px;font-weight:700;line-height:1.28;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.remark{margin-top:5px;font-size:12px;color:rgba(255,255,255,.66);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.empty{grid-column:1/-1;text-align:center;color:rgba(255,255,255,.62);padding:40px 0}.sheet,.config-mask{position:fixed;inset:0;background:rgba(0,0,0,.48);display:none;z-index:20;align-items:flex-end}.sheet.show,.config-mask.show{display:flex}.detail-panel,.config-panel{width:100%;max-height:86vh;overflow:auto;background:linear-gradient(180deg,rgba(18,28,40,.96),rgba(8,14,22,.98));backdrop-filter:blur(16px);border-radius:24px 24px 0 0;border:1px solid rgba(255,255,255,.12);padding:18px}.detail-top{display:grid;grid-template-columns:110px 1fr;gap:14px}.detail-pic{width:110px;border-radius:14px;aspect-ratio:2/3;object-fit:cover;background:#17202c}.detail-title{font-size:20px;font-weight:900;margin-bottom:8px}.meta{font-size:13px;color:rgba(255,255,255,.72);line-height:1.55}.desc{margin:12px 0;font-size:13px;color:rgba(255,255,255,.75);line-height:1.6}.eps{display:grid;grid-template-columns:repeat(auto-fill,minmax(82px,1fr));gap:9px}.ep{padding:10px 8px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.row{display:grid;grid-template-columns:88px 1fr;gap:8px;align-items:center;margin:9px 0}.cfg-title{font-size:18px;font-weight:900;margin-bottom:10px}.parser-list{display:grid;gap:8px}.parser-item{display:grid;grid-template-columns:22px 90px 1fr 42px;gap:8px;align-items:center}.small{font-size:12px;color:rgba(255,255,255,.62);line-height:1.5}.pager{display:flex;gap:10px;justify-content:center;align-items:center;margin:18px 0 4px}.pager button{border:1px solid rgba(255,255,255,.14);background:rgba(255,255,255,.09);color:#fff;border-radius:14px;padding:10px 18px}.pager button:disabled{opacity:.38}.toast{position:fixed;left:50%;bottom:28px;transform:translateX(-50%);background:rgba(0,0,0,.72);padding:10px 14px;border-radius:999px;display:none;z-index:30}
9+
</style>
10+
</head>
11+
<body>
12+
<main class="app">
13+
<div class="top-title"><div class="brand"><div class="logo">TX</div><div>腾讯视频</div></div><button class="icon-btn" id="configBtn">解析设置</button></div>
14+
<div class="search-row"><button class="cfg-btn" id="homeBtn">首页</button><form id="searchForm"><input id="kw" placeholder="搜索电影 / 电视剧 / 动漫 / 综艺"></form><button class="cfg-btn" id="searchBtn">搜索</button></div>
15+
<div class="tabs" id="tabs"></div>
16+
<div class="section-head"><h2 id="sectionTitle">精选</h2><div class="hint" id="status">就绪</div></div>
17+
<section id="content"></section><div class="pager" id="pager"><button id="prevPage">上一页</button><span id="pageText">第 1 页</span><button id="nextPage">下一页</button></div>
18+
</main>
19+
<div class="sheet" id="detailSheet"><div class="detail-panel" id="detailPanel"></div></div>
20+
<div class="config-mask" id="configMask"><div class="config-panel"><div class="cfg-title">自定义解析设置</div><div class="small">解析地址支持 <b>{url}</b> 占位符;不写占位符时会自动拼接 encodeURIComponent(播放页URL)。启用后详情页会生成对应线路,可随时增删改。</div><div id="parserList" class="parser-list"></div><div class="row"><span>名称</span><input id="pName" placeholder="例如 虾米解析"></div><div class="row"><span>地址</span><input id="pUrl" placeholder="https://xxx/?url={url}"></div><div style="display:flex;gap:8px;margin-top:12px"><button class="cfg-btn" id="addParser">添加</button><button class="cfg-btn" id="saveParser">保存</button><button class="cfg-btn" id="resetParser">重置</button><button class="cfg-btn" id="closeCfg">关闭</button></div></div></div>
21+
<div class="toast" id="toast"></div>
22+
<script>
23+
const BASE='https://v.qq.com',API='https://node.video.qq.com',CATS=[['choice','精选'],['movie','电影'],['tv','电视剧'],['variety','综艺'],['cartoon','动漫'],['child','少儿'],['doco','纪录片']],UA='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120 Safari/537.36';
24+
let activeCat='choice',page=1,lastList=[],currentDetail=null,activeLine='';
25+
let parsers=loadParsers();
26+
const $=s=>document.querySelector(s),esc=s=>String(s||'').replace(/[&<>"]/g,m=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'"'}[m])),clean=s=>String(s||'').trim(),abs=u=>!u?'':/^https?:/i.test(u)?u:u.startsWith('//')?'https:'+u:new URL(u,BASE).href;
27+
function toast(s){$('#toast').textContent=s;$('#toast').style.display='block';setTimeout(()=>$('#toast').style.display='none',1600)}
28+
function setStatus(s){$('#status').textContent=s}
29+
function loadParsers(){try{return JSON.parse(localStorage.tx_parsers||'')}catch(e){}return[]}
30+
function saveParsers(){localStorage.tx_parsers=JSON.stringify(parsers)}
31+
async function req(url,opt={}){let o=Object.assign({headers:{'User-Agent':UA,'Referer':BASE+'/'}},opt);if(window.fm&&fm.req){let r=await fm.req(url,o);return typeof r==='string'?r:(r&&r.body)||JSON.stringify(r||{})}let r=await fetch(url,o);return await r.text()}
32+
async function json(url,opt={}){let t=await req(url,opt);return JSON.parse(t.replace(/^QZOutputJson=/,'').replace(/;\s*$/,''))}
33+
function renderTabs(){tabs.innerHTML=CATS.map(x=>`<button class="tab ${activeCat===x[0]?'active':''}" data-id="${x[0]}">${x[1]}</button>`).join('');tabs.querySelectorAll('.tab').forEach(b=>b.onclick=()=>{activeCat=b.dataset.id;page=1;renderTabs();loadCategory()})}
34+
function parseCards(html,cat){let arr=[],ms=String(html||'').match(/<div[^>]*class=["']?list_item["']?[^>]*>[\s\S]*?<\/div>/gi)||[];ms.forEach(it=>{let n=(it.match(/<img[^>]*alt=["']?([^"']*)/i)||[])[1]||'',p=(it.match(/<img[^>]*src=["']?([^"'\s>]+)/i)||[])[1]||'',u=(it.match(/<a[^>]*data-float=["']?([^"'\s>]+)/i)||[])[1]||(it.match(/href=["']?([^"'\s>]+)/i)||[])[1]||'',d=(it.match(/<a[^>]*>([\s\S]*?)<\/a>/i)||[])[1]||'';if(n&&p)arr.push({vod_id:(cat?cat+'$':'')+u,vod_name:n,vod_pic:abs(p),vod_remarks:d.replace(/<[^>]+>/g,'').trim()})});return arr}
35+
async function loadCategory(){setStatus('加载中');sectionTitle.textContent=(CATS.find(x=>x[0]===activeCat)||CATS[0])[1];content.innerHTML='<div class="empty">加载中...</div>';let ch=activeCat==='choice'?'cartoon':activeCat,off=(page-1)*21,u=`${BASE}/x/bu/pagesheet/list?_all=1&append=1&channel=${encodeURIComponent(ch)}&listpage=${page}&offset=${off}&pagesize=21&iarea=-1&sort=18`;try{let h=await req(u);lastList=parseCards(h,ch);renderCards(lastList);updatePager(lastList.length>=21);setStatus('第 '+page+' 页')}catch(e){content.innerHTML='<div class="empty">加载失败</div>';updatePager(false);setStatus('失败')}}
36+
function renderCards(arr){content.innerHTML=arr.length?arr.map((v,i)=>`<button class="card" data-i="${i}"><img class="poster" src="${esc(v.vod_pic)}"><div class="card-info"><div class="name">${esc(v.vod_name)}</div><div class="remark">${esc(v.vod_remarks)}</div></div></button>`).join(''):'<div class="empty">暂无内容</div>';content.querySelectorAll('.card').forEach(b=>b.onclick=()=>openDetail(lastList[+b.dataset.i]))}
37+
function updatePager(hasNext){if(!window.pager)return;pager.style.display=kw.value.trim()?'none':'flex';pageText.textContent='第 '+page+' 页';prevPage.disabled=page<=1;nextPage.disabled=!hasNext}
38+
async function batchInfo(vids){let out=[];for(let i=0;i<vids.length;i+=30){let b=vids.slice(i,i+30);try{let j=await json(`https://union.video.qq.com/fcgi-bin/data?otype=json&tid=1804&appid=20001238&appkey=6c03bbe9658448a4&union_platform=1&idlist=${b.join(',')}`);(j.results||[]).forEach(x=>{let f=x.fields||{};out.push({vid:f.vid,title:f.title,type:f.category_map&&f.category_map.length>1?f.category_map[1]:''})})}catch(e){}}return out}
39+
async function openDetail(v){detailSheet.classList.add('show');detailPanel.innerHTML='<div class="empty">详情加载中...</div>';let raw=String(v.vod_id||''),sp=raw.split('$'),cid=sp[1]||sp[0];try{let j=await json(`${API}/x/api/float_vinfo2?cid=${encodeURIComponent(cid)}`),c=j.c||{},vids=c.video_ids||[],infos=await batchInfo(vids),ordered=vids.map(x=>infos.find(y=>y.vid===x)||{vid:x,title:'',type:''}),main=ordered.filter(x=>!x.type||x.type==='正片'),extra=ordered.filter(x=>x.type&&x.type!=='正片'),mk=x=>x.map((it,i)=>({name:(/^\d+$/.test(it.title)?'第'+it.title+'集':it.title)||('第'+(i+1)+'集'),url:`${BASE}/x/cover/${cid}/${it.vid}.html`}));let lines=[];if(main.length){lines.push({name:'智能线路',eps:mk(main)});parsers.filter(p=>p.enabled&&clean(p.url)).forEach(p=>lines.push({name:p.name,parser:p,eps:mk(main)}))}if(extra.length)lines.push({name:'花絮/预告',eps:mk(extra)});currentDetail={vod:{vod_id:raw,vod_name:c.title||v.vod_name||'',vod_pic:abs(c.pic||v.vod_pic||''),vod_remarks:j.rec||v.vod_remarks||'',vod_year:c.year||'',type_name:(j.typ||[]).join(','),vod_actor:(j.nam||[]).join(','),vod_content:c.description||''},lines};renderDetail()}catch(e){detailPanel.innerHTML='<div class="empty">详情加载失败</div>'}}
40+
function renderDetail(){let d=currentDetail.vod,lines=currentDetail.lines;activeLine=lines[0]&&lines[0].name||'';detailPanel.innerHTML=`<div class="detail-top"><img class="detail-pic" src="${esc(d.vod_pic)}"><div><div class="detail-title">${esc(d.vod_name)}</div><div class="meta">${esc([d.type_name,d.vod_year,d.vod_actor,d.vod_remarks].filter(Boolean).join(' · '))}</div></div></div><div class="desc">${esc(d.vod_content||'暂无简介')}</div><div class="line-tabs" id="lineTabs"></div><div class="eps" id="eps"></div>`;renderLines()}
41+
function renderLines(){lineTabs.innerHTML=currentDetail.lines.map(x=>`<button class="line-tab ${activeLine===x.name?'active':''}" data-line="${esc(x.name)}">${esc(x.name)}</button>`).join('');lineTabs.querySelectorAll('.line-tab').forEach(b=>b.onclick=()=>{activeLine=b.dataset.line;renderLines()});let ln=currentDetail.lines.find(x=>x.name===activeLine)||currentDetail.lines[0],eps=ln&&ln.eps||[];document.querySelector('#eps').innerHTML=eps.length?eps.map((e,i)=>`<button class="ep" data-i="${i}">${esc(e.name)}</button>`).join(''):'<div class="empty">暂无分集</div>';document.querySelectorAll('.ep').forEach(b=>b.onclick=()=>playEpisode(ln,+b.dataset.i))}
42+
function parseUrl(p,u){u=String(u||'');if(!p||!clean(p.url))return u;let x=clean(p.url);return x.includes('{url}')?x.replaceAll('{url}',encodeURIComponent(u)):x+encodeURIComponent(u)}
43+
function useNativePlay(){return window.fm&&typeof fm.vodInline==='function'}
44+
function isDirect(u){return /\.m3u8|\.mp4|tc\.qq\.com|defaultts|omts|v3-web|byte/i.test(String(u||''))}
45+
async function resolvePlay(u){let x=String(u||'');if(!x||isDirect(x))return x;try{let t=await req(x,{headers:{'User-Agent':UA,'Referer':BASE+'/'}}),j=null;try{j=JSON.parse(t)}catch(e){};if(j&&j.url)x=j.url||x;else{let m=String(t).match(/https?:[^\"'<>]+(?:m3u8|mp4)[^\"'<>]*/i);if(m)x=m[0].replace(/\\\//g,'/')}}catch(e){}return x}
46+
async function resolveEpisode(line,e,i,total){if(e.real&&isDirect(e.real))return e.real;toast('解析 '+(i+1)+'/'+total);let u=await resolvePlay(parseUrl(line.parser,e.url));if(isDirect(u))e.real=u;return e.real||u}
47+
async function playEpisode(line,index){let d=currentDetail.vod,cur=line.eps[index];if(!cur)return;if(!line.parser){let p=parsers.find(x=>x.enabled&&clean(x.url));if(p)line={name:p.name,parser:p,eps:line.eps};else return toast('请先在解析设置里填写可用解析地址')};let total=line.eps.length,eps=[];for(let i=0;i<total;i++){let e=line.eps[i],u=await resolveEpisode(line,e,i,total);eps.push({name:e.name,url:u})}let real=eps[index]&&eps[index].url;if(!isDirect(real))return toast('解析失败,未得到m3u8直链');let from=[line.name],urls=[eps.map(e=>`${e.name}$${e.url}`).join('#')],vod={vod_id:d.vod_id,vod_name:d.vod_name,vod_pic:d.vod_pic,vod_remarks:d.vod_remarks,vod_content:d.vod_content,vod_play_from:from.join('$$$'),vod_play_url:urls.join('$$$'),play_from:line.name,mark:cur.name,episodes:eps,url:real,parse:0,jx:0,header:{'User-Agent':UA,'Referer':BASE+'/'}};toast('开始播放');if(useNativePlay()){await fm.vodInline(vod);return}if(window.fm&&fm.play){await fm.play(real,d.vod_name+' '+cur.name);return}location.href=real}
48+
async function search(){let wd=clean(kw.value);if(!wd)return;setStatus('搜索中');sectionTitle.textContent='搜索:'+wd;content.innerHTML='<div class="empty">搜索中...</div>';try{let payload={version:'25042201',clientType:1,query:wd,pagenum:0,pagesize:30,extraInfo:{isNewMarkLabel:'1',multi_terminal_pc:'1',themeType:'1'}},t=await req('https://pbaccess.video.qq.com/trpc.videosearch.mobile_search.MultiTerminalSearch/MbSearch?vplatform=2',{method:'POST',headers:{'User-Agent':UA,'Content-Type':'application/json','Origin':BASE,'Referer':BASE+'/'},body:JSON.stringify(payload)}),j=JSON.parse(t),arr=[],push=it=>{if(it&&it.doc&&it.doc.id&&it.videoInfo&&it.doc.id.length>11)arr.push({vod_id:it.doc.id,vod_name:(it.videoInfo.title||'').replace(/<\/?em>/g,''),vod_pic:it.videoInfo.imgUrl||'',vod_remarks:it.videoInfo.firstLine||it.videoInfo.secondLine||''})};(((j.data||{}).normalList||{}).itemList||[]).forEach(push);((j.data||{}).areaBoxList||[]).forEach(a=>(a.itemList||[]).forEach(push));lastList=arr;renderCards(arr);pager.style.display='none';setStatus(arr.length+' 条')}catch(e){content.innerHTML='<div class="empty">搜索失败</div>';setStatus('失败')}}
49+
function renderParserCfg(){parserList.innerHTML=parsers.map((p,i)=>`<div class="parser-item"><input type="checkbox" data-i="${i}" ${p.enabled?'checked':''}><input data-n="${i}" value="${esc(p.name)}"><input data-u="${i}" value="${esc(p.url)}" placeholder="https://.../?url={url}"><button class="cfg-btn" data-d="${i}">删</button></div>`).join('');parserList.querySelectorAll('[data-i]').forEach(x=>x.onchange=()=>parsers[x.dataset.i].enabled=x.checked);parserList.querySelectorAll('[data-n]').forEach(x=>x.oninput=()=>parsers[x.dataset.n].name=x.value);parserList.querySelectorAll('[data-u]').forEach(x=>x.oninput=()=>parsers[x.dataset.u].url=x.value);parserList.querySelectorAll('[data-d]').forEach(x=>x.onclick=()=>{parsers.splice(+x.dataset.d,1);renderParserCfg()})}
50+
configBtn.onclick=()=>{renderParserCfg();configMask.classList.add('show')};closeCfg.onclick=()=>configMask.classList.remove('show');addParser.onclick=()=>{let n=clean(pName.value),u=clean(pUrl.value);if(!n||!u)return toast('请填写名称和地址');parsers.push({name:n,url:u,enabled:true});pName.value=pUrl.value='';renderParserCfg()};saveParser.onclick=()=>{saveParsers();toast('已保存')};resetParser.onclick=()=>{parsers=[];localStorage.removeItem('tx_parsers');renderParserCfg();toast('已清空')};detailSheet.onclick=e=>{if(e.target===detailSheet)detailSheet.classList.remove('show')};configMask.onclick=e=>{if(e.target===configMask)configMask.classList.remove('show')};searchForm.onsubmit=e=>{e.preventDefault();search()};searchBtn.onclick=search;prevPage.onclick=()=>{if(page>1){page--;loadCategory();scrollTo(0,0)}};nextPage.onclick=()=>{page++;loadCategory();scrollTo(0,0)};homeBtn.onclick=()=>{kw.value='';page=1;loadCategory()};renderTabs();loadCategory();
51+
</script>
52+
</body>
53+
</html>

0 commit comments

Comments
 (0)