43 lines
1.3 KiB
Python
43 lines
1.3 KiB
Python
|
|
"""Free per-channel RSS feed reader (no API quota). Returns the channel's most recent
|
||
|
|
~15 uploads as lightweight stubs for fast fresh-video detection."""
|
||
|
|
from datetime import datetime, timezone
|
||
|
|
|
||
|
|
import feedparser
|
||
|
|
import httpx
|
||
|
|
|
||
|
|
RSS_URL = "https://www.youtube.com/feeds/videos.xml?channel_id={channel_id}"
|
||
|
|
|
||
|
|
|
||
|
|
def fetch_channel_feed(channel_id: str) -> list[dict]:
|
||
|
|
url = RSS_URL.format(channel_id=channel_id)
|
||
|
|
try:
|
||
|
|
resp = httpx.get(url, timeout=20.0, headers={"User-Agent": "Subfeed/1.0"})
|
||
|
|
except httpx.HTTPError:
|
||
|
|
return []
|
||
|
|
if resp.status_code != 200:
|
||
|
|
return []
|
||
|
|
|
||
|
|
parsed = feedparser.parse(resp.content)
|
||
|
|
out: list[dict] = []
|
||
|
|
for entry in parsed.entries:
|
||
|
|
video_id = entry.get("yt_videoid")
|
||
|
|
if not video_id:
|
||
|
|
continue
|
||
|
|
published = None
|
||
|
|
if entry.get("published_parsed"):
|
||
|
|
published = datetime(*entry.published_parsed[:6], tzinfo=timezone.utc)
|
||
|
|
thumbnail = None
|
||
|
|
media = entry.get("media_thumbnail") or []
|
||
|
|
if media:
|
||
|
|
thumbnail = media[0].get("url")
|
||
|
|
out.append(
|
||
|
|
{
|
||
|
|
"id": video_id,
|
||
|
|
"channel_id": channel_id,
|
||
|
|
"title": entry.get("title"),
|
||
|
|
"published_at": published,
|
||
|
|
"thumbnail_url": thumbnail,
|
||
|
|
}
|
||
|
|
)
|
||
|
|
return out
|