From 7f3ca21cc42979b8f1898f5dfd81f51f04aed5e0 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Thu, 7 May 2026 15:56:35 +0300 Subject: Fix podcast browser workflows for k1 --- web/js/podcasts.js | 74 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 14 deletions(-) (limited to 'web/js/podcasts.js') diff --git a/web/js/podcasts.js b/web/js/podcasts.js index 1883e63..4692f7b 100644 --- a/web/js/podcasts.js +++ b/web/js/podcasts.js @@ -1,6 +1,8 @@ // podcastUI.js — Podcast feed manager + episode rendering. import { API } from './api.js'; +import { state } from './state.js'; import { escapeHtml, fmtDur, toast } from './utils.js'; +import { renderSets } from './views/sets.js'; export function initPodcasts() { const modal = document.getElementById('podcast-modal'); @@ -32,6 +34,7 @@ export function initPodcasts() { urlInput.value = ''; nameInput.value = ''; refreshPodcasts(); + refreshSets(); } catch (err) { toast(err.message || 'Subscribe failed', 'error'); } @@ -46,7 +49,8 @@ export function initPodcasts() { return; } listEl.innerHTML = podcasts.map(p => - `
+ `
+ ${escapeHtml(p.name)} ${escapeHtml(p.root_path)}
` @@ -55,6 +59,15 @@ export function initPodcasts() { listEl.innerHTML = `

${escapeHtml(err.message)}

`; } } + + async function refreshSets() { + try { + state.sets = await API.sets() || []; + renderSets(); + } catch { + // The subscription succeeded; leave the existing sidebar in place if refresh fails. + } + } } export function renderPodcastEpisodes(grid, episodes) { @@ -68,21 +81,50 @@ export function renderPodcastEpisodes(grid, episodes) { const card = document.createElement('div'); card.className = 'media-card episode-card'; card.dataset.id = ep.id; - card.innerHTML = renderEpisodeHtml(ep); + renderEpisodeCard(card, ep); grid.appendChild(card); + }); +} + +function renderEpisodeCard(card, ep) { + card.innerHTML = renderEpisodeHtml(ep); + + const playBtn = card.querySelector('[data-action="play"]'); + const downloadBtn = card.querySelector('[data-action="download-episode"]'); + const completeBtn = card.querySelector('.btn-complete'); + + playBtn?.addEventListener('click', (e) => { + e.stopPropagation(); + toast(ep.is_downloaded ? 'Play from downloads' : 'Download first to play', 'info'); + }); - const playBtn = card.querySelector('[data-action="play"]'); - const completeBtn = card.querySelector('.btn-complete'); - playBtn?.addEventListener('click', () => { - toast(ep.is_downloaded ? 'Play from downloads' : 'Download first to play', 'info'); - }); - completeBtn?.addEventListener('click', async () => { - try { - const res = await API.toggleEpisodeComplete(ep.id); - completeBtn.classList.toggle('active'); - toast(res.is_completed ? 'Marked listened' : 'Marked unlistened'); - } catch (err) { toast(err.message || 'Toggle failed', 'error'); } - }); + downloadBtn?.addEventListener('click', async (e) => { + e.stopPropagation(); + downloadBtn.disabled = true; + try { + const media = await API.downloadEpisode(ep.id); + ep.is_downloaded = true; + ep.media_id = media.id; + ep.file_name = media.file_name; + toast('Episode downloaded'); + card.dispatchEvent(new CustomEvent('podcast:episode-downloaded', { bubbles: true, detail: { media } })); + renderEpisodeCard(card, ep); + } catch (err) { + downloadBtn.disabled = false; + toast(err.message || 'Download failed', 'error'); + } + }); + + completeBtn?.addEventListener('click', async (e) => { + e.stopPropagation(); + try { + await API.toggleEpisodeComplete(ep.id); + ep.is_completed = !ep.is_completed; + completeBtn.classList.toggle('active', ep.is_completed); + toast(ep.is_completed ? 'Marked listened' : 'Marked unlistened'); + } catch (err) { + toast(err.message || 'Toggle failed', 'error'); + } }); } @@ -90,6 +132,9 @@ function renderEpisodeHtml(ep) { const completed = ep.is_completed; const dateStr = ep.published_at ? new Date(ep.published_at).toLocaleDateString() : ''; const duration = ep.duration_seconds ? fmtDur(ep.duration_seconds) : ''; + const downloadButton = ep.is_downloaded + ? 'Downloaded' + : ''; return `
🎙️ @@ -102,6 +147,7 @@ function renderEpisodeHtml(ep) {
${escapeHtml(ep.title || 'Untitled')}
${escapeHtml(ep.description || 'Podcast episode')}
+ ${downloadButton}
`; } -- cgit v1.2.3