Subham9126 commited on
Commit
bc9545e
·
verified ·
1 Parent(s): 77bca8d

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +712 -156
index.html CHANGED
@@ -3,183 +3,739 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Basic M3U8 Player</title>
7
  <style>
 
 
 
 
 
 
8
  body {
9
- font-family: sans-serif;
10
- padding: 20px;
11
- background-color: #f4f4f4;
12
- }
13
- #player-container {
14
- margin-top: 20px;
15
- background-color: #fff;
16
- padding: 15px;
17
- border-radius: 5px;
18
- box-shadow: 0 2px 5px rgba(0,0,0,0.1);
19
- }
20
- #videoPlayer {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  width: 100%;
22
- max-width: 800px; /* Adjust as needed */
23
- background-color: #000; /* Black background for letterboxing */
24
- display: block; /* Prevents extra space below video */
25
- margin-top: 10px;
26
- }
27
- #urlInput {
28
- width: calc(100% - 100px); /* Adjust width */
29
- padding: 10px;
30
- margin-right: 5px;
31
- border: 1px solid #ccc;
32
- border-radius: 3px;
33
- }
34
- #loadButton {
35
- padding: 10px 15px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  cursor: pointer;
37
- background-color: #007bff;
38
- color: white;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  border: none;
40
- border-radius: 3px;
 
 
 
 
 
41
  }
42
- #loadButton:hover {
43
- background-color: #0056b3;
 
 
44
  }
45
- #status {
46
- margin-top: 10px;
47
- font-style: italic;
48
- color: #555;
49
  }
50
- .error {
51
- color: red;
52
- font-weight: bold;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  }
54
  </style>
55
- <!-- 1. Include hls.js library -->
56
- <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
57
  </head>
58
  <body>
 
 
 
 
 
 
 
 
 
 
59
 
60
- <h1>Basic M3U8 Web Player</h1>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
- <div id="player-container">
63
- <label for="urlInput">M3U8 URL:</label>
64
- <input type="text" id="urlInput" placeholder="https://example.com/stream.m3u8">
65
- <button id="loadButton">Load Stream</button>
 
 
 
 
 
 
 
 
 
66
 
67
- <div id="status">Enter an M3U8 URL and click Load.</div>
68
-
69
- <!-- 2. The Video Element -->
70
- <video id="videoPlayer" controls></video>
71
- </div>
 
 
72
 
73
  <script>
