diff --git a/backend/services/ytdlp.py b/backend/services/ytdlp.py index c58a844..3c7c570 100644 --- a/backend/services/ytdlp.py +++ b/backend/services/ytdlp.py @@ -82,6 +82,19 @@ def _normalize_video(info: dict) -> dict: } +def _channel_banner(thumbnails: list | None) -> str | None: + if not thumbnails: + return None + for t in thumbnails: + if "banner" in str(t.get("id") or "").lower(): + return t.get("url") + wide = [t for t in thumbnails + if t.get("width") and t.get("height") and t["width"] > t["height"] * 3] + if wide: + return max(wide, key=lambda t: t.get("width") or 0).get("url") + return None + + def _channel_avatar(thumbnails: list | None) -> str | None: """Pick the channel avatar from yt-dlp's thumbnails list. @@ -109,7 +122,7 @@ def _normalize_channel(info: dict) -> dict: "name": info.get("channel") or info.get("title") or info.get("uploader") or None, "description": info.get("description") or None, "thumbnail_url": _channel_avatar(info.get("thumbnails")), - "banner_url": None, + "banner_url": _channel_banner(info.get("thumbnails")), "subscriber_count": info.get("channel_follower_count"), } diff --git a/frontend/src/components/ChannelCard.jsx b/frontend/src/components/ChannelCard.jsx index ece9080..38c6967 100644 --- a/frontend/src/components/ChannelCard.jsx +++ b/frontend/src/components/ChannelCard.jsx @@ -1,6 +1,6 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; import { useNavigate } from "react-router-dom"; -import { followChannel, unfollowChannel } from "../api"; +import { followChannel, unfollowChannel, followChannelByUrl } from "../api"; function formatSubs(n) { if (!n) return null; @@ -21,6 +21,19 @@ export default function ChannelCard({ channel }) { onSuccess: () => qc.invalidateQueries({ queryKey: ["channels"] }), }); + const followAndNavMut = useMutation({ + mutationFn: () => followChannelByUrl({ youtube_channel_id: channel.youtube_channel_id }), + onSuccess: (res) => { + qc.invalidateQueries({ queryKey: ["channels"] }); + navigate(`/channels/${res.data.channel_id}`); + }, + }); + + const handleClick = () => { + if (channelId) navigate(`/channels/${channelId}`); + else if (channel.youtube_channel_id) followAndNavMut.mutate(); + }; + const subs = formatSubs(channel.subscriber_count); const meta = [ subs && `${subs} subscribers`, @@ -30,7 +43,7 @@ export default function ChannelCard({ channel }) { return (