From 6e54573eec056326a8da7a859eea00907297ba86 Mon Sep 17 00:00:00 2001 From: Julian Dice <19397727+windoze95@users.noreply.github.com> Date: Thu, 5 Mar 2026 16:21:40 -0600 Subject: [PATCH 1/2] Add endpoint to refresh channel images on open POST /api/channels/{id}/refresh-images fetches fresh avatar and banner URLs from YouTube and updates the channel record, so images stay current whenever a user opens a channel. Co-Authored-By: Claude Opus 4.6 --- app/api/channels.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/app/api/channels.py b/app/api/channels.py index 59b9853..7e30eae 100644 --- a/app/api/channels.py +++ b/app/api/channels.py @@ -144,6 +144,30 @@ async def subscribe( return out +@router.post("/{channel_id}/refresh-images", response_model=ChannelDetail) +async def refresh_channel_images( + channel_id: str, + user: User = Depends(get_current_user), + db: AsyncSession = Depends(get_db), +) -> ChannelDetail: + """Fetch fresh avatar and banner images from YouTube and update the channel.""" + result = await db.execute(select(Channel).where(Channel.id == channel_id)) + channel = result.scalar_one_or_none() + if not channel: + raise HTTPException(status_code=404, detail="Channel not found") + + images = await _resolve_channel_images(channel.youtube_channel_id) + if images.get("avatar_url"): + channel.avatar_url = images["avatar_url"] + if images.get("banner_url"): + channel.banner_url = images["banner_url"] + await db.commit() + await db.refresh(channel) + + detail = ChannelDetail.model_validate(channel) + return detail + + @router.delete("/{channel_id}/unsubscribe") async def unsubscribe( channel_id: str, From 6293536b0f294486925e4fb20e39b439fa1dd2ff Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Mar 2026 23:44:06 +0000 Subject: [PATCH 2/2] Fix refresh-images endpoint returning empty channel stats The POST /api/channels/{id}/refresh-images endpoint was returning ChannelDetail with default values for subscriber_count, video_count, is_subscribed, and tracking_mode because it never queried for those derived fields. This caused UI state desync after a successful image refresh. Now populates all stats the same way get_channel does. https://claude.ai/code/session_01MaYebt19nccXjyuYueW9oq --- app/api/channels.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/app/api/channels.py b/app/api/channels.py index 7e30eae..6ce0db7 100644 --- a/app/api/channels.py +++ b/app/api/channels.py @@ -164,7 +164,32 @@ async def refresh_channel_images( await db.commit() await db.refresh(channel) + sub_count_result = await db.execute( + select(func.count()) + .select_from(UserSubscription) + .where(UserSubscription.channel_id == channel_id) + ) + subscriber_count = sub_count_result.scalar() or 0 + + video_count_result = await db.execute( + select(func.count()).select_from(Video).where(Video.channel_id == channel_id) + ) + video_count = video_count_result.scalar() or 0 + + sub_result = await db.execute( + select(UserSubscription).where( + UserSubscription.user_id == user.id, + UserSubscription.channel_id == channel_id, + ) + ) + sub = sub_result.scalar_one_or_none() + detail = ChannelDetail.model_validate(channel) + detail.subscriber_count = subscriber_count + detail.video_count = video_count + detail.is_subscribed = sub is not None + if sub: + detail.tracking_mode = sub.tracking_mode return detail