Commit 260ba01

benny-dou <60535774+benny-dou@users.noreply.github.com>
2025-05-06 12:55:32
fix(ytdlp): use YouTube API to get video publish time
1 parent 62949a1
Changed files (4)
src/preview/utils.py
@@ -2,7 +2,7 @@
 # -*- coding: utf-8 -*-
 import asyncio
 import re
-from datetime import datetime
+from datetime import UTC, datetime
 from pathlib import Path
 from zoneinfo import ZoneInfo
 
@@ -11,7 +11,7 @@ from glom import glom
 from loguru import logger
 from pyrogram.parser.markdown import BLOCKQUOTE_EXPANDABLE_DELIM
 
-from config import READING_SPEED, TZ, cache
+from config import PROXY, READING_SPEED, TOKEN, TZ, cache
 from cookies import bilibili_cookie_dict
 from networking import hx_req
 from others.emoji import emojify
@@ -130,6 +130,37 @@ async def get_bilibili_comments(url_or_vid: int | str) -> list[str]:
     return comments
 
 
+@cache.memoize(ttl=120)
+async def fetch_youtube_video_info(video_id: str) -> dict:
+    """Fetch YouTube video info."""
+    if not video_id:
+        return {}
+    try:
+        logger.info(f"Fetch Video info for {video_id=}, proxy={PROXY.SUBTITLE}")
+        api = "https://www.googleapis.com/youtube/v3/videos"
+        params = {"key": TOKEN.YOUTUBE_API_KEY, "part": "snippet", "id": video_id, "hl": "zh-CN"}
+        resp = await hx_req(api, proxy=PROXY.SUBTITLE, params=params, check_keys=["items"], max_retry=0)
+        if resp.get("hx_error"):
+            logger.warning(f"YouTube Videos API failed: {resp['hx_error']}")
+            return {}
+        title = glom(resp, "items.0.snippet.title")
+        desc = glom(resp, "items.0.snippet.description")
+        author = glom(resp, "items.0.snippet.channelTitle")
+        channel = glom(resp, "items.0.snippet.channelId")
+        pubdate = glom(resp, "items.0.snippet.publishedAt")
+    except Exception as e:
+        logger.error(f"Failed to get video info: {e}")
+        return {}
+    return {
+        "title": title,
+        "description": desc,
+        "author": author,
+        "channel": f"https://www.youtube.com/channel/{channel}",
+        "date": datetime.strptime(pubdate, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=UTC).astimezone(ZoneInfo(TZ)),
+        "emoji": "๐Ÿ”ด",
+    }
+
+
 def has_markdown_img(text: str) -> bool:
     """Check if the text contains markdown img format.
 
src/preview/ytdlp.py
@@ -43,9 +43,9 @@ from messages.sender import send2tg
 from messages.utils import blockquote, count_without_entities, get_reply_to, smart_split, warp_comments
 from multimedia import convert_to_h264, generate_cover
 from networking import hx_req
-from preview.utils import get_bilibili_comments, make_bvid_clickable
+from preview.utils import fetch_youtube_video_info, get_bilibili_comments, make_bvid_clickable
 from subtitles.base import fetch_subtitle
-from utils import publish_telegraph, readable_size, readable_time, remove_none_values, soup_to_text, to_int, true, ts_to_dt, unicode_to_ascii
+from utils import nowdt, publish_telegraph, readable_size, readable_time, remove_none_values, soup_to_text, to_int, true, ts_to_dt, unicode_to_ascii
 
 
 class ProxyError(Exception):
@@ -174,6 +174,10 @@ async def preview_ytdlp(
         create_time = f"{dt:%Y-%m-%d %H:%M:%S}"
     elif info.get("upload_date"):
         create_time = info["update_date"]
+    elif "youtube" in info["extractor"]:
+        vinfo = await fetch_youtube_video_info(kwargs.get("vid", ""))
+        dt = vinfo.get("date", nowdt())
+        create_time = f"{dt:%Y-%m-%d %H:%M:%S}"
     if not true(kwargs.get("no_date")):
         texts += f"\n๐Ÿ•’{create_time}"
 
src/subtitles/base.py
@@ -1,15 +1,13 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
-from datetime import UTC, datetime, timedelta
-from zoneinfo import ZoneInfo
+from datetime import timedelta
 
-from glom import glom
 from loguru import logger
 from pyrogram.client import Client
 from pyrogram.types import Message
 from youtube_transcript_api import YouTubeTranscriptApi  # type: ignore
 
-from config import API, PREFIX, PROXY, READING_SPEED, TOKEN, TZ, cache
+from config import API, PREFIX, PROXY, READING_SPEED, TOKEN, cache
 from messages.parser import parse_msg
 from messages.utils import startswith_prefix
 from networking import hx_req, match_social_media_link
@@ -158,31 +156,3 @@ def to_webvtt(subtitles: list[dict]) -> dict:
     except Exception as e:
         logger.error(f"Failed to convert subtitles to WebVTT: {e}")
         return {"error": str(e)}
-
-
-async def fetch_youtube_video_info(video_id: str) -> dict:
-    """Fetch YouTube video info."""
-    try:
-        logger.info(f"Fetch Video info for {video_id=}, proxy={PROXY.SUBTITLE}")
-        api = "https://www.googleapis.com/youtube/v3/videos"
-        params = {"key": TOKEN.YOUTUBE_API_KEY, "part": "snippet", "id": video_id, "hl": "zh-CN"}
-        resp = await hx_req(api, proxy=PROXY.SUBTITLE, params=params, check_keys=["items"], max_retry=0)
-        if resp.get("hx_error"):
-            logger.warning(f"YouTube Videos API failed: {resp['hx_error']}")
-            return {}
-        title = glom(resp, "items.0.snippet.title")
-        desc = glom(resp, "items.0.snippet.description")
-        author = glom(resp, "items.0.snippet.channelTitle")
-        channel = glom(resp, "items.0.snippet.channelId")
-        pubdate = glom(resp, "items.0.snippet.publishedAt")
-    except Exception as e:
-        logger.error(f"Failed to get video info: {e}")
-        return {}
-    return {
-        "title": title,
-        "description": desc,
-        "author": author,
-        "channel": f"https://www.youtube.com/channel/{channel}",
-        "date": datetime.strptime(pubdate, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=UTC).astimezone(ZoneInfo(TZ)),
-        "emoji": "๐Ÿ”ด",
-    }
src/subtitles/subtitle.py
@@ -14,9 +14,9 @@ from messages.progress import modify_progress
 from messages.sender import send2tg
 from messages.utils import equal_prefix
 from networking import match_social_media_link
-from preview.utils import get_bilibili_video_info
+from preview.utils import fetch_youtube_video_info, get_bilibili_video_info
 from preview.ytdlp import preview_ytdlp
-from subtitles.base import fetch_subtitle, fetch_youtube_video_info, match_url
+from subtitles.base import fetch_subtitle, match_url
 from utils import publish_telegraph, to_int
 
 HELP = f"""๐Ÿ“ƒ**ๆๅ–ๅญ—ๅน•**