phimfull.pro Review
phimfull.pro Review
| Titletag | Descriptiontag | language |
|---|
| Phim Full, Xem Phim AI, Phim Xuyên Không, Hệ Thống, Tu Tiên Cập Nhật Mỗi Ngày | |
Vietnamese |
| Ip adress | 172.67.215.228 | Nameserver | christina.ns.cloudflare.com decker.ns.cloudflare.com |
Status code | 200 |
<!DOCTYPE html>
<html lang="vi">
<head>
<base href="http://phimfull.pro/">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="referrer" content="strict-origin-when-cross-origin">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<link rel="icon" type="image/jpeg" href="logo.jpg">
<link rel="apple-touch-icon" href="logo.jpg">
<!-- ========================================== -->
<!-- SEO META TAGS TIÊU CHUẨN -->
<!-- ========================================== -->
<title id="seo-title">Phim Full, Xem Phim AI, Phim Xuyên Không, Hệ Thống, Tu Tiên Cập Nhật Mỗi Ngày</title>
<meta id="seo-meta-title" name="title" content="Phim Full, Xem Phim AI, Phim Xuyên Không, Hệ Thống, Tu Tiên Cập Nhật Mỗi Ngày">
<meta id="seo-meta-desc" name="description" content="Phim AI, Phim Hoạt Hình AI, Phim Ngắn AI, Phim Do AI Tạo Ra, Phim AI Trung Quốc, Phim Cổ Trang AI, Phim Tiên Hiệp AI, Phim Xuyên Không AI, Phim Tận Thế AI, Phim Sinh Tồn AI, Phim AI Full HD, Phim AI Mới Nhất">
<meta id="seo-meta-keywords" name="keywords" content="Phim AI, Phim Hoạt Hình AI, Phim Ngắn AI, Phim Do AI Tạo Ra, Phim AI Trung Quốc, Phim Cổ Trang AI, Phim Tiên Hiệp AI, Phim Xuyên Không AI, Phim Tận Thế AI, Phim Sinh Tồn AI, Phim AI Full HD, Phim AI Mới Nhất">
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1">
<link id="seo-canonical" rel="canonical" href="">
<!-- Đồng bộ sớm SEO Title và Description khi mở trang (0ms delay) -->
<script>
(function() {
try {
let slug = null;
const p = window.location.pathname;
const m = p.match(/\/(?:phim|movie)\/([^\/?#]+)/i);
if (m && m[1]) slug = decodeURIComponent(m[1]);
if (!slug) {
const params = new URLSearchParams(window.location.search);
slug = params.get('phim') || params.get('movie') || params.get('id');
}
if (!slug && window.location.hash) {
const hm = window.location.hash.match(/#\/?(?:phim|movie)\/([^\/?#]+)/i);
if (hm && hm[1]) slug = decodeURIComponent(hm[1]);
}
if (slug) {
const clean = slug.toLowerCase().trim();
let movie = null;
try {
const raw = localStorage.getItem('minhsam_movies') || localStorage.getItem('langlangson_movies');
if (raw) {
const list = JSON.parse(raw);
if (Array.isArray(list)) {
movie = list.find(x => (x.id && x.id.toLowerCase() === clean) || (x.slug && x.slug.toLowerCase() === clean));
}
}
} catch(e) {}
if (!movie) {
const fallbackMap = {};
movie = fallbackMap[clean];
}
if (movie && movie.title) {
const mTitle = movie.title.trim();
const mDesc = (movie.desc && movie.desc.trim()) ? movie.desc.trim() : `Tóm tắt nội dung phim ${mTitle}: Xem trọn bộ Full HD Vietsub Thuyết Minh mới nhất tại Phim Full.`;
document.title = mTitle;
const tEl = document.getElementById('seo-title');
if (tEl) { tEl.textContent = mTitle; tEl.innerText = mTitle; }
const mtEl = document.getElementById('seo-meta-title');
if (mtEl) mtEl.setAttribute('content', mTitle);
const mdEl = document.getElementById('seo-meta-desc');
if (mdEl) mdEl.setAttribute('content', mDesc);
const ogT = document.getElementById('seo-og-title');
if (ogT) ogT.setAttribute('content', mTitle);
const ogD = document.getElementById('seo-og-desc');
if (ogD) ogD.setAttribute('content', mDesc);
const twT = document.getElementById('seo-tw-title');
if (twT) twT.setAttribute('content', mTitle);
const twD = document.getElementById('seo-tw-desc');
if (twD) twD.setAttribute('content', mDesc);
}
}
} catch(e) {}
})();
</script>
<!-- Open Graph / Facebook / Zalo -->
<meta id="seo-og-type" property="og:type" content="website">
<meta id="seo-og-url" property="og:url" content="">
<meta id="seo-og-title" property="og:title" content="Phim Full, Xem Phim AI, Phim Xuyên Không, Hệ Thống, Tu Tiên Cập Nhật Mỗi Ngày">
<meta id="seo-og-desc" property="og:description" content="Phim AI, Phim Hoạt Hình AI, Phim Ngắn AI, Phim Do AI Tạo Ra, Phim AI Trung Quốc, Phim Cổ Trang AI, Phim Tiên Hiệp AI, Phim Xuyên Không AI, Phim Tận Thế AI, Phim Sinh Tồn AI, Phim AI Full HD, Phim AI Mới Nhất">
<meta id="seo-og-image" property="og:image" content="logo.jpg">
<meta id="seo-og-site" property="og:site_name" content="Phim Full">
<!-- Twitter Cards -->
<meta name="twitter:card" content="summary_large_image">
<meta id="seo-tw-url" name="twitter:url" content="">
<meta id="seo-tw-title" name="twitter:title" content="Phim Full, Xem Phim AI, Phim Xuyên Không, Hệ Thống, Tu Tiên Cập Nhật Mỗi Ngày">
<meta id="seo-tw-desc" name="twitter:description" content="Phim AI, Phim Hoạt Hình AI, Phim Ngắn AI, Phim Do AI Tạo Ra, Phim AI Trung Quốc, Phim Cổ Trang AI, Phim Tiên Hiệp AI, Phim Xuyên Không AI, Phim Tận Thế AI, Phim Sinh Tồn AI, Phim AI Full HD, Phim AI Mới Nhất">
<meta id="seo-tw-image" name="twitter:image" content="logo.jpg">
<!-- Schema.org JSON-LD Structured Data (Rich Snippets) -->
<script id="seo-schema-jsonld" type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebSite",
"name": "Phim Full",
"alternateName": ["Phim AI", "Xem Phim AI", "Phim Xuyên Không", "Phim Full HD"],
"url": "https://phimfull.pro",
"description": "Phim AI, Phim Hoạt Hình AI, Phim Ngắn AI, Phim Do AI Tạo Ra, Phim AI Trung Quốc, Phim Cổ Trang AI, Phim Tiên Hiệp AI, Phim Xuyên Không AI, Phim Tận Thế AI, Phim Sinh Tồn AI, Phim AI Full HD, Phim AI Mới Nhất"
}
</script>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- HLS.js & ArtPlayer (Thư viện phát video HLS m3u8 thực tế) -->
<script src="https://cdn.jsdelivr.net/npm/hls.js@1.5.7/dist/hls.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/artplayer@5.1.7/dist/artplayer.js"></script>
<!-- Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&family=Cinzel:wght@600;700;900&display=swap" rel="stylesheet">
<style>
body { font-family: 'Plus Jakarta Sans', sans-serif; }
.font-cinzel { font-family: 'Cinzel', serif; }
.custom-scrollbar::-webkit-scrollbar { width: 5px; height: 5px; }
.custom-scrollbar::-webkit-scrollbar-track { background: rgba(15, 23, 42, 0.6); }
.custom-scrollbar::-webkit-scrollbar-thumb { background: rgba(245, 158, 11, 0.4); border-radius: 4px; }
.custom-scrollbar::-webkit-scrollbar-thumb:hover { background: rgba(245, 158, 11, 0.8); }
.gold-gradient-text {
background: linear-gradient(135deg, #fef08a 0%, #f59e0b 50%, #d97706 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.mountain-glow {
box-shadow: 0 0 40px -10px rgba(245, 158, 11, 0.3);
}
</style>
</head>
<body class="bg-[#090d16] text-slate-100 font-sans antialiased min-h-screen custom-scrollbar selection:bg-amber-500 selection:text-black">
<!-- ========================================== -->
<!-- 2. MAIN HEADER & NAVIGATION -->
<!-- ========================================== -->
<header class="sticky top-0 z-40 backdrop-blur-md bg-[#090d16]/90 border-b border-slate-800/80 transition-all">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-16 flex items-center justify-between gap-4">
<!-- LOGO THƯƠNG HIỆU -->
<a href="/" onclick="handleGoHome(event)" class="flex items-center gap-2.5 sm:gap-3 group select-none" title="Về Trang Chủ">
<img src="logo.jpg"
onerror="this.onerror=null; this.src='/logo.jpg';"
alt="Logo Phim"
class="h-11 sm:h-12 w-11 sm:w-12 rounded-full object-cover border-2 border-amber-500/60 shadow-lg shadow-amber-500/25 group-hover:scale-105 group-hover:border-amber-400 transition duration-300">
</a>
<!-- MENU ĐIỀU HƯỚNG TRANG CHỦ THEO CHUẨN MINH SÂM -->
<nav class="hidden lg:flex items-center gap-1 text-xs font-semibold uppercase tracking-wider">
<button onclick="filterStatusTab('all')" class="status-nav-btn px-3 py-2 rounded-lg text-amber-400 bg-amber-500/10 border border-amber-500/30 transition">
Trang Chủ
</button>
<button onclick="filterStatusTab('hot')" class="status-nav-btn px-3 py-2 rounded-lg text-slate-300 hover:text-amber-400 hover:bg-slate-800/80 transition flex items-center gap-1">
<span>🔥</span> Phim HOT
</button>
<button onclick="filterStatusTab('new')" class="status-nav-btn px-3 py-2 rounded-lg text-slate-300 hover:text-amber-400 hover:bg-slate-800/80 transition flex items-center gap-1">
<span>⚡</span> Mới Cập Nhật
</button>
<button onclick="filterStatusTab('cay-dem')" class="status-nav-btn px-3 py-2 rounded-lg text-slate-300 hover:text-amber-400 hover:bg-slate-800/80 transition flex items-center gap-1">
<span>🌙</span> Cày Đêm
</button>
<button onclick="filterStatusTab('hoan-thanh')" class="status-nav-btn px-3 py-2 rounded-lg text-slate-300 hover:text-amber-400 hover:bg-slate-800/80 transition flex items-center gap-1">
<span>✨</span> Trọn Bộ
</button>
<button onclick="scrollToElement('section-luan-dao')" class="status-nav-btn px-3 py-2 rounded-lg text-slate-300 hover:text-amber-400 hover:bg-slate-800/80 transition flex items-center gap-1">
<span>💬</span> Luận Đạo
</button>
</nav>
<!-- SEARCH BAR -->
<div class="relative flex-1 min-w-[70px] max-w-[110px] sm:max-w-xs">
<input
id="search-input"
type="text"
placeholder="Tìm phim..."
onkeyup="handleSearch(this.value)"
class="w-full bg-[#0d1322] border border-slate-700/80 rounded-full py-1.5 pl-8 pr-2.5 text-xs text-slate-200 placeholder-slate-400 focus:outline-none focus:border-amber-500 focus:ring-1 focus:ring-amber-500 transition"
>
<svg class="w-3.5 h-3.5 text-slate-400 absolute left-2.5 top-2.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
</div>
<!-- KHU VỰC TÀI KHOẢN TU TIÊN ("ĐĂNG NHẬP / ĐĂNG KÝ / PROFILE") -->
<div class="flex items-center gap-1.5 sm:gap-3 relative flex-shrink-0">
<!-- TRƯỜNG HỢP 1: CHƯA ĐĂNG NHẬP (GUEST) - GIAO DIỆN CHUẨN THEO ẢNH -->
<div id="header-guest-box" class="flex items-center gap-1.5 sm:gap-2">
<button onclick="openAuthModal('login')" class="px-3 py-1.5 sm:px-4 sm:py-2 rounded-full bg-[#0b101b] border border-amber-500/80 hover:border-amber-400 hover:bg-amber-500/15 text-amber-300 hover:text-amber-200 text-xs sm:text-sm font-bold transition flex items-center gap-1.5 shadow-sm active:scale-95 whitespace-nowrap">
<span>🔑</span>
<span>Đăng Nhập</span>
</button>
<button onclick="openAuthModal('register')" class="px-3.5 py-1.5 sm:px-4 sm:py-2 rounded-full bg-gradient-to-r from-amber-500 via-orange-500 to-amber-600 hover:from-amber-400 hover:to-orange-400 text-black text-xs sm:text-sm font-black shadow-lg shadow-orange-500/30 hover:shadow-orange-500/50 transition active:scale-95 flex items-center gap-1.5 whitespace-nowrap">
<span>✨</span>
<span>Đăng Ký</span>
</button>
</div>
<!-- TRƯỜNG HỢP 2: ĐÃ ĐĂNG NHẬP (LOGGED IN) -->
<div id="header-user-box" class="hidden flex items-center gap-2 sm:gap-3">
<!-- Nút Điểm Danh -->
<button id="btn-checkin" onclick="dailyCheckIn()" class="hidden xl:flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-semibold bg-gradient-to-r from-amber-500 to-orange-500 text-black hover:from-amber-400 hover:to-orange-400 shadow-md shadow-amber-500/20 transition active:scale-95">
<span>📿</span>
<span id="checkin-text">Điểm Danh (+Tu Vi)</span>
</button>
<!-- User Badge (Bấm để bật/tắt dropdown menu tài khoản) -->
<div id="user-badge" class="flex items-center gap-2.5 bg-slate-900/90 border border-slate-800 hover:border-amber-500/50 rounded-full p-1 pr-3 cursor-pointer transition group" onclick="toggleUserDropdown(event)" title="Bấm để mở bảng tu vi & cài đặt">
<div class="relative">
<div class="w-8 h-8 rounded-full bg-gradient-to-tr from-purple-600 via-amber-600 to-amber-400 flex items-center justify-center font-bold text-xs text-white ring-2 ring-amber-500/40">
☯️
</div>
<div class="absolute -bottom-0.5 -right-0.5 w-3 h-3 bg-emerald-500 border-2 border-slate-950 rounded-full"></div>
</div>
<div class="text-left">
<div class="text-xs font-bold text-slate-200 group-hover:text-amber-400 flex items-center gap-1">
<span id="user-name-display">Bắc Minh Chân Nhân</span>
<span class="text-[9px] bg-amber-500/20 text-amber-300 px-1 py-0.2 rounded font-mono" id="user-role-display">ĐẠI THẦN</span>
</div>
<div class="text-[11px] text-amber-400/90 font-medium flex items-center gap-1">
<span id="user-realm-display">Kim Đan Kỳ (Tầng 4)</span>
<span class="text-slate-500">•</span>
<span id="user-tuvi-display" class="font-mono text-emerald-400">3,450 Tu Vi</span>
</div>
</div>
<svg class="w-3.5 h-3.5 text-slate-400 group-hover:text-amber-400 transition ml-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
</div>
<!-- Nút Đăng Xuất nhanh -->
<button onclick="handleLogout()" class="hidden md:flex items-center gap-1 px-2.5 py-1.5 rounded-xl bg-slate-900/80 hover:bg-rose-500/20 hover:text-rose-400 text-slate-400 border border-slate-800 text-xs font-medium transition" title="Đăng Xuất Khỏi Tông Môn">
<span>🚪</span>
<span class="hidden lg:inline text-[11px]">Đăng Xuất</span>
</button>
</div>
<!-- DROPDOWN MENU TÀI KHOẢN TU TIÊN -->
<div id="user-profile-dropdown" class="hidden absolute right-0 top-14 w-72 bg-slate-900/98 border border-amber-500/30 backdrop-blur-2xl rounded-2xl shadow-2xl z-50 p-4 space-y-3">
<div class="flex items-center justify-between border-b border-slate-800 pb-3">
<div class="flex items-center gap-2.5">
<div class="w-10 h-10 rounded-xl bg-gradient-to-tr from-amber-500 to-orange-600 flex items-center justify-center font-bold text-black text-lg shadow">
☯️
</div>
<div>
<div class="font-bold text-sm text-slate-100" id="dropdown-daohieu">Bắc Minh Chân Nhân</div>
<div class="text-[10px] text-slate-400 flex items-center gap-1">
<span>@</span><span id="dropdown-username">bacminh</span>
<span class="text-slate-600">•</span>
<span class="text-amber-400" id="dropdown-sect">Minh Sâm</span>
</div>
</div>
</div>
</div>
<!-- Chỉ số Tu Vi & Linh Thạch -->
<div class="grid grid-cols-2 gap-2 text-center p-2.5 bg-slate-950/80 rounded-xl border border-slate-800">
<div>
<div class="text-[10px] text-slate-400">Tu Vi Tích Lũy</div>
<div class="text-xs font-mono font-bold text-emerald-400" id="dropdown-tuvi">3,450</div>
</div>
<div class="border-l border-slate-800">
<div class="text-[10px] text-slate-400">Linh Thạch</div>
<div class="text-xs font-mono font-bold text-amber-400" id="dropdown-linhthach">1,250 💎</div>
</div>
</div>
<!-- Thanh tiến trình Cảnh giới -->
<div class="space-y-1">
<div class="flex items-center justify-between text-[11px]">
<span class="text-slate-400">Cảnh giới:</span>
<span class="font-bold text-amber-300" id="dropdown-realm">Kim Đan Kỳ</span>
</div>
<div class="w-full bg-slate-800 h-1.5 rounded-full overflow-hidden">
<div class="bg-gradient-to-r from-amber-500 to-emerald-400 h-full rounded-full" id="dropdown-progress-bar" style="width: 65%;"></div>
</div>
</div>
<!-- Menu Danh mục hành động -->
<div class="space-y-1 pt-1 text-xs border-t border-slate-800">
<button onclick="openModal('tu-tien-info'); closeUserDropdown();" class="w-full flex items-center gap-2 px-2.5 py-2 rounded-xl text-slate-300 hover:text-white hover:bg-slate-800/80 transition text-left">
<span>📜</span>
<span>Quy Tắc Đột Phá Cảnh Giới</span>
</button>
<button onclick="dailyCheckIn(); closeUserDropdown();" class="w-full flex items-center gap-2 px-2.5 py-2 rounded-xl text-slate-300 hover:text-white hover:bg-slate-800/80 transition text-left">
<span>📿</span>
<span>Điểm Danh Nhận Tu Vi Hôm Nay</span>
</button>
<button onclick="openChangeProfileModal(); closeUserDropdown();" class="w-full flex items-center gap-2 px-2.5 py-2 rounded-xl text-slate-300 hover:text-white hover:bg-slate-800/80 transition text-left">
<span>⚙️</span>
<span>Đổi Đạo Hiệu / Mật Khẩu</span>
</button>
<button onclick="handleLogout()" class="w-full flex items-center gap-2 px-2.5 py-2 rounded-xl text-rose-400 hover:text-rose-300 hover:bg-rose-500/10 transition text-left font-semibold">
<span>🚪</span>
<span>Đăng Xuất (Xuất Sơn)</span>
</button>
</div>
</div>
</div>
</div>
</header>
<!-- ================================================================= -->
<!-- 3. MAIN CONTENT: GIAO DIỆN & BỐ CỤC CHUẨN MINH SÂM (PORTAL) -->
<!-- ================================================================= -->
<main class="max-w-7xl mx-auto px-2.5 sm:px-6 lg:px-8 py-3.5 sm:py-5 space-y-5 sm:space-y-7" id="main-movies-section">
<!-- KHỐI THANH ĐIỀU HƯỚNG BỘ LỌC PHIM CHUYÊN NGHIỆP -->
<div class="space-y-3 bg-slate-900/60 p-3.5 sm:p-4 rounded-2xl border border-slate-800/80 backdrop-blur-sm shadow-xl">
<!-- Hàng 1: Tabs phân loại trạng thái phim nhanh (Phim HOT, Mới Cập Nhật, Cày Đêm, Hoàn Thành, Đã Lưu) -->
<div class="flex flex-wrap items-center justify-between gap-3 border-b border-slate-800/80 pb-3">
<div id="status-tabs" class="flex flex-wrap items-center gap-1.5 sm:gap-2 text-xs font-bold">
<button onclick="filterStatusTab('all')" class="status-tab-btn px-3.5 py-1.5 rounded-xl bg-gradient-to-r from-amber-500 to-orange-500 text-black shadow-md shadow-amber-500/20 transition">
Tất Cả Phim
</button>
<button onclick="filterStatusTab('hot')" class="status-tab-btn px-3.5 py-1.5 rounded-xl bg-slate-800 text-slate-300 hover:text-white hover:bg-slate-700 transition flex items-center gap-1">
<span>🔥</span> Phim HOT
</button>
<button onclick="filterStatusTab('new')" class="status-tab-btn px-3.5 py-1.5 rounded-xl bg-slate-800 text-slate-300 hover:text-white hover:bg-slate-700 transition flex items-center gap-1">
<span>⚡</span> Mới Cập Nhật
</button>
<button onclick="filterStatusTab('cay-dem')" class="status-tab-btn px-3.5 py-1.5 rounded-xl bg-slate-800 text-slate-300 hover:text-white hover:bg-slate-700 transition flex items-center gap-1">
<span>🌙</span> Cày Đêm
</button>
<button onclick="filterStatusTab('hoan-thanh')" class="status-tab-btn px-3.5 py-1.5 rounded-xl bg-slate-800 text-slate-300 hover:text-white hover:bg-slate-700 transition flex items-center gap-1">
<span>✨</span> Hoàn Thành (Full)
</button>
</div>
<!-- Bộ lọc sắp xếp -->
<div class="flex items-center gap-2 text-xs text-slate-400">
<span class="hidden sm:inline">Sắp xếp:</span>
<select id="sort-select" onchange="handleSortChange(this.value)" class="bg-slate-950 border border-slate-700/80 rounded-xl px-2.5 py-1 text-slate-200 text-xs focus:outline-none focus:border-amber-500">
<option value="newest">⚡ Mới cập nhật</option>
<option value="views">🔥 Lượt xem nhiều nhất</option>
<option value="rating">⭐ Đánh giá cao nhất</option>
</select>
</div>
</div>
<!-- Hàng 2: Dải thể loại phong phú đặc trưng tu tiên (Horizontal Scrollable Chips) -->
<div class="flex items-center gap-1.5 sm:gap-2 overflow-x-auto custom-scrollbar pb-1 text-xs whitespace-nowrap" id="genre-chips-container">
<span class="text-slate-400 font-semibold text-[11px] uppercase tracking-wider mr-1 flex items-center gap-1">
<span>🏷️</span> Thể loại:
</span>
<button onclick="filterGenre('all')" class="genre-pill px-3 py-1 rounded-lg bg-amber-500 text-black font-bold transition">Tất Cả</button>
<button onclick="filterGenre('tu-tien')" class="genre-pill px-3 py-1 rounded-lg bg-slate-800/80 text-slate-300 hover:text-white hover:bg-slate-700 transition">Tu Tiên</button>
<button onclick="filterGenre('huyen-huyen')" class="genre-pill px-3 py-1 rounded-lg bg-slate-800/80 text-slate-300 hover:text-white hover:bg-slate-700 transition">Huyền Huyễn</button>
<button onclick="filterGenre('xuyen-khong')" class="genre-pill px-3 py-1 rounded-lg bg-slate-800/80 text-slate-300 hover:text-white hover:bg-slate-700 transition">Xuyên Không</button>
<button onclick="filterGenre('trong-sinh')" class="genre-pill px-3 py-1 rounded-lg bg-slate-800/80 text-slate-300 hover:text-white hover:bg-slate-700 transition">Trọng Sinh</button>
<button onclick="filterGenre('he-thong')" class="genre-pill px-3 py-1 rounded-lg bg-slate-800/80 text-slate-300 hover:text-white hover:bg-slate-700 transition">Hệ Thống</button>
<button onclick="filterGenre('vo-dich')" class="genre-pill px-3 py-1 rounded-lg bg-slate-800/80 text-slate-300 hover:text-white hover:bg-slate-700 transition">Vô Địch Lưu</button>
<button onclick="filterGenre('do-thi')" class="genre-pill px-3 py-1 rounded-lg bg-slate-800/80 text-slate-300 hover:text-white hover:bg-slate-700 transition">Đô Thị Dị Năng</button>
<button onclick="filterGenre('va-mat')" class="genre-pill px-3 py-1 rounded-lg bg-slate-800/80 text-slate-300 hover:text-white hover:bg-slate-700 transition">Vả Mặt</button>
<button onclick="filterGenre('nghich-tap')" class="genre-pill px-3 py-1 rounded-lg bg-slate-800/80 text-slate-300 hover:text-white hover:bg-slate-700 transition">Nghịch Tập</button>
<button onclick="filterGenre('hai-huoc')" class="genre-pill px-3 py-1 rounded-lg bg-slate-800/80 text-slate-300 hover:text-white hover:bg-slate-700 transition">Hài Hước</button>
</div>
</div>
<!-- TIÊU ĐỀ KHỐI PHIM CHÍNH -->
<div class="flex items-center justify-between border-b border-slate-800 pb-2.5">
<div class="flex items-center gap-2.5">
<span class="w-2.5 h-6 bg-gradient-to-b from-amber-400 to-orange-600 rounded-full"></span>
<h2 class="text-base sm:text-lg font-black text-white tracking-wider uppercase font-cinzel gold-gradient-text" id="catalog-section-title">
TẬP MỚI CẬP NHẬT
</h2>
<span class="text-xs text-slate-400 font-normal" id="catalog-total-count">(12 bộ phim)</span>
</div>
<div class="text-xs text-amber-400/90 font-medium hidden sm:flex items-center gap-1.5">
<span class="w-2 h-2 rounded-full bg-emerald-400 animate-pulse"></span>
<span>Cập nhật liên tục 24/7</span>
</div>
</div>
<!-- LƯỚI DANH SÁCH PHIM TRANG CHỦ (CHUẨN VIDEO 16:9 - 2 CỘT MOBILE, 4 CỘT DESKTOP THEO ẢNH MẪU) -->
<div id="movies-grid" class="grid grid-cols-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-2.5 sm:gap-4 lg:gap-5">
<!-- Injected by JS -->
</div>
<!-- KHỐI PHÂN TRANG (PAGINATION) CHUẨN THEO ẢNH MẪU (16 PHIM / TRANG) -->
<div id="movies-pagination" class="hidden flex items-center justify-center gap-1.5 sm:gap-2 pt-6 pb-2">
<!-- Injected by JS -->
</div>
<!-- KHU VỰC CỘNG ĐỒNG TU TIÊN: TOP XEM NHIỀU & LÔI ĐÀI LUẬN ĐẠO -->
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 pt-4 border-t border-slate-800/80" id="section-luan-dao">
<!-- TOP DONGHUA XEM NHIỀU -->
<div class="bg-slate-900/70 border border-slate-800 rounded-2xl p-5 space-y-3.5 shadow-xl">
<div class="flex items-center justify-between border-b border-slate-800 pb-2.5">
<h3 class="text-sm font-bold text-white flex items-center gap-2">
<span>🔥</span> Top Donghua Thịnh Hành Tuần Này
</h3>
<span class="text-[10px] bg-amber-500/10 text-amber-300 border border-amber-500/30 px-2 py-0.5 rounded-full font-medium">Bảng Tu Vi</span>
</div>
<div class="space-y-2.5" id="top-views-list">
<!-- Dynamically populated via JS -->
</div>
</div>
<!-- LÔI ĐÀI LUẬN ĐẠO (LIVE CHAT) -->
<div class="bg-slate-900/70 border border-slate-800 rounded-2xl p-5 flex flex-col justify-between shadow-xl">
<div>
<div class="flex items-center justify-between border-b border-slate-800 pb-2.5 mb-3">
<h3 class="text-sm font-bold text-white flex items-center gap-2">
<span>💬</span> Lôi Đài Luận Đạo (Đạo Hữu Đàm Luận)
</h3>
<span class="text-[10px] text-emerald-400 animate-pulse font-mono">● 18,492 online</span>
</div>
<div class="space-y-2.5 text-xs max-h-56 overflow-y-auto custom-scrollbar pr-1" id="chat-messages">
<div class="p-2.5 rounded-xl bg-slate-800/50 border border-slate-800">
<span class="font-bold text-amber-400">Kiếm Ma Tôn Giả:</span>
<span class="text-slate-300"> Đợi tập mới Phàm Nhân mà như độ kiếp nghìn năm...</span>
</div>
<div class="p-2.5 rounded-xl bg-slate-800/50 border border-slate-800">
<span class="font-bold text-emerald-400">Thảo Dược Tiên Tử:</span>
<span class="text-slate-300"> Vừa điểm danh nhận được 50 Linh Thạch, chuẩn bị đột phá Kim Đan rồi ae!</span>
</div>
<div class="p-2.5 rounded-xl bg-slate-800/50 border border-slate-800">
<span class="font-bold text-purple-400">Bắc Minh Chân Nhân:</span>
<span class="text-slate-300"> Bộ Thế Giới Hoàn Mỹ tập này combat cháy khét lẹt luôn các đạo hữu! 🔥</span>
</div>
</div>
</div>
<div class="mt-3 pt-3 border-t border-slate-800/80">
<div class="flex gap-2">
<input type="text" id="live-chat-input" placeholder="Phát biểu luận điểm (nhận +5 Tu Vi)..." class="flex-1 bg-slate-950 border border-slate-700/80 rounded-xl px-3 py-2 text-xs text-slate-200 focus:outline-none focus:border-amber-500">
<button onclick="sendLiveComment()" class="px-4 py-2 bg-gradient-to-r from-amber-500 to-orange-500 text-black font-extrabold rounded-xl text-xs hover:from-amber-400 hover:to-orange-400 shadow-md shadow-amber-500/20 transition whitespace-nowrap">
Luận Đạo
</button>
</div>
</div>
</div>
</div>
</main>
<!-- ================================================================= -->
<!-- 4. MOVIE DETAIL PAGE: GIAO DIỆN CHÍNH CHO TỪNG BỘ PHIM (/phim/ten-phim) -->
<!-- ================================================================= -->
<div id="movie-detail-view" class="hidden min-h-screen text-slate-100 pb-16">
<!-- THANH BREADCRUMB ĐIỀU HƯỚNG VỤN BÁNH MÌ -->
<div class="bg-slate-950/80 border-b border-slate-800/80 px-4 sm:px-6 lg:px-8 py-2.5">
<div class="max-w-7xl mx-auto flex flex-wrap items-center justify-between gap-2 text-xs">
<div class="flex items-center gap-2 text-slate-400 flex-wrap">
<button onclick="handleGoHome(event)" class="hover:text-amber-400 transition flex items-center gap-1 font-semibold">
<span>🏠</span> Trang Chủ
</button>
<span>›</span>
<span id="detail-breadcrumb-genre" class="text-slate-300 font-medium">Tu Tiên • Huyền Huyễn</span>
<span>›</span>
<span id="detail-breadcrumb-title" class="text-amber-400 font-bold truncate max-w-[240px] sm:max-w-md">Tên Phim</span>
</div>
<div class="flex items-center gap-3 text-[11px] text-slate-400">
<span id="detail-breadcrumb-rating" class="text-amber-400 font-semibold">⭐ 9.8</span>
<span>•</span>
<span id="detail-breadcrumb-views" class="text-amber-300 font-mono font-bold">👁️ 14,000 lượt xem</span>
<span class="hidden sm:inline">•</span>
<span class="text-emerald-400 font-medium hidden sm:inline">⚡ Full HD / 4K</span>
</div>
</div>
</div>
<!-- KHỐI HERO BANNER CỦA BỘ PHIM (CHUẨN 100% THEO ẢNH MẪU) -->
<div id="movie-detail-hero" class="relative w-full overflow-hidden border-b border-slate-800/80 bg-[#070b14] min-h-[400px] sm:min-h-[460px] flex items-center">
<!-- 1. Lớp ambient background phủ mờ toàn diện giữ tone màu đặc trưng của từng bộ phim -->
<div id="detail-hero-ambient" class="absolute inset-0 bg-cover bg-center opacity-30 filter blur-3xl scale-110 pointer-events-none transition-all duration-700"></div>
<!-- 2. Ảnh nền Poster / Banner của từng bộ phim hiển thị rõ nét, sắc sảo phía bên phải chuẩn cinema theo đúng ảnh mẫu -->
<div id="detail-hero-bg" class="absolute right-0 top-0 bottom-0 w-full sm:w-2/3 md:w-3/5 lg:w-1/2 bg-cover bg-top sm:bg-center bg-no-repeat opacity-95 transition-all duration-700 pointer-events-none"></div>
<!-- 3. Lớp gradient che phủ từ trái sang phải: bảo đảm khu vực thông tin chữ bên trái luôn rõ nét dễ đọc, bên phải nhìn rõ tranh phim -->
<div class="absolute inset-0 bg-gradient-to-r from-[#070b14] via-[#070b14]/90 sm:via-[#070b14]/75 via-45% to-transparent pointer-events-none"></div>
<!-- 4. Lớp gradient đáy chuyển mượt xuống danh sách tập phim -->
<div class="absolute inset-0 bg-gradient-to-t from-[#070b14] via-transparent to-transparent pointer-events-none"></div>
<div class="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 sm:py-12 lg:py-16 space-y-4 sm:space-y-5 w-full">
<!-- HÀNG 1: BADGES / THẺ TAGS (Nam Chính, Tu Tiên, Nữ Chính, Vả Mặt, Cập Nhật...) -->
<div id="detail-badges-container" class="flex flex-wrap items-center gap-2 sm:gap-2.5 text-xs">
<!-- Injected via JS -->
</div>
<!-- HÀNG 2: TIÊU ĐỀ PHIM CỠ LỚN (IN HOA/ĐẬM CHUẨN ĐỒ HỌA THEO ẢNH MẪU) -->
<h1 id="detail-movie-title" class="text-2xl sm:text-3xl md:text-4xl lg:text-[40px] font-black text-white leading-tight tracking-tight max-w-4xl drop-shadow-2xl">
Tro Tàn Cửu Châu: Ta Xuyên Không Về Cổ Đại Dùng Kiến Thức Hiện Đại Xoay Chuyển Càn Khôn
</h1>
<!-- HÀNG 3: SUB-INFO (Phim hoạt hình • Thời lượng • Số mùa/tập) -->
<div id="detail-meta-container" class="flex flex-wrap items-center gap-2 sm:gap-3 text-xs sm:text-sm text-slate-300 font-semibold">
<span class="flex items-center gap-1.5 text-slate-200">
<span>🔲</span> <span>Phim hoạt hình</span>
</span>
<span class="text-slate-500">•</span>
<span class="flex items-center gap-1.5 text-slate-200" id="detail-duration-display">
<span>🕒</span> <span>46h 12p</span>
</span>
<span class="text-slate-500">•</span>
<span class="flex items-center gap-1.5 text-slate-200" id="detail-episodes-display">
<span>🔲</span> <span>50 tập</span>
</span>
<span class="text-slate-500">•</span>
<span class="flex items-center gap-1 text-amber-400 font-bold" id="detail-rating-display">
<span>⭐</span> <span>9.8</span>
</span>
</div>
<!-- HÀNG 4: CÁC NÚT HÀNH ĐỘNG CHÍNH (Xem phim [Cyan], Lưu phim [Dark Pill], Chia sẻ [Dark Pill]) -->
<div class="flex flex-wrap items-center gap-3 pt-1">
<!-- Nút Xem phim màu Cyan theo đúng ảnh -->
<button id="btn-detail-watch" onclick="startWatchingDetailMovie(1)" class="px-6 sm:px-8 py-3 rounded-xl bg-[#00a8e8] hover:bg-[#0096d6] text-white font-black text-sm sm:text-base flex items-center gap-2.5 shadow-xl shadow-[#00a8e8]/30 transition-all transform active:scale-95">
<svg class="w-4 h-4 sm:w-5 sm:h-5 fill-current" viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>
<span>Xem phim</span>
</button>
<!-- Nút Lưu phim -->
<button id="btn-detail-favorite" onclick="toggleDetailFavorite()" class="px-5 sm:px-6 py-3 rounded-xl bg-slate-900/80 hover:bg-slate-800 text-slate-100 hover:text-white font-bold text-sm border border-slate-700/80 flex items-center gap-2 transition-all active:scale-95 shadow-lg backdrop-blur-md">
<svg id="detail-fav-icon" class="w-4 h-4 fill-none stroke-current" viewBox="0 0 24 24" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"/>
</svg>
<span id="detail-fav-text">Lưu phim</span>
</button>
<!-- Nút Chia sẻ -->
<button onclick="shareDetailMovie()" class="px-5 sm:px-6 py-3 rounded-xl bg-slate-900/80 hover:bg-slate-800 text-slate-100 hover:text-white font-bold text-sm border border-slate-700/80 flex items-center gap-2 transition-all active:scale-95 shadow-lg backdrop-blur-md">
<svg class="w-4 h-4 fill-none stroke-current" viewBox="0 0 24 24" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z"/>
</svg>
<span>Chia sẻ</span>
</button>
</div>
<!-- HÀNG 5: NỘI DUNG TÓM TẮT & XEM THÊM -->
<div class="max-w-3xl text-xs sm:text-sm text-slate-300 leading-relaxed pt-1">
<span id="detail-desc-text">Nội dung tóm tắt phim...</span>
<button id="btn-detail-desc-toggle" onclick="toggleDetailDescription()" class="text-amber-400 hover:text-amber-300 font-bold ml-1 inline-block focus:outline-none">Xem thêm</button>
</div>
</div>
</div>
<!-- KHỐI "DANH SÁCH TẬP PHIM" (ĐÃ XÓA PHẦN MÙA, CHỈ ĐỂ DANH SÁCH TẬP) -->
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pt-6 sm:pt-8" id="movie-seasons-container">
<div class="bg-[#0b1220] border border-slate-800/90 rounded-2xl p-4 sm:p-6 shadow-2xl space-y-4">
<!-- HEADER KHỐI: DANH SÁCH TẬP PHIM -->
<div class="flex flex-wrap items-center justify-between gap-3 border-b border-slate-800/80 pb-3">
<div class="flex items-center gap-2.5">
<span class="text-amber-400 text-lg sm:text-xl">📁</span>
<h2 class="text-sm sm:text-base font-black text-amber-400 tracking-wider uppercase">DANH SÁCH TẬP PHIM</h2>
<span id="detail-episodes-total-badge" class="px-2.5 py-0.5 rounded-full bg-amber-500/10 text-amber-400 border border-amber-500/20 text-xs font-bold font-mono">50 Tập</span>
</div>
<div class="text-xs text-slate-400 flex items-center gap-1.5 font-medium">
<svg class="w-3.5 h-3.5 text-amber-400" fill="currentColor" viewBox="0 0 24 24">
<path d="M8 5v14l11-7z"/>
</svg>
<span>Bấm vào tập để bắt đầu xem</span>
</div>
</div>
<!-- LƯỚI DANH SÁCH CÁC TẬP PHIM (TẬP 1, TẬP 2, TẬP 3...) -->
<div id="detail-episodes-section" class="pt-1">
<div id="detail-episodes-grid" class="grid grid-cols-3 sm:grid-cols-5 md:grid-cols-7 lg:grid-cols-9 xl:grid-cols-10 gap-2 sm:gap-2.5">
<!-- Injected via JS -->
</div>
</div>
</div>
</div>
<!-- KHU VỰC BÌNH LUẬN & ĐỀ CỬ PHIM CÙNG THỂ LOẠI -->
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pt-6 sm:pt-8 grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Cột trái (2 cols): Đạo Hữu Luận Đàm (Bình Luận) -->
<div id="detail-comments-container" class="lg:col-span-2 bg-slate-900/70 border border-slate-800 rounded-2xl p-5 space-y-4 shadow-xl">
<div class="flex items-center justify-between border-b border-slate-800 pb-2.5">
<h3 class="text-sm font-bold text-white flex items-center gap-2">
<span>💬</span> Đạo Hữu Luận Đàm
<span id="detail-comments-count" class="text-xs font-normal text-slate-400">(0 bình luận)</span>
</h3>
<span class="text-[10px] text-emerald-400 font-mono">● Cộng Đồng Tu Tiên</span>
</div>
<!-- Khung nhập bình luận -->
<div class="space-y-2.5 bg-slate-950/80 p-3.5 rounded-xl border border-slate-800">
<div class="flex items-center justify-between text-xs text-slate-400">
<span class="flex items-center gap-1.5">
<span>Đạo Hữu:</span>
<span id="detail-comment-user" class="text-amber-400 font-bold">Khách Vãng Lai</span>
</span>
<span class="text-[10px] text-slate-500">Bình luận nhận +5 Tu Vi</span>
</div>
<textarea id="detail-comment-input" rows="2" placeholder="Để lại luận đàm của đạo hữu về bộ phim này..." class="w-full bg-slate-900 border border-slate-700/80 rounded-xl p-2.5 text-xs text-slate-200 placeholder-slate-500 focus:outline-none focus:border-amber-500 resize-none"></textarea>
<div class="flex items-center justify-between">
<div class="flex gap-1.5 text-xs text-slate-400">
<button onclick="addDetailCommentEmoji('🔥')" class="px-2 py-1 rounded bg-slate-800 hover:bg-slate-700">🔥</button>
<button onclick="addDetailCommentEmoji('💯')" class="px-2 py-1 rounded bg-slate-800 hover:bg-slate-700">💯</button>
<button onclick="addDetailCommentEmoji('⚔️')" class="px-2 py-1 rounded bg-slate-800 hover:bg-slate-700">⚔️</button>
<button onclick="addDetailCommentEmoji('🍿')" class="px-2 py-1 rounded bg-slate-800 hover:bg-slate-700">🍿</button>
</div>
<button onclick="postDetailComment()" class="px-4 py-1.5 bg-gradient-to-r from-amber-500 to-orange-500 text-black font-extrabold rounded-xl text-xs hover:from-amber-400 hover:to-orange-400 shadow-md transition">
Gửi Luận Đàm
</button>
</div>
</div>
<!-- Danh sách bình luận -->
<div id="detail-comments-list" class="space-y-2.5 max-h-96 overflow-y-auto custom-scrollbar pr-1">
<!-- Injected via JS -->
</div>
</div>
<!-- Cột phải (1 col): Phim Cùng Thể Loại Đề Cử -->
<div class="bg-slate-900/70 border border-slate-800 rounded-2xl p-5 space-y-3.5 shadow-xl h-fit">
<div class="flex items-center justify-between border-b border-slate-800 pb-2.5">
<h3 class="text-sm font-bold text-white flex items-center gap-2">
<span>🔥</span> Phim Cùng Thể Loại
</h3>
<span class="text-[10px] bg-amber-500/10 text-amber-300 border border-amber-500/30 px-2 py-0.5 rounded-full font-medium">Đề cử</span>
</div>
<div id="detail-related-movies-list" class="space-y-2.5">
<!-- Injected via JS -->
</div>
</div>
</div>
</div>
<!-- ================================================================= -->
<!-- 6. KHUNG XEM PHIM (CHẾ ĐỘ RẠP PHIM FULL MÀN HÌNH CÓ LOGO & MENU) -->
<!-- ================================================================= -->
<div id="modal-video-player" class="hidden fixed inset-0 z-50 bg-[#070a13] text-slate-100 overflow-y-auto custom-scrollbar flex flex-col">
<!-- THANH HEADER ĐIỀU HƯỚNG CÓ LOGO VÀ MENU CỐ ĐỊNH KHI XEM PHIM -->
<header class="sticky top-0 z-50 backdrop-blur-md bg-[#090d16]/95 border-b border-slate-800/90 shadow-2xl">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-16 flex items-center justify-between gap-3 sm:gap-4">
<!-- LOGO KHI VÀO XEM PHIM (BẤM ĐỂ VỀ TRANG CHỦ) -->
<div onclick="handleGoHomeFromPlayer()" class="flex items-center gap-2.5 sm:gap-3 cursor-pointer group select-none" title="Bấm để về Trang Chủ">
<img src="logo.jpg"
onerror="this.onerror=null; this.src='/logo.jpg';"
alt="Logo Phim"
class="h-10 sm:h-11 w-10 sm:w-11 rounded-full object-cover border-2 border-amber-500/60 shadow-lg shadow-amber-500/25 group-hover:scale-105 group-hover:border-amber-400 transition duration-300">
</div>
<!-- MENU ĐIỀU HƯỚNG BÊN TRONG PHIM -->
<nav class="hidden md:flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wider">
<button onclick="handleGoHomeFromPlayer()" class="px-3 py-2 rounded-lg text-slate-300 hover:text-white hover:bg-slate-800/80 transition flex items-center gap-1.5">
<span>🏠</span> Trang Chủ
</button>
<button onclick="navigateFromPlayer('tu-tien')" class="px-3 py-2 rounded-lg text-slate-300 hover:text-amber-400 hover:bg-slate-800/80 transition">
Tu Tiên
</button>
<button onclick="navigateFromPlayer('huyen-huyen')" class="px-3 py-2 rounded-lg text-slate-300 hover:text-amber-400 hover:bg-slate-800/80 transition">
Huyền Huyễn
</button>
<button onclick="navigateFromPlayer('xuyen-khong')" class="px-3 py-2 rounded-lg text-slate-300 hover:text-amber-400 hover:bg-slate-800/80 transition">
Xuyên Không
</button>
<button onclick="scrollToPlayerSection('movie-comments-container')" class="px-3 py-2 rounded-lg text-amber-400 bg-amber-500/10 border border-amber-500/30 hover:bg-amber-500/20 transition flex items-center gap-1.5">
<span>💬</span> Bình Luận
</button>
</nav>
<!-- TÌM KIẾM ĐỔI PHIM TRỰC TIẾP TRONG PLAYER -->
<div class="relative flex-1 max-w-xs hidden sm:block">
<input
id="player-search-input"
type="text"
placeholder="Tìm phim khác..."
oninput="handlePlayerSearch(this.value)"
class="w-full bg-slate-900/90 border border-slate-700/80 rounded-full py-1.5 pl-9 pr-4 text-xs text-slate-200 placeholder-slate-500 focus:outline-none focus:border-amber-500 focus:ring-1 focus:ring-amber-500 transition"
>
<svg class="w-4 h-4 text-slate-500 absolute left-3 top-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
<!-- Live results dropdown -->
<div id="player-search-results" class="hidden absolute left-0 right-0 top-10 bg-slate-900 border border-slate-700 rounded-2xl shadow-2xl overflow-hidden max-h-72 overflow-y-auto custom-scrollbar z-50 p-2 space-y-1">
</div>
</div>
<!-- RIGHT ACTIONS: ĐẠO HỮU BADGE & NÚT VỀ TRANG CHỦ -->
<div class="flex items-center gap-2 sm:gap-3">
<div class="hidden xl:flex items-center gap-2 bg-slate-900/90 border border-slate-800 px-3 py-1.5 rounded-xl text-xs">
<span class="w-2 h-2 rounded-full bg-emerald-400 animate-pulse"></span>
<span class="text-slate-400">Đạo Hiệu:</span>
<span class="text-amber-400 font-bold" id="player-user-daohieu">Bắc Minh Chân Nhân</span>
</div>
<button id="btn-open-movie-page" onclick="returnToDetailFromPlayer()" class="hidden sm:flex items-center gap-1.5 px-3 py-1.5 rounded-xl bg-slate-800 hover:bg-slate-700 text-slate-300 hover:text-amber-300 border border-slate-700 text-xs font-semibold transition shadow" title="Về trang chi tiết bộ phim">
<span>📄</span>
<span class="text-[11px]">Trang Phim</span>
</button>
<button onclick="shareCurrentMovie()" class="px-3 sm:px-3.5 py-1.5 rounded-xl bg-amber-500/10 hover:bg-amber-500/20 text-amber-300 border border-amber-500/30 text-xs font-bold transition flex items-center gap-1.5 shadow" title="Sao chép link xem phim này">
<span>🔗</span>
<span class="hidden sm:inline">Chia Sẻ Link</span>
</button>
<button onclick="handleGoHomeFromPlayer()" class="px-3.5 py-1.5 rounded-xl bg-slate-800 hover:bg-amber-500 hover:text-black text-slate-200 border border-slate-700/80 text-xs font-bold transition flex items-center gap-1.5 shadow" title="Đóng player và về Trang Chủ">
<span>✕</span>
<span>Về Trang Chủ</span>
</button>
</div>
</div>
<!-- THANH ĐIỀU HƯỚNG VỤN BÁNH MÌ (BREADCRUMB) & TRẠNG THÁI TẬP PHIM -->
<div class="bg-slate-950/90 border-t border-slate-800/60 px-4 sm:px-6 lg:px-8 py-2">
<div class="max-w-7xl mx-auto flex flex-wrap items-center justify-between gap-2 text-xs">
<div class="flex items-center gap-2 text-slate-400 flex-wrap">
<button onclick="handleGoHomeFromPlayer()" class="hover:text-amber-400 transition flex items-center gap-1">
<span>🏠</span> Trang Chủ
</button>
<span>›</span>
<button id="modal-breadcrumb-genre" onclick="navigateFromPlayer(currentMovie ? currentMovie.genre : 'tu-tien')" class="capitalize text-slate-300 hover:text-amber-400 transition font-medium">
Tu Tiên
</button>
<span>›</span>
<button onclick="returnToDetailFromPlayer()" class="text-amber-300 hover:text-amber-400 font-bold truncate max-w-[200px] sm:max-w-md transition text-left" id="modal-breadcrumb-title">
Phàm Nhân Tu Tiên
</button>
<span>›</span>
<span class="bg-amber-500/20 text-amber-400 px-2.5 py-0.5 rounded-full font-bold text-[11px] border border-amber-500/30" id="modal-breadcrumb-ep">
Tập 115
</span>
</div>
<div class="flex items-center gap-3 text-[11px] text-slate-400">
<span class="text-amber-400 flex items-center gap-1 font-semibold" id="modal-breadcrumb-rating">⭐ 9.8</span>
<span class="hidden sm:inline">•</span>
<span class="text-amber-300 font-mono font-bold flex items-center gap-1" id="modal-breadcrumb-views">👁️ 482,100 xem</span>
<span class="hidden sm:inline">•</span>
<span class="text-emerald-400 font-medium flex items-center gap-1">
<span class="w-1.5 h-1.5 rounded-full bg-emerald-400 animate-pulse"></span> HLS 4K UltraHD
</span>
<span class="hidden sm:inline">•</span>
<span class="text-slate-400">Thuyết Minh / Vietsub</span>
</div>
</div>
</div>
</header>
<!-- NỘI DUNG CHÍNH KHUNG XEM PHIM (CHIA 2 CỘT) -->
<div class="max-w-7xl mx-auto px-3 sm:px-6 py-5 w-full flex-1">
<!-- TIÊU ĐỀ PHIM & TẬP ĐANG PHÁT -->
<div class="flex items-center justify-between pb-3 mb-2 border-b border-slate-800/80">
<div class="flex items-center gap-3">
<div class="w-8 h-8 rounded-lg bg-sky-950/80 border border-sky-500/30 text-sky-400 flex items-center justify-center font-bold shadow-sm">
<svg class="w-4 h-4 fill-sky-400" viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>
</div>
<div>
<h2 class="text-base sm:text-lg font-bold text-white flex items-center gap-2" id="modal-player-title">
Phàm Nhân Tu Tiên
</h2>
<div class="text-xs text-slate-400 flex items-center gap-2">
<span class="text-amber-400 font-semibold" id="modal-player-ep-label">Đang phát Tập 115</span>
<span>•</span>
<span class="text-amber-300 font-mono font-bold flex items-center gap-1" id="modal-player-views-count">👁️ 482,100 lượt xem</span>
<span>•</span>
<span class="text-emerald-400">Tốc độ cao không giật lag</span>
</div>
</div>
</div>
<div class="flex items-center gap-2">
<button onclick="scrollToPlayerSection('movie-comments-container')" class="px-3 py-1.5 rounded-xl bg-slate-900 hover:bg-slate-800 text-slate-300 hover:text-white border border-slate-800 text-xs transition flex items-center gap-1.5">
<span>💬</span> <span class="hidden sm:inline">Viết bình luận</span>
</button>
</div>
</div>
<!-- Player & Episodes Grid -->
<div class="grid grid-cols-1 lg:grid-cols-4 gap-4 sm:gap-6">
<!-- Video Screen (3 cols) -->
<div class="lg:col-span-3 space-y-3">
<div class="relative bg-black rounded-2xl overflow-hidden aspect-video border border-slate-800 shadow-2xl">
<div id="artplayer-container" class="hidden w-full h-full"></div>
<iframe id="iframe-player" class="w-full h-full border-0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
<!-- LỚP THÔNG BÁO KHI TẬP CHƯA CÓ LINK SERVER PHIM (CHỐNG TỰ ĐỘNG BỊ CHUYỂN VỀ TRANG PHIM) -->
<div id="player-no-link-overlay" class="hidden absolute inset-0 z-30 bg-[#070a13]/95 backdrop-blur-md flex flex-col items-center justify-center p-6 text-center space-y-3.5 select-none">
<div class="w-14 h-14 sm:w-16 sm:h-16 rounded-2xl bg-amber-500/15 border border-amber-500/35 flex items-center justify-center text-3xl sm:text-4xl shadow-xl shadow-amber-500/10">
⏳
</div>
<div class="space-y-1.5 max-w-md">
<h3 id="no-link-overlay-title" class="text-base sm:text-lg font-black text-white">Tập phim đang cập nhật nguồn phát</h3>
<p id="no-link-overlay-desc" class="text-xs sm:text-sm text-slate-400 leading-relaxed">
Tập này hiện chưa có link máy chủ phim. Đạo hữu vui lòng chọn tập khác trong danh sách hoặc quay lại sau!
</p>
</div>
<div class="flex items-center gap-2.5 pt-1">
<button type="button" onclick="changeDetailEpisode(-1)" class="px-3.5 py-2 rounded-xl bg-slate-800 hover:bg-slate-700 text-slate-300 hover:text-white text-xs font-bold border border-slate-700 transition flex items-center gap-1.5 shadow">
<span>⏮️</span> <span>Tập Trước</span>
</button>
<button type="button" onclick="changeDetailEpisode(1)" class="px-3.5 py-2 rounded-xl bg-gradient-to-r from-amber-500 to-orange-500 hover:from-amber-400 hover:to-orange-400 text-black text-xs font-black transition flex items-center gap-1.5 shadow-lg shadow-amber-500/25">
<span>Tập Kế Tiếp</span> <span>⏭️</span>
</button>
</div>
</div>
</div>
<!-- Controls & Server selection bar (ƯU TIÊN SERVER IFRAME) -->
<div class="p-3.5 bg-slate-950/80 border border-slate-800 rounded-2xl flex flex-col sm:flex-row sm:items-center justify-between gap-3 text-xs">
<div class="flex flex-wrap items-center gap-1.5 sm:gap-2">
<span class="text-slate-400 font-semibold flex items-center gap-1 mr-1">
<span>🖥️</span> Server:
</span>
<button onclick="switchServer('iframe1')" id="btn-srv-3" class="px-3 py-1.5 rounded-xl bg-amber-500 text-black font-bold flex items-center gap-1 shadow transition">
<span>🌐</span> SV Youtube
</button>
<button onclick="switchServer('iframe2')" id="btn-srv-4" class="px-3 py-1.5 rounded-xl bg-slate-800 text-slate-300 hover:bg-slate-700 transition flex items-center gap-1">
<span>🌐</span> Sever FB
</button>
<button onclick="switchServer('hls1')" id="btn-srv-1" class="px-3 py-1.5 rounded-xl bg-slate-800 text-slate-300 hover:bg-slate-700 transition flex items-center gap-1">
<span>⚡</span> VIP HLS #1
</button>
<button onclick="switchServer('hls2')" id="btn-srv-2" class="px-3 py-1.5 rounded-xl bg-slate-800 text-slate-300 hover:bg-slate-700 transition">
Dự Phòng HLS
</button>
<button onclick="toggleCustomIframeBox()" class="px-2.5 py-1.5 rounded-xl bg-amber-500/10 border border-amber-500/30 text-amber-300 hover:bg-amber-500/20 text-[11px] transition">
+ Nhập Link Iframe
</button>
</div>
<div class="flex items-center gap-2 sm:gap-3">
<div class="hidden md:flex items-center gap-1.5 bg-emerald-500/10 border border-emerald-500/30 text-emerald-400 px-2.5 py-1 rounded-full text-[11px] font-medium" title="Hệ thống tự động chuyển sang server dự phòng nếu server hiện tại bị lỗi">
<span class="w-1.5 h-1.5 rounded-full bg-emerald-400 animate-pulse"></span>
<span>Tự Chuyển Server Khi Lỗi: Bật</span>
</div>
<div class="bg-amber-500/20 text-amber-300 px-3 py-1 rounded-full border border-amber-500/30 flex items-center gap-1.5 font-medium">
<span>⚡</span>
<span id="tuvi-watch-counter">Đang tu luyện: +10 Tu Vi/phút xem</span>
</div>
</div>
</div>
<!-- Custom Iframe Input Form (Tự động chuyển đổi mọi dạng link YouTube sang Embed) -->
<div id="custom-iframe-box" class="hidden p-3.5 bg-slate-950/90 border border-amber-500/30 rounded-2xl space-y-2.5 text-xs">
<div class="flex items-center justify-between">
<span class="font-bold text-amber-300 flex items-center gap-1.5">
<span>🔗</span> Nhập Link Iframe / YouTube / Doodstream / Streamtape...
</span>
<button onclick="toggleCustomIframeBox()" class="text-slate-400 hover:text-white text-base">×</button>
</div>
<div class="flex flex-col sm:flex-row gap-2">
<input type="text" id="custom-iframe-url" placeholder="Dán link YouTube (watch?v=..., youtu.be/..., shorts/..., embed/...) hoặc mã <iframe src=...>" class="flex-1 bg-slate-900 border border-slate-700 rounded-xl px-3 py-2 text-xs text-white focus:outline-none focus:border-amber-500">
<button onclick="loadCustomIframe()" class="px-4 py-2 bg-gradient-to-r from-amber-500 to-orange-500 text-black font-bold rounded-xl hover:from-amber-400 hover:to-orange-400 transition whitespace-nowrap shadow-md">
Phát Iframe Ngay
</button>
</div>
<div class="flex flex-wrap items-center justify-between text-[11px] text-slate-400 pt-1 border-t border-slate-800/80 gap-2">
<div class="flex items-center gap-1.5">
<span class="text-amber-400">💡 Tự động thông minh:</span>
<span>Hỗ trợ mọi dạng link YouTube (watch, share, shorts) tự chuyển thành chuẩn Embed không bị chặn.</span>
</div>
<div class="flex items-center gap-2">
<a id="btn-open-direct-yt" href="#" target="_blank" class="hidden text-emerald-400 hover:underline items-center gap-1">
<span>↗️</span> Mở trên YouTube
</a>
</div>
</div>
</div>
<!-- DANH SÁCH TẬP (NẰM NGAY BÊN DƯỚI PHẦN SERVER) -->
<div class="p-4 bg-slate-950/80 border border-slate-800 rounded-2xl space-y-3">
<div class="flex items-center justify-between border-b border-slate-800/80 pb-2.5">
<div class="flex items-center gap-2 text-xs font-bold text-white uppercase tracking-wider">
<span class="text-amber-400">📑</span>
<span>Danh Sách Tập Phim</span>
<span class="text-[11px] text-slate-400 font-normal font-sans" id="modal-total-eps-label">(Tập 1 - 115)</span>
</div>
<span class="text-[11px] text-amber-400 font-semibold" id="modal-player-ep-indicator">Đang xem: Tập 115</span>
</div>
<!-- Grid các nút chọn tập hiển thị dàn hàng ngang rộng rãi dưới video -->
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 xl:grid-cols-8 gap-2 max-h-60 overflow-y-auto custom-scrollbar p-1" id="modal-episodes-list">
<!-- Injected by JS -->
</div>
</div>
<!-- Movie Description / Tóm tắt nội dung phim -->
<div class="p-4 bg-slate-950/80 rounded-2xl border border-slate-800 space-y-2">
<div class="flex items-center gap-2 text-xs font-bold text-amber-400 uppercase tracking-wider">
<span>📜</span>
<span>Tóm Tắt Nội Dung Phim</span>
</div>
<p class="text-xs sm:text-sm text-slate-300 leading-relaxed" id="modal-player-desc"></p>
</div>
<!-- PHẦN BÌNH LUẬN Ở CUỐI TÓM TẮT NỘI DUNG PHIM -->
<div class="p-4 sm:p-5 bg-slate-950/90 border border-slate-800 rounded-2xl space-y-4" id="movie-comments-container">
<div class="flex items-center justify-between border-b border-slate-800 pb-3">
<div class="flex items-center gap-2 text-xs sm:text-sm font-bold text-white uppercase tracking-wider">
<span class="text-amber-400 text-base">💬</span>
<span>Đạo Hữu Luận Bàn & Đánh Giá</span>
<span class="text-[11px] font-normal text-slate-400 font-sans" id="movie-comments-count">(3 bình luận)</span>
</div>
<div class="text-[11px] text-amber-300 flex items-center gap-1.5 font-medium bg-amber-500/10 border border-amber-500/20 px-2.5 py-1 rounded-full">
<span>✨</span> +5 Tu Vi khi bình luận
</div>
</div>
<!-- Khung Nhập Bình Luận Của Đạo Hữu -->
<div class="p-3 bg-slate-900/90 border border-slate-800 rounded-xl space-y-2.5">
<div class="flex items-center justify-between text-xs">
<div class="flex items-center gap-2">
<div class="w-6 h-6 rounded-full bg-gradient-to-tr from-amber-500 to-orange-500 text-black font-extrabold flex items-center justify-center text-[10px]">
ĐH
</div>
<span class="text-slate-200 font-bold" id="comment-current-user">Bắc Minh Chân Nhân</span>
<span class="px-1.5 py-0.5 rounded bg-amber-500/10 text-amber-400 border border-amber-500/30 text-[10px] font-medium" id="comment-current-realm">Hóa Thần Kỳ</span>
</div>
<div class="flex items-center gap-1.5 text-slate-400 text-xs">
<span class="text-[10px] text-slate-500">Biểu cảm:</span>
<button type="button" onclick="addCommentEmoji('🔥')" class="hover:scale-125 transition" title="Cháy">🔥</button>
<button type="button" onclick="addCommentEmoji('⚔️')" class="hover:scale-125 transition" title="Chiến">⚔️</button>
<button type="button" onclick="addCommentEmoji('☯️')" class="hover:scale-125 transition" title="Đạo">☯️</button>
<button type="button" onclick="addCommentEmoji('🍿')" class="hover:scale-125 transition" title="Hóng">🍿</button>
<button type="button" onclick="addCommentEmoji('💯')" class="hover:scale-125 transition" title="Đỉnh">💯</button>
</div>
</div>
<div>
<textarea id="movie-comment-textarea" rows="2" placeholder="Đạo hữu có suy nghĩ gì về bộ phim và tình tiết tập này? Hãy phát biểu luận điểm..." class="w-full bg-slate-950 border border-slate-700/80 rounded-xl p-3 text-xs text-white placeholder-slate-500 focus:outline-none focus:border-amber-500 transition resize-none"></textarea>
</div>
<div class="flex items-center justify-between pt-0.5">
<span class="text-[10px] text-slate-500">
ℹ️ Tuân thủ tông quy, không thóa mạ đồng đạo hoặc spoil phim
</span>
<button onclick="handlePostMovieComment()" class="px-4 py-1.5 rounded-xl bg-gradient-to-r from-amber-500 to-orange-500 text-black font-extrabold text-xs hover:from-amber-400 hover:to-orange-400 shadow-md shadow-amber-500/20 transition active:scale-95 flex items-center gap-1.5">
<span>🚀</span> Gửi Bình Luận
</button>
</div>
</div>
<!-- Danh Sách Các Bình Luận Của Phim -->
<div class="space-y-3 max-h-80 overflow-y-auto custom-scrollbar pr-1" id="movie-comments-list">
<!-- Rendered by JS per movie -->
</div>
</div>
</div>
<!-- RIGHT SIDEBAR (1 col): DANH SÁCH CÁC PHIM MỚI ĐĂNG -->
<div class="bg-slate-950 border border-slate-800 rounded-2xl p-4 flex flex-col h-full max-h-[640px]">
<div class="flex items-center justify-between border-b border-slate-800 pb-2.5 mb-3 flex-shrink-0">
<div class="text-xs font-bold text-white flex items-center gap-1.5 uppercase tracking-wider">
<span>🔥</span> Phim Mới Đăng
</div>
<span class="text-[10px] bg-amber-500/10 text-amber-300 border border-amber-500/30 px-2 py-0.5 rounded-full font-medium">Đề cử</span>
</div>
<!-- Danh sách phim mới đăng cuộn dọc mượt mà -->
<div class="flex-1 overflow-y-auto custom-scrollbar pr-1 space-y-2.5" id="modal-recent-movies-list">
<!-- Injected by JS -->
</div>
</div>
</div>
</div>
</div>
<!-- ================================================== -->
<!-- 7. MODAL: ĐĂNG KÝ & ĐĂNG NHẬP TU TIÊN (AUTH SYSTEM) -->
<!-- ================================================== -->
<div id="modal-auth" class="hidden fixed inset-0 z-50 bg-black/85 backdrop-blur-md flex items-center justify-center p-3 sm:p-4">
<div class="bg-gradient-to-b from-slate-900 via-slate-900 to-slate-950 border border-amber-500/40 rounded-3xl max-w-md w-full p-5 sm:p-6 space-y-4 shadow-2xl relative custom-scrollbar max-h-[92vh] overflow-y-auto">
<!-- Nút đóng modal -->
<button onclick="closeAuthModal()" class="absolute top-4 right-4 text-slate-400 hover:text-white text-xl w-8 h-8 rounded-full bg-slate-800/60 hover:bg-slate-800 flex items-center justify-center transition">×</button>
<!-- Logo và Tiêu đề -->
<div class="text-center space-y-1.5 pt-1">
<img src="logo.jpg"
onerror="this.onerror=null; this.src='/logo.jpg';"
alt="Logo"
class="w-14 h-14 mx-auto rounded-full object-cover border-2 border-amber-500/60 shadow-lg shadow-amber-500/30">
<h3 class="text-base sm:text-lg font-black text-amber-300 uppercase tracking-wider font-cinzel gold-gradient-text" id="auth-modal-title">
CỔNG ĐẠO MINH SÂM
</h3>
<p class="text-[11px] text-slate-400" id="auth-modal-subtitle">
Nhập sơn hôm nay, lưu danh thiên bảng
</p>
</div>
<!-- TABS CHUYỂN ĐỔI: ĐĂNG NHẬP / ĐĂNG KÝ -->
<div class="grid grid-cols-2 p-1 bg-slate-950/90 border border-slate-800 rounded-2xl text-xs font-bold">
<button id="auth-tab-btn-login" onclick="switchAuthTab('login')" class="py-2.5 rounded-xl transition flex items-center justify-center gap-1.5 bg-gradient-to-r from-amber-500 to-orange-500 text-black shadow">
<span>🔑</span> Đăng Nhập
</button>
<button id="auth-tab-btn-register" onclick="switchAuthTab('register')" class="py-2.5 rounded-xl transition flex items-center justify-center gap-1.5 text-slate-400 hover:text-white">
<span>✨</span> Đăng Ký (Nhập Sơn)
</button>
</div>
<!-- FORM 1: ĐĂNG NHẬP -->
<div id="auth-form-login" class="space-y-3.5">
<div class="space-y-3 text-xs">
<div>
<label class="block text-slate-300 font-semibold mb-1 flex items-center justify-between">
<span>Tên Đăng Nhập / Email / Đạo Hiệu</span>
<span class="text-[10px] text-amber-400 font-normal">*Bắt buộc</span>
</label>
<div class="relative">
<input
type="text"
id="auth-login-account"
placeholder="Nhập username hoặc đạo hiệu..."
class="w-full bg-slate-950 border border-slate-700/80 rounded-xl py-2.5 pl-9 pr-3 text-xs text-white placeholder-slate-500 focus:outline-none focus:border-amber-500 transition"
>
<span class="absolute left-3 top-2.5 text-slate-500">👤</span>
</div>
</div>
<div>
<label class="block text-slate-300 font-semibold mb-1 flex items-center justify-between">
<span>Mật Khẩu Tu Chân</span>
<button type="button" onclick="showToast('💡 Mật khẩu tài khoản mẫu là: 123')" class="text-[10px] text-amber-400 hover:underline">Quên mật khẩu?</button>
</label>
<div class="relative">
<input
type="password"
id="auth-login-password"
placeholder="Nhập mật khẩu..."
class="w-full bg-slate-950 border border-slate-700/80 rounded-xl py-2.5 pl-9 pr-10 text-xs text-white placeholder-slate-500 focus:outline-none focus:border-amber-500 transition"
>
<span class="absolute left-3 top-2.5 text-slate-500">🔒</span>
<button type="button" onclick="togglePasswordVisibility('auth-login-password', this)" class="absolute right-3 top-2.5 text-slate-400 hover:text-amber-400 text-xs">
👁️
</button>
</div>
</div>
<div class="flex items-center justify-between text-[11px] text-slate-400 pt-0.5">
<label class="flex items-center gap-1.5 cursor-pointer select-none">
<input type="checkbox" id="auth-login-remember" checked class="rounded border-slate-700 text-amber-500 focus:ring-0 bg-slate-950">
<span>Ghi nhớ tu vi trên thiết bị này</span>
</label>
</div>
</div>
<button onclick="handleLoginSubmit()" class="w-full py-3 rounded-xl bg-gradient-to-r from-amber-500 via-orange-500 to-amber-600 text-black font-extrabold text-xs hover:from-amber-400 hover:to-orange-400 shadow-lg shadow-amber-500/25 transition flex items-center justify-center gap-2 active:scale-98">
<span>⚡</span> Đăng Nhập Minh Sâm
</button>
<!-- ĐĂNG NHẬP NHANH BẰNG TÀI KHOẢN MẪU -->
<div class="pt-2 border-t border-slate-800/80 space-y-2">
<div class="text-[11px] text-slate-400 font-medium flex items-center justify-between">
<span>⚡ Hoặc đăng nhập nhanh bằng tài khoản có sẵn:</span>
</div>
<div class="grid grid-cols-3 gap-2 text-[10px]">
<button onclick="quickFillAccount('bacminh', '123')" class="p-2 rounded-xl bg-slate-950/80 hover:bg-slate-800 border border-slate-800 hover:border-amber-500/50 text-slate-300 hover:text-white transition text-center space-y-0.5">
<div class="font-bold text-amber-400 truncate">Bắc Minh</div>
<div class="text-[9px] text-slate-400">Kim Đan Kỳ</div>
</button>
<button onclick="quickFillAccount('hanlap', '123')" class="p-2 rounded-xl bg-slate-950/80 hover:bg-slate-800 border border-slate-800 hover:border-amber-500/50 text-slate-300 hover:text-white transition text-center space-y-0.5">
<div class="font-bold text-amber-400 truncate">Hàn Thần Ma</div>
<div class="text-[9px] text-slate-400">Hóa Thần Kỳ</div>
</button>
<button onclick="quickFillAccount('tieuviem', '123')" class="p-2 rounded-xl bg-slate-950/80 hover:bg-slate-800 border border-slate-800 hover:border-amber-500/50 text-slate-300 hover:text-white transition text-center space-y-0.5">
<div class="font-bold text-amber-400 truncate">Viêm Đế</div>
<div class="text-[9px] text-slate-400">Đấu Thánh</div>
</button>
</div>
</div>
<div class="text-center text-xs text-slate-400 pt-1">
Chưa có đạo tịch tông môn?
<button onclick="switchAuthTab('register')" class="text-amber-400 font-bold hover:underline ml-1">Đăng ký nhập sơn ngay</button>
</div>
</div>
<!-- FORM 2: ĐĂNG KÝ (NHẬP SƠN) -->
<div id="auth-form-register" class="hidden space-y-3.5">
<!-- QUÀ TÂN THỦ BANNER -->
<div class="p-2.5 rounded-xl bg-amber-500/10 border border-amber-500/30 flex items-center gap-2.5 text-xs text-amber-200">
<span class="text-xl flex-shrink-0">🎁</span>
<div class="text-[11px] leading-tight">
<strong class="text-amber-400 font-bold">Phúc Lợi Nhập Môn:</strong> Tặng ngay <strong>+100 Tu Vi</strong>, <strong>+50 Linh Thạch</strong> và cấp chứng nhận Đạo Tịch!
</div>
</div>
<div class="space-y-2.5 text-xs">
<div>
<label class="block text-slate-300 font-semibold mb-1">
Tên Tài Khoản (Username)
</label>
<div class="relative">
<input
type="text"
id="auth-reg-username"
placeholder="Ví dụ: daohuukiem (viết liền không dấu)..."
class="w-full bg-slate-950 border border-slate-700/80 rounded-xl py-2.5 pl-9 pr-3 text-xs text-white placeholder-slate-500 focus:outline-none focus:border-amber-500 transition"
>
<span class="absolute left-3 top-2.5 text-slate-500">🪪</span>
</div>
</div>
<div>
<label class="block text-slate-300 font-semibold mb-1">
Đạo Hiệu Tu Chân (Tên hiển thị)
</label>
<div class="relative">
<input
type="text"
id="auth-reg-daohieu"
placeholder="Ví dụ: Vô Danh Kiếm Tiên, Dạ Vũ Cư Sĩ..."
class="w-full bg-slate-950 border border-slate-700/80 rounded-xl py-2.5 pl-9 pr-3 text-xs text-white placeholder-slate-500 focus:outline-none focus:border-amber-500 transition"
>
<span class="absolute left-3 top-2.5 text-slate-500">⚔️</span>
</div>
</div>
<div>
<label class="block text-slate-300 font-semibold mb-1">
Email Liên Lạc (Tùy chọn)
</label>
<div class="relative">
<input
type="email"
id="auth-reg-email"
placeholder="daohuu@gmail.com..."
class="w-full bg-slate-950 border border-slate-700/80 rounded-xl py-2.5 pl-9 pr-3 text-xs text-white placeholder-slate-500 focus:outline-none focus:border-amber-500 transition"
>
<span class="absolute left-3 top-2.5 text-slate-500">✉️</span>
</div>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2.5">
<div>
<label class="block text-slate-300 font-semibold mb-1">Mật Khẩu</label>
<div class="relative">
<input
type="password"
id="auth-reg-password"
placeholder="Tối thiểu 3 ký tự..."
class="w-full bg-slate-950 border border-slate-700/80 rounded-xl py-2.5 pl-8 pr-8 text-xs text-white placeholder-slate-500 focus:outline-none focus:border-amber-500 transition"
>
<span class="absolute left-2.5 top-2.5 text-slate-500">🔒</span>
<button type="button" onclick="togglePasswordVisibility('auth-reg-password', this)" class="absolute right-2.5 top-2.5 text-slate-400 hover:text-amber-400 text-xs">
👁️
</button>
</div>
</div>
<div>
<label class="block text-slate-300 font-semibold mb-1">Nhập Lại Mật Khẩu</label>
<div class="relative">
<input
type="password"
id="auth-reg-repassword"
placeholder="Xác nhận lại..."
class="w-full bg-slate-950 border border-slate-700/80 rounded-xl py-2.5 pl-8 pr-8 text-xs text-white placeholder-slate-500 focus:outline-none focus:border-amber-500 transition"
>
<span class="absolute left-2.5 top-2.5 text-slate-500">🔒</span>
<button type="button" onclick="togglePasswordVisibility('auth-reg-repassword', this)" class="absolute right-2.5 top-2.5 text-slate-400 hover:text-amber-400 text-xs">
👁️
</button>
</div>
</div>
</div>
<div>
<label class="block text-slate-300 font-semibold mb-1">Gia Nhập Tông Môn Ban Đầu</label>
<div class="relative">
<select id="auth-reg-sect" class="w-full bg-slate-950 border border-slate-700/80 rounded-xl py-2.5 pl-9 pr-3 text-xs text-white focus:outline-none focus:border-amber-500 transition">
<option value="Minh Sâm Chánh Tông">🏔️ Minh Sâm Chánh Tông</option>
<option value="Hoàng Phong Cốc">🍂 Hoàng Phong Cốc (Tu Tiên Phàm Nhân)</option>
<option value="Gia Nam Học Viện">🔥 Gia Nam Học Viện (Đấu Khí Tiêu Viêm)</option>
<option value="Bổ Thiên Các">🏛️ Bổ Thiên Các (Thế Giới Hoàn Mỹ)</option>
<option value="Cực Âm Tông">🌑 Cực Âm Tông (Ma Đạo Nghịch Tu)</option>
<option value="Linh Khê Tông">💧 Linh Khê Tông (Nhất Niệm Vĩnh Hằng)</option>
</select>
<span class="absolute left-3 top-2.5 text-slate-500">🏯</span>
</div>
</div>
</div>
<button onclick="handleRegisterSubmit()" class="w-full py-3 rounded-xl bg-gradient-to-r from-amber-500 via-orange-500 to-amber-600 text-black font-extrabold text-xs hover:from-amber-400 hover:to-orange-400 shadow-lg shadow-amber-500/25 transition flex items-center justify-center gap-2 active:scale-98">
<span>🔥</span> Đăng Ký Tài Khoản & Nhập Sơn
</button>
<div class="text-center text-xs text-slate-400 pt-1">
Đã có đạo tịch tông môn?
<button onclick="switchAuthTab('login')" class="text-amber-400 font-bold hover:underline ml-1">Đăng nhập ngay</button>
</div>
</div>
</div>
</div>
<!-- MODAL: ĐỔI THÔNG TIN / ĐẠO HIỆU / MẬT KHẨU -->
<div id="modal-change-profile" class="hidden fixed inset-0 z-50 bg-black/85 backdrop-blur-sm flex items-center justify-center p-4">
<div class="bg-slate-900 border border-amber-500/40 rounded-3xl max-w-md w-full p-6 space-y-4 shadow-2xl relative">
<button onclick="closeModal('change-profile')" class="absolute top-4 right-4 text-slate-400 hover:text-white text-lg">×</button>
<div class="flex items-center gap-3 border-b border-slate-800 pb-3">
<div class="w-10 h-10 rounded-xl bg-amber-500/20 text-amber-400 border border-amber-500/30 flex items-center justify-center text-lg">
⚙️
</div>
<div>
<h3 class="text-sm font-bold text-white uppercase">Cài Đặt Đạo Tịch</h3>
<p class="text-[11px] text-slate-400">Thay đổi Đạo Hiệu, Tông Môn và Mật Khẩu</p>
</div>
</div>
<div class="space-y-3 text-xs">
<div>
<label class="block text-slate-300 font-semibold mb-1">Đạo Hiệu Mới</label>
<input type="text" id="input-edit-daohieu" class="w-full bg-slate-950 border border-slate-700/80 rounded-xl p-2.5 text-xs text-white focus:outline-none focus:border-amber-500">
</div>
<div>
<label class="block text-slate-300 font-semibold mb-1">Tông Môn Trực Thuộc</label>
<select id="select-edit-sect" class="w-full bg-slate-950 border border-slate-700/80 rounded-xl p-2.5 text-xs text-white focus:outline-none focus:border-amber-500">
<option value="Minh Sâm Chánh Tông">🏔️ Minh Sâm Chánh Tông</option>
<option value="Hoàng Phong Cốc">🍂 Hoàng Phong Cốc</option>
<option value="Gia Nam Học Viện">🔥 Gia Nam Học Viện</option>
<option value="Bổ Thiên Các">🏛️ Bổ Thiên Các</option>
<option value="Cực Âm Tông">🌑 Cực Âm Tông</option>
<option value="Linh Khê Tông">💧 Linh Khê Tông</option>
</select>
</div>
<div>
<label class="block text-slate-300 font-semibold mb-1">Mật Khẩu Mới (Để trống nếu không đổi)</label>
<input type="password" id="input-edit-pass" placeholder="Nhập mật khẩu mới..." class="w-full bg-slate-950 border border-slate-700/80 rounded-xl p-2.5 text-xs text-white focus:outline-none focus:border-amber-500">
</div>
</div>
<div class="flex items-center gap-2 pt-2">
<button onclick="closeModal('change-profile')" class="flex-1 py-2.5 rounded-xl bg-slate-800 text-slate-300 font-semibold text-xs hover:bg-slate-700">
Hủy
</button>
<button onclick="handleSaveProfileChanges()" class="flex-1 py-2.5 rounded-xl bg-gradient-to-r from-amber-500 to-orange-500 text-black font-bold text-xs hover:from-amber-400 hover:to-orange-400 shadow">
Lưu Cập Nhật
</button>
</div>
</div>
</div>
<!-- MODAL: HỆ THỐNG CẢNH GIỚI TU TIÊN -->
<div id="modal-tu-tien-info" class="hidden fixed inset-0 z-50 bg-black/85 backdrop-blur-sm flex items-center justify-center p-4">
<div class="bg-slate-900 border border-amber-500/40 rounded-3xl max-w-lg w-full p-6 space-y-5 shadow-2xl relative">
<button onclick="closeModal('tu-tien-info')" class="absolute top-4 right-4 text-slate-400 hover:text-white text-lg">×</button>
<div class="flex items-center gap-3">
<div class="w-12 h-12 rounded-2xl bg-amber-500/20 border border-amber-500 flex items-center justify-center text-2xl">
☯️
</div>
<div>
<h3 class="text-base font-bold text-amber-300 uppercase font-cinzel">HỆ THỐNG CẢNH GIỚI TU TIÊN</h3>
<p class="text-xs text-slate-400">Xem phim tích lũy tu vi, độ kiếp thành tiên</p>
</div>
</div>
<div class="space-y-2 text-xs">
<div class="p-3 rounded-xl bg-slate-800/60 border border-slate-700/60 flex items-center justify-between">
<span>1. Luyện Khí Kỳ (Tầng 1 - 9)</span>
<span class="text-slate-400">0 - 500 Tu Vi</span>
</div>
<div class="p-3 rounded-xl bg-slate-800/60 border border-slate-700/60 flex items-center justify-between">
<span>2. Trúc Cơ Kỳ (Sơ - Trung - Hậu)</span>
<span class="text-slate-400">500 - 2,000 Tu Vi</span>
</div>
<div class="p-3 rounded-xl bg-amber-500/20 border border-amber-500 text-amber-200 font-bold flex items-center justify-between">
<span>3. Kim Đan Kỳ (Cảnh giới hiện tại của bạn)</span>
<span class="text-amber-400 font-mono">2,000 - 8,000 Tu Vi</span>
</div>
<div class="p-3 rounded-xl bg-slate-800/60 border border-slate-700/60 flex items-center justify-between">
<span>4. Nguyên Anh Kỳ & Hóa Thần Kỳ</span>
<span class="text-slate-400 font-mono">8,000 - 50,000+ Tu Vi</span>
</div>
</div>
<button onclick="closeModal('tu-tien-info')" class="w-full py-2.5 rounded-xl bg-amber-500 text-black font-bold text-xs hover:bg-amber-400">
Đã Hiểu (Đóng)
</button>
</div>
</div>
<!-- TOAST NOTIFICATION CONTAINER -->
<div id="toast-box" class="fixed bottom-6 right-6 z-50 pointer-events-none space-y-2"></div>
<!-- ========================================== -->
<!-- 8. FOOTER TÔNG MÔN MINH SÂM -->
<!-- ========================================== -->
<footer class="border-t border-slate-800 bg-[#060910] py-12 text-xs text-slate-400">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 space-y-8">
<div class="grid grid-cols-1 md:grid-cols-4 gap-8">
<div class="md:col-span-2 space-y-3">
<div class="flex items-center gap-3">
<img src="logo.jpg" onerror="this.onerror=null; this.src='/logo.jpg';" alt="Logo" class="w-11 h-11 rounded-full object-cover border border-amber-500/50 shadow-md shadow-amber-500/20">
<span class="text-base font-black text-white font-cinzel tracking-wider uppercase">CỔNG PHIM DONGHUA</span>
</div>
<p class="text-slate-400 leading-relaxed max-w-md">
Cổng thông tin giải trí & phim hoạt hình 3D Trung Quốc (Donghua) hàng đầu. Nơi hội tụ các siêu phẩm Tu Tiên, Huyền Huyễn, Xuyên Không, Trùng Sinh cùng hệ thống Gamification tu chân độc nhất vô nhị.
</p>
<div class="text-amber-400/90 font-medium italic">
"Nhập sơn hôm nay, lưu danh thiên bảng"
</div>
</div>
<div class="space-y-2">
<h4 class="text-xs font-bold text-slate-200 uppercase tracking-wider">Danh Mục Nổi Bật</h4>
<ul class="space-y-1.5 text-slate-400">
<li><a href="#" onclick="filterGenre('tu-tien')" class="hover:text-amber-400">Donghua Tu Tiên</a></li>
<li><a href="#" onclick="filterGenre('huyen-huyen')" class="hover:text-amber-400">Donghua Huyền Huyễn</a></li>
<li><a href="#" onclick="filterGenre('xuyen-khong')" class="hover:text-amber-400">Xuyên Không • Hệ Thống</a></li>
<li><a href="#section-schedule" class="hover:text-amber-400">Lịch Chiếu Phim</a></li>
</ul>
</div>
<div class="space-y-2">
<h4 class="text-xs font-bold text-slate-200 uppercase tracking-wider">Thông Tin Tông Môn</h4>
<ul class="space-y-1.5 text-slate-400">
<li><a href="#" onclick="openModal('tu-tien-info')" class="hover:text-amber-400">Quy Tắc Đột Phá Cảnh Giới</a></li>
<li><a href="#" class="hover:text-amber-400">Báo Lỗi Tập Phim</a></li>
<li><a href="#" class="hover:text-amber-400">Miễn Trừ Trách Nhiệm</a></li>
<li><a href="#section-luan-dao" class="hover:text-amber-400">Lôi Đài Luận Đạo</a></li>
</ul>
</div>
</div>
<div class="pt-6 border-t border-slate-800/80 flex flex-col sm:flex-row items-center justify-between gap-4 text-[11px] text-slate-500">
<div>© 2026 MINH SÂM (minhsam.vn). Tất cả nội dung được tổng hợp phục vụ cộng đồng tu tiên.</div>
<div>Tối ưu HLS Streaming 4K • ArtPlayer Engine</div>
</div>
</div>
</footer>
<!-- ========================================== -->
<!-- 9. SCRIPT CHÍNH & XỬ LÝ DỮ LIỆU ĐỒNG BỘ -->
<!-- ========================================== -->
<script>
// DATA MẪU PHIM CHUẨN MINH SÂM (CÁC SIÊU PHẨM DONGHUA THEO ẢNH MẪU MOBILE & DESKTOP)
const SCREENSHOT_MOVIES = [];
let MOVIES_DATABASE = [];
// STATE TÀI KHOẢN VÀ NGƯỜI DÙNG TU TIÊN
const DEFAULT_ACCOUNTS = [
{
username: "bacminh",
password: "123",
name: "Bắc Minh Chân Nhân",
email: "bacminh@phimfull.pro",
realm: "Kim Đan Kỳ (Tầng 4)",
tuVi: 3450,
linhThach: 1250,
sect: "Minh Sâm Chánh Tông",
checkedIn: false
},
{
username: "hanlap",
password: "123",
name: "Hàn Thần Ma",
email: "hanlap@hoangphongcoc.vn",
realm: "Hóa Thần Kỳ (Tầng 9)",
tuVi: 98420,
linhThach: 15600,
sect: "Hoàng Phong Cốc",
checkedIn: true
},
{
username: "tieuviem",
password: "123",
name: "Viêm Đế Tiêu Viêm",
email: "tieuviem@gianam.edu.vn",
realm: "Đấu Thánh (Tầng 7)",
tuVi: 85210,
linhThach: 9800,
sect: "Gia Nam Học Viện",
checkedIn: false
}
];
let currentUser = null; // Đối tượng người dùng đang đăng nhập (mặc định là Khách)
let userState = null; // Tương thích ngược
let artPlayerInstance = null;
let currentMovie = null;
let currentEpisode = 1;
let watchTimer = null;
// STATE BỘ LỌC, TÌM KIẾM, SẮP XẾP & PHÂN TRANG (16 PHIM / TRANG)
let currentStatusFilter = 'all';
let currentGenreFilter = 'all';
let currentSortFilter = 'newest';
let currentSearchKeyword = '';
const MOVIES_PER_PAGE = 16;
let currentMoviePage = 1;
// ==================================================
// HỆ THỐNG ĐƯỜNG DẪN TỪNG BỘ PHIM: tenmien.com/phim/ten-phim
// ==================================================
const API_BASE = (window.location.protocol === 'file:') ? '' : '/';
// Chuyển tiêu đề phim thành slug URL chuẩn (ví dụ: "Phàm Nhân Tu Tiên" -> "phan-nhan-tu-tien")
function generateSlug(str) {
if (!str) return '';
return str.toString().toLowerCase()
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.replace(/[đĐ]/g, 'd')
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '');
}
// Lấy slug duy nhất của bộ phim
function getMovieSlug(movie) {
if (!movie) return '';
if (movie.slug && movie.slug.trim()) return movie.slug.trim();
if (movie.id && /^[a-z0-9-]+$/.test(movie.id)) return movie.id;
return generateSlug(movie.title) || movie.id || 'phim';
}
// Lấy đường dẫn xem phim (hỗ trợ cả web server và mở file offline)
function getMovieUrl(movie, ep = null) {
const slug = getMovieSlug(movie);
const epSuffix = (ep && ep > 1) ? `?tap=${ep}` : '';
if (window.location.protocol === 'file:') {
return `#/phim/${slug}${epSuffix}`;
}
return `/phim/${slug}${epSuffix}`;
}
// Tìm phim theo slug hoặc id hoặc tiêu đề
function findMovieBySlugOrId(slugOrId) {
if (!slugOrId) return null;
const clean = decodeURIComponent(slugOrId).toLowerCase().trim();
// 1. Khớp chính xác ID
let found = MOVIES_DATABASE.find(m => m.id && m.id.toLowerCase() === clean);
if (found) return found;
// 2. Khớp thuộc tính slug (nếu có)
found = MOVIES_DATABASE.find(m => m.slug && m.slug.toLowerCase() === clean);
if (found) return found;
// 3. Khớp theo slug tạo từ tiêu đề tiếng Việt
found = MOVIES_DATABASE.find(m => m.title && generateSlug(m.title) === clean);
if (found) return found;
// 4. Khớp gần đúng (bắt đầu hoặc chứa slug)
found = MOVIES_DATABASE.find(m => m.id && (m.id.toLowerCase().startsWith(clean) || clean.startsWith(m.id.toLowerCase())));
if (found) return found;
found = MOVIES_DATABASE.find(m => m.title && (generateSlug(m.title).startsWith(clean) || clean.startsWith(generateSlug(m.title))));
return found || null;
}
// Cập nhật thanh địa chỉ URL của trình duyệt thành tenmien.com/phim/ten-phim
function updateMovieBrowserUrl(movie, ep) {
if (!movie) return;
const slug = getMovieSlug(movie);
const epSuffix = (ep && ep > 1) ? `?tap=${ep}` : '';
if (window.location.protocol === 'file:') {
window.location.hash = `/phim/${slug}${epSuffix}`;
return;
}
const targetPath = `/phim/${slug}${epSuffix}`;
try {
const currentPathAndQuery = window.location.pathname + window.location.search;
if (currentPathAndQuery !== targetPath) {
window.history.pushState({ movieId: movie.id, ep: ep }, '', targetPath);
}
} catch (e) {
window.location.hash = `/phim/${slug}${epSuffix}`;
}
}
// Xóa slug trên URL khi đóng modal xem phim (trở về trang chủ)
function clearMovieBrowserUrl() {
if (window.location.protocol === 'file:') {
if (window.location.hash.includes('/phim/')) {
window.location.hash = '';
}
return;
}
try {
const homePath = window.location.pathname.includes('index.html') ? 'index.html' : '/';
if (window.location.pathname.includes('/phim/')) {
window.history.pushState(null, '', homePath);
}
} catch (e) {
window.location.hash = '';
}
}
// ==================================================
// HỆ THỐNG SEO ĐỘNG CHO TỪNG BỘ PHIM
// (Title: Tên phim, Description: Tóm tắt nội dung phim)
// ==================================================
const DEFAULT_SEO = {
title: "Phim Full, Xem Phim AI, Phim Xuyên Không, Hệ Thống, Tu Tiên Cập Nhật Mỗi Ngày",
description: "Phim AI, Phim Hoạt Hình AI, Phim Ngắn AI, Phim Do AI Tạo Ra, Phim AI Trung Quốc, Phim Cổ Trang AI, Phim Tiên Hiệp AI, Phim Xuyên Không AI, Phim Tận Thế AI, Phim Sinh Tồn AI, Phim AI Full HD, Phim AI Mới Nhất",
keywords: "Phim AI, Phim Hoạt Hình AI, Phim Ngắn AI, Phim Do AI Tạo Ra, Phim AI Trung Quốc, Phim Cổ Trang AI, Phim Tiên Hiệp AI, Phim Xuyên Không AI, Phim Tận Thế AI, Phim Sinh Tồn AI, Phim AI Full HD, Phim AI Mới Nhất",
image: "logo.jpg",
type: "website"
};
function updateMovieSEO(movie, epData = null) {
if (!movie) return;
// 1. Thẻ Title: CHÍNH XÁC là tên phim theo đúng yêu cầu
const movieTitle = (movie.title || 'Xem Phim').trim();
document.title = movieTitle;
// Cập nhật tất cả các thẻ <title> trong DOM
const titleTags = document.querySelectorAll('title, #seo-title');
titleTags.forEach(el => {
el.textContent = movieTitle;
el.innerText = movieTitle;
});
// Cập nhật thẻ <meta name="title">
const metaTitles = document.querySelectorAll('meta[name="title"], #seo-meta-title');
metaTitles.forEach(el => el.setAttribute('content', movieTitle));
// 2. Thẻ Description: CHÍNH XÁC là nội dung tóm tắt của phim theo đúng yêu cầu
const movieDesc = (movie.desc && movie.desc.trim())
? movie.desc.trim()
: `Tóm tắt nội dung phim ${movieTitle}: Xem trọn bộ Full HD Vietsub Thuyết Minh mới nhất tại Phim Full.`;
// Cập nhật tất cả thẻ meta description trong DOM
const metaDescs = document.querySelectorAll('meta[name="description"], #seo-meta-desc');
if (metaDescs.length > 0) {
metaDescs.forEach(el => el.setAttribute('content', movieDesc));
} else {
const meta = document.createElement('meta');
meta.name = 'description';
meta.id = 'seo-meta-desc';
meta.content = movieDesc;
document.head.appendChild(meta);
}
// 3. Keywords
const genreLabels = (typeof getMovieGenresList === 'function' && typeof getGenreLabel === 'function')
? getMovieGenresList(movie).map(g => getGenreLabel(g)).join(', ')
: 'Tu Tiên, Huyền Huyễn';
const seoKeywords = `${movieTitle}, xem phim ${movieTitle}, ${movieTitle} trọn bộ, ${movieTitle} full hd, phim hoạt hình 3d, donghua, ${genreLabels}`;
const metaKeywords = document.querySelectorAll('meta[name="keywords"], #seo-meta-keywords');
metaKeywords.forEach(el => el.setAttribute('content', seoKeywords));
// 4. Canonical URL
const slug = (typeof getMovieSlug === 'function') ? getMovieSlug(movie) : (movie.id || 'phim');
const canonicalUrl = (window.location.protocol === 'file:')
? window.location.href.split('#')[0] + `#/phim/${slug}`
: `${window.location.origin}/phim/${slug}`;
const canonicals = document.querySelectorAll('link[rel="canonical"], #seo-canonical');
canonicals.forEach(el => el.setAttribute('href', canonicalUrl));
// 5. Open Graph (Facebook / Zalo / Telegram...)
const ogTitles = document.querySelectorAll('meta[property="og:title"], #seo-og-title');
ogTitles.forEach(el => el.setAttribute('content', movieTitle));
const ogDescs = document.querySelectorAll('meta[property="og:description"], #seo-og-desc');
ogDescs.forEach(el => el.setAttribute('content', movieDesc));
const ogUrls = document.querySelectorAll('meta[property="og:url"], #seo-og-url');
ogUrls.forEach(el => el.setAttribute('content', canonicalUrl));
const ogTypes = document.querySelectorAll('meta[property="og:type"], #seo-og-type');
ogTypes.forEach(el => el.setAttribute('content', 'video.movie'));
// 6. Twitter Cards
const twTitles = document.querySelectorAll('meta[name="twitter:title"], #seo-tw-title');
twTitles.forEach(el => el.setAttribute('content', movieTitle));
const twDescs = document.querySelectorAll('meta[name="twitter:description"], #seo-tw-desc');
twDescs.forEach(el => el.setAttribute('content', movieDesc));
const twUrls = document.querySelectorAll('meta[name="twitter:url"], #seo-tw-url');
twUrls.forEach(el => el.setAttribute('content', canonicalUrl));
// 7. Hình ảnh đại diện
const fullImg = (movie.image && movie.image.startsWith('http'))
? movie.image
: (window.location.origin + '/' + (movie.image || 'logo.jpg'));
const ogImages = document.querySelectorAll('meta[property="og:image"], #seo-og-image');
ogImages.forEach(el => el.setAttribute('content', fullImg));
const twImages = document.querySelectorAll('meta[name="twitter:image"], #seo-tw-image');
twImages.forEach(el => el.setAttribute('content', fullImg));
// 8. Schema.org JSON-LD cho Google Rich Snippets
const schemaEl = document.getElementById('seo-schema-jsonld');
if (schemaEl) {
const genresList = (typeof getMovieGenresList === 'function' && typeof getGenreLabel === 'function')
? getMovieGenresList(movie).map(g => getGenreLabel(g))
: ['Tu Tiên'];
const schemaObj = {
"@context": "https://schema.org",
"@type": "Movie",
"name": movieTitle,
"headline": movieTitle,
"description": movieDesc,
"image": fullImg,
"url": canonicalUrl,
"genre": genresList,
"datePublished": movie.updateDate || "2026",
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": movie.rating ? String(movie.rating) : "9.8",
"bestRating": "10",
"ratingCount": String(movie.views ? Math.max(120, Math.floor(movie.views / 150)) : "520")
}
};
schemaEl.textContent = JSON.stringify(schemaObj, null, 2);
}
}
function resetDefaultSEO() {
document.title = DEFAULT_SEO.title;
const titleTags = document.querySelectorAll('title, #seo-title');
titleTags.forEach(el => {
el.textContent = DEFAULT_SEO.title;
el.innerText = DEFAULT_SEO.title;
});
const metaTitles = document.querySelectorAll('meta[name="title"], #seo-meta-title');
metaTitles.forEach(el => el.setAttribute('content', DEFAULT_SEO.title));
const metaDescs = document.querySelectorAll('meta[name="description"], #seo-meta-desc');
metaDescs.forEach(el => el.setAttribute('content', DEFAULT_SEO.description));
const metaKeywords = document.querySelectorAll('meta[name="keywords"], #seo-meta-keywords');
metaKeywords.forEach(el => el.setAttribute('content', DEFAULT_SEO.keywords));
const homeUrl = (window.location.protocol === 'file:') ? window.location.href.split('#')[0] : (window.location.origin + '/');
const canonicals = document.querySelectorAll('link[rel="canonical"], #seo-canonical');
canonicals.forEach(el => el.setAttribute('href', homeUrl));
const ogTitles = document.querySelectorAll('meta[property="og:title"], #seo-og-title');
ogTitles.forEach(el => el.setAttribute('content', DEFAULT_SEO.title));
const ogDescs = document.querySelectorAll('meta[property="og:description"], #seo-og-desc');
ogDescs.forEach(el => el.setAttribute('content', DEFAULT_SEO.description));
const ogUrls = document.querySelectorAll('meta[property="og:url"], #seo-og-url');
ogUrls.forEach(el => el.setAttribute('content', homeUrl));
const ogTypes = document.querySelectorAll('meta[property="og:type"], #seo-og-type');
ogTypes.forEach(el => el.setAttribute('content', 'website'));
const ogImages = document.querySelectorAll('meta[property="og:image"], #seo-og-image');
ogImages.forEach(el => el.setAttribute('content', (window.location.protocol === 'file:') ? 'logo.jpg' : (window.location.origin + '/logo.jpg')));
const twTitles = document.querySelectorAll('meta[name="twitter:title"], #seo-tw-title');
twTitles.forEach(el => el.setAttribute('content', DEFAULT_SEO.title));
const twDescs = document.querySelectorAll('meta[name="twitter:description"], #seo-tw-desc');
twDescs.forEach(el => el.setAttribute('content', DEFAULT_SEO.description));
const twUrls = document.querySelectorAll('meta[name="twitter:url"], #seo-tw-url');
twUrls.forEach(el => el.setAttribute('content', homeUrl));
const twImages = document.querySelectorAll('meta[name="twitter:image"], #seo-tw-image');
twImages.forEach(el => el.setAttribute('content', (window.location.protocol === 'file:') ? 'logo.jpg' : (window.location.origin + '/logo.jpg')));
const schemaEl = document.getElementById('seo-schema-jsonld');
if (schemaEl) {
const homeSchema = {
"@context": "https://schema.org",
"@type": "WebSite",
"name": "Phim Full",
"alternateName": ["Phim AI", "Xem Phim AI", "Phim Xuyên Không", "Phim Full HD"],
"url": homeUrl,
"description": DEFAULT_SEO.description
};
schemaEl.textContent = JSON.stringify(homeSchema, null, 2);
}
}
// Kiểm tra nhanh URL ngay khi script nạp để thiết lập SEO lập tức (chống giật tiêu đề khi mở deep link)
function initEarlyMovieSEO() {
try {
let slug = window.__INITIAL_MOVIE_ID__ || null;
const path = window.location.pathname;
const match = path.match(/\/(?:phim|movie)\/([^\/?#&]+)/i);
if (match && match[1]) slug = decodeURIComponent(match[1]);
if (!slug) {
const params = new URLSearchParams(window.location.search);
slug = params.get('phim') || params.get('movie') || params.get('id') || params.get('slug');
}
if (!slug && window.location.search) {
const sMatch = window.location.search.match(/(?:phim|movie)\/([^\/?#&]+)/i);
if (sMatch && sMatch[1]) slug = decodeURIComponent(sMatch[1]);
}
if (!slug && window.location.hash) {
const hMatch = window.location.hash.match(/#\/?(?:phim|movie)\/([^\/?#&]+)/i);
if (hMatch && hMatch[1]) slug = decodeURIComponent(hMatch[1]);
}
if (slug) {
slug = slug.replace(/\.(html?|php)$/i, '');
let list = [];
if (typeof MOVIES_DATABASE !== 'undefined' && Array.isArray(MOVIES_DATABASE) && MOVIES_DATABASE.length > 0) {
list = MOVIES_DATABASE;
} else {
const saved = localStorage.getItem('minhsam_movies') || localStorage.getItem('langlangson_movies');
if (saved) {
try { list = JSON.parse(saved); } catch(e){}
}
if (!list || list.length === 0) {
list = (typeof SCREENSHOT_MOVIES !== 'undefined') ? SCREENSHOT_MOVIES : [];
}
}
const clean = slug.toLowerCase().trim();
let found = list.find(m => (m.id && m.id.toLowerCase() === clean) || (m.slug && m.slug.toLowerCase() === clean) || (m.title && generateSlug(m.title) === clean));
if (!found) {
found = list.find(m => (m.id && (m.id.toLowerCase().includes(clean) || clean.includes(m.id.toLowerCase()))) || (m.title && generateSlug(m.title).includes(clean)));
}
if (found) {
updateMovieSEO(found);
}
}
} catch(e) {}
}
// ==================================================
// HỆ THỐNG TRANG CHI TIẾT PHIM CHÍNH (/phim/ten-phim)
// CHUẨN ĐỒ HỌA 100% THEO ẢNH MẪU (HERO + MÙA & TẬP)
// ==================================================
let currentDetailMovie = null;
let currentDetailSeason = null;
let currentDetailEpisode = 1;
let currentDetailServer = 'iframe1';
let isDetailDescExpanded = false;
let detailArtPlayerInstance = null;
// Lấy danh sách tags/badges cho bộ phim (vd: ✨ Nam Chính, 😊 Tu Tiên, 🕒 Nữ Chính, Vả Mặt, 🗂️ Cập nhật...)
function getMovieTags(movie) {
if (!movie) return ['✨ Nam Chính', '😊 Tu Tiên', 'Vả Mặt'];
if (Array.isArray(movie.tags) && movie.tags.length > 0) return movie.tags;
const tags = ['✨ Nam Chính'];
const genres = getMovieGenresList(movie);
if (genres.length > 0) {
tags.push('😊 ' + getGenreLabel(genres[0]));
}
if (genres.length > 1) {
tags.push('🕒 ' + getGenreLabel(genres[1]));
} else {
tags.push('🕒 Nữ Chính');
}
if (movie.status === 'hot' || (movie.rating && movie.rating >= 9.6)) {
tags.push('Vả Mặt');
}
const updateDate = getMovieUpdateBadge(movie);
tags.push(`🗂️ Cập nhật ${updateDate}`);
return tags;
}
// Lấy danh sách các Mùa của bộ phim (vd: Mùa 1-7, Mùa 8, Mùa 9...)
function getMovieSeasons(movie) {
if (!movie) return ['Mùa 1'];
if (Array.isArray(movie.seasons) && movie.seasons.length > 0) {
return movie.seasons;
}
if (movie.id === 'tro-tan-cuu-chau') {
return [
'Mùa 1-7', 'Mùa 8', 'Mùa 9', 'Mùa 10', 'Mùa 11', 'Mùa 12',
'Mùa 13', 'Mùa 14', 'Mùa 15', 'Mùa 26', 'Mùa 27', 'Mùa 28',
'Mùa 29', 'Mùa 30', 'Mùa 31', 'Mùa 32', 'Mùa 33', 'Mùa 34'
];
}
if (movie.season && typeof movie.season === 'number' && movie.season > 1) {
return Array.from({ length: movie.season }, (_, i) => `Mùa ${i + 1}`);
}
const total = Math.max(movie.ep || 1, movie.totalEp || 1);
if (total > 30) {
const num = Math.min(18, Math.ceil(total / 25));
return Array.from({ length: num }, (_, i) => `Mùa ${i + 1}`);
}
return ['Mùa 1-7', 'Mùa 8', 'Mùa 9', 'Mùa 10'];
}
function getMovieSeasonsCount(movie) {
const list = getMovieSeasons(movie);
return `${list.length} mùa`;
}
// Mở trang chi tiết phim chuyên biệt (/phim/ten-phim)
function openMovieDetailPage(movieIdOrSlug, targetEp = null, shouldPushState = true) {
const movie = findMovieBySlugOrId(movieIdOrSlug);
if (!movie) return false;
currentMovie = movie;
currentDetailMovie = movie;
currentDetailEpisode = targetEp ? parseInt(targetEp) : 1;
// Đăng ký lượt xem
registerMovieView(movie.id);
// Ẩn trang chủ, hiện trang chi tiết phim, luôn đảm bảo đóng player xem phim
const homeSection = document.getElementById('main-movies-section');
const detailView = document.getElementById('movie-detail-view');
const playerModal = document.getElementById('modal-video-player');
if (homeSection) {
homeSection.classList.add('hidden');
homeSection.style.display = 'none';
}
if (detailView) {
detailView.classList.remove('hidden');
detailView.style.display = '';
}
if (playerModal) {
playerModal.classList.add('hidden');
}
if (typeof hideNoEpisodeLinkOverlay === 'function') {
hideNoEpisodeLinkOverlay();
}
document.body.style.overflow = '';
if (typeof artPlayerInstance !== 'undefined' && artPlayerInstance) {
artPlayerInstance.pause();
}
const iframe = document.getElementById('iframe-player');
if (iframe) iframe.src = 'about:blank';
if (typeof watchTimer !== 'undefined' && watchTimer) clearInterval(watchTimer);
// Đưa thanh cuộn về đầu trang
window.scrollTo({ top: 0, behavior: 'smooth' });
// Cập nhật URL trình duyệt (tenmien.com/phim/ten-phim)
if (shouldPushState) {
updateMovieBrowserUrl(movie, targetEp);
}
// Cập nhật SEO Title & Description
updateMovieSEO(movie);
// Render nội dung trang chi tiết
renderMovieDetailPage(movie, targetEp);
return true;
}
// Render thông tin chi tiết phim
function renderMovieDetailPage(movie, targetEp = null) {
if (!movie) return;
// 1. Breadcrumbs
const bGenre = document.getElementById('detail-breadcrumb-genre');
if (bGenre) {
const gList = getMovieGenresList(movie);
bGenre.innerText = gList.map(g => getGenreLabel(g)).join(' • ') || 'Tu Tiên';
}
const bTitle = document.getElementById('detail-breadcrumb-title');
if (bTitle) bTitle.innerText = movie.title;
const bRating = document.getElementById('detail-breadcrumb-rating');
if (bRating) bRating.innerText = `⭐ ${movie.rating || '9.8'}`;
const bViews = document.getElementById('detail-breadcrumb-views');
if (bViews) bViews.innerText = `👁️ ${(movie.views || 0).toLocaleString('vi-VN')} lượt xem`;
// 2. Hero Background (Tự động cập nhật ảnh nền theo đúng hình ảnh poster/banner của từng phim)
const heroBg = document.getElementById('detail-hero-bg');
const ambientBg = document.getElementById('detail-hero-ambient');
const bgImg = movie.banner || movie.bannerImage || movie.image || 'logo.jpg';
if (heroBg) {
heroBg.style.backgroundImage = `url('${bgImg}')`;
}
if (ambientBg) {
ambientBg.style.backgroundImage = `url('${bgImg}')`;
}
// 3. Badges Tags
const badgesContainer = document.getElementById('detail-badges-container');
if (badgesContainer) {
const tags = getMovieTags(movie);
badgesContainer.innerHTML = tags.map(tag => `
<span class="bg-slate-900/80 border border-amber-500/35 text-amber-300 font-semibold text-xs px-3 py-1 rounded-full flex items-center gap-1.5 shadow-sm backdrop-blur-md">
${escapeHtml(tag)}
</span>
`).join('');
}
// 4. Tiêu đề phim
const titleEl = document.getElementById('detail-movie-title');
if (titleEl) titleEl.innerText = movie.title;
// 5. Meta info
const durEl = document.getElementById('detail-duration-display');
if (durEl) durEl.innerHTML = `<span>🕒</span> <span>${escapeHtml(movie.duration || getMovieDuration(movie))}</span>`;
const seaEl = document.getElementById('detail-episodes-display') || document.getElementById('detail-seasons-display');
if (seaEl) seaEl.innerHTML = `<span>🔲</span> <span>${getMovieEpisodesTotal(movie)} tập</span>`;
const ratEl = document.getElementById('detail-rating-display');
if (ratEl) ratEl.innerHTML = `<span>⭐</span> <span>${escapeHtml(String(movie.rating || '9.8'))}</span>`;
// 6. Nút Lưu Phim Favorite
updateDetailFavBtn(movie.id);
// 7. Nội dung tóm tắt & Xem thêm
const descEl = document.getElementById('detail-desc-text');
const toggleBtn = document.getElementById('btn-detail-desc-toggle');
isDetailDescExpanded = false;
const fullDesc = movie.desc || `Xem phim ${movie.title} trọn bộ Full HD Vietsub Thuyết Minh mới nhất tại Phim Full.`;
if (descEl) {
descEl.dataset.fullDesc = fullDesc;
if (fullDesc.length > 140) {
descEl.innerText = fullDesc.substring(0, 140) + '... ';
if (toggleBtn) {
toggleBtn.classList.remove('hidden');
toggleBtn.innerText = 'Xem thêm';
}
} else {
descEl.innerText = fullDesc;
if (toggleBtn) toggleBtn.classList.add('hidden');
}
}
// 8. Khởi tạo danh sách Tập phim (trực tiếp không qua mùa)
renderDetailEpisodesList(movie, targetEp);
// 9. Bình luận & Luận Đàm
renderDetailComments(movie.id);
// 10. Đề cử phim cùng thể loại
renderDetailRelatedMovies(movie);
}
// Toggle xem thêm / thu gọn mô tả phim
function toggleDetailDescription() {
const descEl = document.getElementById('detail-desc-text');
const toggleBtn = document.getElementById('btn-detail-desc-toggle');
if (!descEl || !descEl.dataset.fullDesc) return;
isDetailDescExpanded = !isDetailDescExpanded;
if (isDetailDescExpanded) {
descEl.innerText = descEl.dataset.fullDesc + ' ';
if (toggleBtn) toggleBtn.innerText = 'Thu gọn';
} else {
descEl.innerText = descEl.dataset.fullDesc.substring(0, 140) + '... ';
if (toggleBtn) toggleBtn.innerText = 'Xem thêm';
}
}
// Cập nhật trạng thái nút Lưu Phim
function updateDetailFavBtn(movieId) {
const favs = getFavorites();
const isFav = favs.includes(movieId);
const icon = document.getElementById('detail-fav-icon');
const text = document.getElementById('detail-fav-text');
if (icon) {
icon.className = `w-4 h-4 ${isFav ? 'fill-red-500 text-red-500 stroke-red-500' : 'fill-none stroke-current'}`;
}
if (text) {
text.innerText = isFav ? 'Đã lưu phim' : 'Lưu phim';
}
}
function toggleDetailFavorite() {
if (!currentDetailMovie) return;
toggleFavoriteMovie(currentDetailMovie.id);
updateDetailFavBtn(currentDetailMovie.id);
}
function shareDetailMovie() {
if (!currentDetailMovie) return;
const slug = getMovieSlug(currentDetailMovie);
const shareUrl = (window.location.protocol === 'file:')
? window.location.href.split('#')[0] + `#/phim/${slug}`
: `${window.location.origin}/phim/${slug}`;
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(shareUrl).then(() => {
showToast(`📋 Đã sao chép liên kết phim: ${shareUrl}`);
}).catch(() => {
prompt("Sao chép liên kết xem phim:", shareUrl);
});
} else {
prompt("Sao chép liên kết xem phim:", shareUrl);
}
}
// Lấy tổng số tập của bộ phim
function getMovieEpisodesTotal(movie) {
if (!movie) return 1;
if (Array.isArray(movie.episodes) && movie.episodes.length > 0) {
return movie.episodes.length;
}
return Math.max(movie.totalEp || 0, movie.ep || 0, 1);
}
// Lấy toàn bộ danh sách tập của bộ phim
function getMovieEpisodesList(movie) {
if (!movie) return [{ ep: 1, title: 'Tập 1' }];
if (Array.isArray(movie.episodes) && movie.episodes.length > 0) {
return movie.episodes;
}
const total = getMovieEpisodesTotal(movie);
return Array.from({ length: total }, (_, i) => ({
ep: i + 1,
title: `Tập ${i + 1}`
}));
}
// Render danh sách tập phim trực tiếp (Tập 1, Tập 2, Tập 3...)
function renderDetailEpisodesList(movie, activeEp = null) {
const grid = document.getElementById('detail-episodes-grid');
const badge = document.getElementById('detail-episodes-total-badge');
if (!grid) return;
grid.innerHTML = '';
const episodes = getMovieEpisodesList(movie);
if (badge) badge.innerText = `${episodes.length} Tập`;
const currentActive = activeEp ? parseInt(activeEp) : (currentDetailEpisode || 1);
episodes.forEach(item => {
const isCurrent = (item.ep === currentActive);
const hasLink = hasEpisodeServerLink(movie, item.ep);
const btn = document.createElement('button');
btn.className = isCurrent
? "py-2.5 px-3 rounded-xl text-xs sm:text-sm font-black bg-gradient-to-r from-amber-500 to-orange-500 text-black text-center shadow-lg shadow-amber-500/30 ring-2 ring-amber-400 transition active:scale-95 flex items-center justify-center min-w-0"
: (hasLink
? "py-2.5 px-3 rounded-xl text-xs sm:text-sm font-bold bg-[#0f172a] hover:bg-slate-800 text-slate-300 hover:text-white text-center border border-slate-800/90 hover:border-amber-500/50 transition active:scale-95 flex items-center justify-center min-w-0"
: "py-2.5 px-3 rounded-xl text-xs sm:text-sm font-medium bg-[#0f172a]/60 hover:bg-slate-800 text-slate-500 hover:text-slate-300 text-center border border-dashed border-slate-800 hover:border-amber-500/40 transition active:scale-95 flex items-center justify-center min-w-0");
btn.innerHTML = `<span class="truncate block w-full text-center" title="${escapeHtml(item.title)}${hasLink ? '' : ' (Chưa có link server - Đang cập nhật)'}">${escapeHtml(item.title)}</span>`;
btn.onclick = () => openVideoModal(movie.id, item.title, item.ep, true);
grid.appendChild(btn);
});
}
// Stubs tương thích
function renderDetailSeasonsList() {}
function selectDetailSeason() {}
// Bắt đầu xem phim (Mở giao diện player xem phim độc quyền chuẩn 100% theo ảnh)
function startWatchingDetailMovie(epNum = null) {
const movie = currentDetailMovie || currentMovie;
if (!movie) return;
let ep = epNum ? parseInt(epNum) : (currentDetailEpisode || 1);
// Nếu tập được chọn chưa có link, ưu tiên chuyển đến tập đầu tiên có link sẵn
if (!hasEpisodeServerLink(movie, ep)) {
const epList = getMovieEpisodesList(movie);
const firstWithLink = epList.find(e => hasEpisodeServerLink(movie, e.ep));
if (firstWithLink) {
ep = firstWithLink.ep;
}
}
currentDetailEpisode = ep;
currentEpisode = ep;
const epData = getCurrentEpisodeData(movie, ep);
const epTitle = epData.title || `Tập ${ep}`;
openVideoModal(movie.id, epTitle, ep, true);
}
function closeDetailPlayer() {
closeVideoModal(true);
}
function switchDetailServer(srv) {
switchServer(srv);
}
function changeDetailEpisode(delta) {
if (!currentMovie) return;
const total = getMovieEpisodesTotal(currentMovie);
const newEp = Math.min(total, Math.max(1, currentEpisode + delta));
const epData = getCurrentEpisodeData(currentMovie, newEp);
openVideoModal(currentMovie.id, epData.title, newEp, true);
}
function scrollToDetailComments() {
const el = document.getElementById('detail-comments-container') || document.getElementById('movie-comments-container');
if (el) {
el.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}
// Render bình luận ở trang chi tiết phim
function renderDetailComments(movieId) {
const container = document.getElementById('detail-comments-list');
const countEl = document.getElementById('detail-comments-count');
const userEl = document.getElementById('detail-comment-user');
if (userEl) userEl.innerText = currentUser ? currentUser.name : 'Khách Vãng Lai';
const comments = getMovieComments(movieId);
if (countEl) countEl.innerText = `(${comments.length} bình luận)`;
if (!container) return;
if (comments.length === 0) {
container.innerHTML = `<div class="text-center py-6 text-slate-500 text-xs italic">Chưa có đạo hữu nào luận đàm. Hãy là người đầu tiên để lại ý kiến!</div>`;
return;
}
container.innerHTML = comments.map(c => `
<div class="p-3 rounded-xl bg-slate-900/60 border border-slate-800/80 space-y-2 hover:border-slate-700/80 transition">
<div class="flex items-center justify-between text-xs">
<div class="flex items-center gap-2.5">
<div class="w-7 h-7 rounded-lg bg-gradient-to-br from-amber-500/20 to-orange-500/20 border border-amber-500/30 flex items-center justify-center text-xs font-bold text-amber-300">
${escapeHtml((c.author || 'Đ').charAt(0))}
</div>
<div>
<div class="flex items-center gap-2">
<span class="font-bold text-slate-200">${escapeHtml(c.author)}</span>
<span class="px-1.5 py-0.5 rounded bg-amber-500/10 text-amber-400 border border-amber-500/20 text-[9px] font-medium">${escapeHtml(c.realm || 'Luyện Khí')}</span>
</div>
<div class="text-[10px] text-slate-500">${escapeHtml(c.time || 'Vừa xong')}</div>
</div>
</div>
<button onclick="toggleCommentLike('${movieId}', ${c.id}); renderDetailComments('${movieId}');" class="flex items-center gap-1.5 text-[11px] px-2.5 py-1 rounded-lg ${c.liked ? 'bg-amber-500/20 text-amber-300 border border-amber-500/40' : 'bg-slate-800/70 text-slate-400 hover:text-white'} transition">
<span>👍</span> <span class="font-mono font-bold">${c.likes || 0}</span>
</button>
</div>
<p class="text-xs text-slate-300 leading-relaxed pl-9">${escapeHtml(c.text)}</p>
</div>
`).join('');
}
function addDetailCommentEmoji(emoji) {
const ta = document.getElementById('detail-comment-input');
if (ta) { ta.value += emoji; ta.focus(); }
}
function postDetailComment() {
const ta = document.getElementById('detail-comment-input');
if (!ta || !currentDetailMovie) return;
const text = ta.value.trim();
if (!text) {
showToast("⚠️ Vui lòng nhập nội dung luận đàm!");
return;
}
const comments = getMovieComments(currentDetailMovie.id);
const newComment = {
id: Date.now(),
author: currentUser ? currentUser.name : "Khách Vãng Lai",
realm: currentUser ? currentUser.realm : "Chưa Nhập Sơn",
text: text,
time: "Vừa xong",
likes: 1,
liked: true
};
comments.unshift(newComment);
saveMovieComments(currentDetailMovie.id, comments);
ta.value = '';
if (currentUser) {
currentUser.tuVi = (currentUser.tuVi || 0) + 5;
saveCurrentUserData();
updateUserDisplay();
showToast("💬 Đã gửi luận đàm: +5 Tu Vi!");
} else {
showToast("💬 Đã gửi luận đàm dưới danh nghĩa Khách Vãng Lai!");
}
renderDetailComments(currentDetailMovie.id);
}
// Render danh sách phim đề cử cùng thể loại
function renderDetailRelatedMovies(movie) {
const container = document.getElementById('detail-related-movies-list');
if (!container) return;
container.innerHTML = '';
const related = MOVIES_DATABASE.filter(m => m.id !== movie.id).slice(0, 5);
container.innerHTML = related.map(m => {
const movieUrl = getMovieUrl(m);
return `
<a href="${movieUrl}" onclick="event.preventDefault(); openMovieDetailPage('${m.id}', null, true);" class="flex items-center gap-3 p-2 rounded-xl transition bg-slate-900/60 hover:bg-slate-800/80 border border-slate-800/60 group">
<img src="${m.image}" class="w-11 h-14 rounded-lg object-cover bg-slate-800 flex-shrink-0 group-hover:scale-105 transition-transform">
<div class="flex-1 min-w-0">
<h4 class="text-xs font-bold text-slate-200 truncate group-hover:text-amber-400 transition">${escapeHtml(m.title)}</h4>
<div class="text-[10px] text-slate-400 flex items-center gap-2 mt-1">
<span class="text-amber-300 font-semibold truncate max-w-[100px]">${escapeHtml(getLatestEpisodeTitle(m))}</span>
<span>•</span>
<span class="text-amber-400">⭐ ${m.rating || 9.8}</span>
</div>
</div>
</a>
`;
}).join('');
}
// Trở về trang chủ
function handleGoHome(e) {
if (e) e.preventDefault();
closeDetailPlayer();
closeVideoModal(false);
const homeSection = document.getElementById('main-movies-section');
const detailView = document.getElementById('movie-detail-view');
if (homeSection) {
homeSection.classList.remove('hidden');
homeSection.style.display = '';
}
if (detailView) {
detailView.classList.add('hidden');
}
currentDetailMovie = null;
clearMovieBrowserUrl();
resetDefaultSEO();
window.scrollTo({ top: 0, behavior: 'smooth' });
}
// Tự động kiểm tra URL khi người dùng vào thẳng link tenmien.com/phim/ten-phim
function checkUrlAndOpenMovie(shouldPushState = false) {
let slug = window.__INITIAL_MOVIE_ID__ || null;
// 1. Kiểm tra từ pathname (ví dụ: /phim/phan-nhan-tu-tien hoặc /movie/phan-nhan-tu-tien)
const path = window.location.pathname;
const match = path.match(/\/(?:phim|movie)\/([^\/?#&]+)/i);
if (match && match[1]) {
slug = decodeURIComponent(match[1]);
}
// 2. Kiểm tra từ query param (?phim=ten-phim hoặc ?movie=ten-phim hoặc ?id=ten-phim hoặc ?slug=ten-phim)
const params = new URLSearchParams(window.location.search);
const qSlug = params.get('phim') || params.get('movie') || params.get('id') || params.get('slug');
if (!slug && qSlug) {
slug = qSlug.trim();
}
// 2.1 Kiểm tra nếu Nginx rewrite dạng ?/phim/ten-phim
if (!slug && window.location.search) {
const sMatch = window.location.search.match(/(?:phim|movie)\/([^\/?#&]+)/i);
if (sMatch && sMatch[1]) {
slug = decodeURIComponent(sMatch[1]);
}
}
// 3. Kiểm tra từ hash (#/phim/ten-phim hoặc #/movie/ten-phim)
const hash = window.location.hash;
if (!slug && hash) {
const hashMatch = hash.match(/#\/?(?:phim|movie)\/([^\/?#&]+)/i);
if (hashMatch && hashMatch[1]) {
slug = decodeURIComponent(hashMatch[1]);
}
}
if (slug) {
slug = slug.replace(/\.(html?|php)$/i, '');
}
// Đọc số tập từ query string (nếu có: ?tap=2 hoặc &ep=2)
let epNum = null;
const epParam = params.get('tap') || params.get('ep');
if (epParam) {
const p = parseInt(epParam);
if (!isNaN(p) && p > 0) epNum = p;
}
if (!epNum && hash.includes('?')) {
const hashQuery = hash.split('?')[1];
const hParams = new URLSearchParams(hashQuery);
const hEp = hParams.get('tap') || hParams.get('ep');
if (hEp) {
const p = parseInt(hEp);
if (!isNaN(p) && p > 0) epNum = p;
}
}
if (slug) {
// Khi truy cập /phim/ten-phim hoặc bấm vào trang phim: Luôn hiển thị trang chi tiết phim, không tự động phát video
const opened = openMovieDetailPage(slug, null, shouldPushState);
if (opened) return true;
} else {
handleGoHome();
}
return false;
}
// Lắng nghe nút Back / Forward trên trình duyệt
window.addEventListener('popstate', function(e) {
checkUrlAndOpenMovie(false);
});
// ==================================================
// QUẢN LÝ DỮ LIỆU & ĐỒNG BỘ THỜI GIAN THỰC (HYBRID LOCAL + SERVER API)
// ==================================================
let isSyncingFromServer = false;
function initDefaultMoviesWithTimestamps() {
const baseTime = 1729800000000;
return SCREENSHOT_MOVIES.map((m, idx) => ({
...m,
updatedAt: m.updatedAt || (baseTime - idx * 10000),
updateDate: m.updateDate || 'HÔM NAY'
}));
}
function loadMoviesDatabase() {
const saved = localStorage.getItem('minhsam_movies') || localStorage.getItem('langlangson_movies');
if (saved !== null) {
try {
const parsed = JSON.parse(saved);
if (Array.isArray(parsed)) {
const baseTime = 1729800000000;
parsed.forEach((m, idx) => {
if (!m.status) m.status = 'new';
if (m.views === undefined || m.views === null || isNaN(m.views)) {
m.views = 0;
} else {
m.views = parseInt(m.views) || 0;
}
if (!m.updatedAt) {
m.updatedAt = baseTime - idx * 10000;
}
if (m.iframeUrl && m.iframeUrl.includes('youtube-nocookie.com')) {
m.iframeUrl = m.iframeUrl.replace('youtube-nocookie.com', 'youtube.com').replace('&enablejsapi=1', '');
}
if (m.iframeBackupUrl && m.iframeBackupUrl.includes('youtube-nocookie.com')) {
m.iframeBackupUrl = m.iframeBackupUrl.replace('youtube-nocookie.com', 'youtube.com').replace('&enablejsapi=1', '');
}
});
// Sắp xếp phim mới đăng hoặc mới cập nhật tập mới lên đầu danh sách
parsed.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0));
MOVIES_DATABASE = parsed;
} else {
MOVIES_DATABASE = initDefaultMoviesWithTimestamps();
}
} catch(e){ MOVIES_DATABASE = initDefaultMoviesWithTimestamps(); }
} else {
MOVIES_DATABASE = initDefaultMoviesWithTimestamps();
}
// Tự động đối soát và kéo dữ liệu mới nhất từ Máy Chủ aaPanel / Hosting
syncMoviesFromServer();
}
// Tự động kiểm tra và tải dữ liệu mới nhất từ Server (api.php hoặc data.json)
async function syncMoviesFromServer() {
if (window.location.protocol === 'file:' || isSyncingFromServer) return;
isSyncingFromServer = true;
try {
// Ưu tiên gọi api.php, nếu không có PHP thì đọc thẳng data.json
const res = await fetch(API_BASE + 'api.php?action=get_all&t=' + Date.now(), { cache: 'no-store' })
.catch(() => fetch(API_BASE + 'data.json?t=' + Date.now(), { cache: 'no-store' }));
if (res && res.ok) {
const data = await res.json();
const serverMovies = data.movies || (Array.isArray(data) ? data : null);
if (Array.isArray(serverMovies)) {
const sTime = data.last_updated || 0;
const localStoredTime = parseInt(localStorage.getItem('minhsam_last_updated') || '0');
const baseTime = 1729800000000;
serverMovies.forEach((m, idx) => {
if (!m.status) m.status = 'new';
if (m.views === undefined || m.views === null || isNaN(m.views)) {
m.views = 0;
} else {
m.views = parseInt(m.views) || 0;
}
if (!m.updatedAt) {
m.updatedAt = baseTime - idx * 10000;
}
if (m.iframeUrl && m.iframeUrl.includes('youtube-nocookie.com')) {
m.iframeUrl = m.iframeUrl.replace('youtube-nocookie.com', 'youtube.com').replace('&enablejsapi=1', '');
}
if (m.iframeBackupUrl && m.iframeBackupUrl.includes('youtube-nocookie.com')) {
m.iframeBackupUrl = m.iframeBackupUrl.replace('youtube-nocookie.com', 'youtube.com').replace('&enablejsapi=1', '');
}
});
// Phim mới đăng hoặc mới cập nhật tập mới sẽ luôn hiển thị lên đầu
serverMovies.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0));
const currentStr = JSON.stringify(MOVIES_DATABASE);
const serverStr = JSON.stringify(serverMovies);
if (currentStr !== serverStr || (sTime && sTime > localStoredTime)) {
MOVIES_DATABASE = serverMovies;
localStorage.setItem('minhsam_movies', serverStr);
localStorage.setItem('langlangson_movies', serverStr);
if (sTime) localStorage.setItem('minhsam_last_updated', sTime.toString());
if (Array.isArray(data.genres) && data.genres.length > 0) {
localStorage.setItem('minhsam_genres', JSON.stringify(data.genres));
localStorage.setItem('langlangson_genres', JSON.stringify(data.genres));
}
if (Array.isArray(data.statuses) && data.statuses.length > 0) {
localStorage.setItem('minhsam_statuses', JSON.stringify(data.statuses));
localStorage.setItem('langlangson_statuses', JSON.stringify(data.statuses));
}
if (Array.isArray(data.schedules) && data.schedules.length > 0) {
localStorage.setItem('minhsam_schedules', JSON.stringify(data.schedules));
localStorage.setItem('langlangson_schedules', JSON.stringify(data.schedules));
}
refreshWebsiteData();
}
}
}
} catch (err) {
// Offline / file protocol fallback mượt mà
} finally {
isSyncingFromServer = false;
}
}
function refreshWebsiteData() {
renderStatusTabs();
renderGenreChips();
applyFiltersAndSort();
renderTopViews();
// Nếu đang mở khung xem phim hoặc trang chi tiết phim, đồng bộ dữ liệu phim hiện tại
if (currentMovie) {
const stillExists = MOVIES_DATABASE.find(m => m.id === currentMovie.id);
if (!stillExists) {
closeVideoModal();
showToast("⚠️ Bộ phim đang xem vừa được quản trị viên gỡ bỏ khỏi hệ thống!");
} else {
currentMovie = stillExists;
}
}
const playerModal = document.getElementById('modal-video-player');
const isPlayerOpen = playerModal && !playerModal.classList.contains('hidden');
// Nếu đang mở xem phim trong modal player, tuyệt đối không re-render trang chi tiết để không bị văng về trang phim
if (!isPlayerOpen) {
if (currentDetailMovie) {
const stillExistsDetail = MOVIES_DATABASE.find(m => m.id === currentDetailMovie.id);
if (stillExistsDetail) {
currentDetailMovie = stillExistsDetail;
renderMovieDetailPage(currentDetailMovie, null);
}
} else {
// Tự động kiểm tra và mở trang chi tiết phim nếu người dùng truy cập trực tiếp bằng URL /phim/ten-phim
checkUrlAndOpenMovie(false);
}
}
}
// ==================================================
// BỘ ĐẾM LƯỢT XEM CHUẨN (STANDARD PERSISTENT VIEW COUNTER)
// ==================================================
function registerMovieView(movieId) {
if (!movieId) return;
const viewKey = 'minhsam_view_' + movieId;
const now = Date.now();
const lastViewTime = parseInt(sessionStorage.getItem(viewKey) || '0');
// Đếm lượt xem chính xác (chống click đúp trong 1.5 giây)
if (now - lastViewTime > 1500) {
sessionStorage.setItem(viewKey, now.toString());
const movie = MOVIES_DATABASE.find(m => m.id === movieId);
if (movie) {
movie.views = (parseInt(movie.views) || 0) + 1;
// Cập nhật lượt xem trên thẻ phim ngoài trang chủ tức thì
updateCardViews(movieId, movie.views);
// Cập nhật lượt xem trong modal player
updateModalPlayerViews(movie.views);
// Cập nhật bảng xếp hạng Top Views
renderTopViews();
// Lưu vào LocalStorage
try {
const json = JSON.stringify(MOVIES_DATABASE);
localStorage.setItem('minhsam_movies', json);
localStorage.setItem('langlangson_movies', json);
} catch(e) {}
// Đồng bộ các tab khác qua BroadcastChannel
try {
const syncChannel = new BroadcastChannel('minhsam_sync_channel');
syncChannel.postMessage({ type: 'VIEW_INCREMENTED', movieId: movieId, views: movie.views });
} catch(e) {}
// Gửi lệnh cập nhật lên máy chủ web aaPanel
if (window.location.protocol !== 'file:') {
fetch(API_BASE + `api.php?action=increment_view&id=${encodeURIComponent(movieId)}&t=${now}`, {
method: 'POST'
})
.then(res => res.json())
.then(data => {
if (data && data.success && data.views) {
movie.views = data.views;
updateCardViews(movieId, data.views);
updateModalPlayerViews(data.views);
}
})
.catch(() => {});
}
}
}
}
function updateCardViews(movieId, views) {
const el = document.getElementById(`movie-card-views-${movieId}`);
if (el) {
el.innerText = formatCompactViews(views);
const parent = el.closest('[title]');
if (parent) {
parent.title = `${(views || 0).toLocaleString('vi-VN')} lượt xem`;
}
}
}
function updateModalPlayerViews(views) {
const el = document.getElementById('modal-player-views-count');
if (el) {
el.innerHTML = `<span>👁️</span> ${(views || 0).toLocaleString('vi-VN')} lượt xem`;
}
const badgeEl = document.getElementById('modal-breadcrumb-views');
if (badgeEl) {
badgeEl.innerHTML = `<span>👁️</span> ${(views || 0).toLocaleString('vi-VN')} xem`;
}
}
// 1. Đồng bộ tức thì đa tab qua BroadcastChannel (độ trễ 0ms)
try {
const syncChannel = new BroadcastChannel('minhsam_sync_channel');
syncChannel.onmessage = function(event) {
if (event.data && (event.data.type === 'MOVIES_UPDATED' || event.data.type === 'TAXONOMY_UPDATED')) {
syncMoviesFromServer();
refreshWebsiteData();
showToast("⚡ Dữ liệu phim vừa được cập nhật tức thì!");
} else if (event.data && event.data.type === 'VIEW_INCREMENTED') {
const m = MOVIES_DATABASE.find(x => x.id === event.data.movieId);
if (m) {
m.views = event.data.views;
updateCardViews(event.data.movieId, event.data.views);
updateModalPlayerViews(event.data.views);
}
}
};
} catch(e) {}
// 2. Lắng nghe sự kiện Storage thay đổi từ tab khác
window.addEventListener('storage', function(e) {
if (e.key === 'minhsam_movies' || e.key === 'langlangson_movies' || e.key === 'minhsam_last_updated' ||
e.key === 'minhsam_genres' || e.key === 'langlangson_genres' ||
e.key === 'minhsam_statuses' || e.key === 'langlangson_statuses' ||
e.key === 'minhsam_schedules' || e.key === 'langlangson_schedules') {
loadMoviesDatabase();
refreshWebsiteData();
}
});
// 3. Tự động kiểm tra và làm mới dữ liệu khi người dùng chuyển lại tab này
document.addEventListener('visibilitychange', function() {
if (!document.hidden) {
syncMoviesFromServer();
refreshWebsiteData();
}
});
window.addEventListener('focus', function() {
syncMoviesFromServer();
refreshWebsiteData();
});
// 4. Định kỳ kiểm tra cập nhật từ Máy Chủ (Polling mỗi 10 giây khi chạy trên Web)
if (window.location.protocol !== 'file:') {
setInterval(syncMoviesFromServer, 10000);
}
// Chạy ngay lập tức khi file script tải xong để nhận diện SEO phim sớm nhất
initEarlyMovieSEO();
// KHỞI ĐỘNG TRANG WEB
window.onload = function() {
initEarlyMovieSEO();
loadMoviesDatabase();
// Khởi tạo hệ thống tài khoản & xác thực
initAuthSystem();
renderStatusTabs();
renderGenreChips();
applyFiltersAndSort();
renderTopViews();
// Tự động kiểm tra URL xem có yêu cầu mở phim trực tiếp không (vd: tenmien.com/phim/ten-phim)
checkUrlAndOpenMovie(false);
};
// DANH SÁCH THỂ LOẠI & DYNAMIC STORAGE (ĐỒNG BỘ CÙNG TRANG QUẢN TRỊ ADMIN)
const DEFAULT_GENRES = [
{ key: 'tu-tien', label: 'Tu Tiên' },
{ key: 'huyen-huyen', label: 'Huyền Huyễn' },
{ key: 'xuyen-khong', label: 'Xuyên Không' },
{ key: 'trong-sinh', label: 'Trọng Sinh' },
{ key: 'he-thong', label: 'Hệ Thống' },
{ key: 'vo-dich', label: 'Vô Địch Lưu' },
{ key: 'do-thi', label: 'Đô Thị Dị Năng' },
{ key: 'va-mat', label: 'Vả Mặt' },
{ key: 'nghich-tap', label: 'Nghịch Tập' },
{ key: 'hai-huoc', label: 'Hài Hước' }
];
function getStoredGenres() {
const stored = localStorage.getItem('minhsam_genres') || localStorage.getItem('langlangson_genres');
if (stored) {
try {
const parsed = JSON.parse(stored);
if (Array.isArray(parsed) && parsed.length > 0) return parsed;
} catch(e){}
}
return [...DEFAULT_GENRES];
}
// LẤY TÊN TIẾNG VIỆT CỦA THỂ LOẠI (HỖ TRỢ CẢ THỂ LOẠI MỚI TẠO TỪ ADMIN)
function getGenreLabel(genreKey) {
const genres = getStoredGenres();
const found = genres.find(g => g.key === genreKey);
if (found) return found.label;
return genreKey || 'Tu Tiên';
}
// LẤY DANH SÁCH TẤT CẢ THỂ LOẠI CỦA BỘ PHIM (HỖ TRỢ CHỌN NHIỀU THỂ LOẠI)
function getMovieGenresList(movie) {
if (!movie) return ['tu-tien'];
if (Array.isArray(movie.genres) && movie.genres.length > 0) return movie.genres;
if (Array.isArray(movie.genre) && movie.genre.length > 0) return movie.genre;
if (typeof movie.genre === 'string' && movie.genre) {
if (movie.genre.includes(',')) {
return movie.genre.split(',').map(s => s.trim()).filter(Boolean);
}
return [movie.genre];
}
return ['tu-tien'];
}
// RENDER THANH THỂ LOẠI CHIPS TỰ ĐỘNG CẬP NHẬT
function renderGenreChips() {
const container = document.getElementById('genre-chips-container');
if (!container) return;
const genres = getStoredGenres();
let html = `
<span class="text-slate-400 font-semibold text-[11px] uppercase tracking-wider mr-1 flex items-center gap-1 flex-shrink-0">
<span>🏷️</span> Thể loại:
</span>
<button onclick="filterGenre('all')" class="genre-pill flex-shrink-0 px-3 py-1 rounded-lg ${currentGenreFilter === 'all' ? 'bg-amber-500 text-black font-bold' : 'bg-slate-800/80 text-slate-300 hover:text-white hover:bg-slate-700'} transition">
Tất Cả
</button>
`;
genres.forEach(g => {
const isActive = (currentGenreFilter === g.key);
html += `
<button onclick="filterGenre('${g.key}')" class="genre-pill flex-shrink-0 px-3 py-1 rounded-lg ${isActive ? 'bg-amber-500 text-black font-bold' : 'bg-slate-800/80 text-slate-300 hover:text-white hover:bg-slate-700'} transition">
${g.label}
</button>
`;
});
container.innerHTML = html;
}
// ==================================================
// 🏷️ QUẢN LÝ TRẠNG THÁI & LỊCH CHIẾU (DỮ LIỆU ĐỒNG BỘ TỪ ADMIN)
// ==================================================
const DEFAULT_STATUSES = [
{ key: 'new', label: 'Mới Cập Nhật', icon: '⚡' },
{ key: 'hot', label: 'Phim HOT', icon: '🔥' },
{ key: 'cay-dem', label: 'Cày Đêm', icon: '🌙' },
{ key: 'hoan-thanh', label: 'Hoàn Thành (Full)', icon: '✨' }
];
const DEFAULT_SCHEDULES = [
{ key: 't2', label: 'Thứ 2', fullLabel: 'Thứ Hai' },
{ key: 't3', label: 'Thứ 3', fullLabel: 'Thứ Ba' },
{ key: 't4', label: 'Thứ 4', fullLabel: 'Thứ Tư' },
{ key: 't5', label: 'Thứ 5', fullLabel: 'Thứ Năm' },
{ key: 't6', label: 'Thứ 6', fullLabel: 'Thứ Sáu' },
{ key: 't7', label: 'Thứ 7', fullLabel: 'Thứ Bảy' },
{ key: 'cn', label: 'Chủ Nhật', fullLabel: 'Chủ Nhật' }
];
function getStoredStatuses() {
const stored = localStorage.getItem('minhsam_statuses') || localStorage.getItem('langlangson_statuses');
if (stored) {
try {
const parsed = JSON.parse(stored);
if (Array.isArray(parsed) && parsed.length > 0) return parsed;
} catch(e){}
}
return [...DEFAULT_STATUSES];
}
function getStoredSchedules() {
const stored = localStorage.getItem('minhsam_schedules') || localStorage.getItem('langlangson_schedules');
if (stored) {
try {
const parsed = JSON.parse(stored);
if (Array.isArray(parsed) && parsed.length > 0) return parsed;
} catch(e){}
}
return [...DEFAULT_SCHEDULES];
}
function getStatusLabel(statusKey) {
const statuses = getStoredStatuses();
const found = statuses.find(s => s.key === statusKey);
if (found) return found.label;
if (statusKey === 'hot') return 'Phim HOT';
if (statusKey === 'new') return 'Mới Cập Nhật';
if (statusKey === 'cay-dem') return 'Cày Đêm';
if (statusKey === 'hoan-thanh') return 'Hoàn Thành';
return statusKey || 'Mới';
}
function getScheduleLabel(dayKey) {
const schedules = getStoredSchedules();
const found = schedules.find(sc => sc.key === dayKey);
if (found) return found.label;
const map = { t2: 'Thứ 2', t3: 'Thứ 3', t4: 'Thứ 4', t5: 'Thứ 5', t6: 'Thứ 6', t7: 'Thứ 7', cn: 'Chủ Nhật' };
return map[dayKey] || dayKey || 'Thứ 2';
}
// RENDER THANH TABS TRẠNG THÁI PHIM TỰ ĐỘNG CẬP NHẬT TỪ HỆ THỐNG
function renderStatusTabs() {
const container = document.getElementById('status-tabs');
if (!container) return;
const statuses = getStoredStatuses();
let html = `
<button onclick="filterStatusTab('all')" class="status-tab-btn px-3.5 py-1.5 rounded-xl ${currentStatusFilter === 'all' ? 'bg-gradient-to-r from-amber-500 to-orange-500 text-black shadow-md shadow-amber-500/20' : 'bg-slate-800 text-slate-300 hover:text-white hover:bg-slate-700'} font-bold transition flex items-center gap-1">
Tất Cả Phim
</button>
`;
statuses.forEach(s => {
const isActive = (currentStatusFilter === s.key);
html += `
<button onclick="filterStatusTab('${s.key}')" class="status-tab-btn px-3.5 py-1.5 rounded-xl ${isActive ? 'bg-gradient-to-r from-amber-500 to-orange-500 text-black shadow-md shadow-amber-500/20' : 'bg-slate-800 text-slate-300 hover:text-white hover:bg-slate-700'} font-bold transition flex items-center gap-1">
<span>${s.icon || '⚡'}</span> ${escapeHtml(s.label)}
</button>
`;
});
container.innerHTML = html;
}
function formatEpisodeDisplay(ep) {
if (ep === undefined || ep === null || ep === '') return 'Tập 1';
const str = String(ep).trim();
if (str.toLowerCase().startsWith('tập') || str.toLowerCase().startsWith('full') || str.toLowerCase().startsWith('ep')) {
return str;
}
return `Tập ${str}`;
}
// LẤY TÊN TẬP MỚI NHẤT CỦA BỘ PHIM
function getLatestEpisodeTitle(movie) {
if (!movie) return 'Tập 1';
if (Array.isArray(movie.episodes) && movie.episodes.length > 0) {
const last = movie.episodes[movie.episodes.length - 1];
if (last && last.title && last.title.trim()) {
return last.title.trim();
}
}
return formatEpisodeDisplay(movie.ep || 1);
}
// ==========================================
// CÁC HÀM ĐỊNH DẠNG THEO GIAO DIỆN CHUẨN (ẢNH MẪU 16:9)
// ==========================================
function formatCompactViews(views) {
const v = parseInt(views) || 0;
if (v >= 1000000) {
const m = (v / 1000000).toFixed(1).replace('.0', '');
return `${m}M`;
}
if (v >= 10000) {
return `${Math.round(v / 1000)}K`;
}
if (v >= 1000) {
const k = (v / 1000).toFixed(1).replace('.0', '');
return `${k}K`;
}
return `${v}`;
}
function getMovieDuration(movie) {
if (movie.duration && String(movie.duration).trim()) {
return movie.duration;
}
const match = String(movie.ep || '').match(/\d+/);
const epNum = match ? parseInt(match[0]) : (Array.isArray(movie.episodes) ? movie.episodes.length : 1);
const totalMinutes = epNum * 21;
const hours = Math.floor(totalMinutes / 60);
const mins = totalMinutes % 60;
if (hours > 0) {
return `${hours}h ${mins > 0 ? (mins < 10 ? '0' + mins : mins) + 'p' : ''}`.trim();
}
return `${mins || 21}p`;
}
function getMovieSeasonEpLabel(movie) {
const epVal = movie.ep !== undefined ? movie.ep : 1;
const epStr = String(epVal).trim();
if (epStr.toLowerCase().startsWith('tập') || epStr.toLowerCase().startsWith('full') || epStr.toLowerCase().startsWith('ep')) {
return epStr;
}
return `Tập ${epStr}`;
}
function getMovieUpdateBadge(movie) {
if (movie.updatedAt && (Date.now() - movie.updatedAt < 86400000)) {
return 'HÔM NAY';
}
if (movie.updateDate && String(movie.updateDate).trim()) {
return movie.updateDate;
}
if (movie.status === 'new' || movie.day === 't2' || movie.day === 't3') {
return 'HÔM NAY';
}
const daysMap = {
't2': '26/10/2026',
't3': '27/10/2026',
't4': '28/10/2026',
't5': '22/10/2026',
't6': '23/10/2026',
't7': '24/10/2026',
'cn': '25/10/2026'
};
return daysMap[movie.day] || '26/10/2026';
}
function getLatestEpisodeBadge(movie) {
if (!movie) return 'Tập 1';
let epLabel = '';
if (Array.isArray(movie.episodes) && movie.episodes.length > 0) {
const last = movie.episodes[movie.episodes.length - 1];
if (last && last.title && last.title.trim()) {
epLabel = last.title.trim();
const epMatch = epLabel.match(/^(tập\s*\d+|full(?:\s*\d+)?(?:\s*tập)?|ep\s*\d+)/i);
if (epMatch) {
epLabel = epMatch[0];
}
}
}
if (!epLabel) {
epLabel = formatEpisodeDisplay(movie.ep || 1);
}
const isFull = movie.status === 'hoan-thanh' || (movie.title && movie.title.toLowerCase().includes('full')) || (movie.ep && movie.totalEp && movie.ep >= movie.totalEp);
if (isFull && !epLabel.toLowerCase().includes('full')) {
return `${epLabel} (Full)`;
}
return epLabel;
}
function getLatestEpisodeTitle(movie) {
return getLatestEpisodeBadge(movie);
}
function getFavorites() {
try {
return JSON.parse(localStorage.getItem('minhsam_favorites') || '[]');
} catch(e) { return []; }
}
function toggleFavoriteMovie(movieId, e) {
if (e) e.stopPropagation();
let favs = getFavorites();
const idx = favs.indexOf(movieId);
if (idx > -1) {
favs.splice(idx, 1);
showToast("🤍 Đã bỏ khỏi danh sách Yêu Thích!");
} else {
favs.push(movieId);
showToast("❤️ Đã thêm vào danh sách Yêu Thích!");
}
localStorage.setItem('minhsam_favorites', JSON.stringify(favs));
applyFiltersAndSort();
}
function shareMovie(movieId, e) {
if (e) e.stopPropagation();
const m = MOVIES_DATABASE.find(x => x.id === movieId);
if (!m) return;
const slug = getMovieSlug(m);
const shareUrl = (window.location.protocol === 'file:')
? window.location.href.split('#')[0] + `#/phim/${slug}`
: `${window.location.origin}/phim/${slug}`;
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(shareUrl).then(() => {
showToast(`📋 Đã sao chép liên kết phim: ${shareUrl}`);
}).catch(() => {
prompt("Sao chép liên kết xem phim:", shareUrl);
});
} else {
prompt("Sao chép liên kết xem phim:", shareUrl);
}
}
function shareCurrentMovie() {
if (!currentMovie) return;
const slug = getMovieSlug(currentMovie);
const epSuffix = (currentEpisode && currentEpisode > 1) ? `?tap=${currentEpisode}` : '';
const shareUrl = (window.location.protocol === 'file:')
? window.location.href.split('#')[0] + `#/phim/${slug}${epSuffix}`
: `${window.location.origin}/phim/${slug}${epSuffix}`;
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(shareUrl).then(() => {
showToast(`📋 Đã sao chép link xem phim: ${shareUrl}`);
}).catch(() => {
prompt("Sao chép link xem phim:", shareUrl);
});
} else {
prompt("Sao chép link xem phim:", shareUrl);
}
}
// RENDER LƯỚI DANH SÁCH POSTER PHIM TRANG CHỦ THEO CHUẨN ẢNH MẪU (16:9 - 4 CỘT)
function renderMoviesGrid(movies) {
const grid = document.getElementById('movies-grid');
if (!grid) return;
grid.innerHTML = '';
if (movies.length === 0) {
grid.innerHTML = `
<div class="col-span-full py-16 text-center text-xs text-slate-400 bg-slate-900/50 rounded-2xl border border-slate-800 space-y-2">
<span class="text-3xl block">🎬</span>
<div class="font-bold text-slate-300 text-sm">Hệ thống đang cập nhật các bộ phim mới</div>
<p class="text-slate-500 text-xs">Đạo hữu vui lòng quay lại sau ít phút hoặc đón xem vào các khung giờ phát sóng tiếp theo.</p>
</div>
`;
return;
}
const favs = getFavorites();
movies.forEach(movie => {
const isFav = favs.includes(movie.id);
const compactViews = formatCompactViews(movie.views);
const seasonEpStr = getMovieSeasonEpLabel(movie);
const updateDate = getMovieUpdateBadge(movie);
const isToday = updateDate.toUpperCase() === 'HÔM NAY';
const latestEpBadge = getLatestEpisodeBadge(movie);
const movieSlug = getMovieSlug(movie);
const movieUrl = getMovieUrl(movie);
const card = document.createElement('div');
card.className = "group cursor-pointer flex flex-col";
card.onclick = (e) => {
if (e.target.closest('button')) return;
openMovieDetailPage(movie.id, null, true);
};
card.innerHTML = `
<!-- KHUNG HÌNH THUMBNAIL 16:9 CHUẨN ĐẸP THEO ẢNH MẪU -->
<a href="${movieUrl}" onclick="event.preventDefault(); openMovieDetailPage('${movie.id}', null, true);" class="block relative aspect-video rounded-xl sm:rounded-2xl overflow-hidden bg-slate-900 border border-slate-800/90 group-hover:border-amber-500/60 transition-all duration-300 group-hover:shadow-xl group-hover:shadow-amber-500/10">
<img
src="${movie.image}"
alt="${escapeHtml(movie.title)}"
loading="lazy"
class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500"
>
<!-- Lớp phủ Gradient mờ tối chuẩn cinema -->
<div class="absolute inset-0 bg-gradient-to-t from-black/85 via-black/20 to-black/40 pointer-events-none"></div>
<!-- GÓC TRÊN TRÁI: BADGE TẬP MỚI NHẤT ĐƯỢC CẬP NHẬT -->
<div class="absolute top-2 left-2 sm:top-2.5 sm:left-2.5 z-10 pointer-events-none">
<span class="inline-flex items-center justify-center px-2 py-0.5 sm:px-2.5 rounded-md sm:rounded-lg bg-gradient-to-r from-red-600 to-rose-600 text-white font-black text-[9px] sm:text-[11px] tracking-wide shadow-md shadow-red-950/70">
${escapeHtml(latestEpBadge)}
</span>
</div>
<!-- GÓC TRÊN PHẢI: NÚT TIM YÊU THÍCH VÀ NÚT CHIA SẺ -->
<div class="absolute top-2 right-2 sm:top-2.5 sm:right-2.5 flex flex-col gap-1 sm:gap-1.5 z-20" onclick="event.stopPropagation()">
<button onclick="toggleFavoriteMovie('${movie.id}', event)" id="fav-btn-${movie.id}" class="w-6 h-6 sm:w-7 sm:h-7 rounded-full bg-black/60 hover:bg-black/90 backdrop-blur-md border border-white/15 flex items-center justify-center text-white transition active:scale-90 shadow-lg" title="Thêm vào yêu thích">
<svg class="w-3 h-3 sm:w-3.5 sm:h-3.5 ${isFav ? 'fill-red-500 text-red-500 stroke-red-500' : 'fill-none stroke-current'}" viewBox="0 0 24 24" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" />
</svg>
</button>
<button onclick="shareMovie('${movie.id}', event)" class="w-6 h-6 sm:w-7 sm:h-7 rounded-full bg-black/60 hover:bg-black/90 backdrop-blur-md border border-white/15 flex items-center justify-center text-white transition active:scale-90 shadow-lg" title="Chia sẻ phim">
<svg class="w-3 h-3 sm:w-3.5 sm:h-3.5 fill-none stroke-current" viewBox="0 0 24 24" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z" />
</svg>
</button>
</div>
<!-- GÓC DƯỚI PHẢI: LƯỢT XEM COMPACT (ICON CON MẮT TRẮNG) -->
<div class="absolute bottom-2 right-2 sm:bottom-2.5 sm:right-2.5 flex items-center gap-1 px-1.5 py-0.5 sm:px-2 rounded-md bg-black/75 backdrop-blur-md border border-white/10 text-slate-100 font-mono text-[9px] sm:text-[11px] font-semibold pointer-events-none shadow-sm" title="${(movie.views || 0).toLocaleString('vi-VN')} lượt xem">
<svg class="w-2.5 h-2.5 sm:w-3.5 sm:h-3.5 text-slate-300 flex-shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
<circle cx="12" cy="12" r="3"></circle>
</svg>
<span id="movie-card-views-${movie.id}">${compactViews}</span>
</div>
</a>
<!-- THÔNG TIN PHIM PHÍA DƯỚI ẢNH -->
<div class="pt-2 sm:pt-2.5 space-y-0.5 sm:space-y-1">
<!-- Dòng 1: Tên Phim (In hoa/Đậm/Cắt dòng chuẩn) -->
<a href="${movieUrl}" onclick="event.preventDefault(); openMovieDetailPage('${movie.id}', null, true);" class="block font-bold text-white text-[11px] sm:text-[13px] leading-snug truncate group-hover:text-amber-400 transition-colors uppercase tracking-tight" title="${escapeHtml(movie.title)}">
${escapeHtml(movie.title)}
</a>
<!-- Dòng 2: Mùa & Tập (Vàng) --- Tập mới: Ngày / HÔM NAY -->
<div class="flex items-center justify-between text-[10px] sm:text-xs gap-1">
<span class="text-amber-400 font-bold truncate flex-shrink min-w-0">
${escapeHtml(seasonEpStr)}
</span>
<div class="flex items-center gap-1 text-[9px] sm:text-[11px] text-slate-400 flex-shrink-0">
<span>Tập mới:</span>
<span class="${isToday ? 'bg-slate-800 text-slate-100 font-extrabold px-1.5 py-0.5 rounded text-[8.5px] sm:text-[10px] font-mono' : 'bg-slate-800 text-slate-200 px-1.5 py-0.5 rounded text-[8.5px] sm:text-[10px] font-bold font-mono'}">
${escapeHtml(updateDate)}
</span>
</div>
</div>
</div>
`;
grid.appendChild(card);
});
}
// BỘ LỌC THEO TAB TRẠNG THÁI (TẤT CẢ, HOT, MỚI, CÀY ĐÊM, HOÀN THÀNH)
function filterStatusTab(statusKey) {
currentStatusFilter = statusKey;
// 1. Cập nhật giao diện tab trên thanh công cụ
document.querySelectorAll('#status-tabs .status-tab-btn, .status-tab-btn').forEach(btn => {
btn.className = "status-tab-btn px-3.5 py-1.5 rounded-xl bg-slate-800 text-slate-300 hover:text-white hover:bg-slate-700 transition flex items-center gap-1";
});
const activeBtn = document.querySelector(`.status-tab-btn[onclick*="'${statusKey}'"]`);
if (activeBtn) {
activeBtn.className = "status-tab-btn px-3.5 py-1.5 rounded-xl bg-gradient-to-r from-amber-500 to-orange-500 text-black font-bold shadow-md shadow-amber-500/20 transition flex items-center gap-1";
}
// 2. Cập nhật menu nav trên header
document.querySelectorAll('.status-nav-btn').forEach(btn => {
btn.className = "status-nav-btn px-3 py-2 rounded-lg text-slate-300 hover:text-amber-400 hover:bg-slate-800/80 transition flex items-center gap-1";
});
const activeNav = document.querySelector(`.status-nav-btn[onclick*="'${statusKey}'"]`);
if (activeNav) {
activeNav.className = "status-nav-btn px-3 py-2 rounded-lg text-amber-400 bg-amber-500/10 border border-amber-500/30 transition flex items-center gap-1";
}
// 3. Đổi tiêu đề khối phim
const titles = {
'all': 'TẬP MỚI CẬP NHẬT',
'hot': '🔥 PHIM ĐANG THỊNH HÀNH (HOT)',
'new': '⚡ PHIM MỚI CẬP NHẬT HÔM NAY',
'cay-dem': '🌙 DANH SÁCH TU LUYỆN CÀY ĐÊM',
'hoan-thanh': '✨ PHIM TRỌN BỘ ĐÃ HOÀN THÀNH'
};
const titleEl = document.getElementById('catalog-section-title');
if (titleEl) {
if (titles[statusKey]) {
titleEl.innerText = titles[statusKey];
} else {
titleEl.innerText = `PHIM: ${getStatusLabel(statusKey).toUpperCase()}`;
}
}
applyFiltersAndSort();
}
// BỘ LỌC THEO THỂ LOẠI (DẢI CHIPS CUỘN NGANG)
function filterGenre(genreKey) {
currentGenreFilter = genreKey;
renderGenreChips();
applyFiltersAndSort();
}
// SẮP XẾP DANH SÁCH PHIM
function handleSortChange(sortKey) {
currentSortFilter = sortKey;
applyFiltersAndSort(true);
}
// Hàm loại bỏ dấu tiếng Việt để tìm kiếm không dấu ("tro tan" tìm được "TRO TÀN CỬU CHÂU")
function removeVietnameseTones(str) {
if (!str) return '';
str = String(str).toLowerCase().trim();
str = str.replace(/à|á|ạ|ả|ã|â|ầ|ấ|ậ|ẩ|ẫ|ă|ằ|ắ|ặ|ẳ|ẵ/g, "a");
str = str.replace(/è|é|ẹ|ẻ|ẽ|ê|ề|ế|ệ|ể|ễ/g, "e");
str = str.replace(/ì|í|ị|ỉ|ĩ/g, "i");
str = str.replace(/ò|ó|ọ|ỏ|õ|ô|ồ|ố|ộ|ổ|ỗ|ơ|ờ|ớ|ợ|ở|ỡ/g, "o");
str = str.replace(/ù|ú|ụ|ủ|ũ|ư|ừ|ứ|ự|ử|ữ/g, "u");
str = str.replace(/ỳ|ý|ỵ|ỷ|ỹ/g, "y");
str = str.replace(/đ/g, "d");
str = str.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
return str;
}
// TÌM KIẾM THEO TÊN PHIM HOẶC THỂ LOẠI (HỖ TRỢ CẢ CÓ DẤU VÀ KHÔNG DẤU)
function handleSearch(keyword) {
currentSearchKeyword = (keyword || '').trim();
applyFiltersAndSort(true);
}
// ÁP DỤNG ĐỒNG THỜI BỘ LỌC, TÌM KIẾM, SẮP XẾP VÀ PHÂN TRANG (16 PHIM / TRANG)
function applyFiltersAndSort(resetPage = true) {
if (resetPage) {
currentMoviePage = 1;
}
let filtered = [...MOVIES_DATABASE];
// 1. Lọc theo từ khóa tìm kiếm
if (currentSearchKeyword) {
const clean = currentSearchKeyword.toLowerCase();
const normClean = removeVietnameseTones(clean);
filtered = filtered.filter(m => {
const title = (m.title || '').toLowerCase();
const normTitle = removeVietnameseTones(title);
const desc = (m.desc || '').toLowerCase();
const normDesc = removeVietnameseTones(desc);
const genreStr = getMovieGenresList(m).map(g => getGenreLabel(g)).join(' ').toLowerCase();
const normGenreStr = removeVietnameseTones(genreStr);
const id = (m.id || '').toLowerCase();
return title.includes(clean) ||
normTitle.includes(normClean) ||
desc.includes(clean) ||
normDesc.includes(normClean) ||
genreStr.includes(clean) ||
normGenreStr.includes(normClean) ||
(m.genre && m.genre.toLowerCase().includes(clean)) ||
id.includes(clean);
});
}
// 2. Lọc theo Status Tab
if (currentStatusFilter !== 'all') {
filtered = filtered.filter(m => (m.status || 'new') === currentStatusFilter);
}
// 3. Lọc theo Thể loại (Hỗ trợ phim có nhiều thể loại)
if (currentGenreFilter !== 'all') {
filtered = filtered.filter(m => {
const list = getMovieGenresList(m);
return list.includes(currentGenreFilter);
});
}
// 4. Sắp xếp
if (currentSortFilter === 'views') {
filtered.sort((a, b) => (parseInt(b.views) || 0) - (parseInt(a.views) || 0));
} else if (currentSortFilter === 'rating') {
filtered.sort((a, b) => (parseFloat(b.rating) || 0) - (parseFloat(a.rating) || 0));
} else {
// newest: Phim mới đăng hoặc mới cập nhật tập mới sẽ luôn hiển thị lên đầu tiên
filtered.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0));
}
// Cập nhật số lượng hiển thị tổng cộng
const countEl = document.getElementById('catalog-total-count');
if (countEl) {
countEl.innerText = currentSearchKeyword
? `(${filtered.length} kết quả)`
: `(${filtered.length} bộ phim)`;
}
// 5. Phân trang: Mỗi trang chỉ hiện tối đa 16 phim mới nhất
const totalPages = Math.ceil(filtered.length / MOVIES_PER_PAGE);
if (currentMoviePage > totalPages) {
currentMoviePage = Math.max(1, totalPages);
}
const startIndex = (currentMoviePage - 1) * MOVIES_PER_PAGE;
const paginatedMovies = filtered.slice(startIndex, startIndex + MOVIES_PER_PAGE);
renderMoviesGrid(paginatedMovies);
renderPagination(filtered.length, currentMoviePage);
}
// RENDER THANH PHÂN TRANG (PAGINATION) CHUẨN THEO ẢNH MẪU
function renderPagination(totalItems, currentPage) {
const container = document.getElementById('movies-pagination');
if (!container) return;
const totalPages = Math.ceil(totalItems / MOVIES_PER_PAGE);
// Nếu chỉ có tối đa 16 phim (tức 1 trang hoặc ít hơn) thì ẩn thanh phân trang
if (totalPages <= 1) {
container.innerHTML = '';
container.classList.add('hidden');
return;
}
container.classList.remove('hidden');
container.innerHTML = '';
const btnBaseClass = "min-w-[38px] sm:min-w-[46px] h-9 sm:h-11 px-2.5 rounded-xl sm:rounded-2xl flex items-center justify-center font-black text-xs sm:text-sm transition-all duration-200 select-none";
const activeClass = `${btnBaseClass} bg-amber-500 text-black shadow-lg shadow-amber-500/30 cursor-default`;
const inactiveClass = `${btnBaseClass} bg-[#0d1527] hover:bg-slate-800 text-slate-100 hover:text-amber-400 border border-slate-800 hover:border-amber-500/50 cursor-pointer active:scale-95 shadow-sm`;
const disabledNavClass = `${btnBaseClass} bg-[#0b101c]/60 text-slate-600 border border-slate-800/40 cursor-not-allowed`;
const activeNavClass = `${btnBaseClass} bg-[#0d1527] hover:bg-slate-800 text-slate-300 hover:text-white border border-slate-800 hover:border-amber-500/50 cursor-pointer active:scale-95 shadow-sm`;
// 1. NÚT PREVIOUS (‹)
const prevBtn = document.createElement('button');
prevBtn.innerHTML = '‹';
prevBtn.title = "Trang trước";
if (currentPage > 1) {
prevBtn.className = activeNavClass;
prevBtn.onclick = () => goToMoviePage(currentPage - 1);
} else {
prevBtn.className = disabledNavClass;
prevBtn.disabled = true;
}
container.appendChild(prevBtn);
// 2. TÍNH TOÁN CÁC NÚT SỐ TRANG HIỂN THỊ (CHUẨN THEO ẢNH MẪU)
const pages = [];
if (totalPages <= 7) {
for (let i = 1; i <= totalPages; i++) pages.push(i);
} else {
if (currentPage <= 4) {
pages.push(1, 2, 3, 4, 5, '...', totalPages);
} else if (currentPage >= totalPages - 3) {
pages.push(1, '...', totalPages - 4, totalPages - 3, totalPages - 2, totalPages - 1, totalPages);
} else {
pages.push(1, '...', currentPage - 1, currentPage, currentPage + 1, '...', totalPages);
}
}
pages.forEach(p => {
if (p === '...') {
const ellipsis = document.createElement('span');
ellipsis.className = "w-6 sm:w-8 h-9 sm:h-11 flex items-center justify-center text-slate-400 font-extrabold text-sm sm:text-base select-none tracking-widest";
ellipsis.innerText = '...';
container.appendChild(ellipsis);
} else {
const pageBtn = document.createElement('button');
pageBtn.innerText = p;
if (p === currentPage) {
pageBtn.className = activeClass;
} else {
pageBtn.className = inactiveClass;
pageBtn.onclick = () => goToMoviePage(p);
}
container.appendChild(pageBtn);
}
});
// 3. NÚT NEXT (›)
const nextBtn = document.createElement('button');
nextBtn.innerHTML = '›';
nextBtn.title = "Trang sau";
if (currentPage < totalPages) {
nextBtn.className = activeNavClass;
nextBtn.onclick = () => goToMoviePage(currentPage + 1);
} else {
nextBtn.className = disabledNavClass;
nextBtn.disabled = true;
}
container.appendChild(nextBtn);
}
function goToMoviePage(page) {
currentMoviePage = page;
applyFiltersAndSort(false);
const targetEl = document.getElementById('catalog-section-title') || document.getElementById('main-movies-section');
if (targetEl) {
targetEl.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}
function escapeHtml(str) {
if (!str) return '';
return String(str).replace(/"/g, '"').replace(/'/g, ''');
}
// RENDER TOP VIEWS (KHU VỰC CỘNG ĐỒNG)
function renderTopViews() {
const container = document.getElementById('top-views-list');
if (!container) return;
container.innerHTML = '';
const sorted = [...MOVIES_DATABASE].sort((a, b) => (b.views || 0) - (a.views || 0)).slice(0, 5);
sorted.forEach((m, idx) => {
const slug = getMovieSlug(m);
const movieUrl = getMovieUrl(m);
const item = document.createElement('div');
item.className = "flex items-center gap-3 p-2 rounded-xl hover:bg-slate-800/50 cursor-pointer transition border border-slate-800/40 hover:border-amber-500/30";
item.onclick = (e) => {
if (e.target.closest('button')) return;
openMovieDetailPage(m.id, null, true);
};
item.innerHTML = `
<span class="font-mono font-black text-sm ${idx === 0 ? 'text-amber-400' : (idx === 1 ? 'text-orange-400' : 'text-slate-500')} w-6 text-center">0${idx+1}</span>
<a href="${movieUrl}" onclick="event.preventDefault(); openMovieDetailPage('${m.id}', null, true);" class="block flex-shrink-0">
<img src="${m.image}" class="w-9 h-12 rounded-lg object-cover bg-slate-800">
</a>
<div class="flex-1 min-w-0">
<a href="${movieUrl}" onclick="event.preventDefault(); openMovieDetailPage('${m.id}', null, true);" class="block text-xs font-bold text-slate-200 truncate hover:text-amber-400">${m.title}</a>
<div class="text-[10px] text-slate-400 flex items-center gap-2 mt-0.5">
<span class="text-amber-300 font-semibold truncate max-w-[110px]" title="${escapeHtml(getLatestEpisodeTitle(m))}">⚡ ${escapeHtml(getLatestEpisodeTitle(m))}</span>
<span>•</span>
<span class="text-slate-300 font-mono">👁️ ${(m.views || 0).toLocaleString('vi-VN')}</span>
<span>•</span>
<span class="text-amber-300">⭐ ${m.rating}</span>
</div>
</div>
`;
container.appendChild(item);
});
}
// LẤY THÔNG TIN TẬP PHIM HIỆN TẠI (HỖ TRỢ ĐỔI TÊN TẬP VÀ LINK RIÊNG TỪNG TẬP)
function getCurrentEpisodeData(movie, epNum) {
if (!movie) return { ep: epNum || 1, title: `Tập ${epNum || 1}`, streamUrl: '', iframeUrl: '', iframeBackupUrl: '' };
const targetEp = parseInt(epNum) || 1;
if (Array.isArray(movie.episodes) && movie.episodes.length > 0) {
const found = movie.episodes.find(e => parseInt(e.ep) === targetEp);
if (found) {
const hasOwnStream = !!(found.streamUrl && found.streamUrl.trim());
const hasOwnIframe = !!(found.iframeUrl && found.iframeUrl.trim());
const hasOwnBackup = !!(found.iframeBackupUrl && found.iframeBackupUrl.trim());
// Chỉ cho phép mượn link gốc của phim nếu là Tập 1 và tập 1 chưa điền link riêng
const fallbackStream = (targetEp === 1) ? (movie.streamUrl || '') : '';
const fallbackIframe = (targetEp === 1) ? (movie.iframeUrl || '') : '';
const fallbackBackup = (targetEp === 1) ? (movie.iframeBackupUrl || '') : '';
return {
...found,
ep: targetEp,
title: found.title || `Tập ${targetEp}`,
streamUrl: hasOwnStream ? found.streamUrl.trim() : fallbackStream,
iframeUrl: hasOwnIframe ? found.iframeUrl.trim() : fallbackIframe,
iframeBackupUrl: hasOwnBackup ? found.iframeBackupUrl.trim() : fallbackBackup
};
}
}
// Nếu phim không có mảng episodes (chỉ có tổng số tập):
const fallbackStream = (targetEp === 1) ? (movie.streamUrl || '') : '';
const fallbackIframe = (targetEp === 1) ? (movie.iframeUrl || '') : '';
const fallbackBackup = (targetEp === 1) ? (movie.iframeBackupUrl || '') : '';
return {
ep: targetEp,
title: `Tập ${targetEp}`,
streamUrl: fallbackStream,
iframeUrl: fallbackIframe,
iframeBackupUrl: fallbackBackup
};
}
// Kiểm tra xem tập phim cụ thể có bất kỳ link máy chủ nào (Youtube, FB, HLS) không
function hasEpisodeServerLink(movie, epNum) {
if (!movie) return false;
const epData = getCurrentEpisodeData(movie, epNum);
return !!(
(epData.iframeUrl && epData.iframeUrl.trim()) ||
(epData.iframeBackupUrl && epData.iframeBackupUrl.trim()) ||
(epData.streamUrl && epData.streamUrl.trim())
);
}
// Hiển thị khung thông báo trong player khi tập chưa có link server (giữ nguyên player, không bị văng về trang phim)
function showNoEpisodeLinkOverlay(epTitle) {
const overlay = document.getElementById('player-no-link-overlay');
const iframe = document.getElementById('iframe-player');
const artContainer = document.getElementById('artplayer-container');
const epLabel = document.getElementById('modal-player-ep-label');
if (artPlayerInstance) artPlayerInstance.pause();
if (artContainer) artContainer.classList.add('hidden');
if (iframe) {
iframe.classList.add('hidden');
iframe.src = 'about:blank';
}
if (overlay) {
overlay.classList.remove('hidden');
const titleEl = document.getElementById('no-link-overlay-title');
if (titleEl) titleEl.innerText = `${epTitle || 'Tập phim'} đang cập nhật nguồn phát`;
}
if (epLabel) epLabel.innerText = `Đang xem ${epTitle || ''} • [Chưa có Link Server]`;
showToast(`⚠️ ${epTitle || 'Tập này'} hiện chưa có link máy chủ phát! Đạo hữu vui lòng chọn tập khác.`);
}
// Ẩn khung thông báo khi chuyển sang tập có link
function hideNoEpisodeLinkOverlay() {
const overlay = document.getElementById('player-no-link-overlay');
if (overlay) overlay.classList.add('hidden');
}
// MỞ KHUNG XEM PHIM (INTEGRATED ARTPLAYER & BREADCRUMBS)
function openVideoModal(movieId, title, epNumber, updateUrl = true) {
const movie = MOVIES_DATABASE.find(m => m.id === movieId) || MOVIES_DATABASE[0];
currentMovie = movie;
// ĐĂNG KÝ BỘ ĐẾM LƯỢT XEM CHUẨN (CÓ CHỐNG SPAM)
registerMovieView(movie.id);
// Danh sách tập có cấu trúc (hỗ trợ đổi tên tập)
const epList = (Array.isArray(movie.episodes) && movie.episodes.length > 0)
? movie.episodes
: Array.from({ length: movie.ep || 1 }, (_, i) => ({ ep: i + 1, title: `Tập ${i + 1}` }));
const curEp = epList.find(e => e.ep === epNumber) || epList[0] || { ep: epNumber || 1, title: `Tập ${epNumber || 1}` };
currentEpisode = curEp.ep;
// CẬP NHẬT URL TRÊN THANH ĐỊA CHỈ TRÌNH DUYỆT (tenmien.com/phim/ten-phim)
if (updateUrl) {
updateMovieBrowserUrl(movie, curEp.ep);
}
// Cập nhật SEO động cho từng phim (Title: Tên phim, Description: Tóm tắt nội dung)
updateMovieSEO(movie, curEp);
const playerModal = document.getElementById('modal-video-player');
playerModal.classList.remove('hidden');
document.body.style.overflow = 'hidden';
// Cập nhật lượt xem trong player
updateModalPlayerViews(movie.views || 0);
// Cập nhật tiêu đề phim & tập
document.getElementById('modal-player-title').innerText = movie.title;
document.getElementById('modal-player-ep-label').innerText = `Đang phát ${curEp.title} • [VIP HLS 4K]`;
document.getElementById('modal-player-desc').innerText = movie.desc;
document.getElementById('modal-total-eps-label').innerText = `(Tổng ${epList.length} Tập)`;
const epIndicator = document.getElementById('modal-player-ep-indicator');
if (epIndicator) epIndicator.innerText = `Đang xem: ${curEp.title}`;
// Cập nhật Breadcrumbs trên thanh Header xem phim
const breadcrumbGenre = document.getElementById('modal-breadcrumb-genre');
if (breadcrumbGenre) {
const gList = getMovieGenresList(movie);
breadcrumbGenre.innerText = gList.map(g => getGenreLabel(g)).join(' • ') || 'Tu Tiên';
}
const breadcrumbTitle = document.getElementById('modal-breadcrumb-title');
if (breadcrumbTitle) {
breadcrumbTitle.innerText = movie.title;
breadcrumbTitle.onclick = function(e) {
e.preventDefault();
returnToDetailFromPlayer();
};
}
const breadcrumbEp = document.getElementById('modal-breadcrumb-ep');
if (breadcrumbEp) breadcrumbEp.innerText = curEp.title;
const breadcrumbRating = document.getElementById('modal-breadcrumb-rating');
if (breadcrumbRating) breadcrumbRating.innerText = `⭐ ${movie.rating || '9.8'}`;
// Cập nhật nút mở trang phim độc lập
const openPageBtn = document.getElementById('btn-open-movie-page');
if (openPageBtn) {
openPageBtn.onclick = function(e) {
e.preventDefault();
returnToDetailFromPlayer();
};
}
// Reset ô tìm kiếm trong player
const pSearch = document.getElementById('player-search-input');
if (pSearch) pSearch.value = '';
const pResults = document.getElementById('player-search-results');
if (pResults) {
pResults.classList.add('hidden');
pResults.innerHTML = '';
}
// Cuộn lên đầu trang xem phim khi đổi phim/tập
playerModal.scrollTop = 0;
// 1. SINH DANH SÁCH TẬP (HỖ TRỢ HIỂN THỊ TÊN TẬP TÙY CHỈNH)
const epContainer = document.getElementById('modal-episodes-list');
if (epContainer) {
epContainer.innerHTML = '';
epList.forEach(item => {
const btn = document.createElement('button');
const isActive = (item.ep === currentEpisode);
const hasLink = hasEpisodeServerLink(movie, item.ep);
btn.className = isActive
? "py-2 px-2 rounded-xl text-xs font-black bg-gradient-to-r from-amber-500 to-orange-500 text-black text-center shadow-lg shadow-amber-500/25 ring-2 ring-amber-400 transition active:scale-95 flex items-center justify-center min-w-0"
: (hasLink
? "py-2 px-2 rounded-xl text-xs font-semibold bg-slate-900 hover:bg-slate-800 text-slate-300 hover:text-white text-center border border-slate-800/80 hover:border-amber-500/50 transition active:scale-95 flex items-center justify-center min-w-0"
: "py-2 px-2 rounded-xl text-xs font-medium bg-slate-900/60 hover:bg-slate-800/90 text-slate-500 hover:text-slate-300 text-center border border-dashed border-slate-800 hover:border-amber-500/30 transition active:scale-95 flex items-center justify-center min-w-0");
btn.innerHTML = `<span class="truncate block w-full text-center" title="${escapeHtml(item.title)}${hasLink ? '' : ' (Chưa có link server - Đang cập nhật)'}">${escapeHtml(item.title)}</span>`;
btn.onclick = () => openVideoModal(movieId, item.title, item.ep, true);
epContainer.appendChild(btn);
});
}
// 2. SINH DANH SÁCH CÁC PHIM MỚI ĐĂNG (CỘT BÊN PHẢI)
const recentContainer = document.getElementById('modal-recent-movies-list');
if (recentContainer) {
recentContainer.innerHTML = '';
MOVIES_DATABASE.forEach(m => {
const isCurrent = (m.id === movieId);
const item = document.createElement('div');
item.className = `flex items-center gap-3 p-2 rounded-xl transition cursor-pointer border ${isCurrent ? 'bg-amber-500/10 border-amber-500/40 ring-1 ring-amber-500/20' : 'bg-slate-900/60 hover:bg-slate-800/80 border-slate-800/60'}`;
item.onclick = () => openMovieDetailPage(m.id, null, true);
item.innerHTML = `
<div class="relative w-12 h-16 rounded-lg overflow-hidden flex-shrink-0 bg-slate-800">
<img src="${m.image}" class="w-full h-full object-cover">
<span class="absolute bottom-0 inset-x-0 bg-black/85 text-[9px] text-center font-bold text-amber-300 py-0.5 truncate">${escapeHtml(getLatestEpisodeTitle(m))}</span>
</div>
<div class="flex-1 min-w-0">
<h4 class="text-xs font-bold text-slate-200 truncate hover:text-amber-400 transition">${m.title}</h4>
<div class="text-[10px] text-slate-400 flex items-center gap-2 mt-0.5">
<span class="capitalize text-amber-400/80 truncate max-w-[100px]">${getMovieGenresList(m).map(g => getGenreLabel(g)).join(' • ')}</span>
<span>•</span>
<span>⭐ ${m.rating}</span>
<span>•</span>
<span class="text-slate-300 font-mono">👁️ ${(m.views || 0).toLocaleString('vi-VN')}</span>
</div>
<div class="text-[10px] text-emerald-400 mt-0.5 flex items-center gap-1">
<span class="w-1.5 h-1.5 rounded-full bg-emerald-400"></span> Mới nhất: <strong class="text-amber-300 font-normal truncate">${escapeHtml(getLatestEpisodeTitle(m))}</strong>
</div>
</div>
`;
recentContainer.appendChild(item);
});
}
// Khởi tạo máy chủ phát phim cho tập đang chọn (Kiểm tra an toàn link server)
fallbackAttempted = {};
const hasAnyLink = hasEpisodeServerLink(movie, curEp.ep);
if (!hasAnyLink) {
showNoEpisodeLinkOverlay(curEp.title);
} else {
hideNoEpisodeLinkOverlay();
const epData = getCurrentEpisodeData(movie, curEp.ep);
if (epData.iframeUrl && epData.iframeUrl.trim()) {
switchServer('iframe1');
} else if (epData.iframeBackupUrl && epData.iframeBackupUrl.trim()) {
switchServer('iframe2');
} else if (epData.streamUrl && epData.streamUrl.trim()) {
switchServer('hls1');
} else {
switchServer('iframe1');
}
}
// Tải và hiển thị bình luận ở cuối tóm tắt nội dung phim
renderMovieComments(movie.id);
// Bắt đầu đếm tu vi
startTuViTicker();
}
function closeVideoModal(updateUrl = true) {
hideNoEpisodeLinkOverlay();
const playerModal = document.getElementById('modal-video-player');
if (playerModal) playerModal.classList.add('hidden');
document.body.style.overflow = '';
if (artPlayerInstance) artPlayerInstance.pause();
const iframe = document.getElementById('iframe-player');
if (iframe) iframe.src = 'about:blank';
if (watchTimer) clearInterval(watchTimer);
if (updateUrl) {
if (currentDetailMovie) {
updateMovieBrowserUrl(currentDetailMovie);
} else {
clearMovieBrowserUrl();
}
}
if (currentDetailMovie) {
updateMovieSEO(currentDetailMovie);
} else {
resetDefaultSEO();
}
applyFiltersAndSort(); // Đồng bộ lại thẻ phim và thứ tự sắp xếp theo lượt xem mới nhất
}
function returnToDetailFromPlayer() {
closeVideoModal(false);
if (currentMovie) {
openMovieDetailPage(currentMovie.id, null, true);
}
}
function handleGoHomeFromPlayer() {
closeVideoModal(false);
handleGoHome();
}
// ĐIỀU HƯỚNG TỪ TRANG XEM PHIM VỀ DANH MỤC TRANG CHỦ THEO THỂ LOẠI
function navigateFromPlayer(genreKey) {
closeVideoModal();
if (genreKey) {
filterGenre(genreKey);
}
const section = document.getElementById('main-movies-section');
if (section) {
section.scrollIntoView({ behavior: 'smooth' });
}
}
// CUỘN MƯỢT ĐẾN PHẦN BÌNH LUẬN HOẶC NỘI DUNG TRONG TRANG XEM PHIM
function scrollToPlayerSection(sectionId) {
const el = document.getElementById(sectionId);
if (el) {
el.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}
// TÌM KIẾM ĐỔI PHIM TRỰC TIẾP TRÊN THANH HEADER XEM PHIM (HỖ TRỢ CÓ DẤU & KHÔNG DẤU)
function handlePlayerSearch(keyword) {
const box = document.getElementById('player-search-results');
if (!box) return;
const clean = (keyword || '').toLowerCase().trim();
const normClean = removeVietnameseTones(clean);
if (!clean) {
box.classList.add('hidden');
box.innerHTML = '';
return;
}
const matches = MOVIES_DATABASE.filter(m => {
const title = (m.title || '').toLowerCase();
const normTitle = removeVietnameseTones(title);
const genreStr = getMovieGenresList(m).map(g => getGenreLabel(g)).join(' ').toLowerCase();
const normGenreStr = removeVietnameseTones(genreStr);
const id = (m.id || '').toLowerCase();
return title.includes(clean) ||
normTitle.includes(normClean) ||
genreStr.includes(clean) ||
normGenreStr.includes(normClean) ||
id.includes(clean);
});
if (matches.length === 0) {
box.innerHTML = `<div class="p-3 text-xs text-slate-400 text-center">Không tìm thấy phim phù hợp</div>`;
box.classList.remove('hidden');
return;
}
box.innerHTML = matches.map(m => {
const gText = getMovieGenresList(m).map(g => getGenreLabel(g)).join(' • ');
return `
<div onclick="openMovieDetailPage('${m.id}', null, true); document.getElementById('player-search-results').classList.add('hidden');"
class="flex items-center gap-2.5 p-2 rounded-xl hover:bg-slate-800 cursor-pointer transition">
<img src="${m.image}" class="w-10 h-14 object-cover rounded-lg flex-shrink-0 bg-slate-800 shadow">
<div class="flex-1 min-w-0">
<div class="text-xs font-bold text-slate-200 truncate hover:text-amber-400">${m.title}</div>
<div class="text-[10px] text-slate-400 flex items-center gap-1.5 mt-0.5">
<span class="text-amber-400 truncate max-w-[130px]">${gText}</span>
<span>•</span>
<span>Tập ${m.ep}</span>
<span>•</span>
<span>⭐ ${m.rating}</span>
</div>
</div>
</div>
`;}).join('');
box.classList.remove('hidden');
}
let currentServer = 'iframe1';
let fallbackAttempted = {};
function handleIframeError() {
if (currentServer && currentServer !== 'custom' && currentServer.startsWith('iframe')) {
fallbackToNextServer(currentServer, "Iframe error event triggered");
}
}
function fallbackToNextServer(failedServer, reason = "") {
if (failedServer === 'custom' || fallbackAttempted[failedServer]) return;
fallbackAttempted[failedServer] = true;
console.warn(`[Auto-Fallback] Server ${failedServer} gặp sự cố (${reason}), đang tự động chuyển sang server dự phòng...`);
if (failedServer === 'iframe1') {
showToast("⚠️ SV Youtube gặp sự cố. Đang tự động chuyển sang Sever FB...");
setTimeout(() => switchServer('iframe2', true), 700);
} else if (failedServer === 'iframe2') {
showToast("⚠️ Sever FB không phát được. Đang tự động chuyển sang VIP HLS #1...");
setTimeout(() => switchServer('hls1', true), 700);
} else if (failedServer === 'hls1') {
showToast("⚠️ Server VIP HLS #1 gặp sự cố. Đang tự động chuyển sang Dự Phòng HLS...");
setTimeout(() => switchServer('hls2', true), 700);
}
}
// Lắng nghe tín hiệu thông báo lỗi thật sự từ YouTube Embed API (mã 100: video không tồn tại/đã bị xoá, 101/150: chủ sở hữu chặn quyền nhúng bên ngoài)
window.addEventListener('message', function(event) {
if (!currentServer || currentServer === 'custom' || !currentServer.startsWith('iframe')) return;
try {
let data = event.data;
if (typeof data === 'string') {
try { data = JSON.parse(data); } catch(e) {}
}
if (data && typeof data === 'object') {
// Tuyệt đối không bắt các state thông thường như info 2, 5 trong quá trình nạp
if (data.event === 'onError' && (data.info === 100 || data.info === 101 || data.info === 150)) {
fallbackToNextServer(currentServer, `YouTube error ${data.info}`);
}
}
} catch(e) {}
});
function initArtPlayer(url) {
hideNoEpisodeLinkOverlay();
document.getElementById('iframe-player').classList.add('hidden');
const container = document.getElementById('artplayer-container');
container.classList.remove('hidden');
if (artPlayerInstance) {
artPlayerInstance.destroy(false);
}
artPlayerInstance = new Artplayer({
container: '#artplayer-container',
url: url,
type: 'm3u8',
customType: {
m3u8: function (video, url) {
if (Hls.isSupported()) {
const hls = new Hls();
hls.loadSource(url);
hls.attachMedia(video);
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = url;
} else {
artPlayerInstance.notice.show = 'Trình duyệt không hỗ trợ HLS';
}
},
},
title: currentMovie ? currentMovie.title : '',
poster: currentMovie ? currentMovie.image : '',
volume: 0.8,
autoplay: true,
pip: true,
autoSize: true,
autoMini: true,
screenshot: true,
setting: true,
loop: false,
playbackRate: true,
aspectRatio: true,
fullscreen: true,
fullscreenWeb: true,
theme: '#f59e0b',
highlight: [
{ time: 60, text: 'Hết Nhạc Đầu Phim' },
{ time: 1200, text: 'Bắt Đầu Nhạc Kết Thúc' }
]
});
artPlayerInstance.on('play', () => {
showToast("⚡ Đang phát luồng HLS 4K. Đã bắt đầu hấp thu tu vi!");
});
// Tự động chuyển server nếu luồng HLS gặp lỗi
artPlayerInstance.on('error', (error) => {
console.warn('Artplayer error:', error);
if (currentServer === 'hls1') {
fallbackToNextServer('hls1', 'HLS stream error');
} else if (currentServer === 'hls2') {
fallbackToNextServer('hls2', 'HLS backup error');
}
});
}
function switchServer(srv, isAutoFallback = false) {
currentServer = srv;
const btn1 = document.getElementById('btn-srv-1');
const btn2 = document.getElementById('btn-srv-2');
const btn3 = document.getElementById('btn-srv-3');
const btn4 = document.getElementById('btn-srv-4');
const resetClass = "px-3 py-1.5 rounded-xl bg-slate-800 text-slate-300 hover:bg-slate-700 transition flex items-center gap-1";
const activeClass = "px-3 py-1.5 rounded-xl bg-amber-500 text-black font-bold flex items-center gap-1 shadow transition";
if (btn1) btn1.className = resetClass;
if (btn2) btn2.className = resetClass;
if (btn3) btn3.className = resetClass;
if (btn4) btn4.className = resetClass;
const artContainer = document.getElementById('artplayer-container');
const iframe = document.getElementById('iframe-player');
const epLabel = document.getElementById('modal-player-ep-label');
const epData = getCurrentEpisodeData(currentMovie, currentEpisode);
const epTitle = epData.title || `Tập ${currentEpisode}`;
// Kiểm tra xem tập hiện tại có link hay chưa
const hasLink = hasEpisodeServerLink(currentMovie, currentEpisode);
if (!hasLink) {
showNoEpisodeLinkOverlay(epTitle);
return;
}
hideNoEpisodeLinkOverlay();
if (srv === 'iframe1') {
if (btn3) btn3.className = activeClass;
if (artPlayerInstance) artPlayerInstance.pause();
artContainer.classList.add('hidden');
iframe.classList.remove('hidden');
const rawUrl = (epData.iframeUrl && epData.iframeUrl.trim())
? epData.iframeUrl.trim()
: (currentEpisode === 1 && currentMovie ? (currentMovie.iframeUrl || '') : '');
if (!rawUrl) {
if (epData.iframeBackupUrl && epData.iframeBackupUrl.trim()) {
switchServer('iframe2', true);
return;
}
if (epData.streamUrl && epData.streamUrl.trim()) {
switchServer('hls1', true);
return;
}
showNoEpisodeLinkOverlay(epTitle);
return;
}
const parsed = formatEmbedUrl(rawUrl);
if (!parsed || !parsed.url) {
fallbackToNextServer('iframe1', 'Invalid SV Youtube URL');
return;
}
iframe.referrerPolicy = "strict-origin-when-cross-origin";
iframe.src = parsed.url;
updateDirectYtButton(parsed);
updateYouTubeHelpBar(parsed);
if (epLabel) epLabel.innerText = `Đang phát ${epTitle} • [SV Youtube]`;
if (!isAutoFallback) {
showToast(`🌐 Đang phát ${epTitle} qua SV Youtube!`);
}
} else if (srv === 'iframe2') {
if (btn4) btn4.className = activeClass;
if (artPlayerInstance) artPlayerInstance.pause();
artContainer.classList.add('hidden');
iframe.classList.remove('hidden');
const rawUrl = (epData.iframeBackupUrl && epData.iframeBackupUrl.trim())
? epData.iframeBackupUrl.trim()
: (currentEpisode === 1 && currentMovie && currentMovie.iframeBackupUrl ? currentMovie.iframeBackupUrl.trim() : '');
if (!rawUrl) {
if (epData.streamUrl && epData.streamUrl.trim()) {
switchServer('hls1', true);
return;
}
if (epData.iframeUrl && epData.iframeUrl.trim()) {
switchServer('iframe1', true);
return;
}
showNoEpisodeLinkOverlay(epTitle);
return;
}
const parsed = formatEmbedUrl(rawUrl);
if (!parsed || !parsed.url) {
fallbackToNextServer('iframe2', 'Invalid Sever FB URL');
return;
}
iframe.referrerPolicy = "strict-origin-when-cross-origin";
iframe.src = parsed.url;
updateDirectYtButton(parsed);
updateYouTubeHelpBar(parsed);
if (epLabel) epLabel.innerText = `Đang phát ${epTitle} • [Sever FB]`;
if (!isAutoFallback) {
showToast(`🌐 Đang phát ${epTitle} qua Sever FB`);
}
} else if (srv === 'hls1') {
if (btn1) btn1.className = activeClass;
iframe.classList.add('hidden');
iframe.src = "";
updateYouTubeHelpBar(null);
const hlsUrl = (epData.streamUrl && epData.streamUrl.trim())
? epData.streamUrl.trim()
: (currentEpisode === 1 && currentMovie && currentMovie.streamUrl ? currentMovie.streamUrl.trim() : '');
if (!hlsUrl) {
if (epData.iframeUrl && epData.iframeUrl.trim()) {
switchServer('iframe1', true);
return;
}
if (epData.iframeBackupUrl && epData.iframeBackupUrl.trim()) {
switchServer('iframe2', true);
return;
}
showNoEpisodeLinkOverlay(epTitle);
return;
}
initArtPlayer(hlsUrl);
if (epLabel) epLabel.innerText = `Đang phát ${epTitle} • [VIP HLS 4K]`;
if (!isAutoFallback) {
showToast(`⚡ Đang phát ${epTitle} qua Server VIP HLS 4K`);
}
} else if (srv === 'hls2') {
if (btn2) btn2.className = activeClass;
iframe.classList.add('hidden');
iframe.src = "";
updateYouTubeHelpBar(null);
const hlsUrl = (epData.streamUrl && epData.streamUrl.trim())
? epData.streamUrl.trim()
: (currentEpisode === 1 && currentMovie && currentMovie.streamUrl ? currentMovie.streamUrl.trim() : '');
if (!hlsUrl) {
if (epData.iframeUrl && epData.iframeUrl.trim()) {
switchServer('iframe1', true);
return;
}
if (epData.iframeBackupUrl && epData.iframeBackupUrl.trim()) {
switchServer('iframe2', true);
return;
}
showNoEpisodeLinkOverlay(epTitle);
return;
}
initArtPlayer(hlsUrl);
if (epLabel) epLabel.innerText = `Đang phát ${epTitle} • [Dự Phòng HLS]`;
if (!isAutoFallback) {
showToast(`⚡ Đang phát ${epTitle} qua Server Dự Phòng HLS`);
}
}
}
function toggleCustomIframeBox() {
const box = document.getElementById('custom-iframe-box');
box.classList.toggle('hidden');
}
function extractYouTubeId(input) {
if (!input) return null;
let str = input.trim();
// 1. Trích xuất src từ thẻ iframe nếu có
const iframeSrcMatch = str.match(/src=["']?([^"'\s>]+)["']?/i);
if (iframeSrcMatch && iframeSrcMatch[1]) {
str = iframeSrcMatch[1];
}
str = str.replace(/&/g, '&');
// 2. youtu.be/ID (link rút gọn)
let m = str.match(/youtu\.be\/([a-zA-Z0-9_-]{11})/i);
if (m) return m[1];
// 3. youtube.com/watch?v=ID hoặc kèm tham số
m = str.match(/[?&]v=([a-zA-Z0-9_-]{11})/i);
if (m) return m[1];
// 4. youtube.com/embed/ID (link embed trực tiếp)
m = str.match(/youtube(?:-nocookie)?\.com\/embed\/([a-zA-Z0-9_-]{11})/i);
if (m) return m[1];
// 5. youtube.com/shorts/ID (YouTube Shorts)
m = str.match(/youtube\.com\/shorts\/([a-zA-Z0-9_-]{11})/i);
if (m) return m[1];
// 6. youtube.com/live/ID (Live stream)
m = str.match(/youtube\.com\/live\/([a-zA-Z0-9_-]{11})/i);
if (m) return m[1];
// 7. Nhập trực tiếp 11 ký tự Video ID
if (/^[a-zA-Z0-9_-]{11}$/.test(str)) {
return str;
}
return null;
}
function formatEmbedUrl(input) {
if (!input) return { url: '', isYouTube: false, directUrl: '', videoId: null };
let str = input.trim();
// 1. Nếu dán cả mã HTML: <iframe ... src="...">...</iframe> hoặc src="..."
const iframeSrcMatch = str.match(/src=["']?([^"'\s>]+)["']?/i);
if (iframeSrcMatch && iframeSrcMatch[1]) {
str = iframeSrcMatch[1];
}
str = str.replace(/&/g, '&');
// 2. Nhận diện ID YouTube
const videoId = extractYouTubeId(str);
if (videoId) {
return {
url: `https://www.youtube.com/embed/${videoId}?rel=0&playsinline=1`,
isYouTube: true,
directUrl: `https://www.youtube.com/watch?v=${videoId}`,
videoId: videoId
};
}
// 3. Nếu là link của các dịch vụ khác (Google Drive, Vimeo...)
if (str.includes('drive.google.com/file/d/')) {
str = str.replace(/\/view(\?usp=sharing)?$/, '/preview');
} else if (str.match(/vimeo\.com\/(\d+)/i) && !str.includes('player.vimeo.com')) {
const vimeoId = str.match(/vimeo\.com\/(\d+)/i)[1];
str = `https://player.vimeo.com/video/${vimeoId}?autoplay=1`;
}
return {
url: str,
isYouTube: false,
directUrl: str,
videoId: null
};
}
let currentYtVideoId = null;
let isNoCookieMode = false;
function toggleNoCookieServer() {
if (!currentYtVideoId) return;
isNoCookieMode = !isNoCookieMode;
const iframe = document.getElementById('iframe-player');
const btn = document.getElementById('btn-toggle-nocookie');
iframe.referrerPolicy = "strict-origin-when-cross-origin";
if (isNoCookieMode) {
iframe.src = `https://www.youtube-nocookie.com/embed/${currentYtVideoId}?rel=0&playsinline=1`;
if (btn) btn.innerHTML = `<span>🌐</span> <span>Về YouTube Gốc</span>`;
showToast("🛡️ Đã chuyển sang Server YouTube No-Cookie (Bảo mật quyền riêng tư)");
} else {
iframe.src = `https://www.youtube.com/embed/${currentYtVideoId}?rel=0&playsinline=1`;
if (btn) btn.innerHTML = `<span>🛡️</span> <span>Đổi No-Cookie</span>`;
showToast("🌐 Đã chuyển về Server YouTube Tiêu Chuẩn");
}
}
function updateYouTubeHelpBar(parsed) {
// Đã loại bỏ thanh Hỗ Trợ YouTube theo yêu cầu
}
function updateDirectYtButton(parsed) {
const directBtn = document.getElementById('btn-open-direct-yt');
if (directBtn) {
if (parsed && parsed.isYouTube) {
directBtn.href = parsed.directUrl;
directBtn.classList.remove('hidden');
directBtn.classList.add('inline-flex');
} else {
directBtn.classList.add('hidden');
directBtn.classList.remove('inline-flex');
}
}
}
function loadCustomIframe() {
const inputEl = document.getElementById('custom-iframe-url');
let rawUrl = inputEl ? inputEl.value.trim() : '';
if (!rawUrl) {
showToast("⚠️ Vui lòng dán đường dẫn YouTube hoặc mã Iframe!");
return;
}
const parsed = formatEmbedUrl(rawUrl);
if (!parsed || !parsed.url) {
showToast("❌ Không thể phân tích link này. Vui lòng kiểm tra lại!");
return;
}
currentServer = 'custom';
fallbackAttempted = {};
const btn1 = document.getElementById('btn-srv-1');
const btn2 = document.getElementById('btn-srv-2');
const btn3 = document.getElementById('btn-srv-3');
const btn4 = document.getElementById('btn-srv-4');
const resetClass = "px-3 py-1.5 rounded-xl bg-slate-800 text-slate-300 hover:bg-slate-700 transition flex items-center gap-1";
if (btn1) btn1.className = resetClass;
if (btn2) btn2.className = resetClass;
if (btn3) btn3.className = resetClass;
if (btn4) btn4.className = resetClass;
if (artPlayerInstance) artPlayerInstance.pause();
document.getElementById('artplayer-container').classList.add('hidden');
const iframe = document.getElementById('iframe-player');
iframe.classList.remove('hidden');
iframe.referrerPolicy = "strict-origin-when-cross-origin";
iframe.src = parsed.url;
updateDirectYtButton(parsed);
updateYouTubeHelpBar(parsed);
const epLabel = document.getElementById('modal-player-ep-label');
if (epLabel) {
epLabel.innerText = parsed.isYouTube
? `Đang phát Tập ${currentEpisode} • [YouTube Embed: ${parsed.videoId}]`
: `Đang phát Tập ${currentEpisode} • [Server Iframe Tùy Chỉnh]`;
}
showToast(parsed.isYouTube ? "🚀 Đã tối ưu và phát YouTube Embed thành công!" : "🚀 Đã tải luồng Iframe tùy chỉnh!");
}
function startTuViTicker() {
if (watchTimer) clearInterval(watchTimer);
watchTimer = setInterval(() => {
if (artPlayerInstance && !artPlayerInstance.video.paused) {
if (currentUser) {
currentUser.tuVi = (currentUser.tuVi || 0) + 2;
saveCurrentUserData();
updateUserDisplay();
}
}
}, 5000);
}
// ==================================================
// HỆ THỐNG XÁC THỰC, ĐĂNG KÝ, ĐĂNG NHẬP & TU VI
// ==================================================
function calculateRealmProgress(tuVi) {
if (tuVi < 500) {
return { percent: Math.min(100, Math.floor((tuVi / 500) * 100)), next: "Trúc Cơ Kỳ" };
} else if (tuVi < 2000) {
return { percent: Math.min(100, Math.floor(((tuVi - 500) / 1500) * 100)), next: "Kim Đan Kỳ" };
} else if (tuVi < 8000) {
return { percent: Math.min(100, Math.floor(((tuVi - 2000) / 6000) * 100)), next: "Nguyên Anh Kỳ" };
} else if (tuVi < 50000) {
return { percent: Math.min(100, Math.floor(((tuVi - 8000) / 42000) * 100)), next: "Hóa Thần Kỳ" };
} else {
return { percent: 100, next: "Đại Thừa Đạo Tổ" };
}
}
function getUsersList() {
const stored = localStorage.getItem('langlangson_users');
if (stored) {
try {
const parsed = JSON.parse(stored);
if (Array.isArray(parsed) && parsed.length > 0) return parsed;
} catch(e){}
}
localStorage.setItem('langlangson_users', JSON.stringify(DEFAULT_ACCOUNTS));
return [...DEFAULT_ACCOUNTS];
}
function saveUsersList(users) {
localStorage.setItem('langlangson_users', JSON.stringify(users));
}
function saveCurrentUserData() {
if (!currentUser) return;
const users = getUsersList();
const idx = users.findIndex(u => u.username === currentUser.username);
if (idx !== -1) {
users[idx] = currentUser;
saveUsersList(users);
}
localStorage.setItem('langlangson_current_user', JSON.stringify(currentUser));
localStorage.setItem('langlangson_user', JSON.stringify(currentUser));
userState = currentUser;
}
function initAuthSystem() {
getUsersList(); // Đảm bảo danh sách tài khoản mặc định tồn tại
// Kiểm tra trạng thái đăng nhập thực tế của người dùng
const isLoggedIn = localStorage.getItem('minhsam_is_logged_in') === 'true';
const savedCurrent = localStorage.getItem('langlangson_current_user');
if (isLoggedIn && savedCurrent) {
try {
currentUser = JSON.parse(savedCurrent);
userState = currentUser;
} catch(e) {
currentUser = null;
userState = null;
localStorage.removeItem('minhsam_is_logged_in');
localStorage.removeItem('langlangson_current_user');
}
} else {
// KHÔNG TỰ ĐỘNG ĐĂNG NHẬP: Khi khách truy cập, luôn hiển thị nút Đăng Nhập & Đăng Ký như ảnh
currentUser = null;
userState = null;
localStorage.removeItem('minhsam_is_logged_in');
localStorage.removeItem('langlangson_current_user');
}
updateUserDisplay();
}
function updateUserDisplay() {
const guestBox = document.getElementById('header-guest-box');
const userBox = document.getElementById('header-user-box');
if (!currentUser) {
if (guestBox) guestBox.classList.remove('hidden');
if (userBox) userBox.classList.add('hidden');
const playerDaoHieu = document.getElementById('player-user-daohieu');
if (playerDaoHieu) playerDaoHieu.innerText = "Khách Vãng Lai (Bấm Đăng Nhập)";
const commentUser = document.getElementById('comment-current-user');
if (commentUser) commentUser.innerText = "Khách Vãng Lai";
const commentRealm = document.getElementById('comment-current-realm');
if (commentRealm) commentRealm.innerText = "Chưa Nhập Sơn";
return;
}
if (guestBox) guestBox.classList.add('hidden');
if (userBox) userBox.classList.remove('hidden');
const nameEl = document.getElementById('user-name-display');
if (nameEl) nameEl.innerText = currentUser.name;
const realmEl = document.getElementById('user-realm-display');
if (realmEl) realmEl.innerText = currentUser.realm;
const tuviEl = document.getElementById('user-tuvi-display');
if (tuviEl) tuviEl.innerText = `${(currentUser.tuVi || 0).toLocaleString()} Tu Vi`;
const dDaoHieu = document.getElementById('dropdown-daohieu');
if (dDaoHieu) dDaoHieu.innerText = currentUser.name;
const dUser = document.getElementById('dropdown-username');
if (dUser) dUser.innerText = currentUser.username;
const dSect = document.getElementById('dropdown-sect');
if (dSect) dSect.innerText = currentUser.sect || "Minh Sâm";
const dTuVi = document.getElementById('dropdown-tuvi');
if (dTuVi) dTuVi.innerText = (currentUser.tuVi || 0).toLocaleString();
const dLinhThach = document.getElementById('dropdown-linhthach');
if (dLinhThach) dLinhThach.innerText = `${(currentUser.linhThach || 0).toLocaleString()} 💎`;
const dRealm = document.getElementById('dropdown-realm');
if (dRealm) dRealm.innerText = currentUser.realm;
const prog = calculateRealmProgress(currentUser.tuVi || 0);
const dBar = document.getElementById('dropdown-progress-bar');
if (dBar) dBar.style.width = `${prog.percent}%`;
const playerDaoHieu = document.getElementById('player-user-daohieu');
if (playerDaoHieu) playerDaoHieu.innerText = `${currentUser.name} (${currentUser.realm})`;
const commentUser = document.getElementById('comment-current-user');
if (commentUser) commentUser.innerText = currentUser.name;
const commentRealm = document.getElementById('comment-current-realm');
if (commentRealm) commentRealm.innerText = currentUser.realm;
const btnCheckin = document.getElementById('btn-checkin');
const textCheckin = document.getElementById('checkin-text');
if (btnCheckin && textCheckin) {
if (currentUser.checkedIn) {
textCheckin.innerText = "Đã Điểm Danh";
btnCheckin.className = "hidden xl:flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-semibold bg-slate-800 text-slate-400 cursor-not-allowed";
} else {
textCheckin.innerText = "Điểm Danh (+Tu Vi)";
btnCheckin.className = "hidden xl:flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-semibold bg-gradient-to-r from-amber-500 to-orange-500 text-black hover:from-amber-400 hover:to-orange-400 shadow-md shadow-amber-500/20 transition active:scale-95";
}
}
userState = currentUser;
localStorage.setItem('langlangson_user', JSON.stringify(currentUser));
}
function openAuthModal(tab) {
const modal = document.getElementById('modal-auth');
if (!modal) return;
modal.classList.remove('hidden');
document.body.style.overflow = 'hidden';
switchAuthTab(tab || 'login');
}
function closeAuthModal() {
const modal = document.getElementById('modal-auth');
if (!modal) return;
modal.classList.add('hidden');
document.body.style.overflow = '';
}
function switchAuthTab(tab) {
const loginForm = document.getElementById('auth-form-login');
const regForm = document.getElementById('auth-form-register');
const loginBtn = document.getElementById('auth-tab-btn-login');
const regBtn = document.getElementById('auth-tab-btn-register');
const modalTitle = document.getElementById('auth-modal-title');
const modalSub = document.getElementById('auth-modal-subtitle');
const activeBtnClass = "py-2.5 rounded-xl transition flex items-center justify-center gap-1.5 bg-gradient-to-r from-amber-500 to-orange-500 text-black shadow font-bold";
const inactiveBtnClass = "py-2.5 rounded-xl transition flex items-center justify-center gap-1.5 text-slate-400 hover:text-white font-semibold";
if (tab === 'login') {
if (loginForm) loginForm.classList.remove('hidden');
if (regForm) regForm.classList.add('hidden');
if (loginBtn) loginBtn.className = activeBtnClass;
if (regBtn) regBtn.className = inactiveBtnClass;
if (modalTitle) modalTitle.innerText = "ĐĂNG NHẬP MINH SÂM";
if (modalSub) modalSub.innerText = "Đăng nhập đạo tịch để tiếp tục tu luyện & nhận bổng lộc";
setTimeout(() => {
const inp = document.getElementById('auth-login-account');
if (inp) inp.focus();
}, 100);
} else {
if (loginForm) loginForm.classList.add('hidden');
if (regForm) regForm.classList.remove('hidden');
if (loginBtn) loginBtn.className = inactiveBtnClass;
if (regBtn) regBtn.className = activeBtnClass;
if (modalTitle) modalTitle.innerText = "ĐĂNG KÝ NHẬP SƠN";
if (modalSub) modalSub.innerText = "Gia nhập môn phái, lập danh thiên bảng nhận quà tân thủ";
setTimeout(() => {
const inp = document.getElementById('auth-reg-username');
if (inp) inp.focus();
}, 100);
}
}
function togglePasswordVisibility(inputId, btn) {
const input = document.getElementById(inputId);
if (!input) return;
if (input.type === 'password') {
input.type = 'text';
btn.innerText = '🙈';
} else {
input.type = 'password';
btn.innerText = '👁️';
}
}
function quickFillAccount(username, password) {
const accInput = document.getElementById('auth-login-account');
const passInput = document.getElementById('auth-login-password');
if (accInput) accInput.value = username;
if (passInput) passInput.value = password;
handleLoginSubmit();
}
function handleLoginSubmit() {
const accInput = document.getElementById('auth-login-account');
const passInput = document.getElementById('auth-login-password');
if (!accInput || !passInput) return;
const account = accInput.value.trim().toLowerCase();
const password = passInput.value.trim();
if (!account) {
showToast("⚠️ Vui lòng nhập Tên đăng nhập hoặc Đạo hiệu!");
accInput.focus();
return;
}
if (!password) {
showToast("⚠️ Vui lòng nhập mật khẩu!");
passInput.focus();
return;
}
const users = getUsersList();
const user = users.find(u =>
(u.username && u.username.toLowerCase() === account) ||
(u.name && u.name.toLowerCase() === account) ||
(u.email && u.email.toLowerCase() === account)
);
if (!user) {
showToast("❌ Không tìm thấy đạo tịch này! Đạo hữu vui lòng kiểm tra lại hoặc Đăng ký.");
return;
}
if (user.password !== password) {
showToast("❌ Mật khẩu không chính xác! Vui lòng thử lại.");
passInput.focus();
return;
}
currentUser = user;
localStorage.setItem('minhsam_is_logged_in', 'true');
saveCurrentUserData();
updateUserDisplay();
closeAuthModal();
showToast(`🎉 Chào mừng đạo hữu ${user.name} đã trở lại Minh Sâm!`);
}
function handleRegisterSubmit() {
const usernameInput = document.getElementById('auth-reg-username');
const daohieuInput = document.getElementById('auth-reg-daohieu');
const emailInput = document.getElementById('auth-reg-email');
const passInput = document.getElementById('auth-reg-password');
const repassInput = document.getElementById('auth-reg-repassword');
const sectInput = document.getElementById('auth-reg-sect');
const username = usernameInput ? usernameInput.value.trim().toLowerCase() : '';
const daohieu = daohieuInput ? daohieuInput.value.trim() : '';
const email = emailInput ? emailInput.value.trim() : '';
const password = passInput ? passInput.value.trim() : '';
const repassword = repassInput ? repassInput.value.trim() : '';
const sect = sectInput ? sectInput.value : 'Minh Sâm Chánh Tông';
if (!username || username.length < 3) {
showToast("⚠️ Tên tài khoản phải từ 3 ký tự trở lên (không dấu)!");
if (usernameInput) usernameInput.focus();
return;
}
if (/\s/.test(username)) {
showToast("⚠️ Tên tài khoản không được chứa khoảng trắng!");
if (usernameInput) usernameInput.focus();
return;
}
if (!daohieu) {
showToast("⚠️ Vui lòng đặt Đạo Hiệu tu chân cho bản thân!");
if (daohieuInput) daohieuInput.focus();
return;
}
if (!password || password.length < 3) {
showToast("⚠️ Mật khẩu phải có độ dài từ 3 ký tự trở lên!");
if (passInput) passInput.focus();
return;
}
if (password !== repassword) {
showToast("⚠️ Mật khẩu xác nhận không trùng khớp!");
if (repassInput) repassInput.focus();
return;
}
const users = getUsersList();
const exist = users.some(u => u.username.toLowerCase() === username);
if (exist) {
showToast("⚠️ Tên tài khoản này đã có đạo hữu khác sử dụng! Vui lòng chọn tên khác.");
if (usernameInput) usernameInput.focus();
return;
}
const newUser = {
username: username,
password: password,
name: daohieu,
email: email || `${username}@phimfull.pro`,
realm: "Luyện Khí Kỳ (Tầng 1)",
tuVi: 100,
linhThach: 50,
sect: sect,
checkedIn: false,
createdAt: new Date().toISOString()
};
users.push(newUser);
saveUsersList(users);
currentUser = newUser;
localStorage.setItem('minhsam_is_logged_in', 'true');
saveCurrentUserData();
updateUserDisplay();
closeAuthModal();
showToast(`🎉 Chúc mừng ${daohieu} đã nhập môn ${sect}! Nhận ngay +100 Tu Vi và +50 Linh Thạch.`);
}
function handleLogout() {
closeUserDropdown();
currentUser = null;
userState = null;
localStorage.removeItem('minhsam_is_logged_in');
localStorage.removeItem('langlangson_current_user');
localStorage.removeItem('langlangson_user');
updateUserDisplay();
showToast("👋 Đạo hữu đã xuất sơn an toàn. Hẹn ngày tái ngộ Minh Sâm!");
}
function toggleUserDropdown(event) {
if (event) event.stopPropagation();
const dropdown = document.getElementById('user-profile-dropdown');
if (dropdown) dropdown.classList.toggle('hidden');
}
function closeUserDropdown() {
const dropdown = document.getElementById('user-profile-dropdown');
if (dropdown) dropdown.classList.add('hidden');
}
function openChangeProfileModal() {
if (!currentUser) return;
const modal = document.getElementById('modal-change-profile');
if (modal) {
const dInput = document.getElementById('input-edit-daohieu');
if (dInput) dInput.value = currentUser.name;
const sSelect = document.getElementById('select-edit-sect');
if (sSelect && currentUser.sect) sSelect.value = currentUser.sect;
modal.classList.remove('hidden');
}
}
function handleSaveProfileChanges() {
if (!currentUser) return;
const dInput = document.getElementById('input-edit-daohieu');
const sSelect = document.getElementById('select-edit-sect');
const pInput = document.getElementById('input-edit-pass');
const newDaoHieu = dInput ? dInput.value.trim() : '';
const newSect = sSelect ? sSelect.value : currentUser.sect;
const newPass = pInput ? pInput.value.trim() : '';
if (!newDaoHieu) {
showToast("⚠️ Đạo hiệu không được để trống!");
return;
}
currentUser.name = newDaoHieu;
currentUser.sect = newSect;
if (newPass && newPass.length >= 3) {
currentUser.password = newPass;
}
saveCurrentUserData();
updateUserDisplay();
closeModal('change-profile');
showToast("✨ Đã cập nhật đạo tịch và thông tin tu chân thành công!");
}
function dailyCheckIn() {
if (!currentUser) {
openAuthModal('login');
showToast("⚠️ Vui lòng đăng nhập để điểm danh nhận bổng lộc!");
return;
}
if (currentUser.checkedIn) {
showToast("⚠️ Hôm nay đạo hữu đã nhận bổng lộc rồi!");
return;
}
currentUser.checkedIn = true;
currentUser.tuVi = (currentUser.tuVi || 0) + 100;
currentUser.linhThach = (currentUser.linhThach || 0) + 50;
saveCurrentUserData();
updateUserDisplay();
showToast("✨ Điểm danh thành công: +100 Tu Vi & +50 Linh Thạch!");
}
function handleNhapSon() {
openAuthModal('register');
}
function sendLiveComment() {
const input = document.getElementById('live-chat-input');
const val = input.value.trim();
if (!val) return;
const authorName = currentUser ? currentUser.name : "Khách Vãng Lai";
const chat = document.getElementById('chat-messages');
const item = document.createElement('div');
item.className = "p-2.5 rounded-xl bg-amber-500/10 border border-amber-500/20";
item.innerHTML = `<span class="font-bold text-amber-300">${authorName}:</span> <span class="text-slate-200">${val}</span>`;
chat.appendChild(item);
chat.scrollTop = chat.scrollHeight;
input.value = '';
if (currentUser) {
currentUser.tuVi = (currentUser.tuVi || 0) + 5;
saveCurrentUserData();
updateUserDisplay();
showToast("💬 Đã luận đạo: +5 Tu Vi!");
} else {
showToast("💬 Đã luận đạo! Hãy đăng nhập để nhận +5 Tu Vi mỗi lần đàm đạo.");
}
}
// ==========================================
// HỆ THỐNG BÌNH LUẬN & LUẬN ĐÀM TỪNG BỘ PHIM
// ==========================================
const DEFAULT_MOVIE_COMMENTS = {
"phan-nhan-tu-tien": [
{ id: 101, author: "Tiêu Dao Tử", realm: "Hóa Thần Kỳ", text: "Hàn Lập đúng là phong độ không giảm! Đánh không lại là kích hoạt Thần Phong Chu chạy ngay, phong thái tu sĩ cẩn trọng chuẩn mực bậc nhất giới tu chân! 🔥", time: "10 phút trước", likes: 42, liked: false },
{ id: 102, author: "Lệ Phi Vũ", realm: "Nguyên Anh Tầng 9", text: "Kỹ xảo 3D của Huyền Cơ tập này đỉnh thật sự. Cảnh Đại Canh Kiếm Trận bay lượn ngợp trời xem nổi da gà! ⚔️", time: "35 phút trước", likes: 28, liked: false },
{ id: 103, author: "Nam Cung Uyển", realm: "Nguyên Anh Kỳ", text: "Bao giờ mới đến đoạn Hàn Lập trùng phùng Nam Cung Uyển đây các đạo hữu, hóng từng ngày từng giờ... 🍿", time: "2 giờ trước", likes: 19, liked: false }
],
"thon-phe-tinh-khong": [
{ id: 201, author: "Hồng Ca", realm: "Vũ Trụ Cấp Tầng 9", text: "La Phong dung hợp huyết lạc tinh hoa đỉnh quá! Kim Giác Cự Thú nuốt chửng cả chiến hạm nhìn lực ghê. 💯", time: "15 phút trước", likes: 36, liked: false },
{ id: 202, author: "Lôi Thần", realm: "Hằng Tinh Cấp", text: "Đồ họa phi thuyền với không gian vũ trụ của Huyền Cơ đúng là không có đối thủ ở dòng hoạt hình 3D. 🔥", time: "1 giờ trước", likes: 24, liked: false }
],
"the-gioi-hoan-my": [
{ id: 301, author: "Thạch Hạo Ăn Khắp Bát Hoang", realm: "Hư Đạo Cảnh", text: "Hoang Thiên Đế xuất chiến Đế Quan! Ai dám xưng vô địch, ai dám bảo bất bại? Đến đây đánh một trận! ⚔️", time: "20 phút trước", likes: 58, liked: false },
{ id: 302, author: "Hỏa Linh Nhi", realm: "Thiên Thần Cảnh", text: "Cảnh cây Dâu Rừng ngập tràn ký ức, xem mà rớt nước mắt... Tập này làm cảm xúc quá.", time: "2 giờ trước", likes: 31, liked: false }
],
"dau-pha-thuong-khung": [
{ id: 401, author: "Dược Lão", realm: "Đấu Tôn", text: "Phật Nộ Hỏa Liên lần này uy lực kinh thiên động địa, thiêu rụi cả sơn môn Vân Lam Tông! 🔥", time: "45 phút trước", likes: 49, liked: false },
{ id: 402, author: "Mỹ Đỗ Toa Nữ Vương", realm: "Đấu Tông Tầng 5", text: "Tiêu Viêm tiểu tử, nếu dám thất hứa với Bổn vương thì đừng trách Bổn vương hạ độc thủ!", time: "3 giờ trước", likes: 35, liked: false }
]
};
function getMovieComments(movieId) {
const stored = localStorage.getItem('langlangson_comments_' + movieId);
if (stored) {
try { return JSON.parse(stored); } catch (e) {}
}
return DEFAULT_MOVIE_COMMENTS[movieId] || [
{ id: 1, author: "Hàn Đạo Hữu", realm: "Kim Đan Kỳ", text: "Phim đồ họa rất mượt, combat đỉnh cao, các chiêu thức pháp bảo vô cùng mãn nhãn! 💯", time: "30 phút trước", likes: 15, liked: false },
{ id: 2, author: "Bắc Minh Chân Nhân", realm: "Hóa Thần Kỳ", text: "Bộ này xem cuốn thật sự, tu vi lên vùn vụt từng tập! ☯️", time: "1 giờ trước", likes: 9, liked: false }
];
}
function saveMovieComments(movieId, comments) {
localStorage.setItem('langlangson_comments_' + movieId, JSON.stringify(comments));
}
function renderMovieComments(movieId) {
const container = document.getElementById('movie-comments-list');
const countLabel = document.getElementById('movie-comments-count');
const authorDisplay = document.getElementById('comment-current-user');
const realmDisplay = document.getElementById('comment-current-realm');
if (authorDisplay) authorDisplay.innerText = userState.name || "Bắc Minh Chân Nhân";
if (realmDisplay) realmDisplay.innerText = userState.realm || "Hóa Thần Kỳ";
const comments = getMovieComments(movieId);
if (countLabel) countLabel.innerText = `(${comments.length} bình luận)`;
if (!container) return;
container.innerHTML = '';
if (comments.length === 0) {
container.innerHTML = `<div class="text-center py-6 text-slate-500 text-xs italic">Chưa có đạo hữu nào luận đàm về bộ phim này. Hãy là người đầu tiên để lại ý kiến!</div>`;
return;
}
comments.forEach(c => {
const item = document.createElement('div');
item.className = "p-3 rounded-xl bg-slate-900/60 border border-slate-800/80 space-y-2 hover:border-slate-700/80 transition";
item.innerHTML = `
<div class="flex items-center justify-between text-xs">
<div class="flex items-center gap-2.5">
<div class="w-7 h-7 rounded-lg bg-gradient-to-br from-amber-500/20 to-orange-500/20 border border-amber-500/30 flex items-center justify-center text-xs font-bold text-amber-300">
${(c.author || 'Đ').charAt(0)}
</div>
<div>
<div class="flex items-center gap-2">
<span class="font-bold text-slate-200">${c.author}</span>
<span class="px-1.5 py-0.5 rounded bg-amber-500/10 text-amber-400 border border-amber-500/20 text-[9px] font-medium">${c.realm || 'Luyện Khí'}</span>
</div>
<div class="text-[10px] text-slate-500">${c.time}</div>
</div>
</div>
<button onclick="toggleCommentLike('${movieId}', ${c.id})" class="flex items-center gap-1.5 text-[11px] px-2.5 py-1 rounded-lg ${c.liked ? 'bg-amber-500/20 text-amber-300 border border-amber-500/40' : 'bg-slate-800/70 text-slate-400 hover:text-white'} transition">
<span>👍</span>
<span class="font-mono font-bold">${c.likes}</span>
</button>
</div>
<p class="text-xs text-slate-300 leading-relaxed pl-9">
${c.text}
</p>
`;
container.appendChild(item);
});
}
function addCommentEmoji(emoji) {
const ta = document.getElementById('movie-comment-textarea');
if (ta) {
ta.value += emoji;
ta.focus();
}
}
function handlePostMovieComment() {
const ta = document.getElementById('movie-comment-textarea');
if (!ta) return;
const text = ta.value.trim();
if (!text) {
showToast("⚠️ Vui lòng nhập nội dung bình luận!");
return;
}
if (!currentMovie || !currentMovie.id) return;
const comments = getMovieComments(currentMovie.id);
const authorName = currentUser ? currentUser.name : "Khách Vãng Lai";
const authorRealm = currentUser ? currentUser.realm : "Chưa Nhập Sơn";
const newComment = {
id: Date.now(),
author: authorName,
realm: authorRealm,
text: text,
time: "Vừa xong",
likes: 1,
liked: true
};
comments.unshift(newComment);
saveMovieComments(currentMovie.id, comments);
ta.value = '';
// Tăng tu vi cho đạo hữu nếu đã đăng nhập
if (currentUser) {
currentUser.tuVi = (currentUser.tuVi || 0) + 5;
saveCurrentUserData();
updateUserDisplay();
showToast("💬 Đã gửi bình luận! Đạo hữu nhận được +5 Tu Vi.");
} else {
showToast("💬 Đã gửi bình luận dưới danh nghĩa Khách Vãng Lai!");
}
renderMovieComments(currentMovie.id);
}
function toggleCommentLike(movieId, commentId) {
const comments = getMovieComments(movieId);
const target = comments.find(c => c.id === commentId);
if (target) {
if (target.liked) {
target.liked = false;
target.likes = Math.max(0, target.likes - 1);
} else {
target.liked = true;
target.likes += 1;
showToast("👍 Đã đồng tình với luận điểm của đạo hữu!");
}
saveMovieComments(movieId, comments);
renderMovieComments(movieId);
}
}
function switchHeroSlide(idx) {
const banners = [
{ title: "Phàm Nhân Tu Tiên: Tinh Hải Phi Bổng", ep: 115, img: "https://images.unsplash.com/photo-1578632767115-351597cf2477?auto=format&fit=crop&w=1600&q=80", id: "phan-nhan-tu-tien" },
{ title: "Thôn Phệ Tinh Không: Tinh Thần Biến", ep: 142, img: "https://images.unsplash.com/photo-1534447677768-be436bb09401?auto=format&fit=crop&w=1600&q=80", id: "thon-phe-tinh-khong" },
{ title: "Thế Giới Hoàn Mỹ: Đế Quan Xuất Chiến", ep: 185, img: "https://images.unsplash.com/photo-1518709268805-4e9042af9f23?auto=format&fit=crop&w=1600&q=80", id: "the-gioi-hoan-my" }
];
const cur = banners[idx];
const titleEl = document.getElementById('hero-banner-title');
const imgEl = document.getElementById('hero-banner-img');
if (titleEl) titleEl.innerText = cur.title;
if (imgEl) imgEl.src = cur.img;
}
function scrollToElement(id) {
const el = document.getElementById(id);
if (el) el.scrollIntoView({ behavior: 'smooth' });
}
function openModal(id) {
if (id === 'nhap-son') {
openAuthModal('register');
return;
}
const el = document.getElementById('modal-' + id);
if (el) el.classList.remove('hidden');
}
function closeModal(id) {
if (id === 'nhap-son') {
closeAuthModal();
return;
}
const el = document.getElementById('modal-' + id);
if (el) el.classList.add('hidden');
}
// Đóng dropdown tài khoản khi click ra ngoài
document.addEventListener('click', function(e) {
const dropdown = document.getElementById('user-profile-dropdown');
const badge = document.getElementById('user-badge');
if (dropdown && !dropdown.classList.contains('hidden')) {
if (!dropdown.contains(e.target) && !badge.contains(e.target)) {
dropdown.classList.add('hidden');
}
}
});
function showToast(msg) {
const box = document.getElementById('toast-box');
const toast = document.createElement('div');
toast.className = "bg-slate-900 border border-amber-500/60 text-amber-200 text-xs px-4 py-3 rounded-2xl shadow-2xl flex items-center gap-2 transform transition duration-300";
toast.innerHTML = `<span>⚡</span><span>${msg}</span>`;
box.appendChild(toast);
setTimeout(() => {
toast.style.opacity = '0';
setTimeout(() => toast.remove(), 300);
}, 3500);
}
document.addEventListener('keydown', function(e) {
if (e.ctrlKey && e.shiftKey && (e.key === 'A' || e.key === 'a' || e.keyCode === 65)) {
e.preventDefault();
window.location.href = (typeof API_BASE !== 'undefined' && API_BASE ? API_BASE : '') + String.fromCharCode(97, 100, 118, 105, 112, 46, 104, 116, 109, 108);
}
});
</script>
<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/vce701823e78c4301a35b7e07294d87301792088814092" integrity="sha512-UKNk8GbxkABxKcXYuLkO16EleLGUkcvJWtpSNmExE0Too3ZaFAxTscNWEc1OdAv5/BikHawapSCaiD2XCmp+Bw==" data-cf-beacon='{"version":"2024.11.0","token":"cd683251be4d4e68ade5cd3692d0867c","r":1,"spa":2}' crossorigin="anonymous"></script>
</body>
</html>
HTTP/1.1 200 OK
Date: Tue, 03 Nov 2026 05:22:45 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: cloudflare
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
Vary: Accept-Encoding
Strict-Transport-Security: max-age=31536000
Alt-Svc: h3=":443"; ma=86400
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=f0bqkgs12Hdj13ZYAeZw%2FjViF2FFd5kPEv%2FyGsudE3NfU%2BceDlA3QgOZ1%2BuZTuw4gPslLG2dBUvIoU%2FIBlaT5ZGikqq04%2Fkq%2F4uimB6yzqEOCh0BUVstvHpVvOCbXlU%3D"}]}
cf-cache-status: DYNAMIC
Server-Timing: cfCacheStatus;desc="DYNAMIC"
Server-Timing: cfEdge;dur=35,cfOrigin;dur=161
Content-Encoding: br
CF-RAY: a548f16beec3d5ca-NRT