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:
parent
58a2ec0ab2
commit
1e55cb3f21
682
quick-play.html
682
quick-play.html
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:`);
|
||||
|
|
|
|||
Loading…
Reference in New Issue