Complete Quick Play background video implementation

- Add independent background video system to Quick Play
- Implement VideoLibrary-style scanning for Quick Play
- Add compact floating video controls with opacity cycling
- Create video visibility toggle button (eye icon)
- Fix Quick Play game mode isolation (prevent main game interference)
- Add proper task loading with GameDataManager integration
- Implement Quick Play-specific task completion functions
- Add random image assignment for tasks from linked directories
- Fix syntax errors and improve error handling
- Complete video settings integration with Quick Play preferences

Features:
 Background videos play independently of Porn Cinema
 46 videos detected and playable
 Minimal UI controls that don't obstruct tasks
 Multiple opacity levels (hidden/dim/normal/bright)
 Quick toggle for video visibility
 Proper countdown timer (fixed from counting up)
 Real task loading (17 mainGameData tasks)
 Task images from 60 linked images
 Isolated game state management
This commit is contained in:
dilgenfritz 2025-11-03 21:18:17 -06:00
parent 58a2ec0ab2
commit 1e55cb3f21
2 changed files with 531 additions and 179 deletions

View File

@ -12,6 +12,11 @@
<script src="https://unpkg.com/jszip@3.10.1/dist/jszip.min.js" crossorigin="anonymous"></script>
</head>
<body class="quick-play-mode">
<!-- Video Toggle Button -->
<button class="video-toggle-btn" id="videoToggleBtn" title="Toggle Video Visibility">
👁️
</button>
<!-- Loading Overlay -->
<div id="quick-play-loading" class="loading-overlay">
<div class="loading-content">
@ -527,6 +532,9 @@
// Setup background video specific event listeners
setupBackgroundVideoListeners();
// Initialize video visibility controls
initializeVideoToggle();
// Load random video
await loadRandomBackgroundVideo();
@ -548,6 +556,12 @@
console.log(`🎬 Got ${allVideos.length} videos from VideoLibrary instance`);
}
// NEW: Try to access VideoLibrary videos directly if it exists
if (allVideos.length === 0 && window.VideoLibrary && window.VideoLibrary.videos) {
allVideos = window.VideoLibrary.videos;
console.log(`🎬 Got ${allVideos.length} videos from global VideoLibrary.videos`);
}
// Try desktop file manager
if (allVideos.length === 0 && window.desktopFileManager) {
try {
@ -576,15 +590,24 @@
console.log(`🎬 Got ${allVideos.length} videos from legacy storage`);
}
// NEW: Try accessing VideoLibrary legacy storage directly
if (allVideos.length === 0) {
const videoLibraryData = JSON.parse(localStorage.getItem('videoLibrary') || '[]');
allVideos = Array.isArray(videoLibraryData) ? videoLibraryData : [];
console.log(`🎬 Got ${allVideos.length} videos from VideoLibrary localStorage`);
}
// If still no videos, try to initialize video library
if (allVideos.length === 0) {
console.log('🎬 No videos found, attempting to initialize video library...');
await initializeVideoLibrary();
const initSuccess = await initializeVideoLibrary();
// Try again after initialization
const unifiedData = JSON.parse(localStorage.getItem('unifiedVideoLibrary') || '{}');
allVideos = unifiedData.allVideos || [];
console.log(`🎬 After initialization: ${allVideos.length} videos available`);
if (initSuccess) {
// Try again after initialization
const unifiedData = JSON.parse(localStorage.getItem('unifiedVideoLibrary') || '{}');
allVideos = unifiedData.allVideos || [];
console.log(`🎬 After initialization: ${allVideos.length} videos available`);
}
}
if (allVideos.length === 0) {
@ -593,9 +616,19 @@
return;
}
await playRandomVideoFromArray(allVideos);
} catch (error) {
console.error('❌ Error loading background video:', error);
}
}
// Helper function to play a random video from an array
async function playRandomVideoFromArray(videos) {
try {
// Select random video
const randomIndex = Math.floor(Math.random() * allVideos.length);
const randomVideo = allVideos[randomIndex];
const randomIndex = Math.floor(Math.random() * videos.length);
const randomVideo = videos[randomIndex];
console.log(`🎬 Loading background video: ${randomVideo.name || randomVideo.title}`);
@ -610,7 +643,7 @@
}, 2000);
} catch (error) {
console.error('❌ Error loading background video:', error);
console.error('❌ Error playing random video:', error);
}
}
@ -658,38 +691,124 @@
try {
console.log('🎬 Attempting to initialize video library for Quick Play...');
// Check if we have linked video directories
const linkedDirs = JSON.parse(localStorage.getItem('linkedVideoDirectories') || '[]');
if (linkedDirs.length > 0) {
console.log(`🎬 Found ${linkedDirs.length} linked directories, scanning...`);
// Use the same video loading logic as VideoLibrary class
let linkedDirs;
try {
linkedDirs = JSON.parse(localStorage.getItem('linkedVideoDirectories') || '[]');
if (!Array.isArray(linkedDirs)) {
linkedDirs = [];
}
} catch (e) {
console.log('Error parsing linkedVideoDirectories, resetting to empty array:', e);
linkedDirs = [];
}
let linkedIndividualVideos;
try {
linkedIndividualVideos = JSON.parse(localStorage.getItem('linkedIndividualVideos') || '[]');
if (!Array.isArray(linkedIndividualVideos)) {
linkedIndividualVideos = [];
}
} catch (e) {
console.log('Error parsing linkedIndividualVideos, resetting to empty array:', e);
linkedIndividualVideos = [];
}
const allVideos = [];
console.log(`🎬 Found ${linkedDirs.length} linked directories, scanning...`);
// Load videos from linked directories using Electron API (same as VideoLibrary)
if (window.electronAPI && linkedDirs.length > 0) {
const videoExtensions = /\.(mp4|webm|avi|mov|mkv|wmv|flv|m4v)$/i;
// Instead of creating a full VideoLibrary instance,
// let's directly scan the directories using DesktopFileManager
if (window.desktopFileManager) {
console.log('🎬 Using DesktopFileManager to scan directories...');
// Try to refresh/rescan directories
for (const dir of linkedDirs) {
try {
console.log(`🎬 Scanning directory: ${dir.path}`);
await window.desktopFileManager.scanVideoDirectory(dir.path);
} catch (scanError) {
console.warn(`⚠️ Error scanning directory ${dir.path}:`, scanError);
for (const dir of linkedDirs) {
try {
console.log(`🎬 Scanning directory: ${dir.path}`);
// Use video-specific directory reading for better results (same as VideoLibrary)
let files = [];
if (window.electronAPI.readVideoDirectory) {
files = await window.electronAPI.readVideoDirectory(dir.path);
} else if (window.electronAPI.readVideoDirectoryRecursive) {
files = await window.electronAPI.readVideoDirectoryRecursive(dir.path);
} else if (window.electronAPI.readDirectory) {
const allFiles = await window.electronAPI.readDirectory(dir.path);
files = allFiles.filter(file => videoExtensions.test(file.name));
}
if (files && files.length > 0) {
console.log(`🎬 Found ${files.length} video files in ${dir.path}`);
files.forEach(file => {
allVideos.push({
name: file.name,
path: file.path,
size: file.size || 0,
duration: file.duration || 0,
format: getFormatFromPath(file.path),
dateAdded: new Date().toISOString(),
category: 'directory',
directory: dir.path
});
});
} else {
console.log(`🎬 No video files found in ${dir.path}`);
}
} catch (error) {
console.error(`❌ Error loading videos from directory ${dir.path}:`, error);
continue;
}
// Build unified video library manually
await buildUnifiedVideoLibrary();
return true;
} else {
console.log('🎬 DesktopFileManager not available, using direct directory scan...');
await scanDirectoriesDirectly(linkedDirs);
return true;
}
}
console.log('🎬 No linked directories found');
return false;
// Add individual linked video files (same as VideoLibrary)
linkedIndividualVideos.forEach(video => {
allVideos.push({
name: video.name || 'Unknown Video',
path: video.path,
size: video.size || 0,
duration: video.duration || 0,
format: video.format || getFormatFromPath(video.path),
dateAdded: video.dateAdded || new Date().toISOString(),
category: 'individual',
directory: 'Individual Videos'
});
});
console.log(`🎬 Building unified video library...`);
console.log(`🎬 Added ${allVideos.length} videos from VideoLibrary-style scanning`);
// Save to unified storage (same as VideoLibrary)
if (allVideos.length > 0) {
try {
const unifiedData = {
allVideos: allVideos.map(video => ({
name: video.name,
path: video.path,
size: video.size,
duration: video.duration,
format: video.format,
dateAdded: video.dateAdded,
source: video.category === 'individual' ? 'individual' : 'directory',
directory: video.directory,
thumbnail: video.thumbnail,
resolution: video.resolution || 'Unknown',
bitrate: video.bitrate || 0
})),
lastUpdated: new Date().toISOString(),
source: 'QuickPlay'
};
localStorage.setItem('unifiedVideoLibrary', JSON.stringify(unifiedData));
console.log(`🎬 ✅ Saved ${allVideos.length} videos to unified storage`);
} catch (error) {
console.warn('🎬 ⚠️ Failed to save to unified storage:', error);
}
}
console.log(`🎬 Total videos collected: ${allVideos.length}`);
return allVideos.length > 0;
} catch (error) {
console.error('❌ Error initializing video library:', error);
@ -697,96 +816,76 @@
}
}
async function buildUnifiedVideoLibrary() {
try {
console.log('🎬 Building unified video library...');
const allVideos = [];
// Get videos from desktop file manager
if (window.desktopFileManager) {
const dmVideos = window.desktopFileManager.getAllVideos();
allVideos.push(...dmVideos);
console.log(`🎬 Added ${dmVideos.length} videos from DesktopFileManager`);
}
// Get individual videos
const individualVideos = JSON.parse(localStorage.getItem('videoFiles') || '{}');
Object.values(individualVideos).forEach(videoArray => {
if (Array.isArray(videoArray)) {
allVideos.push(...videoArray);
}
});
console.log(`🎬 Total videos collected: ${allVideos.length}`);
// Save to unified storage
const unifiedLibrary = {
allVideos: allVideos,
lastUpdated: new Date().toISOString(),
totalCount: allVideos.length
};
localStorage.setItem('unifiedVideoLibrary', JSON.stringify(unifiedLibrary));
console.log(`🎬 Unified video library saved with ${allVideos.length} videos`);
} catch (error) {
console.error('❌ Error building unified video library:', error);
// Helper function to get file format from path (same as VideoLibrary)
function getFormatFromPath(path) {
if (!path) return 'mp4';
const extension = path.toLowerCase().split('.').pop();
return extension || 'mp4';
}
// Video visibility control functions
let currentVideoOpacity = 'normal'; // normal, dim, bright, hidden
function cycleVideoOpacity() {
const video = document.querySelector('.background-video');
const btn = document.getElementById('videoOpacityBtn');
if (!video || !btn) return;
// Remove all opacity classes
video.classList.remove('video-hidden', 'video-dim', 'video-normal', 'video-bright');
// Cycle through opacity states
switch (currentVideoOpacity) {
case 'normal':
currentVideoOpacity = 'bright';
video.classList.add('video-bright');
btn.textContent = '🔆';
btn.title = 'Video: Bright';
break;
case 'bright':
currentVideoOpacity = 'dim';
video.classList.add('video-dim');
btn.textContent = '🔅';
btn.title = 'Video: Dim';
break;
case 'dim':
currentVideoOpacity = 'hidden';
video.classList.add('video-hidden');
btn.textContent = '🌑';
btn.title = 'Video: Hidden';
break;
case 'hidden':
currentVideoOpacity = 'normal';
video.classList.add('video-normal');
btn.textContent = '🔆';
btn.title = 'Video: Normal';
break;
}
}
async function scanDirectoriesDirectly(linkedDirs) {
try {
console.log('🎬 Scanning directories directly...');
if (!window.electronAPI || !window.electronAPI.readDirectory) {
console.warn('⚠️ Electron API not available for directory scanning');
return;
}
const allVideos = [];
const videoExtensions = ['.mp4', '.avi', '.mov', '.wmv', '.flv', '.webm', '.mkv', '.m4v'];
for (const dir of linkedDirs) {
try {
console.log(`🎬 Reading directory: ${dir.path}`);
const files = await window.electronAPI.readDirectory(dir.path);
if (Array.isArray(files)) {
const videoFiles = files.filter(file => {
const ext = file.name.toLowerCase().substring(file.name.lastIndexOf('.'));
return videoExtensions.includes(ext);
});
const processedVideos = videoFiles.map(file => ({
name: file.name,
path: file.path,
size: file.size || 0,
dateAdded: new Date().toISOString(),
directory: dir.path,
source: 'directory'
}));
allVideos.push(...processedVideos);
console.log(`🎬 Found ${videoFiles.length} videos in ${dir.path}`);
}
} catch (dirError) {
console.warn(`⚠️ Error reading directory ${dir.path}:`, dirError);
function initializeVideoToggle() {
const toggleBtn = document.getElementById('videoToggleBtn');
if (toggleBtn) {
toggleBtn.addEventListener('click', () => {
const video = document.querySelector('.background-video');
if (!video) return;
if (currentVideoOpacity === 'hidden') {
// Show video at normal opacity
currentVideoOpacity = 'normal';
video.classList.remove('video-hidden');
video.classList.add('video-normal');
toggleBtn.textContent = '👁️';
toggleBtn.title = 'Video Visible';
} else {
// Hide video
currentVideoOpacity = 'hidden';
video.classList.remove('video-dim', 'video-normal', 'video-bright');
video.classList.add('video-hidden');
toggleBtn.textContent = '🙈';
toggleBtn.title = 'Video Hidden';
}
}
// Save to unified storage
const unifiedLibrary = {
allVideos: allVideos,
lastUpdated: new Date().toISOString(),
totalCount: allVideos.length
};
localStorage.setItem('unifiedVideoLibrary', JSON.stringify(unifiedLibrary));
console.log(`🎬 Direct scan complete: ${allVideos.length} videos found`);
} catch (error) {
console.error('❌ Error in direct directory scan:', error);
});
}
}
@ -1035,6 +1134,7 @@
<button class="control-btn mute-btn" title="Mute">🔊</button>
<input type="range" class="volume-slider" min="0" max="100" value="70">
</div>
<button class="control-btn" id="videoOpacityBtn" onclick="cycleVideoOpacity()" title="Video Opacity">🔆</button>
<button class="control-btn random-video-btn" title="Random Video">🎲</button>
</div>
</div>
@ -1174,6 +1274,12 @@
console.log('✅ Set mode to quick-play');
}
// Explicitly disable standard game systems for Quick Play
if (gameInstance.gameState) {
gameInstance.gameState.mode = 'quick-play';
gameInstance.gameState.isQuickPlay = true;
}
// Apply Quick Play settings to game configuration
const gameConfig = {
gameMode: 'timed',
@ -1185,26 +1291,19 @@
enableFlashMessages: quickPlaySettings.enableFlashMessages,
difficulty: quickPlaySettings.difficulty,
includeStandardTasks: quickPlaySettings.includeStandardTasks,
includeScenarioTasks: quickPlaySettings.includeScenarioTasks
includeScenarioTasks: quickPlaySettings.includeScenarioTasks,
// Force standard tasks to be included for Quick Play
isQuickPlay: true
};
console.log('📋 Quick Play config:', gameConfig);
// Configure systems based on Quick Play settings
configureGameSystems(gameConfig);
// Start the game with a simplified approach
if (gameInstance.startGame) {
try {
gameInstance.startGame(gameConfig);
console.log('✅ Game started with startGame method');
} catch (startError) {
console.warn('⚠️ startGame method failed, using fallback:', startError);
setupSimpleGame(gameConfig);
}
} else {
// Fallback: manually set up basic game state
console.log('📋 Using fallback game setup');
setupSimpleGame(gameConfig);
}
// Start the game with Quick Play specific approach
console.log('📋 Starting Quick Play mode - using simplified game setup');
setupSimpleGame(gameConfig);
isGameRunning = true;
@ -1243,9 +1342,44 @@
isPaused: false,
timeLimit: config.timeLimit,
tasksCompleted: 0,
xp: 0
xp: 0,
mode: 'quick-play',
isQuickPlay: true
};
// Ensure game data is available - try multiple approaches for Quick Play
if (!gameInstance.gameData) {
try {
// First try the GameDataManager
if (window.gameDataManager) {
gameInstance.gameData = window.gameDataManager.getDataForMode('standard');
console.log('📋 Loaded game data from GameDataManager:', gameInstance.gameData);
}
// If that didn't work, try direct access to mainGameData
if (!gameInstance.gameData || !gameInstance.gameData.mainTasks) {
if (window.mainGameData) {
gameInstance.gameData = window.mainGameData;
console.log('📋 Loaded game data directly from mainGameData:', gameInstance.gameData);
}
}
// Fallback: create basic tasks
if (!gameInstance.gameData || !gameInstance.gameData.mainTasks) {
gameInstance.gameData = {
mainTasks: [
{ id: 1, text: "Quick Play Task 1", description: "Complete this task", difficulty: "Easy" },
{ id: 2, text: "Quick Play Task 2", description: "Complete this task", difficulty: "Medium" },
{ id: 3, text: "Quick Play Task 3", description: "Complete this task", difficulty: "Easy" }
]
};
console.log('📋 Using fallback game data for Quick Play');
}
} catch (error) {
console.error('❌ Failed to load game data:', error);
}
}
// Start timer
startGameTimer(config.timeLimit);
@ -1278,13 +1412,105 @@
function loadNextTask() {
// Simple task loading for Quick Play
if (gameInstance && gameInstance.gameData && gameInstance.gameData.mainTasks) {
const tasks = gameInstance.gameData.mainTasks;
const randomTask = tasks[Math.floor(Math.random() * tasks.length)];
displayTask(randomTask);
try {
let tasks = null;
// Try to get tasks from multiple sources
if (gameInstance && gameInstance.gameData && gameInstance.gameData.mainTasks) {
tasks = gameInstance.gameData.mainTasks;
} else if (window.gameDataManager) {
const gameData = window.gameDataManager.getDataForMode('standard');
if (gameData && gameData.mainTasks) {
tasks = gameData.mainTasks;
// Store it for future use
if (gameInstance) {
gameInstance.gameData = gameData;
}
}
}
if (tasks && tasks.length > 0) {
const randomTask = tasks[Math.floor(Math.random() * tasks.length)];
console.log('📋 Loading task:', randomTask.text || randomTask.description);
// Try to assign a random image from the game's image library
let taskWithImage = { ...randomTask };
// Check multiple possible image sources
let availableImages = [];
// Check gameInstance.imageManager
if (gameInstance && gameInstance.imageManager && gameInstance.imageManager.taskImages) {
availableImages = gameInstance.imageManager.taskImages;
console.log('📸 Found images in imageManager.taskImages:', availableImages.length);
}
// Check gameInstance.taskImages
else if (gameInstance && gameInstance.taskImages) {
availableImages = gameInstance.taskImages;
console.log('📸 Found images in gameInstance.taskImages:', availableImages.length);
}
// Check window.linkedImages
else if (window.linkedImages && window.linkedImages.task) {
availableImages = window.linkedImages.task;
console.log('📸 Found images in window.linkedImages.task:', availableImages.length);
}
if (availableImages.length > 0) {
const randomImage = availableImages[Math.floor(Math.random() * availableImages.length)];
taskWithImage.image = randomImage.path || randomImage.src || randomImage.filePath || randomImage;
console.log('📸 Assigned random image:', taskWithImage.image);
} else {
console.log('📸 No images found for tasks');
}
displayTask(taskWithImage);
} else {
console.error('❌ No tasks available for Quick Play');
// Create a fallback task
displayTask({
text: 'Quick Play Task',
description: 'Complete this simple task to continue your Quick Play session.',
image: null
});
}
} catch (error) {
console.error('❌ Error loading task:', error);
// Fallback task in case of error
displayTask({
text: 'Basic Task',
description: 'Complete this task to continue.',
image: null
});
}
}
// Quick Play specific task completion functions
function quickPlayCompleteTask(task) {
console.log('✅ Quick Play task completed:', task.text);
// Update game state
if (gameInstance && gameInstance.gameState) {
gameInstance.gameState.tasksCompleted = (gameInstance.gameState.tasksCompleted || 0) + 1;
gameInstance.gameState.xp = (gameInstance.gameState.xp || 0) + 10;
}
// Update UI
updateGameStatus({
tasksCompleted: gameInstance.gameState.tasksCompleted,
xp: gameInstance.gameState.xp
});
// Load next task
loadNextTask();
}
function quickPlaySkipTask(task) {
console.log('⏭️ Quick Play task skipped:', task.text);
// Just load next task without updating stats
loadNextTask();
}
function displayTask(task) {
console.log('Displaying task:', task);
@ -1296,31 +1522,77 @@
const skipBtn = document.getElementById('skip-task');
const endBtn = document.getElementById('end-game');
if (taskTitle) taskTitle.textContent = task.text || 'Complete the task';
if (taskText) taskText.textContent = task.description || 'Follow the instructions to complete this task.';
console.log('Task display elements found:', {
taskTitle: !!taskTitle,
taskText: !!taskText,
taskImage: !!taskImage,
taskImageContainer: !!taskImageContainer
});
if (taskImage && task.image) {
taskImage.src = task.image;
taskImage.style.display = 'block';
// Clear any previously set dimensions to let CSS handle sizing
taskImage.style.width = '';
taskImage.style.height = '';
// Ensure proper image scaling when loaded
taskImage.onload = function() {
console.log('Image loaded, dimensions:', this.naturalWidth, 'x', this.naturalHeight);
// Let CSS handle the scaling with object-fit: contain
// Just ensure max dimensions are respected
this.style.maxWidth = '100%';
this.style.maxHeight = '100%';
if (taskTitle) {
taskTitle.textContent = task.text || 'Complete the task';
console.log('Set task title to:', task.text);
} else {
console.error('task-title element not found!');
}
if (taskText) {
taskText.textContent = task.description || 'Follow the instructions to complete this task.';
console.log('Set task text to:', task.description || 'Follow the instructions to complete this task.');
} else {
console.error('task-text element not found!');
}
// Store the current task in game state so updateTaskDisplay doesn't overwrite it
if (gameInstance && gameInstance.gameState) {
gameInstance.gameState.currentTask = {
title: task.text,
text: task.description || 'Follow the instructions to complete this task.',
image: task.image
};
// Fallback for cached images
if (taskImage.complete) {
taskImage.onload();
}
console.log('Task image info:', {
hasImage: !!task.image,
imagePath: task.image,
imageElement: !!taskImage
});
if (taskImage) {
if (task.image) {
console.log('Setting task image to:', task.image);
taskImage.src = task.image;
taskImage.style.display = 'block';
// Clear any previously set dimensions to let CSS handle sizing
taskImage.style.width = '';
taskImage.style.height = '';
// Ensure proper image scaling when loaded
taskImage.onload = function() {
console.log('Image loaded successfully, dimensions:', this.naturalWidth, 'x', this.naturalHeight);
// Let CSS handle the scaling with object-fit: contain
// Just ensure max dimensions are respected
this.style.maxWidth = '100%';
this.style.maxHeight = '100%';
};
taskImage.onerror = function() {
console.error('Failed to load task image:', task.image);
this.style.display = 'none';
};
// Fallback for cached images
if (taskImage.complete) {
taskImage.onload();
}
} else {
console.log('No image for this task, hiding image element');
taskImage.style.display = 'none';
}
} else {
console.error('Task image element not found!');
}
// Set up button event handlers with proper error handling
@ -1332,7 +1604,7 @@
newCompleteBtn.addEventListener('click', (e) => {
e.preventDefault();
console.log('Complete task button clicked');
completeTask(task);
quickPlayCompleteTask(task);
});
}
@ -1344,7 +1616,7 @@
newSkipBtn.addEventListener('click', (e) => {
e.preventDefault();
console.log('Skip task button clicked');
skipTask(task);
quickPlaySkipTask(task);
});
}
@ -2547,40 +2819,88 @@
object-fit: cover;
object-position: center;
transition: opacity 0.3s ease;
opacity: 0.4; /* Increased from very low to visible but not overwhelming */
}
.background-video-controls {
position: absolute;
bottom: 10px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.7);
border-radius: 20px;
padding: 8px 16px;
top: 10px;
right: 60px;
background: none;
border-radius: 0;
padding: 0;
opacity: 0;
transition: opacity 0.3s ease;
z-index: 10;
min-width: auto;
width: auto;
}
.background-video-container:hover .background-video-controls {
opacity: 1;
}
/* Quick Video Toggle Button */
.video-toggle-btn {
position: fixed;
top: 20px;
right: 20px;
background: rgba(0, 0, 0, 0.7);
color: white;
border: none;
border-radius: 50%;
width: 50px;
height: 50px;
font-size: 20px;
cursor: pointer;
z-index: 1000;
transition: all 0.3s ease;
backdrop-filter: blur(5px);
}
.video-toggle-btn:hover {
background: rgba(0, 0, 0, 0.9);
transform: scale(1.1);
}
/* Video visibility states */
.background-video.video-hidden {
opacity: 0 !important;
}
.background-video.video-dim {
opacity: 0.2 !important;
}
.background-video.video-normal {
opacity: 0.4 !important;
}
.background-video.video-bright {
opacity: 0.7 !important;
}
.background-video-controls .controls-row {
display: flex;
align-items: center;
gap: 12px;
gap: 2px;
}
.background-video-controls .control-btn {
background: transparent;
background: rgba(0, 0, 0, 0.6);
border: none;
color: white;
font-size: 14px;
cursor: pointer;
padding: 4px 8px;
border-radius: 4px;
transition: background-color 0.2s ease;
padding: 3px;
border-radius: 50%;
transition: all 0.2s ease;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
backdrop-filter: blur(3px);
}
.background-video-controls .control-btn:hover {
@ -2590,14 +2910,18 @@
.background-video-controls .volume-control {
display: flex;
align-items: center;
gap: 6px;
gap: 1px;
background: rgba(0, 0, 0, 0.6);
border-radius: 12px;
padding: 2px;
backdrop-filter: blur(3px);
}
.background-video-controls .volume-slider {
width: 60px;
height: 4px;
width: 40px;
height: 2px;
background: rgba(255, 255, 255, 0.3);
border-radius: 2px;
border-radius: 1px;
outline: none;
cursor: pointer;
-webkit-appearance: none;

View File

@ -230,6 +230,34 @@ class VideoLibrary {
console.log(`📁 Processed ${this.videos.length} videos for library display`);
// IMPORTANT: Save successfully loaded videos to unified storage for other components
if (this.videos.length > 0) {
try {
const unifiedData = {
allVideos: this.videos.map(video => ({
name: video.name,
path: video.path,
size: video.size,
duration: video.duration,
format: video.format,
dateAdded: video.dateAdded,
source: video.category === 'individual' ? 'individual' : 'directory',
directory: video.directory,
thumbnail: video.thumbnail,
resolution: video.resolution,
bitrate: video.bitrate
})),
lastUpdated: new Date().toISOString(),
source: 'VideoLibrary'
};
localStorage.setItem('unifiedVideoLibrary', JSON.stringify(unifiedData));
console.log(`📁 ✅ Saved ${this.videos.length} videos to unified storage for other components`);
} catch (error) {
console.warn('📁 ⚠️ Failed to save to unified storage:', error);
}
}
// Debug: Show some sample video names and paths
if (this.videos.length > 0) {
console.log(`📁 Sample videos loaded:`);