582 lines
28 KiB
HTML
582 lines
28 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport"
|
|
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
<meta name="mobile-web-app-capable" content="yes">
|
|
<title>NodeCast TV | IPTV Player</title>
|
|
<meta name="description" content="Stream live TV, movies, and series with EPG support">
|
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
|
<link rel="stylesheet" href="css/main.css">
|
|
<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=Inter:wght@400;500;600;700&family=Outfit:wght@800&display=swap"
|
|
rel="stylesheet">
|
|
<!-- HLS.js for video playback -->
|
|
<script src="https://cdn.jsdelivr.net/npm/hls.js@1.5.7/dist/hls.min.js"></script>
|
|
</head>
|
|
|
|
<body>
|
|
<div id="app">
|
|
<!-- Navigation -->
|
|
<nav class="navbar">
|
|
<div class="navbar-brand">
|
|
<span class="logo"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 187.63 210.6" fill="#6366f1"
|
|
class="icon">
|
|
<path
|
|
d="M169.71,87.87c-4.77,0-9.1,1.88-12.31,4.92L35.3,22.3c.35-1.4.56-2.86.56-4.37C35.86,8.03,27.83,0,17.93,0S0,8.03,0,17.93c0,8.44,5.84,15.5,13.69,17.4v140c-7.71,2.01-13.41,8.99-13.41,17.33,0,9.9,8.03,17.93,17.93,17.93s17.93-8.03,17.93-17.93c0-1.56-.22-3.07-.6-4.51l121.21-69.98c3.26,3.42,7.86,5.55,12.95,5.55,9.9,0,17.93-8.03,17.93-17.93s-8.03-17.93-17.93-17.93ZM152.78,99.92c-.14.41-.27.83-.38,1.25h-51.47l-44.18-24.72L30.4,30.8c.33-.32.64-.65.94-.99l121.45,70.12ZM22.17,175.2V35.33c.23-.05.45-.11.67-.17l26.35,45.65-.34,50.04-25.74,44.59c-.31-.09-.63-.17-.95-.24ZM31.52,180.69c-.27-.3-.55-.6-.84-.89l25.48-44.13,44.64-25.78h51.47c.07.32.15.63.24.94L31.52,180.69Z" />
|
|
</svg></span>
|
|
<span class="brand-text">nodecast-tv</span>
|
|
</div>
|
|
<button class="mobile-menu-toggle" id="mobile-menu-toggle" aria-label="Toggle menu">
|
|
<span></span>
|
|
<span></span>
|
|
<span></span>
|
|
</button>
|
|
<div class="navbar-menu" id="navbar-menu">
|
|
<a href="#" class="nav-link active" data-page="home">
|
|
<span class="nav-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"
|
|
class="icon">
|
|
<path
|
|
d="M21 6h-7.59l3.29-3.29L16 2l-4 4-4-4-.71.71L10.59 6H3a2 2 0 0 0-2 2v12c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V8a2 2 0 0 0-2-2zm0 14H3V8h18v12zM9 10v8l7-4z" />
|
|
</svg></span>
|
|
<span>Live TV</span>
|
|
</a>
|
|
<a href="#" class="nav-link" data-page="guide">
|
|
<span class="nav-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"
|
|
class="icon">
|
|
<path d="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7 7v2h14V7H7z" />
|
|
</svg></span>
|
|
<span>TV Guide</span>
|
|
</a>
|
|
<a href="#" class="nav-link" data-page="movies">
|
|
<span class="nav-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"
|
|
class="icon">
|
|
<path
|
|
d="M18 4l2 4h-3l-2-4h-2l2 4h-3l-2-4H8l2 4H7L5 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h20c1.1 0 2-.9 2-2V4h-4z" />
|
|
</svg></span>
|
|
<span>Movies</span>
|
|
</a>
|
|
<a href="#" class="nav-link" data-page="series">
|
|
<span class="nav-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"
|
|
class="icon">
|
|
<path
|
|
d="M21 3H3c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h5v2h8v-2h5c1.1 0 1.99-.9 1.99-2L23 5c0-1.1-.9-2-2-2zm0 14H3V5h18v12z" />
|
|
</svg></span>
|
|
<span>Series</span>
|
|
</a>
|
|
<a href="#" class="nav-link" data-page="settings">
|
|
<span class="nav-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"
|
|
class="icon">
|
|
<path
|
|
d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L3.16 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.04.64.09.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.58 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z" />
|
|
</svg></span>
|
|
<span>Settings</span>
|
|
</a>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- Main Content Area -->
|
|
<main class="main-content">
|
|
<!-- Home Page -->
|
|
<div id="page-home" class="page active">
|
|
<div class="home-layout">
|
|
<!-- Channel Toggle Button (Mobile) -->
|
|
<button class="channel-toggle-btn" id="channel-toggle-btn">
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="icon">
|
|
<path d="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7 7v2h14V7H7z" />
|
|
</svg>
|
|
<span>Channels</span>
|
|
</button>
|
|
|
|
<!-- Overlay for drawer -->
|
|
<div class="channel-sidebar-overlay" id="channel-sidebar-overlay"></div>
|
|
|
|
<!-- Channel Sidebar -->
|
|
<aside class="channel-sidebar" id="channel-sidebar">
|
|
<div class="sidebar-header">
|
|
<div class="search-wrapper">
|
|
<input type="text" id="channel-search" placeholder="Search channels..." class="search-input">
|
|
<button type="button" class="search-clear" title="Clear search">×</button>
|
|
</div>
|
|
<div class="sidebar-controls">
|
|
<select id="source-select" class="source-select">
|
|
<option value="">All Sources</option>
|
|
</select>
|
|
<button id="toggle-groups" class="btn btn-sm btn-ghost" title="Expand/Collapse All">
|
|
<span><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="icon">
|
|
<path
|
|
d="M12 5.83L15.17 9l1.41-1.41L12 3 7.41 7.59 8.83 9 12 5.83zm0 12.34L8.83 15l-1.41 1.41L12 21l4.59-4.59L15.17 15 12 18.17z" />
|
|
</svg></span>
|
|
</button>
|
|
|
|
</div>
|
|
</div>
|
|
<div id="channel-list" class="channel-list">
|
|
<div class="empty-state">
|
|
<p>No channels loaded</p>
|
|
<p class="hint">Add a source in Settings to get started</p>
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
|
|
<!-- Video Player Area -->
|
|
<section class="player-section">
|
|
<div class="video-container">
|
|
<video id="video-player" controls playsinline></video>
|
|
|
|
<!-- Custom Mobile Controls -->
|
|
<div class="video-controls" id="video-controls">
|
|
<button class="video-control-btn" id="btn-play" title="Play/Pause">
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="icon">
|
|
<path d="M8 5v14l11-7z" />
|
|
</svg>
|
|
</button>
|
|
<button class="video-control-btn" id="btn-mute" title="Mute/Unmute">
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="icon">
|
|
<path
|
|
d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z" />
|
|
</svg>
|
|
</button>
|
|
<button class="video-control-btn" id="btn-pip" title="Picture in Picture">
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="icon">
|
|
<path
|
|
d="M19 7h-8v6h8V7zm2-4H3c-1.1 0-2 .9-2 2v14c0 1.1.9 1.98 2 1.98h18c1.1 0 2-.88 2-1.98V5c0-1.1-.9-2-2-2zm0 16.01H3V4.98h18v14.03z" />
|
|
</svg>
|
|
</button>
|
|
<button class="video-control-btn" id="btn-fullscreen" title="Fullscreen">
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="icon">
|
|
<path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="player-overlay" id="player-overlay">
|
|
<div class="overlay-content">
|
|
<p>Select a channel to start watching</p>
|
|
</div>
|
|
</div>
|
|
<!-- Now Playing Overlay -->
|
|
<div class="now-playing-overlay hidden" id="now-playing">
|
|
<div class="now-playing-info">
|
|
<h3 class="channel-name">No channel selected</h3>
|
|
<p class="program-title"></p>
|
|
<p class="program-time"></p>
|
|
</div>
|
|
<div class="up-next">
|
|
<h4>Up Next</h4>
|
|
<ul id="up-next-list"></ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Guide Page -->
|
|
<div id="page-guide" class="page">
|
|
<div class="guide-header">
|
|
<h2>TV Guide</h2>
|
|
<div class="guide-controls">
|
|
<select id="epg-group-select" class="source-select">
|
|
<option value="">All Groups</option>
|
|
</select>
|
|
<div class="search-wrapper">
|
|
<input type="text" id="epg-search" placeholder="Search channels..." class="search-input">
|
|
<button type="button" class="search-clear" title="Clear search">×</button>
|
|
</div>
|
|
<button id="guide-prev" class="btn btn-ghost">← Earlier</button>
|
|
<span id="guide-date" class="guide-date">Today</span>
|
|
<button id="guide-next" class="btn btn-ghost">Later →</button>
|
|
</div>
|
|
</div>
|
|
<div id="epg-grid" class="epg-grid">
|
|
<div class="empty-state">
|
|
<p>No EPG data available</p>
|
|
<p class="hint">Add an EPG source in Settings</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Movies Page -->
|
|
<div id="page-movies" class="page">
|
|
<div class="movies-header">
|
|
<h2>Movies</h2>
|
|
<div class="movies-controls">
|
|
<select id="movies-source-select" class="source-select">
|
|
<option value="">All Sources</option>
|
|
</select>
|
|
<select id="movies-category-select" class="source-select">
|
|
<option value="">All Categories</option>
|
|
</select>
|
|
<div class="search-wrapper">
|
|
<input type="text" id="movies-search" placeholder="Search movies..." class="search-input">
|
|
<button type="button" class="search-clear" title="Clear search">×</button>
|
|
</div>
|
|
<button id="movies-favorites-btn" class="btn btn-icon btn-ghost" title="Show Favorites Only">
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="icon">
|
|
<path
|
|
d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" />
|
|
</svg> Favorites
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div id="movies-grid" class="movies-grid">
|
|
<div class="empty-state">
|
|
<p>Loading movies...</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Series Page -->
|
|
<div id="page-series" class="page">
|
|
<div class="series-header">
|
|
<h2>Series</h2>
|
|
<div class="series-controls">
|
|
<select id="series-source-select" class="source-select">
|
|
<option value="">All Sources</option>
|
|
</select>
|
|
<select id="series-category-select" class="source-select">
|
|
<option value="">All Categories</option>
|
|
</select>
|
|
<div class="search-wrapper">
|
|
<input type="text" id="series-search" placeholder="Search series..." class="search-input">
|
|
<button type="button" class="search-clear" title="Clear search">×</button>
|
|
</div>
|
|
<button id="series-favorites-btn" class="btn btn-icon btn-ghost" title="Show Favorites Only">
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="icon">
|
|
<path
|
|
d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" />
|
|
</svg> Favorites
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="series-content">
|
|
<div id="series-grid" class="series-grid">
|
|
<div class="empty-state">
|
|
<p>Loading series...</p>
|
|
</div>
|
|
</div>
|
|
<!-- Series details panel (seasons/episodes) -->
|
|
<div id="series-details" class="series-details hidden">
|
|
<button class="series-back-btn">← Back to Series</button>
|
|
<div class="series-details-header">
|
|
<img id="series-poster" src="" alt="" class="series-poster">
|
|
<div class="series-info">
|
|
<h3 id="series-title"></h3>
|
|
<p id="series-plot"></p>
|
|
</div>
|
|
</div>
|
|
<div id="series-seasons" class="series-seasons"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Settings Page -->
|
|
<div id="page-settings" class="page">
|
|
<div class="settings-container">
|
|
<h2>Settings</h2>
|
|
|
|
<!-- Tabs -->
|
|
<div class="tabs">
|
|
<button class="tab active" data-tab="sources">Sources</button>
|
|
<button class="tab" data-tab="player">Player</button>
|
|
<button class="tab" data-tab="content">Manage Content</button>
|
|
<button class="tab" data-tab="users" id="users-tab" style="display:none;">Users</button>
|
|
</div>
|
|
|
|
<!-- Sources Tab -->
|
|
<div id="tab-sources" class="tab-content active">
|
|
<div class="source-section">
|
|
<div class="section-header">
|
|
<h3>Xtream Connections</h3>
|
|
<button class="btn btn-primary" id="add-xtream">+ Add Xtream</button>
|
|
</div>
|
|
<div id="xtream-list" class="source-list"></div>
|
|
</div>
|
|
|
|
<div class="source-section">
|
|
<div class="section-header">
|
|
<h3>M3U Playlists</h3>
|
|
<button class="btn btn-primary" id="add-m3u">+ Add M3U</button>
|
|
</div>
|
|
<div id="m3u-list" class="source-list"></div>
|
|
</div>
|
|
|
|
<div class="source-section">
|
|
<div class="section-header">
|
|
<h3>EPG Sources</h3>
|
|
<button class="btn btn-primary" id="add-epg">+ Add EPG</button>
|
|
</div>
|
|
<div id="epg-list" class="source-list"></div>
|
|
</div>
|
|
|
|
<div class="source-section">
|
|
<h3>EPG Data Settings</h3>
|
|
<div class="setting-item">
|
|
<label for="epg-refresh-interval">Auto-refresh EPG data every:</label>
|
|
<select id="epg-refresh-interval" class="form-input">
|
|
<option value="1">1 hour</option>
|
|
<option value="2">2 hours</option>
|
|
<option value="4">4 hours</option>
|
|
<option value="12">12 hours</option>
|
|
<option value="24" selected>24 hours</option>
|
|
<option value="0">Manual only</option>
|
|
</select>
|
|
</div>
|
|
<p class="hint">Use the <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"
|
|
class="icon" style="width: 1em; height: 1em; vertical-align: middle;">
|
|
<path
|
|
d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z" />
|
|
</svg> button next to EPG sources for manual refresh</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Player Tab -->
|
|
<div id="tab-player" class="tab-content">
|
|
<div class="settings-section">
|
|
<h3>Keyboard Controls</h3>
|
|
<div class="setting-item">
|
|
<label class="setting-toggle">
|
|
<input type="checkbox" id="setting-arrow-keys" checked>
|
|
<span class="toggle-slider"></span>
|
|
</label>
|
|
<div class="setting-info">
|
|
<span class="setting-label">Arrow keys change channels</span>
|
|
<span class="setting-hint">When enabled, ↑/↓ change channels and ←/→ adjust volume</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="settings-section">
|
|
<h3>Now Playing Overlay</h3>
|
|
<div class="setting-item">
|
|
<label for="setting-overlay-duration">Display Duration (seconds)</label>
|
|
<input type="number" id="setting-overlay-duration" class="form-input setting-number" min="1" max="30"
|
|
value="5">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="settings-section">
|
|
<h3>Volume Settings</h3>
|
|
<div class="setting-item">
|
|
<label for="setting-default-volume">Default Volume</label>
|
|
<div class="volume-slider-container">
|
|
<input type="range" id="setting-default-volume" class="volume-slider" min="0" max="100" value="80">
|
|
<span id="volume-value">80%</span>
|
|
</div>
|
|
</div>
|
|
<div class="setting-item">
|
|
<label class="setting-toggle">
|
|
<input type="checkbox" id="setting-remember-volume" checked>
|
|
<span class="toggle-slider"></span>
|
|
</label>
|
|
<div class="setting-info">
|
|
<span class="setting-label">Remember Last Volume</span>
|
|
<span class="setting-hint">When enabled, volume persists between sessions</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="settings-section">
|
|
<h3>Playback</h3>
|
|
<div class="setting-item">
|
|
<label class="setting-toggle">
|
|
<input type="checkbox" id="setting-autoplay-next">
|
|
<span class="toggle-slider"></span>
|
|
</label>
|
|
<div class="setting-info">
|
|
<span class="setting-label">Auto-play Next Episode</span>
|
|
<span class="setting-hint">Automatically play the next episode when one ends</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="settings-section">
|
|
<h3>Streaming</h3>
|
|
<div class="setting-item">
|
|
<label class="setting-toggle">
|
|
<input type="checkbox" id="setting-force-proxy">
|
|
<span class="toggle-slider"></span>
|
|
</label>
|
|
<div class="setting-info">
|
|
<span class="setting-label">Force Backend Proxy</span>
|
|
<span class="setting-hint">Route all streams through the proxy server. Enable if streams don't play
|
|
directly.</span>
|
|
</div>
|
|
</div>
|
|
<div class="setting-item">
|
|
<label class="setting-toggle">
|
|
<input type="checkbox" id="setting-force-transcode">
|
|
<span class="toggle-slider"></span>
|
|
</label>
|
|
<div class="setting-info">
|
|
<span class="setting-label">Force Audio Transcode</span>
|
|
<span class="setting-hint">Transcode audio to AAC for browser compatibility. Enable if you get video
|
|
but no audio (fixes Dolby/AC3/EAC3).</span>
|
|
</div>
|
|
</div>
|
|
<div class="setting-item">
|
|
<label class="setting-toggle">
|
|
<input type="checkbox" id="setting-force-remux">
|
|
<span class="toggle-slider"></span>
|
|
</label>
|
|
<div class="setting-info">
|
|
<span class="setting-label">Force Remux</span>
|
|
<span class="setting-hint">Remux streams to MP4 container. Enable for raw .ts streams
|
|
from IPTV middleware like m3u-editor or dispatcharr.</span>
|
|
</div>
|
|
</div>
|
|
<div class="setting-item">
|
|
<div class="setting-info" style="flex: 1;">
|
|
<span class="setting-label">Stream Output Format</span>
|
|
<span class="setting-hint">Container format for Xtream streams. Try TS if you experience buffering
|
|
issues.</span>
|
|
</div>
|
|
<select id="setting-stream-format" class="source-select" style="width: auto; min-width: 200px;">
|
|
<option value="m3u8">HLS (m3u8) - Recommended</option>
|
|
<option value="ts">MPEG-TS (ts) - Better buffer</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="settings-section">
|
|
<h3>Keyboard Shortcuts</h3>
|
|
<div class="shortcuts-grid">
|
|
<div class="shortcut"><kbd>↑</kbd> / <kbd>↓</kbd> Channel up/down (or volume)</div>
|
|
<div class="shortcut"><kbd>←</kbd> / <kbd>→</kbd> Volume down/up (when arrows = channels)</div>
|
|
<div class="shortcut"><kbd>Space</kbd> / <kbd>K</kbd> Play/Pause</div>
|
|
<div class="shortcut"><kbd>F</kbd> Fullscreen</div>
|
|
<div class="shortcut"><kbd>M</kbd> Mute/Unmute</div>
|
|
<div class="shortcut"><kbd>I</kbd> Toggle info overlay</div>
|
|
<div class="shortcut"><kbd>PgUp</kbd> / <kbd>PgDn</kbd> Channel up/down</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Manage Content Tab -->
|
|
<div id="tab-content" class="tab-content">
|
|
<div class="content-browser">
|
|
<div class="content-browser-header">
|
|
<div class="content-type-toggle">
|
|
<button class="btn btn-sm active" id="content-type-channels">Channels</button>
|
|
<button class="btn btn-sm" id="content-type-movies">Movies</button>
|
|
<button class="btn btn-sm" id="content-type-series">Series</button>
|
|
</div>
|
|
<select id="content-source-select" class="source-select">
|
|
<option value="">Select a source...</option>
|
|
</select>
|
|
<div class="content-actions">
|
|
<button class="btn btn-sm btn-secondary" id="content-show-all">Show All</button>
|
|
<button class="btn btn-sm btn-secondary" id="content-hide-all">Hide All</button>
|
|
<button class="btn btn-sm btn-primary" id="content-save"><svg xmlns="http://www.w3.org/2000/svg"
|
|
viewBox="0 0 24 24" fill="currentColor" class="icon">
|
|
<path
|
|
d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z" />
|
|
</svg> Save Changes</button>
|
|
</div>
|
|
</div>
|
|
<p class="hint" style="margin-bottom: var(--space-sm);">✓ Checked = Visible, ☐ Unchecked = Hidden</p>
|
|
<div id="content-tree" class="content-tree">
|
|
<p class="hint">Select a source to view groups and channels</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Users Tab (Admin Only) -->
|
|
<div id="tab-users" class="tab-content">
|
|
<div class="settings-section">
|
|
<h3>User Management</h3>
|
|
<p class="hint">Manage user accounts and permissions</p>
|
|
|
|
<div class="user-list-container">
|
|
<table class="user-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Username</th>
|
|
<th>Role</th>
|
|
<th>Created</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="user-list">
|
|
<tr>
|
|
<td colspan="4" class="hint">Loading users...</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="add-user-section">
|
|
<h4>Add New User</h4>
|
|
<form id="add-user-form" class="user-form">
|
|
<div class="form-group">
|
|
<label for="new-username">Username</label>
|
|
<input type="text" id="new-username" name="username" class="form-input" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="new-password">Password</label>
|
|
<input type="password" id="new-password" name="password" class="form-input" required minlength="6">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="new-role">Role</label>
|
|
<select id="new-role" name="role" class="form-input" required>
|
|
<option value="viewer">Viewer</option>
|
|
<option value="admin">Admin</option>
|
|
</select>
|
|
</div>
|
|
<button type="submit" class="btn btn-primary">Add User</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
|
|
<!-- Modal Template -->
|
|
<div id="modal" class="modal">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h3 id="modal-title">Modal</h3>
|
|
<button class="modal-close">×</button>
|
|
</div>
|
|
<div id="modal-body" class="modal-body"></div>
|
|
<div id="modal-footer" class="modal-footer"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Context Menu Template -->
|
|
<div id="context-menu" class="context-menu">
|
|
<button class="context-item" data-action="play"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
|
|
fill="currentColor" class="icon">
|
|
<path d="M8 5v14l11-7z" />
|
|
</svg> Play</button>
|
|
<button class="context-item" data-action="hide"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
|
|
fill="currentColor" class="icon">
|
|
<path
|
|
d="M12 7c2.76 0 5 2.24 5 5 0 .65-.13 1.26-.36 1.83l2.92 2.92c1.51-1.26 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74.25-4.01.7l2.16 2.16C10.85 7.18 11.4 7 12 7zM2 4.27l2.28 2.28.46.46C3.08 8.3 1.78 10.02 1 12c1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-.3 4.38-.84l.42.42L19.73 22 21 20.73 3.27 3 2 4.27zM7.53 9.8l1.55 1.55c-.05.21-.08.43-.08.65 0 1.66 1.34 3 3 3 .22 0 .44-.03.65-.08l1.55 1.55c-.67.33-1.41.53-2.2.53-2.76 0-5-2.24-5-5 0-.79.2-1.53.53-2.2zm4.31-.78l3.15 3.15.02-.16c0-1.66-1.34-3-3-3l-.17.01z" />
|
|
</svg> Hide</button>
|
|
</div>
|
|
|
|
<!-- JavaScript -->
|
|
<script src="/js/icons.js"></script>
|
|
<script src="/js/api.js?v=2"></script>
|
|
<script src="/js/components/VideoPlayer.js?v=2"></script>
|
|
<script src="/js/components/ChannelList.js?v=3"></script>
|
|
<script src="/js/components/SourceManager.js?v=2"></script>
|
|
<script src="/js/components/EpgGuide.js?v=2"></script>
|
|
<script src="/js/pages/Home.js?v=3"></script>
|
|
<script src="/js/pages/Guide.js?v=2"></script>
|
|
<script src="/js/pages/MoviesPage.js?v=4"></script>
|
|
<script src="/js/pages/SeriesPage.js?v=1"></script>
|
|
<script src="/js/pages/Settings.js?v=2"></script>
|
|
<script src="/js/app.js?v=3"></script>
|
|
</body>
|
|
|
|
</html> |