74
- const videoElement = document.getElementById('videoPlayer');
75
- const urlInput = document.getElementById('urlInput');
76
- const loadButton = document.getElementById('loadButton');
77
- const statusDiv = document.getElementById('status');
78
- let hls = null; // Variable to hold the Hls instance
79
-
80
- loadButton.addEventListener('click', loadStream);
81
-
82
- function loadStream() {
83
- const m3u8Url = urlInput.value.trim();
84
- statusDiv.textContent = ''; // Clear previous status
85
- statusDiv.classList.remove('error');
86
-
87
- if (!m3u8Url) {
88
- statusDiv.textContent = 'Please enter an M3U8 URL.';
89
- statusDiv.classList.add('error');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  return;
91
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
- // Destroy previous instance if it exists
94
- if (hls) {
95
- hls.destroy();
96
- hls = null;
97
- }
98
-
99
- // Check if HLS is supported by the browser (using hls.js)
100
- if (Hls.isSupported()) {
101
- console.log("HLS.js is supported. Initializing...");
102
- statusDiv.textContent = 'Loading stream with HLS.js...';
103
-
104
- hls = new Hls(); // Create a new Hls instance
105
-
106
- // Bind error handling
107
- hls.on(Hls.Events.ERROR, function (event, data) {
108
- if (data.fatal) {
109
- switch(data.type) {
110
- case Hls.ErrorTypes.NETWORK_ERROR:
111
- console.error('Fatal network error encountered:', data);
112
- statusDiv.textContent = `Error: Network error - ${data.details}. Check URL and CORS policy.`;
113
- statusDiv.classList.add('error');
114
- hls.destroy(); // Clean up on fatal error
115
- hls = null;
116
- break;
117
- case Hls.ErrorTypes.MEDIA_ERROR:
118
- console.error('Fatal media error encountered:', data);
119
- statusDiv.textContent = `Error: Media error - ${data.details}. Trying to recover...`;
120
- statusDiv.classList.add('error');
121
- hls.recoverMediaError();
122
- break;
123
- default:
124
- // Cannot recover
125
- console.error('Unrecoverable fatal error:', data);
126
- statusDiv.textContent = `Error: Unrecoverable error - ${data.details}.`;
127
- statusDiv.classList.add('error');
128
- hls.destroy();
129
- hls = null;
130
- break;
131
- }
132
- } else {
133
- console.warn('Non-fatal HLS error:', data);
134
- statusDiv.textContent = `Warning: ${data.details}`;
135
- statusDiv.classList.remove('error'); // Maybe not a fatal error shown to user
136
- }
137
- });
138
-
139
- hls.loadSource(m3u8Url);
140
- hls.attachMedia(videoElement);
141
-
142
- hls.on(Hls.Events.MANIFEST_PARSED, function() {
143
- console.log('Manifest parsed. Ready to play.');
144
- statusDiv.textContent = 'Stream loaded. Press play!';
145
- // You could uncomment the next line to autoplay, but user interaction is often required by browsers
146
- // videoElement.play();
147
- });
148
-
149
- }
150
- // Check for native browser HLS support (e.g., Safari on iOS/macOS)
151
- else if (videoElement.canPlayType('application/vnd.apple.mpegurl')) {
152
- console.log("Native HLS support detected (e.g., Safari).");
153
- statusDiv.textContent = 'Loading stream using native browser support...';
154
- videoElement.src = m3u8Url;
155
- videoElement.addEventListener('loadedmetadata', function() {
156
- console.log('Metadata loaded. Ready to play.');
157
- statusDiv.textContent = 'Stream loaded. Press play!';
158
- // videoElement.play(); // Autoplay if desired and allowed
159
- });
160
- videoElement.addEventListener('error', function(e) {
161
- console.error('Native HLS playback error:', e);
162
- statusDiv.textContent = 'Error loading stream with native player. Check URL/CORS.';
163
- statusDiv.classList.add('error');
164
- });
165
- }
166
- // HLS is not supported on this browser
167
- else {
168
- statusDiv.textContent = 'Error: HLS is not supported in this browser.';
169
- statusDiv.classList.add('error');
170
- console.error("HLS is not supported by hls.js or natively.");
171
- }
172
- }
173
-
174
- // Optional: Add listener to Enter key in input field
175
- urlInput.addEventListener('keypress', function(event) {
176
- if (event.key === 'Enter') {
177
- event.preventDefault(); // Prevent potential form submission
178
- loadButton.click(); // Trigger the button click
179
- }
180
- });
181
 
182
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  </body>
185
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Video Streaming Platform</title>
7
  <style>
8
+ * {
9
+ margin: 0;
10
+ padding: 0;
11
+ box-sizing: border-box;
12
+ }
13
+
14
  body {
15
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
16
+ background: #0f0f0f;
17
+ color: #fff;
18
+ line-height: 1.6;
19
+ }
20
+
21
+ .container {
22
+ max-width: 1400px;
23
+ margin: 0 auto;
24
+ padding: 0 20px;
25
+ }
26
+
27
+ /* Header */
28
+ header {
29
+ background: #212121;
30
+ padding: 1rem 0;
31
+ position: sticky;
32
+ top: 0;
33
+ z-index: 100;
34
+ border-bottom: 1px solid #333;
35
+ }
36
+
37
+ .header-content {
38
+ display: flex;
39
+ justify-content: space-between;
40
+ align-items: center;
41
+ flex-wrap: wrap;
42
+ gap: 1rem;
43
+ }
44
+
45
+ .logo {
46
+ font-size: 1.8rem;
47
+ font-weight: bold;
48
+ color: #ff6b6b;
49
+ cursor: pointer;
50
+ transition: color 0.3s ease;
51
+ }
52
+
53
+ .logo:hover {
54
+ color: #ff5252;
55
+ }
56
+
57
+ .search-container {
58
+ flex: 1;
59
+ max-width: 500px;
60
+ position: relative;
61
+ }
62
+
63
+ #searchInput {
64
  width: 100%;
65
+ padding: 12px 20px;
66
+ background: #333;
67
+ border: 2px solid #444;
68
+ border-radius: 25px;
69
+ color: #fff;
70
+ font-size: 16px;
71
+ transition: all 0.3s ease;
72
+ }
73
+
74
+ #searchInput:focus {
75
+ outline: none;
76
+ border-color: #ff6b6b;
77
+ background: #404040;
78
+ }
79
+
80
+ #searchInput::placeholder {
81
+ color: #aaa;
82
+ }
83
+
84
+ /* Main Content */
85
+ main {
86
+ min-height: calc(100vh - 200px);
87
+ padding: 2rem 0;
88
+ }
89
+
90
+ /* Video Grid */
91
+ .video-grid {
92
+ display: grid;
93
+ grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
94
+ gap: 1.5rem;
95
+ margin-bottom: 2rem;
96
+ }
97
+
98
+ .video-card {
99
+ background: #1e1e1e;
100
+ border-radius: 12px;
101
+ overflow: hidden;
102
+ transition: all 0.3s ease;
103
  cursor: pointer;
104
+ border: 2px solid transparent;
105
+ }
106
+
107
+ .video-card:hover {
108
+ transform: translateY(-8px);
109
+ border-color: #ff6b6b;
110
+ box-shadow: 0 12px 30px rgba(255, 107, 107, 0.3);
111
+ }
112
+
113
+ .video-thumbnail {
114
+ width: 100%;
115
+ height: 180px;
116
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
117
+ display: flex;
118
+ align-items: center;
119
+ justify-content: center;
120
+ position: relative;
121
+ overflow: hidden;
122
+ }
123
+
124
+ .play-icon {
125
+ width: 60px;
126
+ height: 60px;
127
+ background: rgba(255, 255, 255, 0.9);
128
+ border-radius: 50%;
129
+ display: flex;
130
+ align-items: center;
131
+ justify-content: center;
132
+ font-size: 24px;
133
+ color: #333;
134
+ transition: all 0.3s ease;
135
+ }
136
+
137
+ .video-card:hover .play-icon {
138
+ transform: scale(1.1);
139
+ background: #ff6b6b;
140
+ color: #fff;
141
+ }
142
+
143
+ .video-info {
144
+ padding: 1rem;
145
+ }
146
+
147
+ .video-title {
148
+ font-size: 1.1rem;
149
+ font-weight: 600;
150
+ color: #fff;
151
+ margin-bottom: 0.5rem;
152
+ }
153
+
154
+ .video-meta {
155
+ color: #aaa;
156
+ font-size: 0.9rem;
157
+ }
158
+
159
+ /* Video Player Page */
160
+ .player-container {
161
+ display: none;
162
+ }
163
+
164
+ .player-container.active {
165
+ display: block;
166
+ }
167
+
168
+ .video-player-section {
169
+ background: #1e1e1e;
170
+ border-radius: 12px;
171
+ padding: 1rem;
172
+ margin-bottom: 2rem;
173
+ }
174
+
175
+ .video-player {
176
+ width: 100%;
177
+ max-width: 900px;
178
+ height: auto;
179
+ border-radius: 8px;
180
+ margin-bottom: 1rem;
181
+ }
182
+
183
+ .video-details h2 {
184
+ font-size: 1.5rem;
185
+ margin-bottom: 1rem;
186
+ color: #fff;
187
+ }
188
+
189
+ .back-button {
190
+ background: #ff6b6b;
191
+ color: #fff;
192
  border: none;
193
+ padding: 12px 24px;
194
+ border-radius: 25px;
195
+ cursor: pointer;
196
+ font-size: 16px;
197
+ transition: all 0.3s ease;
198
+ margin-bottom: 1rem;
199
  }
