Add podgrab featureset
This commit is contained in:
parent
095bf52a2f
commit
233dd5b5c0
33 changed files with 2315 additions and 125 deletions
|
@ -10,6 +10,9 @@
|
|||
<form action="{{ url_for('podcasts.update', podcast_id=podcast.id) }}" method="post" style="display: inline;">
|
||||
<button type="submit" class="btn btn-primary">Update Episodes</button>
|
||||
</form>
|
||||
<form action="{{ url_for('podcasts.download_all', podcast_id=podcast.id) }}" method="post" style="display: inline; margin-left: 8px;">
|
||||
<button type="submit" class="btn btn-success">Download All Episodes</button>
|
||||
</form>
|
||||
<form action="{{ url_for('podcasts.delete', podcast_id=podcast.id) }}" method="post"
|
||||
style="display: inline; margin-left: 8px;"
|
||||
onsubmit="return confirm('Are you sure you want to delete this podcast?');">
|
||||
|
@ -47,7 +50,17 @@
|
|||
<a href="{{ podcast.feed_url }}" target="_blank" style="color: #58a6ff;">View RSS Feed</a>
|
||||
{% endif %}
|
||||
<a href="#" onclick="document.getElementById('naming-format-modal').style.display='block'; return false;" style="color: #58a6ff;">Configure Naming Format</a>
|
||||
<a href="#" onclick="document.getElementById('tags-modal').style.display='block'; return false;" style="color: #58a6ff;">Manage Tags</a>
|
||||
</div>
|
||||
|
||||
{% if podcast.tags %}
|
||||
<div style="margin-top: 8px;">
|
||||
<span style="font-size: 11px; color: #7d8590;">Tags: </span>
|
||||
{% for tag in podcast.get_tags() %}
|
||||
<a href="{{ url_for('podcasts.filter_by_tag', tag=tag) }}" class="tag-badge">{{ tag }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -55,8 +68,8 @@
|
|||
<!-- Toolbar -->
|
||||
<div class="toolbar">
|
||||
<span class="toolbar-btn">{{ episodes|length }} Episodes</span>
|
||||
<div style="margin-left: auto;">
|
||||
<form action="{{ url_for('podcasts.verify', podcast_id=podcast.id) }}" method="post" style="display: inline;">
|
||||
<div style="margin-left: auto; display: flex; gap: 8px;">
|
||||
<form action="{{ url_for('podcasts.verify', podcast_id=podcast.id) }}" method="post" style="display: inline-block;">
|
||||
<button type="submit" class="toolbar-btn">Verify Files</button>
|
||||
</form>
|
||||
<button class="toolbar-btn" onclick="window.location.reload()">Refresh</button>
|
||||
|
@ -67,40 +80,62 @@
|
|||
<!-- Episodes Table -->
|
||||
<div class="content-area">
|
||||
{% if episodes %}
|
||||
{# Check if any episodes have season information #}
|
||||
{% set has_seasons = false %}
|
||||
{# Group episodes by season or year if season is not available #}
|
||||
{% set seasons = {} %}
|
||||
{% set season_ids = {} %}
|
||||
{% set season_download_counts = {} %}
|
||||
{% set season_counter = 0 %}
|
||||
|
||||
{% for episode in episodes %}
|
||||
{% if episode.season and not has_seasons %}
|
||||
{% set has_seasons = true %}
|
||||
{% set season_key = "" %}
|
||||
{% if episode.season %}
|
||||
{# Use season number if available #}
|
||||
{% set season_key = "Season " ~ episode.season %}
|
||||
{% elif episode.published_date %}
|
||||
{# Use year as season if no season number but published date is available #}
|
||||
{% set season_key = episode.published_date.strftime('%Y') %}
|
||||
{% else %}
|
||||
{# Fallback for episodes with no season or published date #}
|
||||
{% set season_key = "Unsorted Episodes" %}
|
||||
{% endif %}
|
||||
|
||||
{# Initialize season if not exists #}
|
||||
{% if season_key not in seasons %}
|
||||
{% set season_counter = season_counter + 1 %}
|
||||
{% set _ = seasons.update({season_key: []}) %}
|
||||
{% set _ = season_ids.update({season_key: season_counter}) %}
|
||||
{% set _ = season_download_counts.update({season_key: {'downloaded': 0, 'total': 0}}) %}
|
||||
{% endif %}
|
||||
|
||||
{# Add episode to season #}
|
||||
{% set _ = seasons[season_key].append(episode) %}
|
||||
|
||||
{# Update download counts #}
|
||||
{% if episode.downloaded %}
|
||||
{% set downloaded = season_download_counts[season_key]['downloaded'] + 1 %}
|
||||
{% set total = season_download_counts[season_key]['total'] + 1 %}
|
||||
{% else %}
|
||||
{% set downloaded = season_download_counts[season_key]['downloaded'] %}
|
||||
{% set total = season_download_counts[season_key]['total'] + 1 %}
|
||||
{% endif %}
|
||||
{% set _ = season_download_counts.update({season_key: {'downloaded': downloaded, 'total': total}}) %}
|
||||
{% endfor %}
|
||||
|
||||
{% if has_seasons %}
|
||||
{# Group episodes by season #}
|
||||
{% set seasons = {} %}
|
||||
{% for episode in episodes %}
|
||||
{% set season_num = episode.season|default(0) %}
|
||||
{% if season_num not in seasons %}
|
||||
{% set seasons = seasons|merge({season_num: []}) %}
|
||||
{% endif %}
|
||||
{% set _ = seasons[season_num].append(episode) %}
|
||||
{% endfor %}
|
||||
{# Display seasons in reverse order (newest first) #}
|
||||
{% if seasons %}
|
||||
{% for season_key, episodes_list in seasons|dictsort|reverse %}
|
||||
{% set season_id = season_ids[season_key] %}
|
||||
{% set download_stats = season_download_counts[season_key] %}
|
||||
|
||||
{# Display seasons in order #}
|
||||
{% for season_num in seasons|sort %}
|
||||
<div class="season-accordion">
|
||||
<div class="season-header" onclick="toggleSeason('{{ season_num }}')">
|
||||
<div class="season-header" onclick="toggleSeason()">
|
||||
<h3>
|
||||
{% if season_num == 0 %}
|
||||
Unsorted Episodes
|
||||
{% else %}
|
||||
Season {{ season_num }}
|
||||
{% endif %}
|
||||
<span class="episode-count">({{ seasons[season_num]|length }} episodes)</span>
|
||||
{{ season_key }}
|
||||
<span class="episode-count">({{ download_stats['downloaded'] }}/{{ download_stats['total'] }} episodes)</span>
|
||||
</h3>
|
||||
<span id="toggle-icon-{{ season_num }}" class="toggle-icon">▼</span>
|
||||
<span id="toggle-icon-season_{{ season_id }}" class="toggle-icon">▼</span>
|
||||
</div>
|
||||
<div id="season-{{ season_num }}" class="season-content">
|
||||
<div id="season-season_{{ season_id }}" class="season-content">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -112,16 +147,16 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for episode in seasons[season_num]|sort(attribute='episode_number') %}
|
||||
{% for episode in episodes_list|sort(attribute='published_date', reverse=true) %}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="cell-title">
|
||||
{% if episode.episode_number %}
|
||||
<span style="color: #58a6ff; font-weight: bold; margin-right: 5px;">
|
||||
{% if episode.season %}
|
||||
S{{ episode.season }}E{{ episode.episode_number }}
|
||||
S{{ '%02d' % episode.season }}E{{ '%02d' % episode.episode_number|int if episode.episode_number|string|isdigit() else episode.episode_number }}
|
||||
{% else %}
|
||||
#{{ episode.episode_number }}
|
||||
#{{ '%02d' % episode.episode_number|int if episode.episode_number|string|isdigit() else episode.episode_number }}
|
||||
{% endif %}
|
||||
</span>
|
||||
{% endif %}
|
||||
|
@ -194,7 +229,7 @@
|
|||
<td>
|
||||
<div class="cell-title">
|
||||
{% if episode.episode_number %}
|
||||
<span style="color: #58a6ff; font-weight: bold; margin-right: 5px;">#{{ episode.episode_number }}</span>
|
||||
<span style="color: #58a6ff; font-weight: bold; margin-right: 5px;">#{{ '%02d' % episode.episode_number|int if episode.episode_number|string|isdigit() else episode.episode_number }}</span>
|
||||
{% endif %}
|
||||
{{ episode.title }}
|
||||
{% if episode.explicit %}
|
||||
|
@ -260,27 +295,46 @@
|
|||
{% block scripts %}
|
||||
<script>
|
||||
function toggleSeason(seasonId) {
|
||||
const seasonContent = document.getElementById('season-' + seasonId);
|
||||
const toggleIcon = document.getElementById('toggle-icon-' + seasonId);
|
||||
// Find the clicked header element
|
||||
const clickedHeader = event.currentTarget;
|
||||
|
||||
// Find the content and toggle icon elements
|
||||
const seasonContent = clickedHeader.nextElementSibling;
|
||||
const toggleIcon = clickedHeader.querySelector('.toggle-icon');
|
||||
|
||||
if (seasonContent.style.display === 'block') {
|
||||
// If already open, close it
|
||||
seasonContent.style.display = 'none';
|
||||
toggleIcon.innerHTML = '▼';
|
||||
} else {
|
||||
// Close all other accordions first
|
||||
const allSeasonContents = document.querySelectorAll('.season-content');
|
||||
const allToggleIcons = document.querySelectorAll('.toggle-icon');
|
||||
|
||||
allSeasonContents.forEach(function(content) {
|
||||
content.style.display = 'none';
|
||||
});
|
||||
|
||||
allToggleIcons.forEach(function(icon) {
|
||||
icon.innerHTML = '▼';
|
||||
});
|
||||
|
||||
// Then open the clicked one
|
||||
seasonContent.style.display = 'block';
|
||||
toggleIcon.innerHTML = '▲';
|
||||
}
|
||||
}
|
||||
|
||||
// Open the first season by default when the page loads
|
||||
// Initialize all season accordions as collapsed by default
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const firstSeasonAccordion = document.querySelector('.season-accordion');
|
||||
if (firstSeasonAccordion) {
|
||||
const seasonId = firstSeasonAccordion.querySelector('.season-content').id.replace('season-', '');
|
||||
toggleSeason(seasonId);
|
||||
}
|
||||
// Make sure all season contents have display style set to none (collapsed)
|
||||
const allSeasonContents = document.querySelectorAll('.season-content');
|
||||
allSeasonContents.forEach(function(content) {
|
||||
content.style.display = 'none';
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
{% include 'podcasts/naming_format_modal.html' %}
|
||||
{% include 'podcasts/tags_modal.html' %}
|
||||
{% endblock %}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue