- Created base.html template with navigation and flash messages - Created dashboard.html for video listing sorted by date - Created channels.html for channel management - Created add_channel.html with subscription form - Created watch.html with HTML5 video player - Created static/style.css with YouTube-inspired dark theme - Updated main.py with frontend routes: - / (index): Dashboard with all videos - /channels: Channel management page - /add-channel: Add new channel form (GET/POST) - /watch/<video_id>: Video player page - Added new API endpoints: - /api/videos/refresh/<channel_id>: Refresh channel videos - /api/video/stream/<video_id>: Stream/download video files - Enhanced /api/download/<video_id> with status checks - Updated CLAUDE.md with comprehensive frontend documentation Features: - Video grid with thumbnails and download status badges - Inline download buttons for pending videos - Channel subscription and refresh functionality - HTML5 video player for downloaded videos - Auto-refresh during video downloads - Responsive design for mobile/desktop - Flash message system for user feedback - Dark theme with hover effects and animations 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
111 lines
4.1 KiB
HTML
111 lines
4.1 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}{{ video.title }} - YottoB{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="watch-page">
|
|
<div class="video-player-container">
|
|
{% if video.download_status == 'completed' and video.download_path %}
|
|
<video controls class="video-player">
|
|
<source src="/api/video/stream/{{ video.id }}" type="video/mp4">
|
|
Your browser does not support the video tag.
|
|
</video>
|
|
{% elif video.download_status == 'downloading' %}
|
|
<div class="video-placeholder">
|
|
<div class="placeholder-content">
|
|
<h3>Video is downloading...</h3>
|
|
<p>Please check back in a few minutes</p>
|
|
<button class="btn btn-secondary" onclick="location.reload()">Refresh</button>
|
|
</div>
|
|
</div>
|
|
{% elif video.download_status == 'failed' %}
|
|
<div class="video-placeholder error">
|
|
<div class="placeholder-content">
|
|
<h3>Download failed</h3>
|
|
<p>There was an error downloading this video</p>
|
|
<button class="btn btn-primary" onclick="retryDownload()">Retry Download</button>
|
|
</div>
|
|
</div>
|
|
{% else %}
|
|
<div class="video-placeholder">
|
|
<div class="placeholder-content">
|
|
{% if video.thumbnail_url %}
|
|
<img src="{{ video.thumbnail_url }}" alt="{{ video.title }}" class="placeholder-thumbnail">
|
|
{% endif %}
|
|
<h3>Video not downloaded yet</h3>
|
|
<button class="btn btn-primary" onclick="startDownload()">Download Video</button>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="video-details">
|
|
<h1 class="video-title">{{ video.title }}</h1>
|
|
|
|
<div class="video-metadata">
|
|
<div class="channel-info">
|
|
<h3>{{ video.channel.title }}</h3>
|
|
<a href="{{ video.channel.rss_url }}" target="_blank" class="channel-link">View Channel</a>
|
|
</div>
|
|
<div class="video-stats">
|
|
<span class="publish-date">Published: {{ video.published_at.strftime('%B %d, %Y') }}</span>
|
|
{% if video.download_status == 'completed' and video.download_completed_at %}
|
|
<span class="download-date">Downloaded: {{ video.download_completed_at.strftime('%B %d, %Y') }}</span>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
{% if video.description %}
|
|
<div class="video-description">
|
|
<h4>Description</h4>
|
|
<p>{{ video.description }}</p>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="video-links">
|
|
<a href="{{ video.video_url }}" target="_blank" class="btn btn-link">Watch on YouTube</a>
|
|
{% if video.download_status == 'completed' and video.download_path %}
|
|
<a href="/api/video/stream/{{ video.id }}?download=1" class="btn btn-secondary" download>Download MP4</a>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="back-link">
|
|
<a href="/">← Back to all videos</a>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
function startDownload() {
|
|
if (!confirm('Start downloading this video?')) return;
|
|
|
|
fetch('/api/download/{{ video.id }}', {
|
|
method: 'POST'
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.status === 'success') {
|
|
alert('Download started! This page will refresh automatically.');
|
|
setTimeout(() => location.reload(), 2000);
|
|
} else {
|
|
alert('Failed to start download: ' + data.message);
|
|
}
|
|
})
|
|
.catch(error => {
|
|
alert('Error: ' + error);
|
|
});
|
|
}
|
|
|
|
function retryDownload() {
|
|
startDownload();
|
|
}
|
|
|
|
// Auto-refresh if video is downloading
|
|
{% if video.download_status == 'downloading' %}
|
|
setTimeout(() => location.reload(), 10000); // Refresh every 10 seconds
|
|
{% endif %}
|
|
</script>
|
|
{% endblock %}
|