200
+
201
+ .back-button:hover {
202
+ background: #ff5252;
203
+ transform: translateY(-2px);
204
  }
205
+
206
+ .recommendations {
207
+ margin-top: 2rem;
 
208
  }
209
+
210
+ .recommendations h3 {
211
+ margin-bottom: 1rem;
212
+ color: #fff;
213
+ font-size: 1.3rem;
214
+ }
215
+
216
+ .recommendations-grid {
217
+ display: grid;
218
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
219
+ gap: 1rem;
220
+ }
221
+
222
+ .recommendation-card {
223
+ background: #2a2a2a;
224
+ border-radius: 8px;
225
+ padding: 1rem;
226
+ cursor: pointer;
227
+ transition: all 0.3s ease;
228
+ border: 1px solid #444;
229
+ }
230
+
231
+ .recommendation-card:hover {
232
+ background: #333;
233
+ border-color: #ff6b6b;
234
+ }
235
+
236
+ .recommendation-title {
237
+ font-weight: 600;
238
+ margin-bottom: 0.5rem;
239
+ }
240
+
241
+ /* Pagination */
242
+ .pagination {
243
+ display: flex;
244
+ justify-content: center;
245
+ align-items: center;
246
+ gap: 0.5rem;
247
+ margin: 2rem 0;
248
+ flex-wrap: wrap;
249
+ }
250
+
251
+ .pagination button {
252
+ background: #333;
253
+ color: #fff;
254
+ border: none;
255
+ padding: 10px 15px;
256
+ border-radius: 6px;
257
+ cursor: pointer;
258
+ transition: all 0.3s ease;
259
+ font-size: 14px;
260
+ }
261
+
262
+ .pagination button:hover:not(:disabled) {
263
+ background: #ff6b6b;
264
+ transform: translateY(-2px);
265
+ }
266
+
267
+ .pagination button:disabled {
268
+ opacity: 0.5;
269
+ cursor: not-allowed;
270
+ }
271
+
272
+ .pagination button.active {
273
+ background: #ff6b6b;
274
+ }
275
+
276
+ .pagination-info {
277
+ color: #aaa;
278
+ margin: 0 1rem;
279
+ font-size: 14px;
280
+ }
281
+
282
+ /* No Results */
283
+ .no-results {
284
+ text-align: center;
285
+ padding: 3rem;
286
+ color: #aaa;
287
+ }
288
+
289
+ .no-results h3 {
290
+ font-size: 1.5rem;
291
+ margin-bottom: 1rem;
292
+ }
293
+
294
+ .no-results p {
295
+ font-size: 1.1rem;
296
+ }
297
+
298
+ /* Loading */
299
+ .loading {
300
+ text-align: center;
301
+ padding: 3rem;
302
+ color: #aaa;
303
+ }
304
+
305
+ .loading-spinner {
306
+ width: 50px;
307
+ height: 50px;
308
+ border: 3px solid #333;
309
+ border-top: 3px solid #ff6b6b;
310
+ border-radius: 50%;
311
+ animation: spin 1s linear infinite;
312
+ margin: 0 auto 1rem;
313
+ }
314
+
315
+ @keyframes spin {
316
+ 0% { transform: rotate(0deg); }
317
+ 100% { transform: rotate(360deg); }
318
+ }
319
+
320
+ /* Responsive Design */
321
+ @media (max-width: 768px) {
322
+ .header-content {
323
+ flex-direction: column;
324
+ text-align: center;
325
+ }
326
+
327
+ .search-container {
328
+ max-width: 100%;
329
+ }
330
+
331
+ .video-grid {
332
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
333
+ gap: 1rem;
334
+ }
335
+
336
+ .recommendations-grid {
337
+ grid-template-columns: 1fr;
338
+ }
339
+
340
+ .pagination {
341
+ gap: 0.25rem;
342
+ }
343
+
344
+ .pagination button {
345
+ padding: 8px 12px;
346
+ font-size: 12px;
347
+ }
348
+ }
349
+
350
+ @media (max-width: 480px) {
351
+ .video-grid {
352
+ grid-template-columns: 1fr;
353
+ }
354
+
355
+ .video-thumbnail {
356
+ height: 200px;
357
+ }
358
  }
