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.
234 lines
9.2 KiB
234 lines
9.2 KiB
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Reddit Video Maker Bot</title>
|
|
<link rel="stylesheet" href="/static/css/app.css">
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.6.0/socket.io.min.js"></script>
|
|
</head>
|
|
<body>
|
|
<nav class="sidebar">
|
|
<div class="logo">
|
|
<h2>Reddit Video Bot</h2>
|
|
</div>
|
|
<ul class="nav-links">
|
|
<li><a href="/" class="active">Dashboard</a></li>
|
|
<li><a href="/settings">Settings</a></li>
|
|
<li><a href="/backgrounds">Backgrounds</a></li>
|
|
<li><a href="/videos">Videos</a></li>
|
|
<li><a href="/progress">Progress</a></li>
|
|
</ul>
|
|
</nav>
|
|
|
|
<main class="content">
|
|
<header>
|
|
<h1>Dashboard</h1>
|
|
<div class="status-indicator" id="status-indicator">
|
|
<span class="dot"></span>
|
|
<span id="status-text">Ready</span>
|
|
</div>
|
|
</header>
|
|
|
|
<div class="dashboard-grid">
|
|
<!-- Quick Actions -->
|
|
<div class="card">
|
|
<h3>Quick Actions</h3>
|
|
<div class="action-buttons">
|
|
<button id="btn-generate" class="btn btn-primary btn-large">
|
|
Generate Video
|
|
</button>
|
|
<button id="btn-stop" class="btn btn-danger btn-large" disabled>
|
|
Stop Generation
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Current Config -->
|
|
<div class="card">
|
|
<h3>Current Configuration</h3>
|
|
<div class="config-summary" id="config-summary">
|
|
<p>Loading...</p>
|
|
</div>
|
|
<a href="/settings" class="btn btn-secondary">Edit Settings</a>
|
|
</div>
|
|
|
|
<!-- Progress -->
|
|
<div class="card card-wide">
|
|
<h3>Current Progress</h3>
|
|
<div id="progress-container">
|
|
<div class="no-progress">
|
|
<p>No video generation in progress</p>
|
|
<p class="hint">Click "Generate Video" to start</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recent Videos -->
|
|
<div class="card card-wide">
|
|
<h3>Recent Videos</h3>
|
|
<div id="recent-videos">
|
|
<p>Loading...</p>
|
|
</div>
|
|
<a href="/videos" class="btn btn-secondary">View All Videos</a>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<script src="/static/js/app.js"></script>
|
|
<script>
|
|
// Initialize dashboard
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
loadConfig();
|
|
loadRecentVideos();
|
|
initProgressSocket();
|
|
|
|
document.getElementById('btn-generate').addEventListener('click', startGeneration);
|
|
document.getElementById('btn-stop').addEventListener('click', stopGeneration);
|
|
});
|
|
|
|
function loadConfig() {
|
|
fetch('/api/config')
|
|
.then(r => r.json())
|
|
.then(config => {
|
|
const summary = document.getElementById('config-summary');
|
|
if (config && config.reddit) {
|
|
summary.innerHTML = `
|
|
<div class="config-item">
|
|
<strong>Subreddit:</strong> r/${config.reddit?.thread?.subreddit || 'Not set'}
|
|
</div>
|
|
<div class="config-item">
|
|
<strong>TTS:</strong> ${config.settings?.tts?.voice_choice || 'Not set'}
|
|
</div>
|
|
<div class="config-item">
|
|
<strong>Theme:</strong> ${config.settings?.theme || 'dark'}
|
|
</div>
|
|
<div class="config-item">
|
|
<strong>Resolution:</strong> ${config.settings?.resolution_w || 1080}x${config.settings?.resolution_h || 1920}
|
|
</div>
|
|
`;
|
|
} else {
|
|
summary.innerHTML = '<p class="warning">Not configured. <a href="/settings">Click here to configure.</a></p>';
|
|
}
|
|
});
|
|
}
|
|
|
|
function loadRecentVideos() {
|
|
fetch('/api/videos')
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
const container = document.getElementById('recent-videos');
|
|
if (data.videos && data.videos.length > 0) {
|
|
const recent = data.videos.slice(0, 3);
|
|
container.innerHTML = recent.map(v => `
|
|
<div class="video-item">
|
|
<span class="video-name">${v.name}</span>
|
|
<span class="video-subreddit">r/${v.subreddit}</span>
|
|
<a href="${v.path}" target="_blank" class="btn btn-small">View</a>
|
|
</div>
|
|
`).join('');
|
|
} else {
|
|
container.innerHTML = '<p class="hint">No videos generated yet</p>';
|
|
}
|
|
});
|
|
}
|
|
|
|
function initProgressSocket() {
|
|
const socket = io('/progress');
|
|
socket.on('progress_update', (data) => {
|
|
updateProgress(data);
|
|
updateGenerationStatus(data);
|
|
});
|
|
}
|
|
|
|
function updateProgress(data) {
|
|
const container = document.getElementById('progress-container');
|
|
if (data.current_job) {
|
|
const job = data.current_job;
|
|
container.innerHTML = `
|
|
<div class="progress-info">
|
|
<div class="progress-title">${job.title}</div>
|
|
<div class="progress-subreddit">r/${job.subreddit}</div>
|
|
<div class="progress-bar-container">
|
|
<div class="progress-bar" style="width: ${job.overall_progress}%"></div>
|
|
</div>
|
|
<div class="progress-percent">${Math.round(job.overall_progress)}%</div>
|
|
<div class="progress-steps">
|
|
${job.steps.map(s => `
|
|
<div class="step ${s.status}">
|
|
<span class="step-icon">${getStepIcon(s.status)}</span>
|
|
<span class="step-name">${s.name}</span>
|
|
</div>
|
|
`).join('')}
|
|
</div>
|
|
</div>
|
|
`;
|
|
} else {
|
|
container.innerHTML = `
|
|
<div class="no-progress">
|
|
<p>No video generation in progress</p>
|
|
<p class="hint">Click "Generate Video" to start</p>
|
|
</div>
|
|
`;
|
|
}
|
|
}
|
|
|
|
function updateGenerationStatus(data) {
|
|
const btnGenerate = document.getElementById('btn-generate');
|
|
const btnStop = document.getElementById('btn-stop');
|
|
const statusIndicator = document.getElementById('status-indicator');
|
|
const statusText = document.getElementById('status-text');
|
|
|
|
if (data.current_job && data.current_job.status === 'in_progress') {
|
|
btnGenerate.disabled = true;
|
|
btnStop.disabled = false;
|
|
statusIndicator.classList.add('running');
|
|
statusText.textContent = 'Generating...';
|
|
} else {
|
|
btnGenerate.disabled = false;
|
|
btnStop.disabled = true;
|
|
statusIndicator.classList.remove('running');
|
|
statusText.textContent = 'Ready';
|
|
}
|
|
}
|
|
|
|
function getStepIcon(status) {
|
|
switch(status) {
|
|
case 'completed': return '✓';
|
|
case 'in_progress': return '◐';
|
|
case 'failed': return '✗';
|
|
default: return '○';
|
|
}
|
|
}
|
|
|
|
function startGeneration() {
|
|
fetch('/api/generate', { method: 'POST' })
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
showNotification('Video generation started!', 'success');
|
|
} else {
|
|
showNotification(data.message, 'error');
|
|
}
|
|
});
|
|
}
|
|
|
|
function stopGeneration() {
|
|
fetch('/api/generate/stop', { method: 'POST' })
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
showNotification(data.message, data.success ? 'success' : 'error');
|
|
});
|
|
}
|
|
|
|
function showNotification(message, type) {
|
|
const notif = document.createElement('div');
|
|
notif.className = `notification ${type}`;
|
|
notif.textContent = message;
|
|
document.body.appendChild(notif);
|
|
setTimeout(() => notif.remove(), 3000);
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|