Subham9126 commited on
Commit
d2873cc
·
verified ·
1 Parent(s): 72f8d55

Update script.js

Browse files
Files changed (1) hide show
  1. script.js +251 -239
script.js CHANGED
@@ -4,307 +4,319 @@ let currentVideoId = null;
4
  let currentPage = 1;
5
  const videosPerPage = 12;
6
  let filteredVideos = [];
 
 
 
7
 
8
- // DOM elements
9
- const videoGrid = document.getElementById('videoGrid');
10
- const suggestionsContainer = document.getElementById('suggestions');
11
- const videoTitle = document.getElementById('videoTitle');
12
- const videoDescription = document.getElementById('videoDescription');
13
- const searchInput = document.getElementById('searchInput');
14
- const searchBtn = document.getElementById('searchBtn');
15
- const paginationContainer = document.getElementById('pagination');
16
-
17
- // Initialize the app based on current page
18
- document.addEventListener('DOMContentLoaded', () => {
19
- loadVideos();
20
 
21
  if (window.location.pathname.includes('player.html')) {
22
- initPlayer();
23
  } else {
24
- // Setup search functionality for index page
 
 
 
 
 
 
 
25
  searchInput.addEventListener('input', handleSearch);
26
  searchBtn.addEventListener('click', handleSearch);
27
  }
28
- });
29
-
30
- // Load videos from database.json
31
- async function loadVideos() {
32
- try {
33
- const response = await fetch('database.json');
34
- videos = await response.json();
35
- filteredVideos = [...videos];
36
-
37
- if (window.location.pathname.includes('player.html')) {
38
- // Player page - load current video and suggestions
39
- const urlParams = new URLSearchParams(window.location.search);
40
- currentVideoId = urlParams.get('v');
41
 
42
- if (currentVideoId) {
43
- loadVideo(currentVideoId);
44
- renderSuggestions();
45
  } else {
46
- // Redirect to home if no video specified
47
  window.location.href = 'index.html';
48
  }
49
- } else {
50
- // Home page - render video grid
51
- renderVideoGrid();
52
- renderPagination();
53
- }
54
- } catch (error) {
55
- console.error('Error loading videos:', error);
56
- alert('Failed to load video data. Please try again later.');
57
  }
58
- }
59
 