359
  </style>
 
 
360
  </head>
361
  <body>
362
+ <header>
363
+ <div class="container">
364
+ <div class="header-content">
365
+ <div class="logo" onclick="showVideoList()">📺 VideoHub</div>
366
+ <div class="search-container">
367
+ <input type="text" id="searchInput" placeholder="Search videos..." oninput="handleSearch()">
368
+ </div>
369
+ </div>
370
+ </div>
371
+ </header>
372
 
373
+ <main>
374
+ <div class="container">
375
+ <!-- Video List View -->
376
+ <div id="videoListContainer">
377
+ <div id="loadingIndicator" class="loading">
378
+ <div class="loading-spinner"></div>
379
+ <p>Loading videos...</p>
380
+ </div>
381
+
382
+ <div id="videoGrid" class="video-grid"></div>
383
+
384
+ <div id="noResults" class="no-results" style="display: none;">
385
+ <h3>No videos found</h3>
386
+ <p>Try adjusting your search terms</p>
387
+ </div>
388
+
389
+ <div id="paginationContainer" class="pagination"></div>
390
+ </div>
391
 
392
+ <!-- Video Player View -->
393
+ <div id="videoPlayerContainer" class="player-container">
394
+ <button class="back-button" onclick="showVideoList()">← Back to Videos</button>
395
+
396
+ <div class="video-player-section">
397
+ <video id="videoPlayer" class="video-player" controls>
398
+ Your browser does not support the video tag.
399
+ </video>
400
+
401
+ <div class="video-details">
402
+ <h2 id="currentVideoTitle">Video Title</h2>
403
+ </div>
404
+ </div>
405
 
