You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
RedditVideoMakerBot/GUI/backgrounds.html

211 lines
8.5 KiB

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Backgrounds - Reddit Video Maker Bot</title>
<link rel="stylesheet" href="/static/css/app.css">
</head>
<body>
<nav class="sidebar">
<div class="logo">
<h2>Reddit Video Bot</h2>
</div>
<ul class="nav-links">
<li><a href="/">Dashboard</a></li>
<li><a href="/settings">Settings</a></li>
<li><a href="/backgrounds" class="active">Backgrounds</a></li>
<li><a href="/videos">Videos</a></li>
<li><a href="/progress">Progress</a></li>
</ul>
</nav>
<main class="content">
<header>
<h1>Backgrounds</h1>
</header>
<!-- Video Backgrounds -->
<div class="card">
<div class="card-header">
<h3>Background Videos</h3>
<label for="video-upload" class="btn btn-primary">
Upload Video
<input type="file" id="video-upload" accept=".mp4,.webm,.mov,.avi,.mkv" hidden>
</label>
</div>
<p class="card-description">Upload 16:9 landscape videos. They will be cropped/scaled to fit 9:16 portrait videos.</p>
<div id="video-list" class="media-grid">
<div class="loading">Loading videos...</div>
</div>
</div>
<!-- Audio Backgrounds -->
<div class="card">
<div class="card-header">
<h3>Background Audio</h3>
<label for="audio-upload" class="btn btn-primary">
Upload Audio
<input type="file" id="audio-upload" accept=".mp3,.wav,.ogg,.m4a" hidden>
</label>
</div>
<p class="card-description">Upload background music tracks. Audio will loop to match video length.</p>
<div id="audio-list" class="media-grid">
<div class="loading">Loading audio...</div>
</div>
</div>
<!-- Upload Progress -->
<div id="upload-progress" class="upload-progress hidden">
<div class="upload-progress-bar">
<div class="upload-progress-fill"></div>
</div>
<span class="upload-progress-text">Uploading...</span>
</div>
</main>
<script src="/static/js/app.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
loadVideos();
loadAudios();
document.getElementById('video-upload').addEventListener('change', (e) => uploadFile(e, 'video'));
document.getElementById('audio-upload').addEventListener('change', (e) => uploadFile(e, 'audio'));
});
function loadVideos() {
fetch('/api/backgrounds/video')
.then(r => r.json())
.then(data => {
const container = document.getElementById('video-list');
if (data.videos && data.videos.length > 0) {
container.innerHTML = data.videos.map(v => `
<div class="media-item">
<div class="media-preview video-preview">
<video src="/backgrounds/video/${v.filename}" muted loop onmouseenter="this.play()" onmouseleave="this.pause(); this.currentTime=0;"></video>
</div>
<div class="media-info">
<span class="media-name">${v.name}</span>
<span class="media-size">${formatFileSize(v.size)}</span>
</div>
<button class="btn btn-danger btn-small" onclick="deleteVideo('${v.filename}')">Delete</button>
</div>
`).join('');
} else {
container.innerHTML = `
<div class="empty-state">
<p>No custom background videos</p>
<p class="hint">Upload a 16:9 video to use as background</p>
</div>
`;
}
})
.catch(err => {
document.getElementById('video-list').innerHTML = '<div class="error">Error loading videos</div>';
});
}
function loadAudios() {
fetch('/api/backgrounds/audio')
.then(r => r.json())
.then(data => {
const container = document.getElementById('audio-list');
if (data.audios && data.audios.length > 0) {
container.innerHTML = data.audios.map(a => `
<div class="media-item">
<div class="media-preview audio-preview">
<audio src="/backgrounds/audio/${a.filename}" controls></audio>
</div>
<div class="media-info">
<span class="media-name">${a.name}</span>
<span class="media-size">${formatFileSize(a.size)}</span>
</div>
<button class="btn btn-danger btn-small" onclick="deleteAudio('${a.filename}')">Delete</button>
</div>
`).join('');
} else {
container.innerHTML = `
<div class="empty-state">
<p>No custom background audio</p>
<p class="hint">Upload audio files to use as background music</p>
</div>
`;
}
})
.catch(err => {
document.getElementById('audio-list').innerHTML = '<div class="error">Error loading audio</div>';
});
}
function uploadFile(event, type) {
const file = event.target.files[0];
if (!file) return;
const formData = new FormData();
formData.append('file', file);
const progressEl = document.getElementById('upload-progress');
progressEl.classList.remove('hidden');
fetch(`/api/backgrounds/${type}`, {
method: 'POST',
body: formData
})
.then(r => r.json())
.then(data => {
progressEl.classList.add('hidden');
if (data.success) {
showNotification(data.message, 'success');
if (type === 'video') loadVideos();
else loadAudios();
} else {
showNotification(data.message, 'error');
}
})
.catch(err => {
progressEl.classList.add('hidden');
showNotification('Upload failed', 'error');
});
// Reset file input
event.target.value = '';
}
function deleteVideo(filename) {
if (!confirm(`Delete video "${filename}"?`)) return;
fetch(`/api/backgrounds/video/${filename}`, { method: 'DELETE' })
.then(r => r.json())
.then(data => {
showNotification(data.message, data.success ? 'success' : 'error');
if (data.success) loadVideos();
})
.catch(err => showNotification('Delete failed', 'error'));
}
function deleteAudio(filename) {
if (!confirm(`Delete audio "${filename}"?`)) return;
fetch(`/api/backgrounds/audio/${filename}`, { method: 'DELETE' })
.then(r => r.json())
.then(data => {
showNotification(data.message, data.success ? 'success' : 'error');
if (data.success) loadAudios();
})
.catch(err => showNotification('Delete failed', 'error'));
}
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
</script>
</body>
</html>