60
- // Handle search functionality
61
- function handleSearch() {
62
- const searchTerm = searchInput.value.toLowerCase();
63
-
64
- if (searchTerm.trim() === '') {
65
- filteredVideos = [...videos];
66
- } else {
67
- filteredVideos = videos.filter(video =>
68
- video.title.toLowerCase().includes(searchTerm) ||
69
- video.description.toLowerCase().includes(searchTerm)
70
- );
71
- }
72
 
73
- currentPage = 1;
74
- renderVideoGrid();
75
- renderPagination();
76
- }
77
-
78
- // Render video grid on home page with pagination
79
- function renderVideoGrid() {
80
- if (!videoGrid) return;
81
 
82
- videoGrid.innerHTML = '';
 
83
 
84
- const startIndex = (currentPage - 1) * videosPerPage;
85
- const endIndex = startIndex + videosPerPage;
86
- const videosToShow = filteredVideos.slice(startIndex, endIndex);
 
 
 
 
87
 
88
- if (videosToShow.length === 0) {
89
- videoGrid.innerHTML = '<p class="no-results">No videos found matching your search.</p>';
90
- return;
91
- }
92
 
93
- videosToShow.forEach(video => {
94
- const videoCard = document.createElement('div');
95
- videoCard.className = 'video-card';
96
- videoCard.addEventListener('click', () => {
97
- window.location.href = `player.html?v=${video.id}`;
98
- });
99
-
100
- videoCard.innerHTML = `
101
- <div class="thumbnail">
102
- <img src="${video.thumbnailPath}" alt="${video.title}" loading="lazy">
103
- ${video.duration ? `<span class="duration">${video.duration}</span>` : ''}
104
- </div>
105
- <div class="video-info">
106
- <h3>${video.title}</h3>
107
- <p>${video.description.substring(0, 100)}...</p>
108
- </div>
109
- `;
110
-
111
- videoGrid.appendChild(videoCard);
112
  });
113
- }
114
-
115
- // Render pagination controls
116
- function renderPagination() {
117
- if (!paginationContainer) return;
118
 
119
- paginationContainer.innerHTML = '';
 
 
 
120
 
121
- const totalPages = Math.ceil(filteredVideos.length / videosPerPage);
 
 
 
 
 
 
 
 
 
 
 
122
 
123
- if (totalPages <= 1) return;
 
 
 
124
 
125
- // Previous button
126
- const prevBtn = document.createElement('button');
127
- prevBtn.className = 'page-btn';
128
- prevBtn.textContent = 'Previous';
129
- prevBtn.disabled = currentPage === 1;
130
- prevBtn.addEventListener('click', () => {
131
- if (currentPage > 1) {
132
- currentPage--;
133
- renderVideoGrid();
134
- renderPagination();
135
- window.scrollTo({ top: 0, behavior: 'smooth' });
136
- }
137
  });
138
- paginationContainer.appendChild(prevBtn);
139
 
140
- // Page buttons
141
- const maxVisiblePages = 5;
142
- let startPage = Math.max(1, currentPage - Math.floor(maxVisiblePages / 2));
143
- let endPage = Math.min(totalPages, startPage + maxVisiblePages - 1);
 
 
 
144
 
145
- if (endPage - startPage + 1 < maxVisiblePages) {
146
- startPage = Math.max(1, endPage - maxVisiblePages + 1);
147
  }
148
 
149
- if (startPage > 1) {
150
- const firstBtn = document.createElement('button');
151
- firstBtn.className = 'page-btn';
152
- firstBtn.textContent = '1';
153
- firstBtn.addEventListener('click', () => {
154
- currentPage = 1;
155
- renderVideoGrid();
156
- renderPagination();
157
- window.scrollTo({ top: 0, behavior: 'smooth' });
158
- });
159
- paginationContainer.appendChild(firstBtn);
160
-
161
- if (startPage > 2) {
162
- const ellipsis = document.createElement('span');
163
- ellipsis.textContent = '...';
164
- paginationContainer.appendChild(ellipsis);
165
- }
166
  }
167
 
168
- for (let i = startPage; i <= endPage; i++) {
169
- const pageBtn = document.createElement('button');
170
- pageBtn.className = `page-btn ${i === currentPage ? 'active' : ''}`;
171
- pageBtn.textContent = i;
172
- pageBtn.addEventListener('click', () => {
173
- currentPage = i;
174
- renderVideoGrid();
175
- renderPagination();
176
- window.scrollTo({ top: 0, behavior: 'smooth' });
177
- });
178
- paginationContainer.appendChild(pageBtn);
 
 
 
179
  }
180
 
181
- if (endPage < totalPages) {
182
- if (endPage < totalPages - 1) {
183
- const ellipsis = document.createElement('span');
184
- ellipsis.textContent = '...';
185
- paginationContainer.appendChild(ellipsis);
186
- }
187
-
188
- const lastBtn = document.createElement('button');
189
- lastBtn.className = 'page-btn';
190
- lastBtn.textContent = totalPages;
191
- lastBtn.addEventListener('click', () => {
192
- currentPage = totalPages;
193
- renderVideoGrid();
194
- renderPagination();
195
- window.scrollTo({ top: 0, behavior: 'smooth' });
196
  });
197
- paginationContainer.appendChild(lastBtn);
198
  }
199
-
200
- // Next button
201
- const nextBtn = document.createElement('button');
202
- nextBtn.className = 'page-btn';
203
- nextBtn.textContent = 'Next';
204
- nextBtn.disabled = currentPage === totalPages;
205
- nextBtn.addEventListener('click', () => {
206
- if (currentPage < totalPages) {
207
- currentPage++;
208
- renderVideoGrid();
209
- renderPagination();
210
- window.scrollTo({ top: 0, behavior: 'smooth' });
211
- }
212
- });
213
- paginationContainer.appendChild(nextBtn);
214
  }
215
 
216
- // Load a specific video on player page
217
  function loadVideo(videoId) {
218
  const video = videos.find(v => v.id === videoId);
219
  if (!video) {
220
- alert('Video not found');
221
  window.location.href = 'index.html';
222
  return;
223
  }
224
 
225
  currentVideoId = videoId;
226
- videoTitle.textContent = video.title;
227
- videoDescription.textContent = video.description;
228
-
229
- // Update page title
230
  document.title = `${video.title} - Video Browser`;
231
 
232
- // Initialize Video.js player
233
- const player = videojs('mainVideo', {
234
- controls: true,
235
- autoplay: false,
236
- preload: 'auto',
237
- responsive: true,
238
- fluid: true,
239
- sources: [{
240
- src: video.videoPath,
241
- type: 'video/mp4' // Adjust based on your video format
242
- }]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
243
  });
244
 
 
 
 
 
 
 
 
245
  // Add subtitle tracks if available
246
  if (video.subtitleTracks) {
 
 
 
 
 
 
 
247
  video.subtitleTracks.forEach(track => {
248
  player.addRemoteTextTrack({
249
  kind: 'subtitles',
250
  src: track.path,
251
  srclang: track.srclang,
252
  label: track.label,
253
- default: track.srclang === 'en' // Default to English if available
254
  }, false);
255
  });
256
  }
257
 
258
- // Handle player errors
259
- player.on('error', () => {
260
- const errorDisplay = player.errorDisplay;
261
- errorDisplay.contentEl().innerHTML = `
262
- <div class="vjs-error-display">
263
- <div class="vjs-modal-dialog-content">
264
- <h1>Error loading video</h1>
265
- <p>The video format may not be supported by your browser.</p>
266
- <p>Try using a different browser or check the video file.</p>
267
- </div>
268
- </div>
269
- `;
270
- errorDisplay.show();
271
- });
272
  }
