INTEGRATE: Session recordings into main media library

CHANGED: Session recording storage system
- Modified saveRecordedSession() to use 'capturedVideos' localStorage key (matches photo pattern)
- Updated all Quick Play gallery functions to use consistent 'capturedVideos' key
- Aligned with existing media library architecture for consistency

ADDED: Captured videos to main library video tab
- Integrated captured session videos into index.html video library display
- Added captured videos section with proper metadata (date, duration, type)
- Videos appear alongside game videos (background, task, reward, punishment)
- Updated total video count to include captured session recordings

IMPLEMENTED: Full video management in main library
- Added playCapturedVideo() function with fullscreen player overlay
- Added downloadCapturedVideo() function with proper filename generation
- Added deleteCapturedVideo() function with confirmation and library refresh
- All functions include proper error handling and user feedback

RESULT: Unified media library experience
- Session recordings now appear in main media library alongside photos
- Users can manage all captured media from single location in index.html
- Consistent interface for viewing, downloading, and deleting recordings
- Seamless integration with existing library architecture and styling
This commit is contained in:
dilgenfritz 2025-11-10 10:49:22 -06:00
parent 6381c292e0
commit 325a71bf75
2 changed files with 138 additions and 19 deletions

View File

@ -4104,8 +4104,9 @@
const taskVideos = videoLibrary.task || [];
const rewardVideos = videoLibrary.reward || [];
const punishmentVideos = videoLibrary.punishment || [];
const capturedVideos = JSON.parse(localStorage.getItem('capturedVideos') || '[]');
let totalVideos = backgroundVideos.length + taskVideos.length + rewardVideos.length + punishmentVideos.length;
let totalVideos = backgroundVideos.length + taskVideos.length + rewardVideos.length + punishmentVideos.length + capturedVideos.length;
// If no categorized videos found but we have "all" videos, use those
let allVideos = [];
@ -4185,7 +4186,32 @@
`;
videoGallery.appendChild(videoElement);
});
// Add captured session videos
const capturedVideos = JSON.parse(localStorage.getItem('capturedVideos') || '[]');
console.log(`📹 Found ${capturedVideos.length} captured session videos`);
capturedVideos.forEach((video, index) => {
const date = new Date(video.timestamp);
const duration = formatVideoDuration(video.duration);
const videoElement = document.createElement('div');
videoElement.className = 'gallery-item captured-video-item';
videoElement.innerHTML = `
<div class="video-info">
<div class="video-icon">📹</div>
<div class="video-name">Session Recording ${index + 1}</div>
<div class="video-type">Captured Video</div>
<div class="video-meta">${date.toLocaleDateString()} - ${duration}</div>
</div>
<div class="video-actions">
<button class="btn-small" onclick="playCapturedVideo('${video.id}')">▶️ Play</button>
<button class="btn-small" onclick="downloadCapturedVideo('${video.id}')">💾 Download</button>
<button class="btn-small btn-danger" onclick="deleteCapturedVideo('${video.id}')">🗑️ Delete</button>
</div>
`;
videoGallery.appendChild(videoElement);
});
// If no categorized videos were added but we have uncategorized videos, add those
if (videoGallery.children.length === 0 && allVideos.length > 0) {
allVideos.forEach((video, index) => {
@ -4590,6 +4616,99 @@
}
}
// Captured Video Functions
function formatVideoDuration(ms) {
const seconds = Math.floor(ms / 1000);
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;
return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`;
}
function playCapturedVideo(videoId) {
const capturedVideos = JSON.parse(localStorage.getItem('capturedVideos') || '[]');
const video = capturedVideos.find(v => v.id === videoId);
if (!video) {
console.warn('Video not found:', videoId);
return;
}
// Create fullscreen video player
const overlay = document.createElement('div');
overlay.className = 'video-player-overlay';
overlay.style.cssText = `
position: fixed; top: 0; left: 0; width: 100%; height: 100vh;
background: rgba(0,0,0,0.95); display: flex; align-items: center;
justify-content: center; z-index: 10000;
`;
overlay.innerHTML = `
<div class="video-player-container" style="position: relative; max-width: 90vw; max-height: 90vh;">
<video controls autoplay style="width: 100%; height: auto; max-height: 90vh; border-radius: 10px;">
<source src="${video.dataURL}" type="video/webm">
</video>
<button class="close-player" onclick="closeCapturedVideoPlayer()"
style="position: absolute; top: -40px; right: 0; background: rgba(255,255,255,0.2);
border: none; border-radius: 50%; width: 35px; height: 35px; color: #fff;
font-size: 1.2rem; cursor: pointer; transition: all 0.3s ease;">✕</button>
</div>
`;
document.body.appendChild(overlay);
window.currentCapturedVideoOverlay = overlay;
}
function closeCapturedVideoPlayer() {
if (window.currentCapturedVideoOverlay) {
document.body.removeChild(window.currentCapturedVideoOverlay);
window.currentCapturedVideoOverlay = null;
}
}
function downloadCapturedVideo(videoId) {
const capturedVideos = JSON.parse(localStorage.getItem('capturedVideos') || '[]');
const video = capturedVideos.find(v => v.id === videoId);
if (!video) {
console.warn('Video not found:', videoId);
return;
}
const a = document.createElement('a');
a.href = video.dataURL;
a.download = `quick-play-session-${new Date(video.timestamp).toISOString().slice(0, 19).replace(/:/g, '-')}.webm`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
console.log('📹 Video downloaded:', videoId);
if (window.game && window.game.flashMessageManager) {
window.game.flashMessageManager.show('📹 Video downloaded successfully!', 'info');
}
}
function deleteCapturedVideo(videoId) {
if (!confirm('⚠️ Are you sure you want to delete this video? This cannot be undone.')) {
return;
}
let capturedVideos = JSON.parse(localStorage.getItem('capturedVideos') || '[]');
capturedVideos = capturedVideos.filter(v => v.id !== videoId);
localStorage.setItem('capturedVideos', JSON.stringify(capturedVideos));
console.log('🗑️ Video deleted:', videoId);
// Refresh the video library
setupLibraryVideoTab();
if (window.game && window.game.flashMessageManager) {
window.game.flashMessageManager.show('🗑️ Video deleted successfully!', 'info');
}
}
// Initialize bulk action event listeners
function initializeBulkActions() {
const selectAllBtn = document.getElementById('select-all-photos');

View File

@ -4607,16 +4607,16 @@
}
};
// Save to localStorage gallery
let savedVideos = JSON.parse(localStorage.getItem('savedSessionVideos') || '[]');
savedVideos.push(videoData);
// Save to localStorage gallery (same pattern as photos)
let capturedVideos = JSON.parse(localStorage.getItem('capturedVideos') || '[]');
capturedVideos.push(videoData);
// Keep only last 10 recordings to manage storage
if (savedVideos.length > 10) {
savedVideos = savedVideos.slice(-10);
if (capturedVideos.length > 10) {
capturedVideos = capturedVideos.slice(-10);
}
localStorage.setItem('savedSessionVideos', JSON.stringify(savedVideos));
localStorage.setItem('capturedVideos', JSON.stringify(capturedVideos));
console.log('✅ Session recording saved to gallery:', videoData.id);
@ -4653,11 +4653,11 @@
}
function loadSessionVideos() {
const savedVideos = JSON.parse(localStorage.getItem('savedSessionVideos') || '[]');
const capturedVideos = JSON.parse(localStorage.getItem('capturedVideos') || '[]');
const videosGrid = document.getElementById('videos-grid');
const noVideosMessage = document.getElementById('no-videos-message');
if (savedVideos.length === 0) {
if (capturedVideos.length === 0) {
videosGrid.innerHTML = '';
noVideosMessage.style.display = 'block';
return;
@ -4666,9 +4666,9 @@
noVideosMessage.style.display = 'none';
// Sort by timestamp (newest first)
savedVideos.sort((a, b) => b.timestamp - a.timestamp);
capturedVideos.sort((a, b) => b.timestamp - a.timestamp);
videosGrid.innerHTML = savedVideos.map(video => {
videosGrid.innerHTML = capturedVideos.map(video => {
const date = new Date(video.timestamp);
const duration = formatDuration(video.duration);
@ -4713,8 +4713,8 @@
}
function playVideo(videoId) {
const savedVideos = JSON.parse(localStorage.getItem('savedSessionVideos') || '[]');
const video = savedVideos.find(v => v.id === videoId);
const capturedVideos = JSON.parse(localStorage.getItem('capturedVideos') || '[]');
const video = capturedVideos.find(v => v.id === videoId);
if (!video) {
console.warn('Video not found:', videoId);
@ -4745,8 +4745,8 @@
}
function downloadVideo(videoId) {
const savedVideos = JSON.parse(localStorage.getItem('savedSessionVideos') || '[]');
const video = savedVideos.find(v => v.id === videoId);
const capturedVideos = JSON.parse(localStorage.getItem('capturedVideos') || '[]');
const video = capturedVideos.find(v => v.id === videoId);
if (!video) {
console.warn('Video not found:', videoId);
@ -4773,10 +4773,10 @@
return;
}
let savedVideos = JSON.parse(localStorage.getItem('savedSessionVideos') || '[]');
savedVideos = savedVideos.filter(v => v.id !== videoId);
let capturedVideos = JSON.parse(localStorage.getItem('capturedVideos') || '[]');
capturedVideos = capturedVideos.filter(v => v.id !== videoId);
localStorage.setItem('savedSessionVideos', JSON.stringify(savedVideos));
localStorage.setItem('capturedVideos', JSON.stringify(capturedVideos));
console.log('🗑️ Video deleted:', videoId);
@ -4789,7 +4789,7 @@
}
function clearAllSessionVideos() {
localStorage.removeItem('savedSessionVideos');
localStorage.removeItem('capturedVideos');
loadSessionVideos();
console.log('🗑️ All session videos cleared');