7 lines
18 KiB
HTML
7 lines
18 KiB
HTML
<!doctypehtml><html lang=zh-CN><meta charset=UTF-8><meta content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"name=viewport><title>SupJav</title><style>*{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent}body,html{min-height:100%;background:0 0}html:not(.fm-native),html:not(.fm-native) body{background:#1a1a2e}body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;color:#e0e0e0}.header{height:52px;background:#16162a;display:flex;align-items:center;padding:0 12px;gap:10px;position:sticky;top:0;z-index:100}.logo{font-size:18px;font-weight:700;white-space:nowrap;color:#fff}.search-group{flex:1;display:flex;align-items:center;background:#2a2a4a;border-radius:25px;padding-right:4px}.search-group .search-box{flex:1;border:none;background:0 0;outline:0;padding:0 10px;height:34px;color:#e0e0e0;font-size:12px}.search-group .search-btn{width:32px;height:28px;background:#e0592f;border:none;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer}.search-group .search-btn svg{width:14px;height:14px;color:#fff}.category-bar{display:flex;gap:8px;padding:8px 12px;overflow-x:auto;background:#16162a}.category-bar::-webkit-scrollbar{display:none}.category-item{padding:6px 16px;border-radius:20px;background:rgba(42,42,74,.6);font-size:13px;white-space:nowrap;color:#e0e0e0;cursor:pointer;transition:all .2s}.category-item.active{background:#e0592f;color:#fff}.list-section{background:rgba(26,26,46,.5);padding:12px}.list-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}.item{display:flex;flex-direction:column;cursor:pointer;min-width:0}.item-img-wrap{position:relative}.item-img{width:100%;aspect-ratio:3/4;background:#16162a;border-radius:8px 8px 0 0;object-fit:cover;display:block}.img-year{position:absolute;top:6px;left:6px;background:#e0592f;color:#fff;font-size:10px;padding:2px 6px;border-radius:4px}.img-remark{position:absolute;bottom:6px;right:6px;background:rgba(0,0,0,.7);color:#fff;font-size:10px;padding:2px 6px;border-radius:4px}.item-title{padding:6px 8px;font-size:12px;text-align:center;background:#16162a;border-radius:0 0 8px 8px;line-height:1.3;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.loading{text-align:center;padding:20px;color:rgba(224,224,224,.5);font-size:12px}.error-tip{text-align:center;padding:40px;color:#e0592f;font-size:14px}.load-more,.no-more{text-align:center;padding:20px;color:rgba(224,224,224,.5);font-size:12px;width:100%}.search-overlay{position:fixed;inset:0;background:#1a1a2e;z-index:150;display:none;overflow-y:auto}.search-overlay.active{display:block}.search-nav{height:52px;background:#16162a;display:flex;align-items:center;justify-content:space-between;padding:0 16px;position:sticky;top:0;z-index:10}.search-title{font-size:16px;font-weight:700;color:#fff}.detail-overlay{position:fixed;inset:0;background:rgba(0,0,0,.95);z-index:200;display:none;overflow-y:auto}.detail-overlay.active{display:block}.detail-container{max-width:600px;margin:0 auto;padding:20px}.detail-close{text-align:right;margin-bottom:12px}.detail-close-btn{background:rgba(255,255,255,.15);border:none;color:#fff;width:32px;height:32px;border-radius:50%;cursor:pointer;font-size:20px}.detail-poster{width:100%;max-height:300px;object-fit:contain;border-radius:8px;background:#16162a;margin-bottom:16px}.detail-title{font-size:18px;font-weight:700;color:#fff;margin-bottom:12px}.detail-desc{font-size:13px;color:rgba(224,224,224,.8);line-height:1.6;margin-bottom:16px}.play-btn{display:block;width:100%;padding:12px;background:#2563eb;border:none;border-radius:8px;color:#fff;font-size:14px;font-weight:700;cursor:pointer;text-align:center;transition:background .2s;margin-bottom:10px}.play-btn:hover{background:#1d4ed8}.play-btn:disabled{background:#555;cursor:not-allowed}.play-btn.loading{background:#f59e0b}.play-btn.success{background:#10b981}.play-btn.error{background:#ef4444}.parse-status{text-align:center;font-size:12px;margin:6px 0;min-height:18px;color:rgba(224,224,224,.7)}.parse-status.loading{color:#2563eb}.parse-status.error{color:#ef4444}.parse-status.success{color:#10b981}.parse-log{background:#0a0a1a;border-radius:8px;padding:10px;margin-top:10px;max-height:150px;overflow-y:auto;font-family:monospace;font-size:11px;color:#888}.parse-log .log-line{margin:2px 0}.parse-log .log-success{color:#10b981}.parse-log .log-error{color:#ef4444}.parse-log .log-info{color:#2563eb}@media (min-width:600px){.list-grid{grid-template-columns:repeat(4,1fr)}}@media (min-width:900px){.list-grid{grid-template-columns:repeat(5,1fr)}}</style><div id=mainView><div class=header><div class=logo id=siteLogo>SupJav</div><div class=search-group><input class=search-box id=searchInput placeholder=搜索影片...> <button class=search-btn id=searchBtn><svg fill=none stroke=currentColor viewBox="0 0 24 24"xmlns=http://www.w3.org/2000/svg><path d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"stroke-linecap=round stroke-linejoin=round stroke-width=2></path></svg></button></div></div><div class=category-bar id=categoryBar></div><div class=list-section><div class=list-grid id=listGrid></div><div id=listTip></div></div></div><div class=search-overlay id=searchOverlay><div class=search-nav><div class=search-title id=searchKeywordTitle>搜索结果</div><button class=detail-close-btn id=searchCloseBtn>×</button></div><div class=list-section><div class=list-grid id=searchListGrid></div><div id=searchListTip></div></div></div><div class=detail-overlay id=detailOverlay><div class=detail-container><div class=detail-close><button class=detail-close-btn id=detailClose>×</button></div><img alt=""class=detail-poster id=detailPoster src=""><div class=detail-title id=detailTitle>加载中...</div><div class=detail-desc id=detailDesc></div><button class=play-btn id=playBtn>正在解析...</button><div class=parse-status id=parseStatus></div><div class=parse-log id=parseLog style=display:none></div></div></div><script>!function(){"use strict";const l={siteName:"SupJav",siteUrl:"https://supjav.com",apiHost:"https://supjav.com/zh",gatewayHost:"https://lk1.supremejav.com",categories:[{id:"censored-jav",name:"有码"},{id:"uncensored-jav",name:"无码"},{id:"amateur",name:"素人"},{id:"chinese-subtitles",name:"中文字幕"},{id:"reducing-mosaic",name:"无码破解"},{id:"english-subtitles",name:"英文字幕"}],cache:{ttl:3e5,prefix:"supjav_"}},h={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36",Accept:"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","Accept-Language":"zh-CN,zh;q=0.9,en;q=0.8","Accept-Encoding":"gzip, deflate",Connection:"keep-alive","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"none","Upgrade-Insecure-Requests":"1"},c={currentCategory:"",currentPage:1,isLoading:!1,hasMore:!0,vodList:[],searchMode:!1,searchKeyword:"",searchPage:1,searchHasMore:!0,searchVodList:[],currentVod:null,detailData:null,m3u8Url:""},d=e=>document.querySelector(e);function u(e,t="info"){console.log(`[SupJav] ${e}`);const a=d("#parseLog");if(a){a.style.display="block";const r=document.createElement("div");r.className=`log-line log-${t}`,r.textContent=`> ${e}`,a.appendChild(r),a.scrollTop=a.scrollHeight}}function m(e,t=""){const a=d("#parseStatus");a&&(a.textContent=e,a.className=`parse-status ${t}`)}const a={getKey(e,t){return l.cache.prefix+"cat_"+(e||"home")+"_p"+t},isValid(e){return!!e&&Date.now()-e.timestamp<l.cache.ttl},async get(e){return window.fm?.cache?window.fm.cache.get(e):localStorage.getItem(e)||""},async set(e,t){window.fm?.cache?await window.fm.cache.set(e,t):localStorage.setItem(e,t)},async getCache(e,t){try{var a=this.getKey(e,t),r=a+"_meta",[s,i]=await Promise.all([this.get(a),this.get(r)]);if(!s||!i)return null;var n=JSON.parse(i);return this.isValid(n)?JSON.parse(s):null}catch(e){return null}},async setCache(e,t,a){try{var r=this.getKey(e,t),s=r+"_meta",i={timestamp:Date.now()};await Promise.all([this.set(r,JSON.stringify(a)),this.set(s,JSON.stringify(i))])}catch(e){}}};async function v(e,t=l.apiHost+"/",a="text",r=30){if(!window.fm?.req)throw new Error("fm.req 不可用");var s={...h,Referer:t};console.log(`[SupJav] GET: ${e}`),console.log(`[SupJav] Referer: ${t}`);s=await window.fm.req(e,{method:"GET",responseType:a,timeout:r,credentials:"include",headers:s});if(!s.ok)throw new Error(`HTTP ${s.status}: ${s.error||"请求失败"}`);return s.body}function g(e){return e?window.fm?.res?window.fm.res(e,{credentials:"include"}):e.startsWith("//")?"https:"+e:e.startsWith("/")?l.siteUrl+e:e:""}function s(e){const c=[],t=new DOMParser,a=t.parseFromString(e,"text/html"),r=a.querySelectorAll(".post");return r.forEach(e=>{const t=e.querySelector("a.img");if(t){var a=t.getAttribute("href");if(a){const i=e.querySelector("img.thumb");if(i){var r=i.getAttribute("data-original")||i.getAttribute("src")||"";const n=e.querySelector("h3 a");var s=n?.textContent.trim()||"";const o=e.querySelector(".meta");e=o?.textContent?.match(/\d{4}\/\d{2}\/\d{2}/)?.[0]||"";c.push({vod_id:a,vod_name:s,vod_pic:r,vod_remarks:e})}}}}),c}function p(){return l.apiHost+"/"}async function i(e,t){let a,r;return r=e?(a=`${l.apiHost}/category/${e}/page/${t}`,1<t?`${l.apiHost}/category/${e}/page/${t-1}`:`${l.apiHost}/category/${e}/`):(a=1<t?`${l.apiHost}/page/${t}`:l.apiHost+"/",1<t?`${l.apiHost}/page/${t-1}`:l.apiHost+"/"),s(await v(a,r))}async function n(e,t){let a,r;return r=1<t?(a=`${l.apiHost}/page/${t}/?s=${encodeURIComponent(e)}`,`${l.apiHost}/page/${t-1}/?s=${encodeURIComponent(e)}`):(a=`${l.apiHost}/?s=${encodeURIComponent(e)}`,l.apiHost+"/"),s(await v(a,r))}async function y(e){var t=e.startsWith("http")?e:l.apiHost+e;u(`正在获取详情页: ${t}`,"info");var a=await v(t,p());const r=/class=["']btn-server[^"']*["'][\s\S]*?data-link=["']([a-f0-9]+)["']>([^<]+)</gi;let s,i=null;for(;null!==(s=r.exec(a));)if("FST"===s[2].trim().toUpperCase()){i=s[1],u(`找到 FST 线路: ${i}`,"success");break}if(!i)throw new Error("未找到 FST 播放线路");e=i.split("").reverse().join(""),e=`${l.gatewayHost}/supjav.php?c=${e}`;if(u(`FST 网关地址: ${e}`,"info"),u("正在请求 FST 网关...","info"),!window.fm?.req)throw new Error("fm.req 不可用");t={...h,Referer:t,"Sec-Fetch-Site":"none"},t=await window.fm.req(e,{method:"GET",responseType:"text",timeout:30,credentials:"include",headers:t});if(!t.ok)throw new Error(`网关请求失败: ${t.status}`);const n=t.body;u("网关响应获取成功,开始解密...","info");t=n.match(/eval\(function\(p,a,c,k,e,d\)[\s\S]*?\.split\('\|'\)\)\)/);if(!t)throw new Error("FST 网关响应体中未包含所需的 eval 混淆打包数据");u("锁定加密块,正在执行反混淆脱壳...","info");const o=function(e){try{const t=new Function(e.replace(/^eval/,"return"));return t()}catch(e){return"Packer 还原出错: "+e.message}}(t[0]);u("反混淆纯化完毕,扫描流配置项...","info");let c="";const d=o.match(/"(https?:\/\/[^"]+?\.m3u8[^"]*?)"/i)||o.match(/file\s*:\s*["']([^"']+?\.m3u8[^"']*?)["']/i);return d&&(c=d[1].replace(/\\/g,""),u(`解析成功: ${c}`,"success")),c}async function f(e){var t=await v(e.startsWith("http")?e:l.apiHost+e,p());const a=new DOMParser,r=a.parseFromString(t,"text/html"),s=r.querySelector("h3 a")||r.querySelector("h1")||r.querySelector("title");var i=s?.textContent?.trim()||"影片详情";const n=r.querySelector(".img img")||r.querySelector("img");let o="";n&&(o=n.getAttribute("data-original")||n.getAttribute("src")||"");const c=r.querySelector(".info-content, .description, .entry-content");t=c?.textContent?.trim()||"";return{vod_id:e,vod_name:i,vod_pic:o,vod_content:t}}function o(e=!1,t=[]){const n=c.searchMode?d("#searchListGrid"):d("#listGrid"),a=c.searchMode?d("#searchListTip"):d("#listTip");if(n&&a){if(!e){n.innerHTML="";var r=c.searchMode?c.searchVodList:c.vodList;if(c.isLoading)return void(a.innerHTML='<div class="loading">加载中...</div>');if(0===r.length)return void(a.innerHTML='<div class="error-tip">暂无内容</div>')}const s=e?t:c.searchMode?c.searchVodList:c.vodList,o=e?c.searchMode?c.searchVodList.length-t.length:c.vodList.length-t.length:0;s.forEach((e,t)=>{var a=g(e.vod_pic),r=e.vod_remarks||"";const s=o+t,i=document.createElement("div");i.className="item",i.innerHTML=`
|
||
<div class="item-img-wrap">
|
||
<img class="item-img" src="${a}" loading="lazy" decoding="async" alt="${e.vod_name}" />
|
||
${r?`<span class="img-year">${r}</span>`:""}
|
||
</div>
|
||
<div class="item-title">${e.vod_name}</div>
|
||
`,i.addEventListener("click",()=>{!async function t(a){c.currentVod=a;c.detailData=null;c.m3u8Url="";d("#detailOverlay").classList.add("active");d("#detailPoster").src=g(a.vod_pic);d("#detailTitle").textContent=a.vod_name;d("#detailDesc").textContent="正在加载详情...";d("#playBtn").textContent="正在解析 FST 线路...";d("#playBtn").disabled=!0;d("#playBtn").className="play-btn loading";d("#parseStatus").textContent="";d("#parseLog").innerHTML="";d("#parseLog").style.display="none";try{const e=await f(a.vod_id);c.detailData=e,d("#detailTitle").textContent=e.vod_name,d("#detailDesc").textContent=e.vod_content||"无描述",m("正在解析 FST 线路...","loading"),u("开始 FST 线路解析流程","info");const r=await y(a.vod_id);if(!r)throw new Error("未能从 FST 线路解析出播放地址");c.m3u8Url=r,d("#playBtn").textContent="▶ 播放 FST 直链",d("#playBtn").className="play-btn success",d("#playBtn").disabled=!1,d("#playBtn").onclick=()=>w(),m("解析成功!","success"),u("FST 直链解析完成!","success")}catch(e){d("#playBtn").textContent="解析失败,点击重试",d("#playBtn").className="play-btn error",d("#playBtn").disabled=!1,d("#playBtn").onclick=()=>t(a),m("解析失败: "+e.message,"error"),u("解析失败: "+e.message,"error")}}((c.searchMode?c.searchVodList:c.vodList)[s])}),n.appendChild(i)});t=c.searchMode?c.searchHasMore:c.hasMore;a.innerHTML=t?'<div class="load-more">上滑加载更多</div>':'<div class="no-more">没有更多了</div>'}}function r(){d("#detailOverlay").classList.remove("active"),c.currentVod=null}async function w(){if(c.m3u8Url)if(window.fm?.play)try{await window.fm.play(c.m3u8Url,c.detailData?.vod_name||"视频",{})}catch(e){u("播放失败: "+e.message,"error"),alert("播放失败: "+e.message)}else alert("当前环境不支持内置播放")}async function L(e){if(e?.trim()){c.searchMode=!0,c.searchKeyword=e.trim(),c.searchPage=1,c.searchVodList=[],c.searchHasMore=!0,c.isLoading=!0,d("#searchKeywordTitle").textContent=`搜索: "${c.searchKeyword}"`,d("#searchOverlay").classList.add("active"),o(!1);try{var t=await n(c.searchKeyword,1);c.searchVodList=t,c.searchHasMore=0<t.length}catch(e){c.searchVodList=[]}o(c.isLoading=!1)}}function e(){d("#searchOverlay").classList.remove("active"),c.searchMode=!1,c.searchKeyword="",c.searchVodList=[]}async function M(e=!1){if(!e&&1===c.currentPage){e=await a.getCache(c.currentCategory,c.currentPage);if(e)return c.vodList=e,void o(!1)}o(!(c.isLoading=!0));try{var t=await i(c.currentCategory,c.currentPage);c.vodList=t,c.hasMore=0<t.length,1===c.currentPage&&await a.setCache(c.currentCategory,c.currentPage,c.vodList)}catch(e){c.vodList=[]}o(c.isLoading=!1)}function t(){let r=null;var e=()=>{r=r||setTimeout(()=>{r=null;var e=c.searchMode?d("#searchOverlay"):window,t=c.searchMode?e.scrollTop:window.scrollY||document.documentElement.scrollTop,a=c.searchMode?e.clientHeight:window.innerHeight,e=(c.searchMode?e:document.documentElement).scrollHeight;(e-t-a<450||.85*e<t+a)&&async function(){if(!c.isLoading){if(c.searchMode){if(!c.searchHasMore)return;c.isLoading=!0;const r=d("#searchListTip");r&&(r.innerHTML='<div class="loading">正在加载更多搜索结果...</div>');var e=c.searchPage+1;try{var t=await n(c.searchKeyword,e);t&&0<t.length?(c.searchPage=e,c.searchVodList=[...c.searchVodList,...t],o(c.searchHasMore=!0,t)):(c.searchHasMore=!1,r&&(r.innerHTML='<div class="no-more">没有更多了</div>'))}catch(e){r&&(r.innerHTML='<div class="load-more">网络异常,滑动重试</div>')}}else{if(!c.hasMore)return;c.isLoading=!0;const s=d("#listTip");s&&(s.innerHTML='<div class="loading">正在加载更多...</div>');t=c.currentPage+1;try{var a=await i(c.currentCategory,t);a&&0<a.length?(c.currentPage=t,c.vodList=[...c.vodList,...a],o(c.hasMore=!0,a)):(c.hasMore=!1,s&&(s.innerHTML='<div class="no-more">没有更多了</div>'))}catch(e){s&&(s.innerHTML='<div class="load-more">网络异常,滑动重试</div>')}}c.isLoading=!1}}()},100)};window.addEventListener("scroll",e,{passive:!0}),d("#searchOverlay").addEventListener("scroll",e,{passive:!0})}!async function(){await async function(){if((window.fongmiBridge||window.fm||window.fongmi)&&document.documentElement.classList.add("fm-native"),window.fm||await new Promise(e=>{const t=()=>{window.fm?e():setTimeout(t,100)};window.addEventListener("fmsdk",t,{once:!0}),setTimeout(e,3e3)}),window.fm?.site)try{var e=await window.fm.site();c.siteKey=e.key||"supjav";const t=d("#siteLogo");t&&(t.textContent=e.name||l.siteName)}catch(e){}}(),function(){const a=d("#categoryBar");if(a){let t='<div class="category-item active" data-id="">首页</div>';l.categories.forEach(e=>{t+=`<div class="category-item" data-id="${e.id}">${e.name}</div>`}),a.innerHTML=t,a.querySelectorAll(".category-item").forEach(t=>{t.addEventListener("click",()=>{var e=t.dataset.id||"";e===c.currentCategory&&0<c.vodList.length&&!c.searchMode||(a.querySelectorAll(".category-item").forEach(e=>e.classList.remove("active")),t.classList.add("active"),c.searchMode=!1,d("#searchOverlay").classList.remove("active"),c.currentCategory=e,c.currentPage=1,c.vodList=[],M(!(c.hasMore=!0)))})})}}(),function(){d("#searchBtn")?.addEventListener("click",()=>{L(d("#searchInput")?.value)}),d("#searchInput")?.addEventListener("keypress",e=>{"Enter"===e.key&&L(e.target.value)}),d("#detailClose")?.addEventListener("click",r),d("#detailOverlay")?.addEventListener("click",e=>{e.target===e.currentTarget&&r()}),d("#searchCloseBtn")?.addEventListener("click",e);let t=0;document.addEventListener("touchstart",e=>{t=e.touches[0].clientY},{passive:!0}),document.addEventListener("touchend",e=>{80<t-e.changedTouches[0].clientY&&window.scrollY<50&&!c.isLoading&&!c.searchMode&&(c.currentPage=1,c.vodList=[],M(c.hasMore=!0))},{passive:!0})}(),t(),await M(!1)}().catch(console.error)}()</script> |