273
 
274
- // Render suggested videos
275
- function renderSuggestions() {
276
- if (!suggestionsContainer) return;
277
-
278
- // Filter out current video
279
- const suggestedVideos = videos.filter(v => v.id !== currentVideoId);
280
-
281
- suggestionsContainer.innerHTML = '<h2>Suggested Videos</h2>';
282
-
283
- suggestedVideos.forEach(video => {
284
- const suggestionCard = document.createElement('div');
285
- suggestionCard.className = 'suggestion-card';
286
- suggestionCard.addEventListener('click', () => {
287
- // Update URL without reloading the page
288
- window.history.pushState({}, '', `player.html?v=${video.id}`);
289
- loadVideo(video.id);
290
- renderSuggestions();
291
- });
 
 
 
 
 
 
 
 
 
 
 
292
 
293
- suggestionCard.innerHTML = `
294
- <div class="suggestion-thumbnail">
295
- <img src="${video.thumbnailPath}" alt="${video.title}" loading="lazy">
296
- </div>
297
- <div class="suggestion-info">
298
- <h3>${video.title}</h3>
299
- ${video.duration ? `<p>${video.duration}</p>` : ''}
300
- </div>
301
- `;
302
 
303
- suggestionsContainer.appendChild(suggestionCard);
304
- });
305
- }
 
 
 
306
 
307
- // Initialize video player (Video.js handles most of this now)
308
- function initPlayer() {
309
- // Video.js is initialized in loadVideo function
310
- }
 
4
  let currentPage = 1;
5
  const videosPerPage = 12;
6
  let filteredVideos = [];
7
+ let player = null;
8
+ let pipPlayer = null;
9
+ let currentPlaybackPosition = {};
10
 
11
+ // Initialize the app
12
+ document.addEventListener('DOMContentLoaded', async () => {
13
+ await loadVideos();
 
 
 
 
 
 
 
 
 
14
 
15
  if (window.location.pathname.includes('player.html')) {
16
+ initPlayerPage();
17
  } else {
18
+ initGalleryPage();
19
+ }
20
+
21
+ // Setup event listeners that exist on both pages
22
+ const searchInput = document.getElementById('searchInput');
23
+ const searchBtn = document.getElementById('searchBtn');
24
+
25
+ if (searchInput && searchBtn) {
26
  searchInput.addEventListener('input', handleSearch);
27
  searchBtn.addEventListener('click', handleSearch);
28
  }
29
+
30
+ // Back button functionality
31
+ const backBtn = document.getElementById('backBtn');
32
+ const homeLogo = document.getElementById('homeLogo');
33
+
34
+ if (backBtn || homeLogo) {
35
+ const goBack = () => {
36
+ if (player && player.isFullscreen()) {
37
+ player.exitFullscreen();
38
+ }
 
 
 
39
 
40
+ if (player && !player.paused()) {
41
+ enterPipMode();
 
42
  } else {
 
43
  window.location.href = 'index.html';
44
  }
45
+ };
46
+
47
+ if (backBtn) backBtn.addEventListener('click', goBack);
48
+ if (homeLogo) homeLogo.addEventListener('click', goBack);
 
 
 
 
49
  }
50
+ });
51
 
