kv-netflix/backend/static/watch.html

452 lines
No EOL
21 KiB
HTML
Executable file

<!DOCTYPE html>
<html class="dark" lang="en">
<head>
<meta charset="utf-8" />
<meta content="width=device-width, initial-scale=1.0, viewport-fit=cover" name="viewport" />
<title>StreamFlix - Movie Details</title>
<meta name="description" content="StreamFlix - Watch Movies Online">
<meta name="theme-color" content="#141414">
<meta name="referrer" content="no-referrer">
<!-- Fonts -->
<link href="https://fonts.googleapis.com" rel="preconnect" />
<link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect" />
<link href="https://fonts.googleapis.com/css2?family=Spline+Sans:wght@300;400;500;600;700&display=swap"
rel="stylesheet" />
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap"
rel="stylesheet" />
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
<!-- Theme Config -->
<script>
tailwind.config = {
darkMode: "class",
theme: {
extend: {
colors: {
"primary": "#ea2a33",
"background-light": "#f8f6f6",
"background-dark": "#141414",
"surface-dark": "#181818",
},
fontFamily: {
"display": ["Spline Sans", "sans-serif"]
},
borderRadius: { "DEFAULT": "0.25rem", "lg": "0.5rem", "xl": "0.75rem", "full": "9999px" },
},
},
}
</script>
<style>
:root {
--safe-top: env(safe-area-inset-top, 0px);
--safe-bottom: env(safe-area-inset-bottom, 0px);
}
@media (max-width: 767px) {
#watchHeader>div {
padding-top: calc(1.5rem + var(--safe-top)) !important;
}
#mobileBottomNav {
padding-bottom: calc(1.25rem + var(--safe-bottom)) !important;
}
}
/* Custom scrollbar */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: #141414;
}
::-webkit-scrollbar-thumb {
background: #333;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #555;
}
.no-scrollbar::-webkit-scrollbar {
display: none;
}
.no-scrollbar {
-ms-overflow-style: none;
scrollbar-width: none;
}
/* Loading spinner */
.loading-spinner {
border: 3px solid rgba(255, 255, 255, 0.1);
border-top-color: #ea2a33;
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
/* TV Focus Ring */
.keyboard-focused {
outline: 3px solid #ea2a33 !important;
outline-offset: 2px !important;
transform: scale(1.05) !important;
z-index: 50 !important;
transition: transform 0.2s ease, outline 0.2s ease !important;
box-shadow: 0 0 20px rgba(234, 42, 51, 0.4) !important;
}
</style>
<!-- PWA Meta Tags -->
<link rel="manifest" href="/manifest.json">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="StreamFlix">
<link rel="icon" type="image/png" href="/icons/icon-512.png">
<link rel="apple-touch-icon" href="/icons/icon-512.png">
<script type="importmap">
{
"imports": {
"@capacitor/status-bar": "/js/capacitor-mock.js",
"@capacitor/haptics": "/js/capacitor-mock.js",
"artplayer": "https://esm.sh/artplayer@5.1.7",
"hls.js": "https://esm.sh/hls.js@1.5.7"
}
}
</script>
<script type="module" crossorigin src="/assets/watch-Cy-oRGVl.js"></script>
<link rel="modulepreload" crossorigin href="/assets/keyboard-nav-D6R5vIR2.js">
</head>
<body class="bg-background-light dark:bg-background-dark text-slate-900 dark:text-white font-display overflow-x-hidden">
<!-- Navigation -->
<nav class="fixed top-0 w-full z-50 transition-all duration-300 bg-gradient-to-b from-black/80 to-transparent pointer-events-none"
id="watchHeader">
<div class="px-4 md:px-12 py-4 pt-6 flex items-center justify-between">
<!-- Back / Close Button -->
<button
class="pointer-events-auto text-white flex items-center justify-center p-2 rounded-full hover:bg-white/10 transition-colors"
id="watchBackBtn">
<span class="material-symbols-outlined text-3xl shadow-md">arrow_back</span>
</button>
<!-- Right Actions -->
<div class="flex items-center gap-4 pointer-events-auto">
<button
class="text-white flex items-center justify-center p-2 rounded-full hover:bg-white/10 transition-colors">
<span class="material-symbols-outlined text-2xl">cast</span>
</button>
<button
class="text-white flex items-center justify-center p-2 rounded-full hover:bg-white/10 transition-colors"
id="searchBtn">
<span class="material-symbols-outlined text-2xl">search</span>
</button>
<a href="/download.html"
class="hidden md:flex items-center gap-2 bg-white/10 hover:bg-white/20 text-white px-3 py-1.5 rounded-full transition-colors text-sm font-medium border border-white/10">
<span class="material-symbols-outlined text-sm">download</span>
<span>Install App</span>
</a>
<!-- Desktop Profile (Hidden on mobile) -->
<div class="hidden md:block size-8 rounded-md bg-cover bg-center cursor-pointer border border-white/20 hover:border-white/60 transition-all"
style="background-image: url('https://wallpapers.com/images/hd/netflix-profile-pictures-1000-x-1000-qo9h82134t9nv0j0.jpg');">
</div>
</div>
</div>
</nav>
<!-- Hero Section (Movie Background) -->
<div class="relative w-full aspect-[4/5] md:aspect-auto md:h-[85vh] md:min-h-[600px] overflow-hidden group/hero"
id="heroSection">
<!-- Hero Background -->
<div class="absolute inset-0 bg-cover bg-center bg-no-repeat transition-transform duration-[10s] ease-out group-hover/hero:scale-105"
id="heroBg" style="background-image: url('');"></div>
<!-- Gradients -->
<div class="absolute inset-0 bg-gradient-to-t from-background-dark via-background-dark/40 to-transparent"></div>
<div
class="absolute inset-0 bg-gradient-to-r from-background-dark/90 via-background-dark/30 to-transparent hidden md:block">
</div>
<!-- Play Button (Centered Mobile) -->
<div class="absolute inset-0 flex items-center justify-center pointer-events-none md:hidden z-20">
<div class="size-16 rounded-full bg-white/20 backdrop-blur-sm flex items-center justify-center pointer-events-auto cursor-pointer hover:scale-105 transition-transform border border-white/30"
id="mobilePlayBtn">
<span class="material-symbols-outlined text-white text-4xl fill-1"
style="font-variation-settings: 'FILL' 1;">play_arrow</span>
</div>
</div>
<!-- Hero Content (Desktop) -->
<div
class="absolute bottom-0 left-0 w-full px-4 md:px-12 pb-12 md:pb-20 z-10 flex flex-col justify-end h-full hidden md:flex">
<div class="max-w-2xl">
<!-- Movie Title -->
<h1 class="text-5xl md:text-7xl font-black text-white tracking-tight leading-[0.9] mb-4 drop-shadow-lg"
id="movieTitleDesktop">Loading...</h1>
<!-- Meta Data -->
<div class="flex items-center flex-wrap gap-4 text-white/90 text-sm md:text-base font-medium mb-6">
<span class="text-[#46d369] font-bold" id="movieMatchDesktop">98% Match</span>
<span class="text-gray-300" id="movieYearDesktop">2024</span>
<span class="border border-white/40 px-1.5 py-0.5 text-xs rounded text-gray-300"
id="movieRatingDesktop">PG-13</span>
<span class="flex items-center gap-1 text-gray-300"><span
class="material-symbols-outlined text-sm">hd</span> <span
id="movieQualityDesktop">HD</span></span>
</div>
<!-- Synopsis -->
<p class="text-white/80 text-lg md:text-xl leading-relaxed font-medium mb-8 drop-shadow-md line-clamp-3"
id="movieDescriptionDesktop">Loading description...</p>
<!-- Actions -->
<div class="flex items-center gap-4">
<button
class="flex items-center gap-2 bg-white text-black px-8 py-3 rounded hover:bg-white/90 transition-colors font-bold text-lg min-w-[140px] justify-center"
id="playBtnDesktop">
<span class="material-symbols-outlined text-3xl"
style="font-variation-settings: 'FILL' 1;">play_arrow</span>
Play
</button>
<button
class="flex items-center gap-2 bg-gray-500/40 hover:bg-gray-500/50 backdrop-blur-sm text-white px-6 py-3 rounded transition-colors font-bold text-lg min-w-[160px] justify-center"
id="addListBtnDesktop">
<span class="material-symbols-outlined text-2xl">add</span>
<span>My List</span>
</button>
</div>
</div>
</div>
</div>
<!-- Mobile Content (Title, Meta, Actions) -->
<div class="relative px-5 -mt-20 z-10 flex flex-col gap-5 md:hidden text-white">
<!-- Title and Badges -->
<div class="flex flex-col gap-2">
<div class="flex items-center gap-2 mb-1">
<span class="material-symbols-outlined text-primary text-2xl"
style="font-variation-settings: 'FILL' 1;">movie</span>
<span class="text-xs font-bold tracking-[0.2em] text-gray-300 uppercase">Series</span>
</div>
<h1 class="text-4xl font-bold tracking-tight text-white leading-none" id="movieTitleMobile">Loading...</h1>
<!-- Metadata Row -->
<div class="flex items-center flex-wrap gap-x-3 gap-y-2 mt-1 text-sm text-gray-300 font-medium">
<span class="text-[#46d369] font-bold" id="movieMatchMobile">98% Match</span>
<span id="movieYearMobile">2024</span>
<span class="bg-gray-700/60 px-1.5 py-0.5 rounded text-xs border border-gray-600"
id="movieRatingMobile">TV-MA</span>
<span id="movieDurationMobile">2h 30m</span>
<span
class="border border-gray-500 rounded px-1 text-[10px] font-bold h-4 flex items-center leading-none"
id="movieQualityMobile">HD</span>
</div>
</div>
<!-- Action Buttons -->
<div class="flex flex-col gap-3 mt-2">
<button
class="flex items-center justify-center gap-2 w-full bg-primary hover:bg-red-700 text-white font-bold py-3 px-4 rounded transition-colors active:scale-[0.98]"
id="playBtnMobile">
<span class="material-symbols-outlined fill-1"
style="font-variation-settings: 'FILL' 1;">play_arrow</span>
<span>Resume</span>
</button>
<div class="flex items-center gap-3 w-full">
<button
class="flex items-center justify-center gap-2 flex-1 bg-[#2b2b2b] hover:bg-[#383838] text-white font-semibold py-3 px-4 rounded transition-colors active:scale-[0.98]"
id="addListBtnMobile">
<span class="material-symbols-outlined">add</span>
<span>My List</span>
</button>
<button
class="flex flex-none items-center justify-center w-12 h-12 bg-[#2b2b2b] hover:bg-[#383838] text-white rounded transition-colors active:scale-[0.98]"
id="shareBtnMobile">
<span class="material-symbols-outlined">share</span>
</button>
</div>
</div>
<!-- Synopsis -->
<div class="mb-4">
<p class="text-sm text-gray-300 leading-relaxed line-clamp-3" id="movieDescriptionMobile">Loading...</p>
</div>
</div>
<!-- Video Player (Hidden by default, shown when playing) -->
<div class="fixed inset-0 z-[100] bg-black hidden" id="videoPlayerContainer">
<!-- Prominent Back Button -->
<button
class="absolute top-6 left-6 z-[110] flex items-center gap-2 text-white bg-black/40 hover:bg-black/60 backdrop-blur-md px-4 py-2 rounded-full transition-all active:scale-95 group"
id="playerBackButton">
<span
class="material-symbols-outlined text-3xl group-hover:-translate-x-1 transition-transform">arrow_back</span>
<span class="font-bold text-lg hidden sm:block">Go Back</span>
</button>
<button class="absolute top-6 right-6 z-[110] text-white/70 hover:text-white transition-colors"
id="closePlayer">
<span class="material-symbols-outlined text-4xl">close</span>
</button>
<div class="w-full h-full" id="videoPlayer">
<div class="w-full h-full flex items-center justify-center" id="playerLoading">
<div class="flex flex-col items-center gap-4">
<div class="loading-spinner"></div>
<span class="text-gray-400">Loading stream...</span>
</div>
</div>
</div>
</div>
<!-- Main Content Container (Removed negative margin on mobile to prevent overlap) -->
<div class="relative z-20 md:-mt-10 px-4 md:px-12 pb-20" id="mainContent">
<!-- Details Layout (Column) -->
<div class="flex flex-col gap-12">
<!-- Top Section: Details & Episodes (Full Width) -->
<div class="space-y-10 w-full">
<!-- Stats & Tags -->
<div class="flex flex-wrap gap-x-8 gap-y-4 text-sm text-gray-400 border-t border-white/10 pt-6"
id="movieTags">
<!-- Genre tags will be injected here -->
</div>
<!-- Tab Navigation -->
<div class="flex items-center gap-8 border-b border-white/10" id="tabNav">
<button class="text-lg font-bold text-white border-b-4 border-primary pb-3 tab-btn active"
data-tab="episodes">Episodes</button>
<button class="text-lg font-medium text-gray-400 pb-3 hover:text-white transition-colors tab-btn"
data-tab="details">Details</button>
</div>
<!-- Episodes Panel -->
<div class="tab-panel" id="episodesPanel">
<!-- Season Select -->
<div class="flex items-center gap-4 mb-6" id="seasonSelectContainer">
<select
class="bg-surface-dark border border-white/20 text-white px-4 py-2 rounded text-sm focus:border-primary focus:ring-0"
id="seasonSelect">
<option value="1">Season 1</option>
</select>
<span class="text-gray-400 text-sm" id="episodeCount">Episodes</span>
</div>
<!-- Episode Grid -->
<div class="space-y-4" id="episodesGrid">
<!-- Episode cards will be injected here -->
<div class="text-gray-400 text-center py-8" id="episodesLoading">
<div class="loading-spinner mx-auto mb-4"></div>
Loading episodes...
</div>
</div>
</div>
<!-- Trailers Panel -->
<div class="tab-panel hidden" id="trailersPanel">
<div class="grid grid-cols-1 md:grid-cols-3 gap-6" id="trailersGrid">
<!-- Trailers will be injected here -->
<p class="text-gray-400 col-span-full text-center py-8">No trailers available</p>
</div>
</div>
<!-- Details Panel -->
<div class="tab-panel hidden" id="detailsPanel">
<!-- Cast Carousel -->
<div class="space-y-4 mb-8">
<h3 class="text-xl font-bold text-white">Top Cast</h3>
<div class="flex gap-4 overflow-x-auto pb-4 no-scrollbar snap-x" id="castCarousel">
<!-- Cast will be injected here -->
</div>
</div>
<!-- Additional Details -->
<div class="bg-surface-dark p-6 rounded-xl border border-white/5" id="additionalDetails">
<h3 class="text-xl font-bold text-white mb-4">About this movie</h3>
<div class="space-y-3 text-gray-400" id="detailsList">
<!-- Details will be injected here -->
</div>
</div>
</div>
</div>
<!-- Bottom Section: More Like This (Smaller Cards) -->
<div class="space-y-6 pt-8 border-t border-white/10">
<!-- Recommendations Section -->
<div class="space-y-8" id="recommendationsContainer">
<!-- Dynamic sections will be injected here -->
</div>
</div>
</div>
</div>
<!-- Mobile Bottom Navigation -->
<nav class="fixed bottom-0 left-0 right-0 z-50 bg-[#121212]/95 backdrop-blur-lg border-t border-white/5 pb-5 pt-3 px-6 md:hidden"
id="mobileBottomNav">
<div class="flex justify-between items-center max-w-lg mx-auto">
<button class="flex flex-col items-center gap-1 text-white cursor-pointer group nav-item" data-view="home">
<span class="material-symbols-outlined text-2xl">home</span>
<span class="text-[10px] font-medium">Home</span>
</button>
<button
class="flex flex-col items-center gap-1 text-gray-400 hover:text-white transition-colors cursor-pointer group nav-item"
data-view="cinema">
<span class="material-symbols-outlined text-2xl">video_library</span>
<span class="text-[10px] font-medium">New & Hot</span>
</button>
<button
class="flex flex-col items-center gap-1 text-gray-400 hover:text-white transition-colors cursor-pointer group nav-item"
data-view="mylist">
<span class="material-symbols-outlined text-2xl">playlist_play</span>
<span class="text-[10px] font-medium">My List</span>
</button>
<button
class="flex flex-col items-center gap-1 text-gray-400 hover:text-white transition-colors cursor-pointer group nav-item"
data-view="search">
<span class="material-symbols-outlined text-2xl">search</span>
<span class="text-[10px] font-medium">Search</span>
</button>
</div>
</nav>
<!-- Search Modal -->
<div class="fixed inset-0 z-[150] bg-black/90 backdrop-blur-sm hidden" id="searchModal">
<div class="w-full max-w-3xl mx-auto px-4 pt-20">
<div class="flex items-center gap-4 mb-6">
<span class="material-symbols-outlined text-white/50 text-3xl">search</span>
<input type="text" id="searchInput"
class="flex-1 bg-transparent border-none text-white text-2xl placeholder-white/30 focus:ring-0 focus:outline-none"
placeholder="Titles, people, genres" autocomplete="off">
<button class="text-white/50 hover:text-white" id="closeSearch">
<span class="material-symbols-outlined text-3xl">close</span>
</button>
</div>
<div id="searchResults" class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-4">
<!-- Search results will be injected here -->
</div>
</div>
</div>
<!-- Toast Container -->
<div class="fixed bottom-4 right-4 z-[200] flex flex-col gap-2" id="toastContainer"></div>
<!-- Video Player Dependencies -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.5.7/hls.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/artplayer/5.3.0/artplayer.js"></script>
<!-- App Scripts -->
<script src="/js/history-service.js"></script>
</body>
</html>