diff --git a/.gitignore b/.gitignore
index f6ba8575..268844b7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,6 +30,4 @@ static/video_editor/videos/sample-video-37s.mp4
.DS_Store
static/video_editor/videos/sample-video-10m.mp4
static/video_editor/videos/sample-video-10s.mp4
-/frontend-tools/chapters-editor/node_modules
-frontend-tools/chapters-editor/client/public/videos/sample-video.mp4
-frontend-tools/video-js/
+frontend-tools/video-js/public/videos/sample-video-white.mp4
diff --git a/frontend-tools/video-js/src/VideoJS.css b/frontend-tools/video-js/src/VideoJS.css
index 7ebee252..7229bb5c 100644
--- a/frontend-tools/video-js/src/VideoJS.css
+++ b/frontend-tools/video-js/src/VideoJS.css
@@ -46,6 +46,70 @@ html {
justify-content: flex-start !important;
padding: 0 12px;
height: 48px;
+ /* position: relative !important; */
+}
+
+/* YouTube-style bottom gradient overlay - covers entire video bottom when controls active */
+.video-js::after {
+ content: "";
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 120px;
+ background: linear-gradient(
+ to top,
+ rgba(0, 0, 0, 0.8) 0%,
+ rgba(0, 0, 0, 0.6) 25%,
+ rgba(0, 0, 0, 0.4) 50%,
+ rgba(0, 0, 0, 0.2) 75%,
+ transparent 100%
+ );
+ pointer-events: none;
+ opacity: 0;
+ transition: opacity 0.3s ease;
+ z-index: 2;
+}
+
+/* Show overlay when controls are active - YouTube style */
+.video-js.vjs-user-active::after,
+.video-js.vjs-paused::after,
+.video-js.vjs-ended::after {
+ opacity: 1;
+}
+
+/* Ensure control bar is above the overlay */
+.video-js .vjs-control-bar {
+ z-index: 6 !important;
+}
+
+/* Progress control above overlay */
+.video-js .vjs-progress-control.vjs-control {
+ z-index: 7 !important;
+}
+
+/* Clean white icons - overlay provides the contrast */
+.video-js .vjs-control-bar .vjs-button .vjs-icon-placeholder::before {
+ color: #ffffff !important;
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6) !important;
+}
+
+/* Clean white time displays */
+.video-js .vjs-control-bar .vjs-time-control {
+ color: #ffffff !important;
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6) !important;
+ font-weight: 500 !important;
+}
+
+/* Keep original progress bar styling */
+
+/* Volume control visibility */
+.video-js .vjs-volume-control .vjs-volume-bar {
+ background: rgba(255, 255, 255, 0.3) !important;
+}
+
+.video-js .vjs-volume-control .vjs-volume-level {
+ background: #ffffff !important;
}
.video-container {
@@ -93,6 +157,7 @@ html {
align-items: center;
justify-content: center;
margin: auto;
+ display: none !important;
}
.vjs-next-video-control .vjs-icon-placeholder svg {
width: 100%;
@@ -577,8 +642,7 @@ html {
background-color: rgba(255, 255, 255, 0.1) !important;
}
.video-js .vjs-settings-button:focus {
- outline: 2px solid #fff !important;
- outline-offset: 2px !important;
+ outline: none !important;
}
.video-js .vjs-settings-button .vjs-icon-cog {
diff --git a/frontend-tools/video-js/src/components/chapter/ChapterList.jsx b/frontend-tools/video-js/src/components/chapter/ChapterList.jsx
deleted file mode 100644
index ee06f37a..00000000
--- a/frontend-tools/video-js/src/components/chapter/ChapterList.jsx
+++ /dev/null
@@ -1,207 +0,0 @@
-import React from 'react';
-
-function ChapterList() {
- const playlistData = [
- {
- id: 1,
- title: 'Class 12 Chapter 1 || Electric Charges and Fields 01 || Quantisation and Conservation of Charge',
- channel: 'Physics Wallah - Alakh Pandey',
- duration: '40:13',
- thumbnail:
- 'https://i.ytimg.com/vi/m5VbK66a254/hqdefault.jpg?sqp=-oaymwEmCKgBEF5IWvKriqkDGQgBFQAAiEIYAdgBAeIBCggYEAIYBjgBQAE=&rs=AOn4CLCt2rMJW2jZAYkcDi9wLQOGVkLSTw',
- selected: true,
- },
- {
- id: 2,
- title: 'Class 12 Chapter 1 || Electric Charges and Fields 01 || Quantisation and Conservation of Charge',
- channel: 'Physics Wallah - Alakh Pandey',
- duration: '40:13',
- thumbnail:
- 'https://i.ytimg.com/vi/m5VbK66a254/hqdefault.jpg?sqp=-oaymwEmCKgBEF5IWvKriqkDGQgBFQAAiEIYAdgBAeIBCggYEAIYBjgBQAE=&rs=AOn4CLCt2rMJW2jZAYkcDi9wLQOGVkLSTw',
- selected: false,
- },
- {
- id: 3,
- title: 'Class 12 Chapter 1 || Electric Charges and Fields 01 || Quantisation and Conservation of Charge',
- channel: 'Physics Wallah - Alakh Pandey',
- duration: '40:13',
- thumbnail:
- 'https://i.ytimg.com/vi/m5VbK66a254/hqdefault.jpg?sqp=-oaymwEmCKgBEF5IWvKriqkDGQgBFQAAiEIYAdgBAeIBCggYEAIYBjgBQAE=&rs=AOn4CLCt2rMJW2jZAYkcDi9wLQOGVkLSTw',
- selected: false,
- },
- {
- id: 4,
- title: 'Class 12 Chapter 1 || Electric Charges and Fields 01 || Quantisation and Conservation of Charge',
- channel: 'Physics Wallah - Alakh Pandey',
- duration: '40:13',
- thumbnail:
- 'https://i.ytimg.com/vi/m5VbK66a254/hqdefault.jpg?sqp=-oaymwEmCKgBEF5IWvKriqkDGQgBFQAAiEIYAdgBAeIBCggYEAIYBjgBQAE=&rs=AOn4CLCt2rMJW2jZAYkcDi9wLQOGVkLSTw',
- selected: false,
- },
- {
- id: 5,
- title: 'Class 12 Chapter 1 || Electric Charges and Fields 01 || Quantisation and Conservation of Charge',
- channel: 'Physics Wallah - Alakh Pandey',
- duration: '40:13',
- thumbnail:
- 'https://i.ytimg.com/vi/m5VbK66a254/hqdefault.jpg?sqp=-oaymwEmCKgBEF5IWvKriqkDGQgBFQAAiEIYAdgBAeIBCggYEAIYBjgBQAE=&rs=AOn4CLCt2rMJW2jZAYkcDi9wLQOGVkLSTw',
- selected: false,
- },
- {
- id: 6,
- title: 'Class 12 Chapter 1 || Electric Charges and Fields 01 || Quantisation and Conservation of Charge',
- channel: 'Physics Wallah - Alakh Pandey',
- duration: '40:13',
- thumbnail:
- 'https://i.ytimg.com/vi/m5VbK66a254/hqdefault.jpg?sqp=-oaymwEmCKgBEF5IWvKriqkDGQgBFQAAiEIYAdgBAeIBCggYEAIYBjgBQAE=&rs=AOn4CLCt2rMJW2jZAYkcDi9wLQOGVkLSTw',
- selected: false,
- },
- {
- id: 7,
- title: 'Class 12 Chapter 1 || Electric Charges and Fields 01 || Quantisation and Conservation of Charge',
- channel: 'Physics Wallah - Alakh Pandey',
- duration: '40:13',
- thumbnail:
- 'https://i.ytimg.com/vi/m5VbK66a254/hqdefault.jpg?sqp=-oaymwEmCKgBEF5IWvKriqkDGQgBFQAAiEIYAdgBAeIBCggYEAIYBjgBQAE=&rs=AOn4CLCt2rMJW2jZAYkcDi9wLQOGVkLSTw',
- selected: false,
- },
- {
- id: 8,
- title: 'Class 12 Chapter 1 || Electric Charges and Fields 01 || Quantisation and Conservation of Charge',
- channel: 'Physics Wallah - Alakh Pandey',
- duration: '40:13',
- thumbnail:
- 'https://i.ytimg.com/vi/m5VbK66a254/hqdefault.jpg?sqp=-oaymwEmCKgBEF5IWvKriqkDGQgBFQAAiEIYAdgBAeIBCggYEAIYBjgBQAE=&rs=AOn4CLCt2rMJW2jZAYkcDi9wLQOGVkLSTw',
- selected: false,
- },
- {
- id: 9,
- title: 'Class 12 Chapter 1 || Electric Charges and Fields 01 || Quantisation and Conservation of Charge',
- channel: 'Physics Wallah - Alakh Pandey',
- duration: '40:13',
- thumbnail:
- 'https://i.ytimg.com/vi/m5VbK66a254/hqdefault.jpg?sqp=-oaymwEmCKgBEF5IWvKriqkDGQgBFQAAiEIYAdgBAeIBCggYEAIYBjgBQAE=&rs=AOn4CLCt2rMJW2jZAYkcDi9wLQOGVkLSTw',
- selected: false,
- },
- ];
-
- return (
-
-
-
-
- {playlistData.map((item) => (
- -
-
-
- ))}
-
-
-
- );
-}
-
-export default ChapterList;
diff --git a/frontend-tools/video-js/src/components/controls/AutoplayToggleButton.js b/frontend-tools/video-js/src/components/controls/AutoplayToggleButton.js
index a7422c50..86dbbec3 100644
--- a/frontend-tools/video-js/src/components/controls/AutoplayToggleButton.js
+++ b/frontend-tools/video-js/src/components/controls/AutoplayToggleButton.js
@@ -11,10 +11,8 @@ class AutoplayToggleButton extends Button {
if (this.userPreferences) {
const savedAutoplay = this.userPreferences.getPreference('autoplay');
this.isAutoplayEnabled = savedAutoplay === true; // Explicit boolean check
- console.log('Autoplay button initialized with saved preference:', this.isAutoplayEnabled);
} else {
this.isAutoplayEnabled = false;
- console.log('Autoplay button initialized with default (no userPreferences):', this.isAutoplayEnabled);
}
// Bind methods
@@ -37,13 +35,10 @@ class AutoplayToggleButton extends Button {
});
// Set initial icon state directly
- console.log('AutoplayToggleButton createEl: isAutoplayEnabled =', this.isAutoplayEnabled);
if (this.isAutoplayEnabled) {
this.iconSpan.innerHTML = `●`;
- console.log('Setting RED icon (autoplay ON)');
} else {
this.iconSpan.innerHTML = `○`;
- console.log('Setting GRAY icon (autoplay OFF)');
}
// Create control text span
@@ -51,8 +46,6 @@ class AutoplayToggleButton extends Button {
className: 'vjs-control-text',
});
controlTextSpan.textContent = this.isAutoplayEnabled ? 'Autoplay is on' : 'Autoplay is off';
-
- console.log('✓ Autoplay button created with initial tooltip:', this.isAutoplayEnabled ? 'Autoplay is on' : 'Autoplay is off');
// Append both spans to button
button.appendChild(this.iconSpan);
@@ -65,49 +58,46 @@ class AutoplayToggleButton extends Button {
}
updateIcon() {
- // Add transition and start fade-out
- this.iconSpan.style.transition = 'opacity 0.1s ease';
- this.iconSpan.style.opacity = '0';
+ // Add transition and start fade-out
+ this.iconSpan.style.transition = 'opacity 0.1s ease';
+ this.iconSpan.style.opacity = '0';
- // After fade-out complete, update innerHTML and fade back in
- setTimeout(() => {
- if (this.isAutoplayEnabled) {
- this.iconSpan.innerHTML = `
+ // After fade-out complete, update innerHTML and fade back in
+ setTimeout(() => {
+ if (this.isAutoplayEnabled) {
+ this.iconSpan.innerHTML = `
`;
- if (this.el()) {
- this.el().title = 'Autoplay is on';
- this.el().setAttribute('aria-label', 'Autoplay is on');
- const controlText = this.el().querySelector('.vjs-control-text');
- if (controlText) controlText.textContent = 'Autoplay is on';
- console.log('✓ Autoplay tooltip updated to: "Autoplay is on"');
- }
- } else {
- this.iconSpan.innerHTML = `
+ if (this.el()) {
+ this.el().title = 'Autoplay is on';
+ this.el().setAttribute('aria-label', 'Autoplay is on');
+ const controlText = this.el().querySelector('.vjs-control-text');
+ if (controlText) controlText.textContent = 'Autoplay is on';
+ }
+ } else {
+ this.iconSpan.innerHTML = `
`;
- if (this.el()) {
- this.el().title = 'Autoplay is off';
- this.el().setAttribute('aria-label', 'Autoplay is off');
- const controlText = this.el().querySelector('.vjs-control-text');
- if (controlText) controlText.textContent = 'Autoplay is off';
- console.log('✓ Autoplay tooltip updated to: "Autoplay is off"');
+ if (this.el()) {
+ this.el().title = 'Autoplay is off';
+ this.el().setAttribute('aria-label', 'Autoplay is off');
+ const controlText = this.el().querySelector('.vjs-control-text');
+ if (controlText) controlText.textContent = 'Autoplay is off';
+ }
}
- }
-
- // Fade back in
- this.iconSpan.style.opacity = '1';
- }, 100);
-}
+ // Fade back in
+ this.iconSpan.style.opacity = '1';
+ }, 100);
+ }
handleClick() {
// Toggle autoplay state
@@ -116,15 +106,11 @@ class AutoplayToggleButton extends Button {
// Save preference if userPreferences is available
if (this.userPreferences) {
this.userPreferences.setAutoplayPreference(this.isAutoplayEnabled);
- console.log('Autoplay preference saved to localStorage:', this.isAutoplayEnabled);
}
// Update icon and accessibility attributes
this.updateIcon();
- console.log('Autoplay toggled:', this.isAutoplayEnabled ? 'ON' : 'OFF');
- console.log('✓ Tooltip should now show:', this.isAutoplayEnabled ? 'Autoplay is on' : 'Autoplay is off');
-
// Trigger custom event for other components to listen to
this.player().trigger('autoplayToggle', { autoplay: this.isAutoplayEnabled });
}
@@ -141,38 +127,38 @@ class AutoplayToggleButton extends Button {
let touchHandled = false;
// Touch start
- button.addEventListener('touchstart', (e) => {
- touchStartTime = Date.now();
- touchHandled = false;
- }, { passive: true });
+ button.addEventListener(
+ 'touchstart',
+ (e) => {
+ touchStartTime = Date.now();
+ touchHandled = false;
+ },
+ { passive: true }
+ );
// Touch end
- button.addEventListener('touchend', (e) => {
- const touchDuration = Date.now() - touchStartTime;
-
- // Only show tooltip for quick taps (not swipes)
- if (touchDuration < 500) {
- e.preventDefault();
- e.stopPropagation();
-
- // Show tooltip
- button.classList.add('touch-active');
- touchHandled = true;
-
- // Hide tooltip after delay
- setTimeout(() => {
- button.classList.remove('touch-active');
- }, 2000);
- }
- }, { passive: false });
+ button.addEventListener(
+ 'touchend',
+ (e) => {
+ const touchDuration = Date.now() - touchStartTime;
- // Click fallback for desktop
- button.addEventListener('click', (e) => {
- if (!touchHandled) {
- // This is a desktop click, tooltip will show on hover
- console.log('Desktop click on autoplay button');
- }
- });
+ // Only show tooltip for quick taps (not swipes)
+ if (touchDuration < 500) {
+ e.preventDefault();
+ e.stopPropagation();
+
+ // Show tooltip
+ button.classList.add('touch-active');
+ touchHandled = true;
+
+ // Hide tooltip after delay
+ setTimeout(() => {
+ button.classList.remove('touch-active');
+ }, 2000);
+ }
+ },
+ { passive: false }
+ );
}
}
diff --git a/frontend-tools/video-js/src/components/controls/CustomChaptersOverlay.js b/frontend-tools/video-js/src/components/controls/CustomChaptersOverlay.js
index ed8bf233..f3ed27e1 100644
--- a/frontend-tools/video-js/src/components/controls/CustomChaptersOverlay.js
+++ b/frontend-tools/video-js/src/components/controls/CustomChaptersOverlay.js
@@ -47,7 +47,6 @@ class CustomChaptersOverlay extends Component {
createOverlay() {
if (!this.chaptersData || this.chaptersData.length === 0) {
- console.log('⚠ No chapters data available for overlay');
return;
}
@@ -232,8 +231,6 @@ class CustomChaptersOverlay extends Component {
playerEl.appendChild(this.overlay);
this.player().on('timeupdate', this.updateCurrentChapter);
-
- console.log('✓ Custom chapters overlay created');
}
setupChaptersButton() {
diff --git a/frontend-tools/video-js/src/components/controls/CustomRemainingTime.js b/frontend-tools/video-js/src/components/controls/CustomRemainingTime.js
index bdb1a2e2..d64340c9 100644
--- a/frontend-tools/video-js/src/components/controls/CustomRemainingTime.js
+++ b/frontend-tools/video-js/src/components/controls/CustomRemainingTime.js
@@ -79,15 +79,6 @@ class CustomRemainingTime extends Component {
return `${customPrefix}${timeString}${customSuffix}`;
}
- /**
- * Add click handler for additional functionality
- */
- handleClick() {
- // Example: Toggle between different time formats
- console.log('Time display clicked');
- // Could toggle between current/duration vs remaining time
- }
-
/**
* Component disposal cleanup
*/
diff --git a/frontend-tools/video-js/src/components/controls/CustomSettingsMenu.js b/frontend-tools/video-js/src/components/controls/CustomSettingsMenu.js
index bf2f3559..7e198ce1 100644
--- a/frontend-tools/video-js/src/components/controls/CustomSettingsMenu.js
+++ b/frontend-tools/video-js/src/components/controls/CustomSettingsMenu.js
@@ -363,32 +363,19 @@ class CustomSettingsMenu extends Component {
const player = this.player();
const tracks = player.textTracks();
let currentSubtitleLabel = 'Off';
- let activeTrack = null;
// Find the active subtitle track
for (let i = 0; i < tracks.length; i++) {
const t = tracks[i];
if (t.kind === 'subtitles' && t.mode === 'showing') {
currentSubtitleLabel = t.label || t.language || 'Subtitles';
- activeTrack = t;
break;
}
}
const currentSubtitlesDisplay = this.settingsOverlay.querySelector('.current-subtitles');
if (currentSubtitlesDisplay) {
- const oldValue = currentSubtitlesDisplay.textContent;
currentSubtitlesDisplay.textContent = currentSubtitleLabel;
-
- // Only log if the value actually changed
- if (oldValue !== currentSubtitleLabel) {
- console.log(`Updated current subtitle display: "${oldValue}" → "${currentSubtitleLabel}"`);
- if (activeTrack) {
- console.log(
- `Active track details: language="${activeTrack.language}", label="${activeTrack.label}", mode="${activeTrack.mode}"`
- );
- }
- }
}
} catch (error) {
console.error('Error updating current subtitle display:', error);
@@ -402,7 +389,6 @@ class CustomSettingsMenu extends Component {
// Listen for real-time subtitle changes
this.player().on('texttrackchange', () => {
- console.log('Text track changed - updating subtitle display');
this.updateCurrentSubtitleDisplay();
// Also refresh the subtitle submenu to show correct selection
this.refreshSubtitlesSubmenu();
@@ -516,7 +502,6 @@ class CustomSettingsMenu extends Component {
const fullscreenIndex = controlBar.children().indexOf(fullscreenToggle);
controlBar.removeChild(this.settingsButton);
controlBar.addChild(this.settingsButton, {}, fullscreenIndex + 1);
- console.log('✓ Settings button positioned after fullscreen toggle');
}, 50);
}
}
@@ -872,8 +857,6 @@ class CustomSettingsMenu extends Component {
// Close only the speed submenu (keep overlay open)
this.speedSubmenu.style.display = 'none';
-
- console.log('Playback speed preference saved:', speed);
}
handleQualityChange(value, qualityOption) {
@@ -1063,8 +1046,6 @@ class CustomSettingsMenu extends Component {
// Close only the quality submenu (keep overlay open)
if (this.qualitySubmenu) this.qualitySubmenu.style.display = 'none';
-
- console.log('Quality preference saved:', value);
}
handleSubtitleChange(lang, optionEl) {
diff --git a/frontend-tools/video-js/src/components/controls/NextVideoButton.js b/frontend-tools/video-js/src/components/controls/NextVideoButton.js
index f83b9e0e..6e7c0e1c 100644
--- a/frontend-tools/video-js/src/components/controls/NextVideoButton.js
+++ b/frontend-tools/video-js/src/components/controls/NextVideoButton.js
@@ -24,7 +24,7 @@ class NextVideoButton extends Button {
// Create SVG that matches Video.js icon dimensions
iconSpan.innerHTML = `
-