From a993e2d658fd7b0176380570d16c2ce6ec95f56c Mon Sep 17 00:00:00 2001 From: R0m1k3 Date: Thu, 16 Apr 2026 14:57:49 +0200 Subject: [PATCH] feat: implement podcast discovery and management controllers and services --- backend/src/controllers/podcastController.ts | 3 +- backend/src/services/podcastIndexService.ts | 8 +- frontend/src/components/AudioPlayer.tsx | 66 ++++----- frontend/src/components/Header.tsx | 80 ++++++----- frontend/src/context/ThemeContext.tsx | 48 +++++++ frontend/src/main.tsx | 5 +- frontend/src/pages/Dashboard.tsx | 20 +-- frontend/src/pages/Library.tsx | 54 +++---- frontend/src/pages/Trending.tsx | 69 ++++++--- frontend/src/services/discoveryService.ts | 4 +- frontend/src/styles/globals.css | 144 ++++++++++++------- 11 files changed, 318 insertions(+), 183 deletions(-) create mode 100644 frontend/src/context/ThemeContext.tsx diff --git a/backend/src/controllers/podcastController.ts b/backend/src/controllers/podcastController.ts index 986201b..7a99921 100644 --- a/backend/src/controllers/podcastController.ts +++ b/backend/src/controllers/podcastController.ts @@ -291,7 +291,8 @@ export const subscribeFromDiscovery = async (req: Request, res: Response) => { export const getTrendingPodcasts = async (req: Request, res: Response) => { try { const limit = Number(req.query.limit) || 20; - const trending = await podcastIndexService.getTrendingPodcasts(limit); + const genre = req.query.genre as string; + const trending = await podcastIndexService.getTrendingPodcasts(limit, genre); res.json({ source: 'itunes', podcasts: trending, count: trending.length }); } catch (error: any) { console.error('Trending podcasts error:', error.message); diff --git a/backend/src/services/podcastIndexService.ts b/backend/src/services/podcastIndexService.ts index 745e033..2f7fd82 100644 --- a/backend/src/services/podcastIndexService.ts +++ b/backend/src/services/podcastIndexService.ts @@ -77,9 +77,11 @@ export const podcastIndexService = { .filter((r): r is SearchResult => r !== null); }, - getTrendingPodcasts: async (limit: number = 20): Promise => { - // iTunes official top podcasts RSS (France) + getTrendingPodcasts: async (limit: number = 20, genreId?: string): Promise => { + // iTunes official top podcasts RSS + // Format: https://itunes.apple.com/fr/rss/toppodcasts/limit=X/genre=Y/json const cap = Math.min(limit, 50); + const genrePath = genreId ? `/genre=${genreId}` : ''; const rssResponse = await axios.get<{ feed: { entry: Array<{ @@ -89,7 +91,7 @@ export const podcastIndexService = { 'im:image': Array<{ label: string; attributes: { height: string } }>; }>; }; - }>(`https://itunes.apple.com/fr/rss/toppodcasts/limit=${cap}/json`, { + }>(`https://itunes.apple.com/fr/rss/toppodcasts/limit=${cap}${genrePath}/json`, { timeout: 10000, }); diff --git a/frontend/src/components/AudioPlayer.tsx b/frontend/src/components/AudioPlayer.tsx index 5517397..1a1452d 100644 --- a/frontend/src/components/AudioPlayer.tsx +++ b/frontend/src/components/AudioPlayer.tsx @@ -122,7 +122,7 @@ export default function AudioPlayer({ episode, onClose, userId }: AudioPlayerPro isExpanded ? 'inset-0 rounded-none' : 'bottom-6 left-1/2 -translate-x-1/2 w-[96%] max-w-5xl rounded-[2rem] h-[88px]' - } premium-glass border-white/10 shadow-2xl overflow-hidden flex flex-col`}> + } premium-glass border-[var(--border-color)] shadow-2xl overflow-hidden flex flex-col`}>