52
+ // PIP Mode functions
53
+ function enterPipMode() {
54
+ if (!player) return;
 
 
 
 
 
 
 
 
 
55
 
56
+ const pipContainer = document.getElementById('pipContainer');
57
+ if (!pipContainer) return;
 
 
 
 
 
 
58
 
59
+ // Save current playback position
60
+ currentPlaybackPosition[currentVideoId] = player.currentTime();
61
 
62
+ // Create PIP player
63
+ pipContainer.innerHTML = `
64
+ <video id="pipVideo" class="video-js vjs-default-skin" controls>
65
+ <source src="${player.currentSrc()}" type="${player.currentType()}">
66
+ </video>
67
+ <button id="closePip" class="pip-close-btn"><i class="fas fa-times"></i></button>
68
+ `;
69
 
70
+ pipContainer.style.display = 'block';
 
 
 
71
 
72
+ pipPlayer = videojs('pipVideo', {
73
+ controls: true,
74
+ autoplay: true,
75
+ fluid: true,
76
+ playbackRates: [0.5, 1, 1.5, 2]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  });
 
 
 
 
 
78
 
79
+ // Restore playback position
80
+ if (currentPlaybackPosition[currentVideoId]) {
81
+ pipPlayer.currentTime(currentPlaybackPosition[currentVideoId]);
82
+ }
83
 
84
+ // Copy tracks from main player
85
+ const textTracks = player.remoteTextTracks();
86
+ for (let i = 0; i < textTracks.length; i++) {
87
+ const track = textTracks[i];
88
+ pipPlayer.addRemoteTextTrack({
89
+ kind: track.kind,
90
+ src: track.src,
91
+ srclang: track.language,
92
+ label: track.label,
93
+ default: track.default
94
+ }, false);
95
+ }
96
 
97
+ // Close button functionality
98
+ document.getElementById('closePip').addEventListener('click', () => {
99
+ exitPipMode(true);
100
+ });
101
 
102
+ // When PIP video ends
103
+ pipPlayer.on('ended', () => {
104
+ exitPipMode();
 
 
 
 
 
 
 
 
 
105
  });
 
106
 
107
+ // Navigate to home
108
+ window.location.href = 'index.html';
109
+ }
110
+
111
+ function exitPipMode(stopPlayback = false) {
112
+ const pipContainer = document.getElementById('pipContainer');
113
+ if (!pipContainer || !pipPlayer) return;
114
 
115
+ if (pipPlayer && !stopPlayback) {
116
+ currentPlaybackPosition[currentVideoId] = pipPlayer.currentTime();
117
  }
118
 
119
+ if (pipPlayer) {
120
+ pipPlayer.dispose();
121
+ pipPlayer = null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  }
123
 
124
+ pipContainer.innerHTML = '';
125
+ pipContainer.style.display = 'none';
126
+ }
127
+
128
+ // Initialize player page
129
+ function initPlayerPage() {
130
+ const urlParams = new URLSearchParams(window.location.search);
131
+ currentVideoId = urlParams.get('v');
132
+
133
+ if (currentVideoId) {
134
+ loadVideo(currentVideoId);
135
+ renderSuggestions();
136
+ } else {
137
+ window.location.href = 'index.html';
138
  }
139
 
140
+ // Setup download button
141
+ const downloadBtn = document.getElementById('downloadBtn');
142
+ if (downloadBtn) {
143
+ downloadBtn.addEventListener('click', () => {
144
+ const video = videos.find(v => v.id === currentVideoId);
145
+ if (video) {
146
+ const link = document.createElement('a');
147
+ link.href = video.videoPath;
148
+ link.download = video.title.replace(/[^a-z0-9]/gi, '_').toLowerCase() + '.mp4';
149
+ document.body.appendChild(link);
150
+ link.click();
151
+ document.body.removeChild(link);
152
+ }
 
 
153
  });
 
154
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  }
156
 
157
+ // Improved video loading with better buffering
158
  function loadVideo(videoId) {
159
  const video = videos.find(v => v.id === videoId);
160
  if (!video) {
 
161
  window.location.href = 'index.html';
162
  return;
163
  }
164
 
165
  currentVideoId = videoId;
166
+ document.getElementById('videoTitle').textContent = video.title;
167
+ document.getElementById('videoDescription').textContent = video.description;
 
 
168
  document.title = `${video.title} - Video Browser`;
169
 
170
+ // Initialize or reuse player
171
+ if (!player) {
172
+ player = videojs('mainVideo', {
173
+ controls: true,
174
+ autoplay: true,
175
+ preload: 'auto',
176
+ responsive: true,
177
+ fluid: true,
178
+ html5: {
179
+ hls: {
180
+ overrideNative: true,
181
+ enableLowInitialPlaylist: true,
182
+ smoothQualityChange: true,
183
+ bandwidth: 2000000
184
+ },
185
+ nativeAudioTracks: false,
186
+ nativeVideoTracks: false
187
+ },
188
+ playbackRates: [0.5, 1, 1.5, 2]
189
+ });
190
+
191
+ // Optimization for better seeking
192
+ player.tech_.on('seekablechanged', function() {
193
+ const seekable = player.seekable();
194
+ if (seekable && seekable.length) {
195
+ player.bufferedPercent = function() {
196
+ const buffered = player.buffered();
197
+ let bufferedEnd = player.bufferedEnd();
198
+ const duration = player.duration();
199
+
200
+ if (duration > 0 && bufferedEnd > 0) {
201
+ return (bufferedEnd / duration) * 100;
202
+ }
203
+ return 0;
204
+ };
205
+ }
206
+ });
207
+
208
+ player.on('seeking', function() {
209
+ if (player.tech_.seeking()) {
210
+ player.addClass('vjs-waiting');
211
+ }
212
+ });
213
+
214
+ player.on('seeked', function() {
215
+ player.removeClass('vjs-waiting');
216
+ });
217
+
218
+ player.on('error', function() {
219
+ const errorDisplay = player.errorDisplay;
220
+ errorDisplay.contentEl().innerHTML = `
221
+ <div class="vjs-error-display">
222
+ <div class="vjs-modal-dialog-content">
223
+ <h1>Error loading video</h1>
224
+ <p>${player.error().message || 'The video format may not be supported by your browser.'}</p>
225
+ <p>Try using a different browser or check the video file.</p>
226
+ </div>
227
+ </div>
228
+ `;
229
+ errorDisplay.show();
230
+ });
231
+ }
232
+
233
+ // Change video source
234
+ player.src({
235
+ src: video.videoPath,
236
+ type: getVideoType(video.videoPath)
237
  });
238
 
239
+ // Restore playback position if available
240
+ if (currentPlaybackPosition[videoId]) {
241
+ player.ready(() => {
242
+ player.currentTime(currentPlaybackPosition[videoId]);
243
+ });
244
+ }
245
+
246
  // Add subtitle tracks if available
247
  if (video.subtitleTracks) {
248
+ // Clear existing tracks
249
+ const existingTracks = player.remoteTextTracks();
250
+ while (existingTracks.length > 0) {
251
+ player.removeRemoteTextTrack(existingTracks[0]);
252
+ }
253
+
254
+ // Add new tracks
255
  video.subtitleTracks.forEach(track => {
256
  player.addRemoteTextTrack({
257
  kind: 'subtitles',
258
  src: track.path,
259
  srclang: track.srclang,
260
  label: track.label,
261
+ default: track.srclang === 'en'
262
  }, false);
263
  });
264
  }
265
 
266
+ // Update view count (simulated)
267
+ if (video.views) {
268
+ document.getElementById('viewCount').textContent = `${formatNumber(video.views)} views`;
269
+ } else {
270
+ document.getElementById('viewCount').textContent = 'No views';
271
+ }
272
+
273
+ // Update upload date (simulated)
274
+ if (video.uploadDate) {
275
+ document.getElementById('uploadDate').textContent = formatDate(video.uploadDate);
276
+ } else {
277
+ document.getElementById('uploadDate').textContent = 'Upload date unknown';
278
+ }
 
279
  }
280
 
281
+ // Helper function to detect video type
282
+ function getVideoType(path) {
283
+ const extension = path.split('.').pop().toLowerCase();
284
+ switch (extension) {
285
+ case 'mp4': return 'video/mp4';
286
+ case 'webm': return 'video/webm';
287
+ case 'ogg': return 'video/ogg';
288
+ case 'mov': return 'video/quicktime';
289
+ default: return 'video/mp4';
290
+ }
291
+ }
292
+
293
+ // Format number for view count
294
+ function formatNumber(num) {
295
+ if (!num) return '0';
296
+ return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
297
+ }
298
+
299
+ // Format date
300
+ function formatDate(dateString) {
301
+ if (!dateString) return '';
302
+ const date = new Date(dateString);
303
+ return date.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' });
304
+ }
305
+
306
+ // When returning to player page from PIP
307
+ window.addEventListener('popstate', (event) => {
308
+ if (window.location.pathname.includes('player.html') && pipPlayer) {
309
+ exitPipMode();
310
 
311
+ const urlParams = new URLSearchParams(window.location.search);
312
+ const newVideoId = urlParams.get('v');
 
 
 
 
 
 
 
313
 
314
+ if (newVideoId && newVideoId !== currentVideoId) {
315
+ loadVideo(newVideoId);
316
+ renderSuggestions();
317
+ }
318
+ }
319
+ });
320
 
321
+ // Other existing functions (loadVideos, renderVideoGrid, renderPagination, etc.)
322
+ // ... (keep all the other functions from previous implementation)