Files
azcomputerguru b3f378a8ef Add web UI for configuration and management
- Flask-based web interface on port 8080
- Dashboard with channel statistics and sync status
- Channel management (add/remove channels via UI)
- Settings page for all configuration options
- Cookie file upload interface
- Real-time log viewer
- Manual sync trigger from web UI
- Updated Dockerfile to include Flask and web assets
- Updated Unraid template with WebUI port
- Updated README with web UI documentation
2026-05-08 19:00:36 -04:00

145 lines
4.8 KiB
HTML

{% extends "base.html" %}
{% block title %}Dashboard{% endblock %}
{% block content %}
<div class="page-header">
<h2>Dashboard</h2>
<div class="header-actions">
<button id="sync-btn" class="btn btn-primary" onclick="startSync()">
<span id="sync-text">Run Sync Now</span>
<span id="sync-spinner" class="spinner" style="display: none;"></span>
</button>
</div>
</div>
<div class="cards">
<div class="card">
<h3>Status</h3>
<div class="status-info">
<div class="status-item">
<span class="label">Sync Status:</span>
<span class="value {% if sync_running %}status-running{% else %}status-idle{% endif %}">
{% if sync_running %}Running{% else %}Idle{% endif %}
</span>
</div>
<div class="status-item">
<span class="label">Channels Configured:</span>
<span class="value">{{ stats|length }}</span>
</div>
<div class="status-item">
<span class="label">Cookies:</span>
<span class="value {% if has_cookies %}status-ok{% else %}status-warning{% endif %}">
{% if has_cookies %}Configured{% else %}Not Set{% endif %}
</span>
</div>
<div class="status-item">
<span class="label">Schedule:</span>
<span class="value">{{ settings.sync_schedule }}</span>
</div>
</div>
</div>
<div class="card">
<h3>Configuration</h3>
<div class="config-info">
<div class="config-item">
<span class="label">Max Quality:</span>
<span class="value">{{ settings.max_quality }}p</span>
</div>
<div class="config-item">
<span class="label">Sleep Interval:</span>
<span class="value">{{ settings.sleep_interval }}s</span>
</div>
<div class="config-item">
<span class="label">Timezone:</span>
<span class="value">{{ settings.timezone }}</span>
</div>
</div>
</div>
</div>
<div class="card">
<h3>Channels</h3>
{% if stats %}
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>Channel Name</th>
<th>Videos</th>
<th>Total Size</th>
<th>Last Sync</th>
</tr>
</thead>
<tbody>
{% for channel in stats %}
<tr>
<td><strong>{{ channel.name }}</strong></td>
<td>{{ channel.video_count }}</td>
<td>{{ channel.total_size }}</td>
<td>{{ channel.last_sync }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="empty-state">
<p>No channels configured.</p>
<a href="{{ url_for('channels') }}" class="btn btn-primary">Add Your First Channel</a>
</div>
{% endif %}
</div>
{% endblock %}
{% block scripts %}
<script>
function startSync() {
const btn = document.getElementById('sync-btn');
const text = document.getElementById('sync-text');
const spinner = document.getElementById('sync-spinner');
btn.disabled = true;
text.style.display = 'none';
spinner.style.display = 'inline-block';
fetch('/api/sync/start', { method: 'POST' })
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
alert('Sync started! Check the Logs page to monitor progress.');
setTimeout(() => location.reload(), 2000);
} else {
alert('Error: ' + data.message);
btn.disabled = false;
text.style.display = 'inline';
spinner.style.display = 'none';
}
})
.catch(error => {
alert('Error starting sync: ' + error);
btn.disabled = false;
text.style.display = 'inline';
spinner.style.display = 'none';
});
}
// Auto-refresh status every 10 seconds
setInterval(() => {
fetch('/api/sync/status')
.then(response => response.json())
.then(data => {
const statusEl = document.querySelector('.status-info .value');
if (data.running) {
statusEl.textContent = 'Running';
statusEl.className = 'value status-running';
} else {
statusEl.textContent = 'Idle';
statusEl.className = 'value status-idle';
}
});
}, 10000);
</script>
{% endblock %}