Files
tvbox_collect/jaychouqq/yingshi/html/ppnix.html
T
2026-06-29 03:41:14 +00:00

637 lines
25 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
<title>PPnix WebHome</title>
<style>
* { margin:0; padding:0; box-sizing:border-box; }
:root {
--panel-rgb: 45, 55, 68;
--panel: rgba(var(--panel-rgb), .62);
--panel-soft: rgba(var(--panel-rgb), .44);
--panel-strong: rgba(var(--panel-rgb), .82);
--accent: #e74c3c;
--text: #e8e8e8;
--text-dim: #999;
--line: rgba(255,255,255,.12);
}
html, body {
margin:0; min-height:100%;
background: transparent;
color: var(--text);
font-family: -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;
font-size:14px;
line-height:1.5;
}
html:not(.fm-native), html:not(.fm-native) body { background: #1a1e26; }
a { color:var(--text); text-decoration:none; }
.header {
position:sticky; top:0; z-index:100;
padding:10px 12px;
background:var(--panel-strong);
backdrop-filter:blur(8px);
display:flex; align-items:center; gap:10px;
border-bottom:1px solid var(--line);
}
.header h1 { font-size:18px; font-weight:700; flex-shrink:0; }
.nav-tabs { display:flex; gap:6px; flex-shrink:0; }
.nav-tab {
padding:4px 12px; border-radius:14px; font-size:13px;
cursor:pointer; background:transparent; color:var(--text-dim);
transition: all .2s;
}
.nav-tab.on { background:var(--accent); color:#fff; }
.header .search-box {
flex:1; display:flex; gap:6px; margin-left:auto;
}
.header .search-box input {
flex:1; padding:6px 12px; border-radius:16px; border:1px solid var(--line);
background:var(--panel); color:var(--text); font-size:13px;
outline:none; min-width:60px;
}
.header .search-box input::placeholder { color:var(--text-dim); }
.header .search-box button {
padding:6px 14px; border:none; border-radius:16px;
background:var(--accent); color:#fff; font-size:13px;
cursor:pointer; white-space:nowrap;
}
.scroll-area { padding:0 12px; }
.section { margin:12px 0; }
.section-title {
font-size:15px; font-weight:600; margin-bottom:8px;
display:flex; align-items:center; gap:8px;
}
.section-title .tab-bar { display:flex; gap:4px; }
.section-title .tab-item {
padding:2px 10px; border-radius:10px; font-size:12px;
cursor:pointer; color:var(--text-dim); font-weight:400;
}
.section-title .tab-item.on { background:var(--accent); color:#fff; }
.section-title .more { margin-left:auto; font-size:12px; color:var(--accent); cursor:pointer; }
.card-grid {
display:grid;
grid-template-columns:repeat(auto-fill, minmax(130px, 1fr));
gap:10px;
}
.card {
background:var(--panel-soft); border-radius:8px; overflow:hidden;
cursor:pointer; transition:transform .15s;
border:1px solid transparent;
}
.card:active, .card.focused { transform:scale(0.97); border-color:var(--accent); }
.card-img {
width:100%; aspect-ratio:2/3; object-fit:cover;
display:block; background:var(--panel);
}
.card-badge {
position:absolute; top:4px; right:4px;
background:rgba(0,0,0,.7); color:#ff6; font-size:11px;
padding:1px 6px; border-radius:6px; z-index:2;
}
.card-body { padding:6px 8px 8px; }
.card-title { font-size:13px; font-weight:500; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.card-meta { font-size:11px; color:var(--text-dim); margin-top:2px; display:flex; align-items:center; gap:4px; }
.star-bar { color:#f5a623; font-size:11px; }
.episode-badge {
position:absolute; bottom:0; left:0; right:0;
background:linear-gradient(transparent, rgba(0,0,0,.8));
padding:20px 6px 4px; text-align:right;
font-size:11px; color:#fff;
}
.detail-view {
position:fixed; inset:0; z-index:200;
background:transparent; overflow-y:auto;
display:none;
}
.detail-view.active { display:block; }
body.detail-active .app { visibility:hidden; pointer-events:none; }
.detail-bg { position:fixed; inset:0; }
.detail-content { position:relative; z-index:2; padding:12px; }
.detail-back {
position:sticky; top:0; z-index:10;
padding:8px 0; margin-bottom:8px;
display:flex; align-items:center; gap:8px;
cursor:pointer; font-size:14px; font-weight:600;
}
.detail-poster {
width:120px; border-radius:8px; float:left; margin:0 12px 12px 0;
aspect-ratio:2/3; object-fit:cover;
}
.detail-info { overflow:hidden; }
.detail-title { font-size:18px; font-weight:700; margin-bottom:4px; }
.detail-year { font-size:13px; color:var(--text-dim); margin-bottom:6px; }
.detail-desc { font-size:12px; color:var(--text-dim); line-height:1.6; margin-bottom:10px; }
.detail-field { font-size:12px; margin-bottom:3px; }
.detail-field-label { color:var(--accent); }
.detail-field-value { color:var(--text-dim); }
.play-btn {
display:inline-block; margin:6px 0;
padding:8px 24px; border:none; border-radius:20px;
background:var(--accent); color:#fff; font-size:14px;
cursor:pointer; font-weight:600;
}
.episode-grid {
display:flex; flex-wrap:wrap; gap:6px; margin-top:10px;
}
.episode-btn {
padding:6px 14px; border-radius:14px; border:1px solid var(--line);
background:var(--panel); color:var(--text); font-size:12px;
cursor:pointer; transition:all .15s;
}
.episode-btn.on { background:var(--accent); border-color:var(--accent); color:#fff; }
.rank-list { list-style:none; }
.rank-item {
display:flex; align-items:center; gap:8px;
padding:8px 0; border-bottom:1px solid var(--line); cursor:pointer;
}
.rank-item:last-child { border-bottom:none; }
.rank-num {
width:20px; text-align:center; font-weight:700; font-size:13px;
color:var(--text-dim); flex-shrink:0;
}
.rank-num.top1 { color:#f5a623; }
.rank-num.top2 { color:#c0c0c0; }
.rank-num.top3 { color:#cd7f32; }
.rank-name { flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:13px; }
.rank-date { font-size:11px; color:var(--text-dim); flex-shrink:0; }
.loading { text-align:center; padding:40px; color:var(--text-dim); font-size:14px; }
.refresh-btn {
width:32px; height:32px; border-radius:50%; border:1px solid var(--line);
background:var(--panel); color:var(--text); font-size:16px;
cursor:pointer; display:flex; align-items:center; justify-content:center; flex-shrink:0;
margin-left:auto;
}
.error-msg { color:#ff6; padding:20px; text-align:center; }
@media (min-width:600px) { .card-grid { grid-template-columns:repeat(auto-fill, minmax(150px, 1fr)); } }
@media (min-width:900px) { .card-grid { grid-template-columns:repeat(auto-fill, minmax(170px, 1fr)); } }
::-webkit-scrollbar { width:4px; }
::-webkit-scrollbar-thumb { background:var(--panel); border-radius:2px; }
</style>
</head>
<body>
<div class="app" id="app">
<div class="header">
<h1>PPnix</h1>
<div class="nav-tabs">
<div class="nav-tab on" data-tab="home">首页</div>
<div class="nav-tab" data-tab="movie">电影</div>
<div class="nav-tab" data-tab="tv">电视剧</div>
</div>
<div class="search-box">
<input id="searchInput" placeholder="搜索电影、电视剧" maxlength="30">
<button id="searchBtn">搜索</button>
</div>
</div>
<div class="scroll-area" id="mainContent">
<div class="loading">加载中...</div>
</div>
</div>
<div class="detail-view" id="detailView">
<div class="detail-bg" id="detailBg"></div>
<div class="detail-content" id="detailContent"></div>
</div>
<script>
var BASE = 'https://www.ppnix.com';
var LANG = '/cn';
function _fm() {
return new Promise(function (r) {
if (window.fm) return r(window.fm);
var t = 0;
(function c() { if (window.fm) return r(window.fm); if (++t > 30) return r(null); setTimeout(c, 100); })();
});
}
if (window.fongmiBridge || window.fm || window.fongmi)
document.documentElement.classList.add('fm-native');
function _req(url) {
return _fm().then(function (f) {
if (f && f.req) return f.req(url, { timeout: 20 });
return fetch(url, { headers: { 'User-Agent': 'Mozilla/5.0' } }).then(function (r) { return r.text(); }).then(function (t) { return { body: t }; });
}).then(function (res) {
return (res && res.body != null) ? (typeof res.body === 'string' ? res.body : JSON.stringify(res.body)) : '';
});
}
function _img(url) {
if (!url) return '';
try { if (window.fm && fm.res) return fm.res(url, { credentials: 'include' }); } catch (e) {}
return url;
}
function _play(url, title) {
var fullUrl = url.indexOf('://') > 0 ? url : BASE + url;
_fm().then(function (f) {
if (f && f.play) return f.play(fullUrl, title || '', {});
window.open(fullUrl);
});
}
function _esc(s) { return (s || '').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;'); }
function parseCards(html, isTV) {
var cards = [];
var re = /<li>([\s\S]*?)<\/li>/g;
var m;
while ((m = re.exec(html)) !== null) {
var block = m[1];
var hm = block.match(/href="([^"]+)"/);
if (!hm) continue;
var href = hm[1];
var idm = href.match(/\/(\d+)\.html/);
if (!idm) continue;
var id = idm[1];
var im = block.match(/src="([^"]+)"/);
var img = im ? im[1] : '';
var altm = block.match(/alt="([^"]+)"/);
var title = altm ? altm[1] : '';
if (!title) {
var tm = block.match(/<h2>[\s\S]*?<a[^>]*>([^<]+)<\/a>/);
title = tm ? tm[1].trim() : '';
}
var rm = block.match(/class="rate">([^<]+)/);
var rate = rm ? rm[1] : '';
var epm = block.match(/<div class="note"><span>([^<]+)<\/span><\/div>/);
var ep = epm ? epm[1] : '';
var ym = block.match(/<span class="orange">([^<]+)<\/span>/);
var year = ym ? ym[1] : '';
var isTv = href.indexOf('/tv/') > 0;
cards.push({ id: id, title: title, img: img, rate: rate, ep: ep, year: year, type: isTv ? 'tv' : 'movie', href: href });
}
return cards;
}
function loadHome() {
var el = document.getElementById('mainContent');
el.innerHTML = '<div class="loading">加载中...</div>';
_req(BASE + LANG + '/').then(function (html) {
if (!html) { el.innerHTML = '<div class="error-msg">加载失败</div>'; return; }
renderHome(html, el);
});
}
function renderHome(html, el) {
var h = '';
var sections = [{ id:'slider', title:'正在上映' }, { id:'slider2', title:'热门电影' }, { id:'slider3', title:'热门电视剧' }];
for (var si = 0; si < sections.length; si++) {
var sid = sections[si].id;
var stitle = sections[si].title;
var sstart = html.indexOf('id="' + sid + '"');
if (sstart < 0) continue;
var sectEnd = html.indexOf('id="slider', sstart + 1);
if (sectEnd < 0) sectEnd = html.indexOf('<footer class="footer"', sstart);
if (sectEnd < 0) sectEnd = sstart + 50000;
var sectHtml = html.substring(sstart, sectEnd);
var tabs = [];
var tabHtml = sectHtml.match(/<dl>([\s\S]*?)<\/dl>/);
if (tabHtml) {
var tdm = tabHtml[1].matchAll(/<dt[^>]*>([\s\S]*?)<\/dt>/g);
for (var t of tdm) {
var tn = t[1].replace(/<[^>]+>/g, '').trim();
if (tn) tabs.push(tn);
}
}
var lists = [];
var lre = /<div class="lists-content">([\s\S]*?)<\/div>\s*<\/div>/g;
var lm;
while ((lm = lre.exec(sectHtml)) !== null) {
var ulm = lm[1].match(/<ul>([\s\S]*?)<\/ul>/);
if (ulm) lists.push(ulm[1]);
}
if (lists.length === 0) continue;
h += '<div class="section">';
h += '<div class="section-title">';
h += '<span>' + _esc(stitle) + '</span>';
if (tabs.length > 0) {
h += '<div class="tab-bar" data-si="' + si + '">';
for (var ti = 0; ti < tabs.length; ti++) {
h += '<span class="tab-item' + (ti === 0 ? ' on' : '') + '" data-ti="' + ti + '">' + _esc(tabs[ti]) + '</span>';
}
h += '</div>';
}
if (sid === 'slider2') h += '<span class="more" data-go="movie">更多 ></span>';
else if (sid === 'slider3') h += '<span class="more" data-go="tv">更多 ></span>';
h += '</div>';
for (var li = 0; li < lists.length; li++) {
var cards = parseCards(lists[li], si === 2 || (si === 0 && li > 0));
var display = li === 0 ? '' : ' style="display:none"';
h += '<div class="card-grid" data-si="' + si + '" data-ti="' + li + '"' + display + '>';
for (var ci = 0; ci < cards.length; ci++) {
h += renderCard(cards[ci]);
}
h += '</div>';
}
h += '</div>';
}
// Rankings
var rankNames = ['本月排行榜', '电影排行榜', '电视剧排行榜'];
h += '<div class="section"><div class="section-title"><span>排行榜</span></div>';
for (var ri = 0; ri < rankNames.length; ri++) {
var idx = html.indexOf(rankNames[ri]);
if (idx < 0) continue;
var chunk = html.substring(idx, idx + 4000);
var ulm = chunk.match(/<ul>([\s\S]*?)<\/ul>/);
if (!ulm) continue;
h += '<div class="section-title" style="font-size:13px;margin-top:8px"><span>' + rankNames[ri] + '</span></div>';
h += '<ul class="rank-list">';
var items = ulm[1].match(/<li>([\s\S]*?)<\/li>/g);
if (items) {
for (var ii = 0; ii < Math.min(items.length, 10); ii++) {
var ib = items[ii];
var a = ib.match(/href="([^"]+)"/);
var t = ib.match(/title="([^"]+)"/);
var date = ib.match(/<time>([^<]+)<\/time>/);
var num = ib.match(/<span>(\d+)<\/span>/);
var tt = '';
if (t) tt = t[1];
else {
var t2 = ib.match(/<h2>[\s\S]*?<a[^>]*>([^<]+)<\/a>/);
if (t2) tt = t2[1];
}
h += '<li class="rank-item" data-href="' + (a ? _esc(a[1]) : '') + '">';
var cls = '';
if (num) { var n = parseInt(num[1]); if (n <= 3) cls = ' top' + n; }
h += '<span class="rank-num' + cls + '">' + (num ? num[1] : '') + '</span>';
h += '<span class="rank-name">' + _esc(tt) + '</span>';
h += '<span class="rank-date">' + (date ? date[1] : '') + '</span>';
h += '</li>';
}
}
h += '</ul>';
}
h += '</div>';
el.innerHTML = h;
bindEvents(el);
}
function renderCard(c) {
var imgUrl = _img(c.img);
var h = '<div class="card" data-id="' + c.id + '" data-type="' + c.type + '" data-href="' + _esc(c.href) + '">';
h += '<div style="position:relative">';
h += '<img class="card-img" src="' + _esc(imgUrl) + '" alt="' + _esc(c.title) + '" loading="lazy" onerror="this.style.display=\'none\'">';
if (c.ep) h += '<div class="episode-badge">' + _esc(c.ep) + '</div>';
else if (c.year) h += '<div class="card-badge">' + _esc(c.year) + '</div>';
h += '</div>';
h += '<div class="card-body">';
h += '<div class="card-title">' + _esc(c.title) + '</div>';
if (c.rate) h += '<div class="card-meta"><span class="star-bar">' + getStars(c.rate) + '</span> ' + _esc(c.rate) + '</div>';
h += '</div></div>';
return h;
}
function getStars(r) {
var v = parseFloat(r);
if (!v) return '';
var s = '';
for (var i = 0; i < 5; i++) s += (i < Math.round(v / 2)) ? '★' : '☆';
return s;
}
function loadCategory(type, page) {
page = page || 1;
var el = document.getElementById('mainContent');
el.innerHTML = '<div class="loading">加载中...</div>';
var url = BASE + LANG + '/' + type + '/';
if (page > 1) url += '---' + (page - 1) + '-.html';
_req(url).then(function (html) {
if (!html) { el.innerHTML = '<div class="error-msg">加载失败</div>'; return; }
renderCategory(html, el, type, page);
});
}
function renderCategory(html, el, type, page) {
var ulm = html.match(/<div class="lists-content">\s*<ul>([\s\S]*?)<\/ul>\s*<\/div>/);
if (!ulm) { el.innerHTML = '<div class="error-msg">没有内容</div>'; return; }
var cards = parseCards(ulm[1]);
var h = '<div class="section"><div class="section-title"><span>' + (type === 'movie' ? '电影' : '电视剧') + '</span></div>';
h += '<div class="card-grid">';
for (var i = 0; i < cards.length; i++) h += renderCard(cards[i]);
h += '</div>';
// Pagination
var pagem = html.match(/<div class="pagination[^"]*">([\s\S]*?)<\/div>/);
if (pagem) {
var pages = [];
var pm = pagem[1].matchAll(/<a[^>]*href="[^"]*---(\d+)-\.html"[^>]*>(\d+)<\/a>/g);
for (var p of pm) pages.push(parseInt(p[1]));
var maxPage = pages.length > 0 ? Math.max.apply(null, pages) : 0;
h += '<div style="display:flex;gap:6px;justify-content:center;padding:12px 0;flex-wrap:wrap">';
var start = Math.max(1, page - 4);
var end = Math.min(maxPage, page + 4);
if (page > 1) h += '<button class="episode-btn page-btn" data-type="' + type + '" data-page="' + (page - 1) + '">上一页</button>';
for (var pp = start; pp <= end; pp++) {
h += '<button class="episode-btn page-btn' + (pp === page ? ' on' : '') + '" data-type="' + type + '" data-page="' + pp + '">' + pp + '</button>';
}
if (page < maxPage) h += '<button class="episode-btn page-btn" data-type="' + type + '" data-page="' + (page + 1) + '">下一页</button>';
h += '</div>';
}
h += '</div>';
el.innerHTML = h;
bindEvents(el);
}
function doSearch(keyword) {
if (!keyword.trim()) return;
var el = document.getElementById('mainContent');
el.innerHTML = '<div class="loading">搜索中...</div>';
var url = BASE + LANG + '/search/' + encodeURIComponent(keyword) + '--.html';
_req(url).then(function (html) {
if (!html) { el.innerHTML = '<div class="error-msg">搜索失败</div>'; return; }
var ulm = html.match(/<div class="lists-content">\s*<ul>([\s\S]*?)<\/ul>\s*<\/div>/);
if (!ulm) {
el.innerHTML = '<div class="section"><div class="section-title"><span>"' + _esc(keyword) + '" 没有找到结果</span></div></div>';
return;
}
var cards = parseCards(ulm[1]);
var h = '<div class="section"><div class="section-title"><span>"' + _esc(keyword) + '" 搜索结果 (' + cards.length + ')</span></div>';
h += '<div class="card-grid">';
for (var i = 0; i < cards.length; i++) h += renderCard(cards[i]);
h += '</div></div>';
el.innerHTML = h;
bindEvents(el);
});
}
function loadDetail(href) {
var el = document.getElementById('detailContent');
var view = document.getElementById('detailView');
view.classList.add('active');
document.body.classList.add('detail-active');
el.innerHTML = '<div class="loading">加载中...</div>';
_req(BASE + href).then(function (html) {
if (!html) { el.innerHTML = '<div class="error-msg">加载失败</div>'; return; }
renderDetail(html, el, href);
});
}
function renderDetail(html, el, href) {
var infoid = 0, m3u8 = [], subs = '', classurl = '';
var vm = html.match(/infoid\s*=\s*(\d+)/);
if (vm) infoid = vm[1];
var mu = html.match(/m3u8\s*=\s*\[([^\]]+)\]/);
if (mu) {
var parts = mu[1].split(',').map(function(s) { return s.replace(/['"\s]/g, ''); }).filter(Boolean);
m3u8 = parts;
}
var su = html.match(/sub\s*=\s*'([^']+)'/);
if (su) subs = su[1];
var cum = html.match(/classurl\s*=\s*'([^']+)'/);
if (cum) classurl = cum[1];
var poster = '';
var pm = html.match(/<img[^>]+class="thumb"[^>]+src="([^"]+)"/);
if (pm) poster = pm[1];
var title = '';
var tm = html.match(/<h1[^>]+class="product-title">([\s\S]*?)<\/h1>/);
if (tm) {
title = tm[1].replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').trim();
}
var year = '';
var ym2 = html.match(/<h1[^>]*>[\s\S]*?<span>\((\d{4})\)<\/span>/);
if (ym2) year = ym2[1];
var rate = '';
var rm = html.match(/class="rate">([^<]+)/);
if (rm) rate = rm[1];
var director = '', cast = '', genre = '', country = '', aka = '', desc = '';
var extractSpan = function(label) {
var re = new RegExp(label + '<span>([\\s\\S]*?)<\\/span>');
var m = html.match(re);
return m ? m[1].replace(/<[^>]+>/g, '').trim() : '';
};
director = extractSpan('导演');
cast = extractSpan('主演');
genre = extractSpan('类型');
country = extractSpan('国家');
aka = extractSpan('又名');
desc = extractSpan('简介');
var isTV = m3u8.length > 1 || (m3u8.length === 1 && m3u8[0] !== '1080P');
var h = '';
h += '<div class="detail-back" id="detailBack"><span>← 返回</span></div>';
h += '<img class="detail-poster" src="' + _img(poster) + '" alt="' + _esc(title) + '" onerror="this.style.display=\'none\'">';
h += '<div class="detail-info">';
h += '<div class="detail-title">' + _esc(title) + '</div>';
if (year || rate) h += '<div class="detail-year">' + (year ? year : '') + (rate ? ' ' + getStars(rate) + ' ' + rate : '') + '</div>';
if (director) h += '<div class="detail-field"><span class="detail-field-label">导演:</span><span class="detail-field-value">' + _esc(director) + '</span></div>';
if (cast) h += '<div class="detail-field"><span class="detail-field-label">主演:</span><span class="detail-field-value">' + _esc(cast) + '</span></div>';
if (genre) h += '<div class="detail-field"><span class="detail-field-label">类型:</span><span class="detail-field-value">' + _esc(genre) + '</span></div>';
if (country) h += '<div class="detail-field"><span class="detail-field-value">' + _esc(country) + '</span></div>';
if (aka) h += '<div class="detail-field"><span class="detail-field-value">又名:' + _esc(aka) + '</span></div>';
h += '</div><div style="clear:both"></div>';
if (desc) h += '<div class="detail-desc">' + _esc(desc) + '</div>';
// Play button or episode grid
if (m3u8.length === 1 && !isTV) {
h += '<button class="play-btn play-action" data-url="/info/m3u8/' + infoid + '/' + m3u8[0] + '.m3u8" data-title="' + _esc(title) + '">▶ 播放</button>';
}
if (m3u8.length > 1 || (m3u8.length === 1 && m3u8[0] !== '1080P')) {
h += '<div style="margin-top:10px"><div style="font-size:13px;font-weight:600;margin-bottom:6px;">选集</div>';
h += '<div class="episode-grid">';
for (var ei = 0; ei < m3u8.length; ei++) {
var ep = m3u8[ei];
var epLabel = ep;
if (!isNaN(parseInt(ep)) && parseInt(ep).toString() === ep) {
epLabel = '第' + ep + '集';
}
h += '<button class="episode-btn play-action" data-url="/info/m3u8/' + infoid + '/' + ep + '.m3u8" data-title="' + _esc(title) + ' ' + epLabel + '">' + _esc(epLabel) + '</button>';
}
h += '</div></div>';
}
el.innerHTML = h;
document.getElementById('detailBack').onclick = closeDetail;
document.getElementById('detailBg').onclick = closeDetail;
var pbs = el.querySelectorAll('.play-action');
for (var i = 0; i < pbs.length; i++) {
pbs[i].onclick = function () {
_play(this.getAttribute('data-url'), this.getAttribute('data-title'));
};
}
}
function closeDetail() {
document.getElementById('detailView').classList.remove('active');
document.body.classList.remove('detail-active');
}
function bindEvents(el) {
var cards = el.querySelectorAll('.card');
for (var i = 0; i < cards.length; i++) {
cards[i].onclick = function () {
var href = this.getAttribute('data-href');
if (href) loadDetail(href);
};
}
var tabs = el.querySelectorAll('.tab-item');
for (var i = 0; i < tabs.length; i++) {
tabs[i].onclick = function () {
var si = this.getAttribute('data-si');
var ti = this.getAttribute('data-ti');
var parent = this.parentNode;
var children = parent.querySelectorAll('.tab-item');
for (var j = 0; j < children.length; j++) children[j].classList.remove('on');
this.classList.add('on');
var grids = el.querySelectorAll('.card-grid[data-si="' + si + '"]');
for (var j = 0; j < grids.length; j++) {
grids[j].style.display = grids[j].getAttribute('data-ti') === ti ? '' : 'none';
}
};
}
var ranks = el.querySelectorAll('.rank-item');
for (var i = 0; i < ranks.length; i++) {
ranks[i].onclick = function () {
var href = this.getAttribute('data-href');
if (href) loadDetail(href);
};
}
var mores = el.querySelectorAll('[data-go]');
for (var i = 0; i < mores.length; i++) {
mores[i].onclick = function () {
setTab(this.getAttribute('data-go'));
};
}
var pbs = el.querySelectorAll('.page-btn');
for (var i = 0; i < pbs.length; i++) {
pbs[i].onclick = function () {
loadCategory(this.getAttribute('data-type'), parseInt(this.getAttribute('data-page')));
};
}
}
function setTab(tab) {
var tabs = document.querySelectorAll('.nav-tab');
for (var i = 0; i < tabs.length; i++) {
tabs[i].classList.toggle('on', tabs[i].getAttribute('data-tab') === tab);
}
if (tab === 'home') loadHome();
else if (tab === 'movie') loadCategory('movie', 1);
else if (tab === 'tv') loadCategory('tv', 1);
}
document.addEventListener('DOMContentLoaded', function () {
var tabs = document.querySelectorAll('.nav-tab');
for (var i = 0; i < tabs.length; i++) {
tabs[i].onclick = function () {
setTab(this.getAttribute('data-tab'));
};
}
document.getElementById('searchBtn').onclick = function () {
doSearch(document.getElementById('searchInput').value);
};
document.getElementById('searchInput').addEventListener('keydown', function (e) {
if (e.key === 'Enter') doSearch(this.value);
});
document.addEventListener('keydown', function (e) {
if (e.key === 'Escape') closeDetail();
});
window.addEventListener('popstate', function () {
if (document.getElementById('detailView').classList.contains('active')) closeDetail();
});
loadHome();
});
</script>
</body>
</html>