From d1b1c055bb9ed49530e9a96fd34b3ada5899bbb5 Mon Sep 17 00:00:00 2001 From: A Farzat Date: Wed, 8 Oct 2025 18:58:50 +0300 Subject: Update front-end to display titles and accomodate playlists --- front-end/src/App.css | 58 ++++++++++++++++++++++++++++++++ front-end/src/App.jsx | 91 +++++++++++++++++++++++++++++++-------------------- 2 files changed, 114 insertions(+), 35 deletions(-) diff --git a/front-end/src/App.css b/front-end/src/App.css index 19cddd2..714d6fb 100644 --- a/front-end/src/App.css +++ b/front-end/src/App.css @@ -88,10 +88,68 @@ body { font-size: 0.9rem; } +.subscription-main { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 0.5rem; + margin: 0 0 0.3rem 0; +} + .channel-info strong { color: #74b9ff; } +.subscription-type { + color: #74b9ff; + font-size: 0.8em; + background: rgba(116, 185, 255, 0.2); + padding: 0.2rem 0.5rem; + border-radius: 10px; +} + +.last-dates { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 1rem; + margin: 0; + font-size: 0.9em; +} + +.last-updated { + color: rgba(255, 255, 255, 0.7); +} + +.last-fetched { + color: rgba(255, 255, 255, 0.7); +} + +.subscription-id { + color: rgba(255, 255, 255, 0.7); + font-size: 0.8em; + font-weight: normal; +} + +/* Responsive updates */ +@media (max-width: 768px) { + .subscription-main { + justify-content: center; + text-align: center; + gap: 0.3rem; + } + + .last-dates { + justify-content: center; + text-align: center; + gap: 0.5rem; + } + + .channel-info { + font-size: 0.8rem; + } +} + .subscription-section { max-width: 600px; margin: 1.5rem auto 0; diff --git a/front-end/src/App.jsx b/front-end/src/App.jsx index 4215650..104b561 100644 --- a/front-end/src/App.jsx +++ b/front-end/src/App.jsx @@ -26,23 +26,29 @@ function App() { const response = await axios.get(`${API_BASE_URL}/subs-info`); if (response.data && Array.isArray(response.data)) { - const formattedChannels = response.data.map(channel => { - // Extract the channel ID from the _id field - const channelId = channel._id.replace('yt:channel:', ''); + const formattedChannels = response.data.map(subscription => { + // Extract the ID and type from the _id field + const isPlaylist = subscription._id.startsWith('yt:playlist:'); + const id = subscription._id.replace('yt:channel:', '').replace('yt:playlist:', ''); + const type = isPlaylist ? 'playlist' : 'channel'; + return { - id: channelId, - _id: channel._id, - last_video_update: channel.last_video_update, - new_vids: channel.new_vids, - time_between_fetches: channel.time_between_fetches, - videos: channel.videos + id: id, + _id: subscription._id, + type: type, + title: subscription.title || id, // Use title if available, fallback to ID + last_fetch: subscription.last_fetch, + last_video_update: subscription.last_video_update, + new_vids: subscription.new_vids, + time_between_fetches: subscription.time_between_fetches, + videos: subscription.videos }; }); setChannels(formattedChannels); } } catch (err) { console.error('Error fetching channels:', err); - setError('Failed to fetch available channels.'); + setError('Failed to fetch available subscriptions.'); } finally { setChannelsLoading(false); } @@ -54,7 +60,11 @@ function App() { setError(null); setExpandedDescriptions({}); // Reset expanded states when fetching new videos - const apiUrl = `${API_BASE_URL}/vid-from-link/yt:channel:${channelId}`; + // Find the full _id for the API call + const subscription = channels.find(ch => ch.id === channelId); + if (!subscription) return; + + const apiUrl = `${API_BASE_URL}/vid-from-link/${subscription._id}`; const response = await axios.get(apiUrl); if (response.data && Array.isArray(response.data)) { @@ -63,7 +73,7 @@ function App() { throw new Error('Invalid response format'); } } catch (err) { - setError('Failed to fetch videos. Please check the channel and ensure the API is running.'); + setError('Failed to fetch videos. Please check the subscription and ensure the API is running.'); console.error('Error fetching videos:', err); } finally { setLoading(false); @@ -200,11 +210,11 @@ function App() { return (
-

YouTube Channel Videos

+

YouTube Subscriptions

- +
@@ -265,13 +285,13 @@ function App() {

Add New Subscription

- + setSubscriptionUrl(e.target.value)} - placeholder="https://www.youtube.com/channel/UCxxxxxxxxxxxxxxxxxx" + placeholder="https://www.youtube.com/channel/UCxxx... or https://www.youtube.com/playlist?list=PLxxx..." className="subscription-input" disabled={addingSubscription} /> @@ -320,7 +340,7 @@ function App() {
- {channelsLoading &&
Loading channels...
} + {channelsLoading &&
Loading subscriptions...
} {error && (
@@ -333,22 +353,23 @@ function App() { {!channelsLoading && channels.length === 0 && !error && (
-

No channels available

-

No YouTube channels found in the subscription list.

+

No subscriptions available

+

No YouTube channels or playlists found in the subscription list.

)} {loading && selectedChannelId && ( -
Loading videos for {selectedChannelId}...
+
Loading videos for {channels.find(ch => ch.id === selectedChannelId)?.title}...
)} {!loading && !error && selectedChannelId && (

- Latest Videos from {selectedChannelId} + Latest Videos from {channels.find(ch => ch.id === selectedChannelId)?.title} + - {selectedChannelId} {videos.length > 0 && ` (${videos.length})`}

@@ -426,15 +447,15 @@ function App() { {!loading && !error && selectedChannelId && videos.length === 0 && (
-

No videos found for this channel

-

The channel might not have any videos or there was an issue loading them.

+

No videos found for this subscription

+

The channel or playlist might not have any videos or there was an issue loading them.

)} {!channelsLoading && !selectedChannelId && channels.length > 0 && (
-

Please select a channel to view videos

-

Choose a channel from the dropdown above to see its latest videos.

+

Please select a subscription to view videos

+

Choose a channel or playlist from the dropdown above to see its latest videos.

)}
-- cgit v1.2.3-70-g09d2