406
+ <div class="recommendations">
407
+ <h3>Up Next</h3>
408
+ <div id="recommendationsGrid" class="recommendations-grid"></div>
409
+ </div>
410
+ </div>
411
+ </div>
412
+ </main>
413
 
414
  <script>
415
+ // Global state
416
+ let allVideos = [];
417
+ let filteredVideos = [];
418
+ let currentPage = 1;
419
+ const videosPerPage = 12;
420
+ let currentVideoIndex = -1;
421
+ let searchQuery = '';
422
+
423
+ // Sample data (replace with actual database.json loading)
424
+ const sampleData = [
425
+ { "title": "E01 - Introduction", "url": "https://example.com/video1.mkv" },
426
+ { "title": "E02 - Getting Started", "url": "https://example.com/video2.mkv" },
427
+ { "title": "E03 - Advanced Concepts", "url": "https://example.com/video3.mkv" },
428
+ { "title": "E04 - Best Practices", "url": "https://example.com/video4.mkv" },
429
+ { "title": "E05 - Case Studies", "url": "https://example.com/video5.mkv" },
430
+ { "title": "E06 - Implementation", "url": "https://example.com/video6.mkv" },
431
+ { "title": "E07 - Testing", "url": "https://example.com/video7.mkv" },
432
+ { "title": "E08 - Deployment", "url": "https://example.com/video8.mkv" },
433
+ { "title": "E09 - Monitoring", "url": "https://example.com/video9.mkv" },
434
+ { "title": "E10 - Optimization", "url": "https://example.com/video10.mkv" },
435
+ { "title": "E11 - Security", "url": "https://example.com/video11.mkv" },
436
+ { "title": "E12 - Maintenance", "url": "https://example.com/video12.mkv" },
437
+ { "title": "E13 - Troubleshooting", "url": "https://example.com/video13.mkv" },
438
+ { "title": "E14 - Future Trends", "url": "https://example.com/video14.mkv" },
439
+ { "title": "E15 - Conclusion", "url": "https://example.com/video15.mkv" }
440
+ ];
441
+
442
+ // Initialize the application
443
+ async function initApp() {
444
+ try {
445
+ // Try to load from database.json, fallback to sample data
446
+ await loadVideos();
447
+ setupEventListeners();
448
+ handleURLHash();
449
+ } catch (error) {
450
+ console.error('Error initializing app:', error);
451
+ // Use sample data as fallback
452
+ allVideos = [...sampleData];
453
+ filteredVideos = [...allVideos];
454
+ hideLoading();
455
+ renderVideoGrid();
456
+ renderPagination();
457
+ }
458
+ }
459
+
460
+ // Load videos from database.json
461
+ async function loadVideos() {
462
+ try {
463
+ const response = await fetch('database.json');
464
+ if (response.ok) {
465
+ const data = await response.json();
466
+ allVideos = data.sort((a, b) => a.title.localeCompare(b.title));
467
+ } else {
468
+ throw new Error('Failed to load database.json');
469
+ }
470
+ } catch (error) {
471
+ console.warn('Could not load database.json, using sample data:', error);
472
+ allVideos = [...sampleData];
473
+ }
474
+
475
+ filteredVideos = [...allVideos];
476
+ hideLoading();
477
+ renderVideoGrid();
478
+ renderPagination();
479
+ }
480
+
481
+ // Setup event listeners
482
+ function setupEventListeners() {
483
+ // Handle browser back/forward
484
+ window.addEventListener('popstate', handleURLHash);
485
+
486
+ // Handle video player events
487
+ const videoPlayer = document.getElementById('videoPlayer');
488
+ videoPlayer.addEventListener('error', handleVideoError);
489
+ videoPlayer.addEventListener('loadedmetadata', handleVideoLoaded);
490
+ }
491
+
492
+ // Handle URL hash changes
493
+ function handleURLHash() {
494
+ const hash = window.location.hash;
495
+ if (hash.startsWith('#play=')) {
496
+ const videoTitle = decodeURIComponent(hash.substring(6));
497
+ const videoIndex = allVideos.findIndex(v => v.title === videoTitle);
498
+ if (videoIndex !== -1) {
499
+ playVideo(videoIndex);
500
+ } else {
501
+ showVideoList();
502
+ }
503
+ } else {
504
+ showVideoList();
505
+ }
506
+ }
507
+
508
+ // Hide loading indicator
509
+ function hideLoading() {
510
+ document.getElementById('loadingIndicator').style.display = 'none';
511
+ }
512
+
513
+ // Handle search input
514
+ function handleSearch() {
515
+ const query = document.getElementById('searchInput').value.toLowerCase().trim();
516
+ searchQuery = query;
517
+
518
+ if (query === '') {
519
+ filteredVideos = [...allVideos];
520
+ } else {
521
+ filteredVideos = allVideos.filter(video =>
522
+ video.title.toLowerCase().includes(query)
523
+ );
524
+ }
525
+
526
+ currentPage = 1;
527
+ renderVideoGrid();
528
+ renderPagination();
529
+ }
530
+
531
+ // Render video grid
532
+ function renderVideoGrid() {
533
+ const grid = document.getElementById('videoGrid');
534
+ const noResults = document.getElementById('noResults');
535
+
536
+ if (filteredVideos.length === 0) {
537
+ grid.innerHTML = '';
538
+ noResults.style.display = 'block';
539
+ return;
540
+ }
541
+
542
+ noResults.style.display = 'none';
543
+
544
+ const startIndex = (currentPage - 1) * videosPerPage;
545
+ const endIndex = startIndex + videosPerPage;
546
+ const videosToShow = filteredVideos.slice(startIndex, endIndex);
547
+
548
+ grid.innerHTML = videosToShow.map((video, index) => {
549
+ const actualIndex = allVideos.findIndex(v => v.title === video.title);
550
+ return `
551
+ <div class="video-card" onclick="playVideo(${actualIndex})">
552
+ <div class="video-thumbnail">
553
+ <div class="play-icon">▶</div>
554
+ </div>
555
+ <div class="video-info">
556
+ <div class="video-title">${escapeHtml(video.title)}</div>
557
+ <div class="video-meta">Click to play</div>
558
+ </div>
559
+ </div>
560
+ `;
561
+ }).join('');
562
+ }
563
+
564
+ // Render pagination
565
+ function renderPagination() {
566
+ const container = document.getElementById('paginationContainer');
567
+ const totalPages = Math.ceil(filteredVideos.length / videosPerPage);
568
+
569
+ if (totalPages <= 1) {
570
+ container.innerHTML = '';
571
  return;
572
  }
573
+
574
+ let paginationHTML = '';
575
+
576
+ // Previous button
577
+ paginationHTML += `
578
+ <button onclick="changePage(${currentPage - 1})" ${currentPage === 1 ? 'disabled' : ''}>
579
+ ← Previous
580
+ </button>
581
+ `;
582
+
583
+ // Page numbers
584
+ const maxVisiblePages = 5;
585
+ let startPage = Math.max(1, currentPage - Math.floor(maxVisiblePages / 2));
586
+ let endPage = Math.min(totalPages, startPage + maxVisiblePages - 1);
587
+
588
+ if (endPage - startPage + 1 < maxVisiblePages) {
589
+ startPage = Math.max(1, endPage - maxVisiblePages + 1);
590
+ }
591
+
592
+ if (startPage > 1) {
593
+ paginationHTML += `<button onclick="changePage(1)">1</button>`;
594
+ if (startPage > 2) {
595
+ paginationHTML += `<span class="pagination-info">...</span>`;
596
+ }
597
+ }
598
+
599
+ for (let i = startPage; i <= endPage; i++) {
600
+ paginationHTML += `
601
+ <button onclick="changePage(${i})" ${i === currentPage ? 'class="active"' : ''}>
602
+ ${i}
603
+ </button>
604
+ `;
605
+ }
606
+
607
+ if (endPage < totalPages) {
608
+ if (endPage < totalPages - 1) {
609
+ paginationHTML += `<span class="pagination-info">...</span>`;
610
+ }
611
+ paginationHTML += `<button onclick="changePage(${totalPages})">${totalPages}</button>`;
612
+ }
613
+
614
+ // Next button
615
+ paginationHTML += `
616
+ <button onclick="changePage(${currentPage + 1})" ${currentPage === totalPages ? 'disabled' : ''}>
617
+ Next →
618
+ </button>
619
+ `;
620
+
621
+ // Page info
622
+ const startItem = (currentPage - 1) * videosPerPage + 1;
623
+ const endItem = Math.min(currentPage * videosPerPage, filteredVideos.length);
624
+ paginationHTML += `
625
+ <span class="pagination-info">
626
+ ${startItem}-${endItem} of ${filteredVideos.length} videos
627
+ </span>
628
+ `;
629
+
630
+ container.innerHTML = paginationHTML;
631
+ }
632
+
633
+ // Change page
634
+ function changePage(page) {
635
+ const totalPages = Math.ceil(filteredVideos.length / videosPerPage);
636
+ if (page >= 1 && page <= totalPages) {
637
+ currentPage = page;
638
+ renderVideoGrid();
639
+ renderPagination();
640
+
641
+ // Scroll to top
642
+ window.scrollTo({ top: 0, behavior: 'smooth' });
643
+ }
644
+ }
645
 
