diff --git a/docs/supportedsites.md b/docs/supportedsites.md
index dc716619..23c65c96 100644
--- a/docs/supportedsites.md
+++ b/docs/supportedsites.md
@@ -136,7 +136,7 @@ Consider all listed sites to potentially be NSFW.
| Bilibili |
https://www.bilibili.com/ |
- Articles, User Articles |
+ Articles, User Articles, User Article Favorites |
|
diff --git a/gallery_dl/extractor/bilibili.py b/gallery_dl/extractor/bilibili.py
index b9de1656..597ec40e 100644
--- a/gallery_dl/extractor/bilibili.py
+++ b/gallery_dl/extractor/bilibili.py
@@ -81,6 +81,27 @@ class BilibiliArticleExtractor(BilibiliExtractor):
yield Message.Url, url, text.nameext_from_url(url, article)
+class BilibiliUserArticlesFavoriteExtractor(BilibiliExtractor):
+ subcategory = "user-articles-favorite"
+ pattern = (r"(?:https?://)?space\.bilibili\.com"
+ r"/(\d+)/favlist\?fid=opus")
+ example = "https://space.bilibili.com/12345/favlist?fid=opus"
+ _warning = True
+
+ def _init(self):
+ BilibiliExtractor._init(self)
+ if self._warning:
+ if not self.cookies_check(("SESSDATA",)):
+ self.log.error("'SESSDATA' cookie required")
+ BilibiliUserArticlesFavoriteExtractor._warning = False
+
+ def items(self):
+ for article in self.api.user_favlist():
+ article["_extractor"] = BilibiliArticleExtractor
+ url = "{}/opus/{}".format(self.root, article["opus_id"])
+ yield Message.Queue, url, article
+
+
class BilibiliAPI():
def __init__(self, extractor):
self.extractor = extractor
@@ -122,3 +143,28 @@ class BilibiliAPI():
raise exception.StopExtraction(
"%s: Unable to extract INITIAL_STATE data", article_id)
self.extractor.wait(seconds=300)
+
+ def user_favlist(self):
+ endpoint = "/opus/feed/fav"
+ params = {"page": 1, "page_size": 20}
+
+ while True:
+ data = self._call(endpoint, params)["data"]
+
+ yield from data["items"]
+
+ if not data.get("has_more"):
+ break
+ params["page"] += 1
+
+ def login_user_id(self):
+ url = "https://api.bilibili.com/x/space/v2/myinfo"
+ data = self.extractor.request(url).json()
+
+ if data["code"] != 0:
+ self.extractor.log.debug("Server response: %s", data)
+ raise exception.StopExtraction("API request failed,Are you login?")
+ try:
+ return data["data"]["profile"]["mid"]
+ except Exception:
+ raise exception.StopExtraction("API request failed")
diff --git a/scripts/supportedsites.py b/scripts/supportedsites.py
index 92fa4268..60e43d87 100755
--- a/scripts/supportedsites.py
+++ b/scripts/supportedsites.py
@@ -206,6 +206,7 @@ SUBCATEGORY_MAP = {
},
"bilibili": {
"user-articles": "User Articles",
+ "user-articles-favorite": "User Article Favorites",
},
"bluesky": {
"posts": "",
diff --git a/test/results/bilibili.py b/test/results/bilibili.py
index d608f78b..2028dc3a 100644
--- a/test/results/bilibili.py
+++ b/test/results/bilibili.py
@@ -65,4 +65,10 @@ __tests__ = (
"#class" : bilibili.BilibiliUserArticlesExtractor,
},
+{
+ "#url" : "https://space.bilibili.com/405279279/favlist?fid=opus",
+ "#class" : bilibili.BilibiliUserArticlesFavoriteExtractor,
+ "#auth" : True,
+},
+
)