Commit 2f83bd1

benny-dou <60535774+benny-dou@users.noreply.github.com>
2025-07-14 09:19:18
feat(ytdlp): add support for bilibili cookies
1 parent 85aead1
Changed files (3)
src/preview/ytdlp.py
@@ -22,6 +22,7 @@ from yt_dlp.utils import DownloadError, ExtractorError, YoutubeDLError
 from asr.voice_recognition import asr_file
 from config import (
     CAPTION_LENGTH,
+    COOKIE,
     DB,
     DOWNLOAD_DIR,
     MAX_FILE_BYTES,
@@ -35,6 +36,7 @@ from config import (
     YTDLP_RE_ENCODING_MAX_FILE_BYTES,
     cache,
 )
+from cookies import ytdlp_bilibili_cookie
 from database.database import get_db
 from messages.database import copy_messages_from_db, save_messages
 from messages.preprocess import preprocess_media
@@ -58,6 +60,7 @@ async def preview_ytdlp(
     message: Message,
     url: str = "",
     *,
+    platform: str = "",
     use_db: bool = True,
     ytdlp_audio_only: bool = False,
     ytdlp_send_video: bool = True,
@@ -133,6 +136,10 @@ async def preview_ytdlp(
         "color": "no_color-tty",
         "logger": logger,
     }
+    if platform == "bilibili" and COOKIE.YTDLP_BILIBILI_USE_COOKIE:
+        cookiefile = await ytdlp_bilibili_cookie()
+        logger.trace(f"Use cookie file: {cookiefile}")
+        ydl_opts["cookiefile"] = cookiefile
     if kwargs.get("show_progress"):
         loop = asyncio.get_running_loop()
         hook = create_hook(kwargs.get("progress"), loop, detail_progress=true(kwargs.get("detail_progress")))
src/config.py
@@ -181,6 +181,7 @@ class COOKIE:  # See: https://github.com/easychen/CookieCloud
     CLOUD_SERVER = os.getenv("COOKIE_CLOUD_SERVER", "")
     CLOUD_KEY = os.getenv("COOKIE_CLOUD_KEY", "")
     CLOUD_PASS = os.getenv("COOKIE_CLOUD_PASS", "")
+    YTDLP_BILIBILI_USE_COOKIE = os.getenv("YTDLP_BILIBILI_USE_COOKIE", "0").lower() in ["1", "y", "yes", "t", "true", "on"]
 
 
 class TID:  # see more TID usecase in `src/permission.py`
src/cookies.py
@@ -3,12 +3,15 @@
 
 
 import re
+from datetime import timedelta
+from pathlib import Path
 
 from httpx import AsyncClient
 from loguru import logger
 
-from config import COOKIE, PROXY, cache
+from config import COOKIE, DOWNLOAD_DIR, PROXY, cache
 from networking import hx_req
+from utils import nowdt
 
 
 @cache.memoize(ttl=3600)
@@ -73,6 +76,30 @@ async def bilibili_cookie_dict() -> dict:
     return cookie
 
 
+@cache.memoize(ttl=7200)
+async def ytdlp_bilibili_cookie(save_path: str | Path = "") -> str:
+    """Get bilibili cookie from cookie cloud and save it to file."""
+    if not save_path:
+        save_path = Path(DOWNLOAD_DIR) / "cookies" / "bilibili.txt"
+        save_path.parent.mkdir(parents=True, exist_ok=True)
+    now = nowdt()
+    expiration = now + timedelta(hours=2)
+    expiration_ts = expiration.timestamp()
+    data = await cookie_cloud()
+    cookie_data = data.get("cookie_data", {})
+    cookie_string = "# Netscape HTTP Cookie File\n\n"
+    for domain, cookies in cookie_data.items():
+        if domain not in [".bilibili.com", "www.bilibili.com"]:
+            continue
+        for x in cookies:
+            expire = round(x.get("expirationDate", expiration_ts))
+            include_subdomains = str(not x.get("hostOnly", False)).upper()
+            secure = str(x.get("secure", False)).upper()
+            cookie_string += f"{x['domain']}\t{include_subdomains}\t{x['path']}\t{secure}\t{expire}\t{x['name']}\t{x['value']}\n"
+    Path(save_path).write_text(cookie_string)
+    return Path(save_path).as_posix()
+
+
 @cache.memoize(ttl=3600)
 async def get_weibo_cookies() -> str:
     """Get Weibo visitor cookies.
@@ -137,5 +164,6 @@ if __name__ == "__main__":
     # print(asyncio.run(cookie_cloud_bilibili()))
     # print(asyncio.run(bilibili_cmt()))
     # print(asyncio.run(cookie_cloud_weibo()))
-    print(asyncio.run(bilibili_cookie_dict()))
+    print(asyncio.run(ytdlp_bilibili_cookie()))
+    # print(asyncio.run(bilibili_cookie_dict()))
     # asyncio.run(debug())