646
+ // Play video
647
+ function playVideo(videoIndex) {
648
+ if (videoIndex < 0 || videoIndex >= allVideos.length) return;
649
+
650
+ currentVideoIndex = videoIndex;
651
+ const video = allVideos[videoIndex];
652
+
653
+ // Update URL hash
654
+ window.history.pushState(null, null, `#play=${encodeURIComponent(video.title)}`);
655
+
656
+ // Hide video list, show player
657
+ document.getElementById('videoListContainer').style.display = 'none';
658
+ document.getElementById('videoPlayerContainer').classList.add('active');
659
+
660
+ // Set up video player
661
+ const videoPlayer = document.getElementById('videoPlayer');
662
+ videoPlayer.src = video.url;
663
+
664
+ // Update video title
665
+ document.getElementById('currentVideoTitle').textContent = video.title;
666
+
667
+ // Generate recommendations
668
+ generateRecommendations();
669
+
670
+ // Scroll to top
671
+ window.scrollTo({ top: 0, behavior: 'smooth' });
672
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
673
 
674
+ // Generate recommendations
675
+ function generateRecommendations() {
676
+ const grid = document.getElementById('recommendationsGrid');
677
+ const recommendations = [];
678
+
679
+ // Get next 5 videos in sequence
680
+ for (let i = 1; i <= 5; i++) {
681
+ const nextIndex = currentVideoIndex + i;
682
+ if (nextIndex < allVideos.length) {
683
+ recommendations.push({ video: allVideos[nextIndex], index: nextIndex });
684
+ }
685
+ }
686
+
687
+ // If we don't have enough recommendations, add some from the beginning
688
+ let startIndex = 0;
689
+ while (recommendations.length < 5 && startIndex < allVideos.length) {
690
+ if (startIndex !== currentVideoIndex &&
691
+ !recommendations.some(r => r.index === startIndex)) {
692
+ recommendations.push({ video: allVideos[startIndex], index: startIndex });
693
+ }
694
+ startIndex++;
695
+ }
696
+
697
+ grid.innerHTML = recommendations.map(({ video, index }) => `
698
+ <div class="recommendation-card" onclick="playVideo(${index})">
699
+ <div class="recommendation-title">${escapeHtml(video.title)}</div>
700
+ <div class="video-meta">Click to play</div>
701
+ </div>
702
+ `).join('');
703
+ }
704
+
705
+ // Show video list
706
+ function showVideoList() {
707
+ // Update URL
708
+ window.history.pushState(null, null, window.location.pathname);
709
+
710
+ // Hide player, show list
711
+ document.getElementById('videoPlayerContainer').classList.remove('active');
712
+ document.getElementById('videoListContainer').style.display = 'block';
713
+
714
+ // Pause current video
715
+ const videoPlayer = document.getElementById('videoPlayer');
716
+ videoPlayer.pause();
717
+ }
718
+
719
+ // Handle video errors
720
+ function handleVideoError(event) {
721
+ console.error('Video error:', event);
722
+ alert('Error loading video. Please check the video URL or try again later.');
723
+ }
724
 
725
+ // Handle video loaded
726
+ function handleVideoLoaded(event) {
727
+ console.log('Video loaded successfully');
728
+ }
729
+
730
+ // Utility function to escape HTML
731
+ function escapeHtml(text) {
732
+ const div = document.createElement('div');
733
+ div.textContent = text;
734
+ return div.innerHTML;
735
+ }
736
+
737
+ // Initialize the app when DOM is loaded
738
+ document.addEventListener('DOMContentLoaded', initApp);
739
+ </script>
740
  </body>
741
  </html>