- Implemented DELETE /api/channels/<id> to remove channels and cleanup downloaded files - Added delete button to channels page with confirmation dialog - Added functionality to add single videos via URL - Updated navigation menu
110 lines
4.0 KiB
HTML
110 lines
4.0 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}Channels - YottoB{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="channels-page">
|
|
<div class="page-header">
|
|
<h2>Subscribed Channels</h2>
|
|
<a href="/add-channel" class="btn btn-primary">Add New Channel</a>
|
|
</div>
|
|
|
|
{% if channels %}
|
|
<div class="channels-list">
|
|
{% for channel in channels %}
|
|
<div class="channel-card">
|
|
<div class="channel-info">
|
|
<h3 class="channel-title">{{ channel.title }}</h3>
|
|
<p class="channel-url">
|
|
<a href="{{ channel.rss_url }}" target="_blank">{{ channel.rss_url }}</a>
|
|
</p>
|
|
<div class="channel-meta">
|
|
<span class="video-count">{{ channel.video_entries|length }} videos</span>
|
|
<span class="last-updated">
|
|
Last updated: {{ channel.last_fetched_at.strftime('%b %d, %Y %I:%M %p') if channel.last_fetched_at else 'Never' }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div class="channel-actions">
|
|
<button class="btn btn-secondary" onclick="refreshChannel({{ channel.id }})">
|
|
Refresh Videos
|
|
</button>
|
|
<button class="btn btn-danger" onclick="deleteChannel({{ channel.id }}, '{{ channel.title|replace("'", "\\'") }}')">
|
|
Delete
|
|
</button>
|
|
<a href="/?channel={{ channel.id }}" class="btn btn-link">View Videos</a>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<div class="empty-state">
|
|
<h3>No channels subscribed</h3>
|
|
<p>Add your first YouTube channel to start downloading videos</p>
|
|
<a href="/add-channel" class="btn btn-primary">Add Channel</a>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
function refreshChannel(channelId) {
|
|
const button = event.target;
|
|
button.disabled = true;
|
|
button.textContent = 'Refreshing...';
|
|
|
|
fetch(`/api/videos/refresh/${channelId}`, {
|
|
method: 'POST'
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.status === 'success') {
|
|
alert(`Refreshed! Found ${data.new_videos} new videos`);
|
|
location.reload();
|
|
} else {
|
|
alert('Failed to refresh: ' + data.message);
|
|
button.disabled = false;
|
|
button.textContent = 'Refresh Videos';
|
|
}
|
|
})
|
|
.catch(error => {
|
|
alert('Error: ' + error);
|
|
button.disabled = false;
|
|
button.textContent = 'Refresh Videos';
|
|
});
|
|
}
|
|
|
|
function deleteChannel(channelId, channelTitle) {
|
|
if (!confirm(`Are you sure you want to delete "${channelTitle}"?\n\nThis will permanently remove:\n- The channel subscription\n- All video history\n- ALL downloaded video files for this channel\n\nThis action cannot be undone.`)) {
|
|
return;
|
|
}
|
|
|
|
const button = event.target;
|
|
const originalText = button.textContent;
|
|
button.disabled = true;
|
|
button.textContent = 'Deleting...';
|
|
|
|
fetch(`/api/channels/${channelId}`, {
|
|
method: 'DELETE'
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.status === 'success') {
|
|
alert(data.message);
|
|
location.reload();
|
|
} else {
|
|
alert('Failed to delete: ' + data.message);
|
|
button.disabled = false;
|
|
button.textContent = originalText;
|
|
}
|
|
})
|
|
.catch(error => {
|
|
alert('Error: ' + error);
|
|
button.disabled = false;
|
|
button.textContent = originalText;
|
|
});
|
|
}
|
|
</script>
|
|
{% endblock %}
|