Sprint 002: Ingest duration & view count, FTS search, infinite scroll pagination, and transcript accordion
Deploy t-youtube / Build & Deploy (push) Failing after 1s
Deploy t-youtube / Build & Deploy (push) Failing after 1s
This commit is contained in:
+27
-4
@@ -6,6 +6,7 @@ import logging
|
||||
import aiosqlite
|
||||
import httpx
|
||||
import xml.etree.ElementTree as ET
|
||||
import re
|
||||
from googleapiclient.discovery import build
|
||||
from googleapiclient.errors import HttpError
|
||||
from auth import get_credentials
|
||||
@@ -65,6 +66,20 @@ async def _fetch_rss(client, channel_id):
|
||||
return []
|
||||
|
||||
|
||||
|
||||
def parse_duration(duration_str: str) -> int:
|
||||
"""Parse ISO 8601 duration string (e.g., PT1H2M10S) to seconds."""
|
||||
if not duration_str:
|
||||
return 0
|
||||
pattern = re.compile(r'PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?')
|
||||
match = pattern.match(duration_str)
|
||||
if not match:
|
||||
return 0
|
||||
hours = int(match.group(1)) if match.group(1) else 0
|
||||
minutes = int(match.group(2)) if match.group(2) else 0
|
||||
seconds = int(match.group(3)) if match.group(3) else 0
|
||||
return hours * 3600 + minutes * 60 + seconds
|
||||
|
||||
async def fetch_subscriptions():
|
||||
"""Fetch latest videos from subscribed channels using RSS + YouTube Data API v3."""
|
||||
try:
|
||||
@@ -144,16 +159,22 @@ async def fetch_subscriptions():
|
||||
for i in range(0, len(new_ids), 50):
|
||||
batch = new_ids[i:i+50]
|
||||
try:
|
||||
resp = youtube.videos().list(part="snippet", id=",".join(batch)).execute()
|
||||
resp = youtube.videos().list(part="snippet,contentDetails,statistics", id=",".join(batch)).execute()
|
||||
for item in resp.get("items", []):
|
||||
vid = item["id"]
|
||||
snippet = item["snippet"]
|
||||
cid, rss_title = rss_map.get(vid, (snippet.get("channelId", ""), snippet.get("title", "")))
|
||||
|
||||
content_details = item.get("contentDetails", {})
|
||||
statistics = item.get("statistics", {})
|
||||
duration_str = content_details.get("duration", "")
|
||||
duration_secs = parse_duration(duration_str)
|
||||
view_count = int(statistics.get("viewCount", 0))
|
||||
|
||||
await db.execute("""
|
||||
INSERT INTO videos
|
||||
(video_id, title, channel_name, channel_id, url, thumbnail_url, publish_date)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
(video_id, title, channel_name, channel_id, url, thumbnail_url, publish_date, duration, view_count)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""", (
|
||||
vid,
|
||||
html.unescape(snippet.get("title", rss_title)),
|
||||
@@ -161,7 +182,9 @@ async def fetch_subscriptions():
|
||||
snippet.get("channelId", cid),
|
||||
f"https://www.youtube.com/watch?v={vid}",
|
||||
snippet.get("thumbnails", {}).get("high", {}).get("url", ""),
|
||||
(snippet.get("publishTime") or "")[:10]
|
||||
(snippet.get("publishTime") or "")[:10],
|
||||
duration_secs,
|
||||
view_count
|
||||
))
|
||||
new_count += 1
|
||||
except HttpError as e:
|
||||
|
||||
Reference in New Issue
Block a user