Commit e7bb5b1

benny-dou <60535774+benny-dou@users.noreply.github.com>
2025-03-03 11:40:39
feat(bilibili): add cookie support for comments
1 parent 509d6f5
Changed files (3)
src/preview/ytdlp.py
@@ -18,6 +18,7 @@ from yt_dlp import YoutubeDL
 from yt_dlp.utils import DownloadError, ExtractorError, YoutubeDLError
 
 from config import API, CAPTION_LENGTH, DB, DOWNLOAD_DIR, MAX_FILE_BYTES, PROVIDER, PROXY, TID, TOKEN, YTDLP_DOWNLOAD_MAX_FILE_BYTES, YTDLP_RE_ENCODING_MAX_FILE_BYTES, cache
+from cookies import cookie_cloud_bilibili
 from database import get_db
 from messages.database import copy_messages_from_db, save_messages
 from messages.preprocess import preprocess_media
@@ -27,7 +28,7 @@ from messages.utils import count_without_entities, get_reply_to, smart_split
 from multimedia import convert_to_h264, generate_cover
 from networking import hx_req
 from others.emoji import emojify
-from preview.utils import make_bvid_clickable
+from preview.utils import bv2av, make_bvid_clickable
 from utils import readable_size, readable_time, soup_to_text, to_int, true, ts_to_dt, unicode_to_ascii
 
 
@@ -464,7 +465,19 @@ async def get_bilibili_comments(bvid: str | None, provider: str = PROVIDER.BILIB
 
     succ = False
     data = []
-    if "free" in provider:
+    if "cookie" in provider:  # try cookie
+        avid = bv2av(bvid)
+        link = f"https://www.bilibili.com/video/{bvid}"
+        cookie = await cookie_cloud_bilibili()
+        if cookie:
+            url = f"https://api.bilibili.com/x/v2/reply?type=1&oid={avid}&sort=1"
+            try:
+                response = await hx_req(url, headers={"referer": link, "cookie": cookie}, check_keys=["data.replies"], check_kv={"code": 0}, max_retry=0, timeout=3)
+                data = sorted(response["data"]["replies"], key=lambda x: x["like"], reverse=True)
+                succ = True
+            except Exception:
+                logger.warning("Bilibili comments API [cookie] failed")
+    if not succ and "free" in provider:
         try:
             api = f"{API.TIKHUB_FREE}/api/bilibili/web/fetch_video_comments?bv_id={bvid}"
             headers = {"accept": "application/json"}
@@ -489,20 +502,24 @@ async def get_bilibili_comments(bvid: str | None, provider: str = PROVIDER.BILIB
             name = glom(x, "member.uname", default="匿名")
             if uid := glom(x, "member.mid", default=""):
                 name = f"[{name}](https://space.bilibili.com/{uid})"
+            location = glom(x, "reply_control.location", default="").removeprefix("IP属地:")  # noqa: RUF001
+            location = f"({location})" if location else ""
             if cmt := glom(x, "content.message", default=""):
                 cmt = cmt.replace("\n", "\n> ")
                 if idx == 0:
                     comments.append("\n**> 💬**点此展开评论区**:")
-                comments.append(f"\n> 💬**{name}**: {emojify(cmt)}")
+                comments.append(f"\n> 💬**{name}**{location}: {emojify(cmt)}")
             # replies of comments, free api only got 3 comments, so we add replies here
             if provider == "free" and (replies := x.get("replies")):
                 for r in replies:
                     name = glom(r, "member.uname", default="匿名")
                     if uid := glom(r, "member.mid", default=""):
                         name = f"[{name}](https://space.bilibili.com/{uid})"
+                    location = glom(r, "reply_control.location", default="").removeprefix("IP属地:")  # noqa: RUF001
+                    location = f"({location})" if location else ""
                     if cmt := glom(r, "content.message", default=""):
                         cmt = cmt.replace("\n", "\n> ")
-                        comments.append(f"\n> ↪️**{name}**: {emojify(cmt)}")
+                        comments.append(f"\n> ↪️**{name}**{location}: {emojify(cmt)}")
     except Exception as e:
         logger.error(f"Failed to get Bilibili comments: {e}")
         return []
src/config.py
@@ -98,7 +98,7 @@ class PROVIDER:  # default API provider
     TWITTER_COMMENTS = os.getenv("TWITTER_COMMENTS_PROVIDER", "tikhub").lower()  # tikhub or a false value (0, false, none, null, etc.)
     INSTAGRAM_COMMENTS = os.getenv("INSTAGRAM_COMMENTS_PROVIDER", "tikhub").lower()  # tikhub or a false value (0, false, none, null, etc.)
     WEIBO_COMMENTS = os.getenv("WEIBO_COMMENTS_PROVIDER", "free").lower()  # free or a false value (0, false, none, null, etc.)
-    BILIBILI_COMMENTS = os.getenv("BILIBILI_COMMENTS_PROVIDER", "free-tikhub").lower()  # free or tikhub or a false value (0, false, none, null, etc.)
+    BILIBILI_COMMENTS = os.getenv("BILIBILI_COMMENTS_PROVIDER", "cookie-free-tikhub").lower()  # or a false value to disable (0, false, none, null, etc.)
     YOUTUBE_COMMENTS = os.getenv("YOUTUBE_COMMENTS_PROVIDER", "free").lower()  # free or a false value (0, false, none, null, etc.)
 
 
src/cookies.py
@@ -43,6 +43,20 @@ async def cookie_cloud_weibo() -> str:
     return cookie
 
 
+@cache.memoize(ttl=7200)
+async def cookie_cloud_bilibili() -> str:
+    data = await cookie_cloud()
+    cookie_data = data.get("cookie_data", {})
+    cookies = []
+    for k, v in cookie_data.items():
+        if k in [".bilibili.com", "www.bilibili.com"]:
+            cookies.extend(v)
+    cookie = ""
+    for x in cookies:
+        cookie += f"{x['name']}={x['value']}; "
+    return cookie
+
+
 @cache.memoize(ttl=3600)
 async def get_weibo_cookies() -> str:
     """Get Weibo visitor cookies.
@@ -90,8 +104,23 @@ async def debug():
     print(res)
 
 
+async def bilibili_cmt(aid: str | int = "114097853038828"):
+    aid = "114097853038828"
+    link = "https://www.bilibili.com/video/BV1M19iY4Ec2"
+    cookie = await cookie_cloud_bilibili()
+    if not cookie:
+        return []
+    url = f"https://api.bilibili.com/x/v2/reply?type=1&oid={aid}&sort=1"
+    response = await hx_req(url, headers={"referer": link, "cookie": cookie}, check_kv={"code": 0}, max_retry=0, timeout=3)
+    data = response.get("data", {}).get("replies", [])
+    print(data)
+    return data
+
+
 if __name__ == "__main__":
     import asyncio
 
-    print(asyncio.run(cookie_cloud_weibo()))
+    # print(asyncio.run(cookie_cloud_bilibili()))
+    print(asyncio.run(bilibili_cmt()))
+    # print(asyncio.run(cookie_cloud_weibo()))
     # asyncio.run(debug())