From 8eaf56fb715ea181029ebaf715c014959d76717c Mon Sep 17 00:00:00 2001 From: svemagie <869694+svemagie@users.noreply.github.com> Date: Tue, 24 Mar 2026 07:01:16 +0100 Subject: [PATCH] fix: decode HTML entities in podroll episode and podcast titles RSS feeds encode special characters as HTML entities; the backend serves them raw, causing " etc. to appear literally in the UI. Decode titles client-side using the browser's HTML parser. Co-Authored-By: Claude Sonnet 4.6 --- podroll.njk | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/podroll.njk b/podroll.njk index a9a3cbd..da48bb9 100644 --- a/podroll.njk +++ b/podroll.njk @@ -286,10 +286,10 @@ function podrollApp() { fetch('/podrollapi/api/status').then(r => r.json()) ]); - this.episodes = episodesRes.items || []; + this.episodes = (episodesRes.items || []).map(ep => this.decodeEpisode(ep)); this.hasMore = episodesRes.hasMore || false; this.offset = 0; - this.sources = sourcesRes.items || []; + this.sources = (sourcesRes.items || []).map(s => ({ ...s, title: this.decodeHtml(s.title) })); this.status = statusRes; } catch (err) { this.error = 'Failed to load podcasts: ' + err.message; @@ -310,7 +310,7 @@ function podrollApp() { url += `&source=${encodeURIComponent(this.filterPodcast)}`; } const res = await fetch(url).then(r => r.json()); - this.episodes = res.items || []; + this.episodes = (res.items || []).map(ep => this.decodeEpisode(ep)); this.hasMore = res.hasMore || false; } catch (err) { this.error = 'Failed to load episodes: ' + err.message; @@ -329,7 +329,7 @@ function podrollApp() { url += `&source=${encodeURIComponent(this.filterPodcast)}`; } const res = await fetch(url).then(r => r.json()); - this.episodes = [...this.episodes, ...(res.items || [])]; + this.episodes = [...this.episodes, ...(res.items || []).map(ep => this.decodeEpisode(ep))]; this.hasMore = res.hasMore || false; this.offset = newOffset; } catch (err) { @@ -374,6 +374,21 @@ function podrollApp() { return mb.toFixed(1) + ' MB'; }, + decodeHtml(str) { + if (!str) return str; + const div = document.createElement('div'); + div.innerHTML = str; + return div.textContent; + }, + + decodeEpisode(ep) { + return { + ...ep, + title: this.decodeHtml(ep.title), + podcast: ep.podcast ? { ...ep.podcast, title: this.decodeHtml(ep.podcast.title) } : ep.podcast + }; + }, + stripHtml(html) { if (!html) return ''; // Use textContent to safely extract text without executing HTML