Skip to content

Commit d1ee418

Browse files
committed
fix: update Bilibili API (close #88)
1 parent d3d3ed3 commit d1ee418

File tree

6 files changed

+68
-92
lines changed

6 files changed

+68
-92
lines changed

docs/site/bilibili.md

+7-21
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Storage path for downloaded images.
1414

1515
### BILIBILI_FILE_NAME
1616

17-
:material-lightbulb-on: Optional, defaults to `{dynamic_id_str}_{index} - {user[name]}({user[uid]})`
17+
:material-lightbulb-on: Optional, defaults to `{id_str}_{index} - {user[name]}({user[mid]})`
1818

1919
File name for downloaded images.
2020

@@ -24,31 +24,17 @@ _Only common used ones are listed._
2424

2525
```json
2626
{
27-
"item": {
28-
"pictures": [
29-
{
30-
"img_height": 900,
31-
"img_size": 840.989990234375,
32-
"img_width": 1600
33-
}
34-
],
35-
"pictures_count": 1,
36-
"reply": 5,
37-
"title": "",
38-
"upload_time": "Upload time"
39-
},
4027
"user": {
4128
"name": "User name",
42-
"uid": "User ID"
29+
"mid": "User ID"
4330
},
44-
"dynamic_id_str": "ID",
45-
"view": 497,
46-
"repost": 5,
47-
"comment": 5,
48-
"like": 68,
31+
"id_str": "ID",
4932
"timestamp": "Timestamp",
5033
"filename": "Original file name, without extension",
51-
"pic": "Current image object in `item.pictures`",
34+
"pic": {
35+
"height": 1440,
36+
"width": 1080
37+
},
5238
"index": "Image index"
5339
}
5440
```

docs/site/bilibili.zh.md

+7-21
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
### BILIBILI_FILE_NAME
1616

17-
:material-lightbulb-on: 可选,默认为 `{dynamic_id_str}_{index} - {user[name]}({user[uid]})`
17+
:material-lightbulb-on: 可选,默认为 `{id_str}_{index} - {user[name]}({user[mid]})`
1818

1919
文件名称。
2020

@@ -24,31 +24,17 @@ _此处只列出常用项。_
2424

2525
```json
2626
{
27-
"item": {
28-
"pictures": [
29-
{
30-
"img_height": 900,
31-
"img_size": 840.989990234375,
32-
"img_width": 1600
33-
}
34-
],
35-
"pictures_count": 1,
36-
"reply": 5,
37-
"title": "",
38-
"upload_time": "上传时间"
39-
},
4027
"user": {
4128
"name": "用户名称",
42-
"uid": "用户ID"
29+
"mid": "用户ID"
4330
},
44-
"dynamic_id_str": "ID",
45-
"view": 497,
46-
"repost": 5,
47-
"comment": 5,
48-
"like": 68,
31+
"id_str": "ID",
4932
"timestamp": "时间戳",
5033
"filename": "原始文件名称,不含扩展名",
51-
"pic": "当前图片在`item.pictures`中的对象",
34+
"pic": {
35+
"height": 1440,
36+
"width": 1080
37+
},
5238
"index": "当前图片索引"
5339
}
5440
```

nazurin/config.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@
4040
UA = (
4141
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
4242
"AppleWebKit/537.36 (KHTML, like Gecko) "
43-
"Chrome/90.0.4430.85 "
44-
"Safari/537.36"
43+
"Chrome/120.0.0.0 Safari/537.36"
4544
)
4645

4746
# Local directory to store database and temporary files

nazurin/sites/bilibili/api.py

+50-47
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import json
21
import os
32
from datetime import datetime
43
from typing import List, Tuple
@@ -13,60 +12,48 @@
1312

1413
class Bilibili:
1514
@network_retry
16-
async def get_dynamic(self, dynamic_id: int):
15+
async def get_dynamic(self, dynamic_id: str):
1716
"""Get dynamic data from API."""
1817
api = (
19-
"https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr"
20-
"/get_dynamic_detail?dynamic_id=" + str(dynamic_id)
18+
f"https://api.bilibili.com/x/polymer/web-dynamic/v1/detail?id={dynamic_id}"
2119
)
2220
async with Request() as request:
2321
async with request.get(api) as response:
2422
response.raise_for_status()
2523
data = await response.json()
2624
# For some IDs, the API returns code 0 but empty content
27-
if data["code"] == 500207 or (
28-
data["code"] == 0 and "card" not in data["data"]
29-
):
25+
code = data.get("code")
26+
if code == 4101147 or "data" not in data:
3027
raise NazurinError("Dynamic not found")
31-
if data["code"] != 0:
32-
raise NazurinError("Failed to get dynamic: " + data["message"])
33-
card = data["data"]["card"]
34-
desc = card["desc"]
35-
card = json.loads(card["card"])
36-
card.update(
37-
{
38-
"type": desc["type"],
39-
"dynamic_id_str": desc["dynamic_id_str"],
40-
"view": desc["view"],
41-
"repost": desc["repost"],
42-
"comment": desc["comment"],
43-
"like": desc["like"],
44-
"timestamp": desc["timestamp"],
45-
}
46-
)
47-
if "vip" in card["user"]:
48-
del card["user"]["vip"]
49-
return card
28+
if code != 0:
29+
raise NazurinError(
30+
f"Failed to get dynamic: code = {code}, message = {data['message']}"
31+
)
32+
item = data["data"]["item"]
33+
return self.cleanup_item(item)
5034

51-
async def fetch(self, dynamic_id: int) -> Illust:
35+
async def fetch(self, dynamic_id: str) -> Illust:
5236
"""Fetch images and detail."""
53-
card = await self.get_dynamic(dynamic_id)
54-
imgs = self.get_images(card)
55-
caption = self.build_caption(card)
56-
caption["url"] = f"https://t.bilibili.com/{dynamic_id}"
57-
return Illust(imgs, caption, card)
37+
item = await self.get_dynamic(dynamic_id)
38+
imgs = self.get_images(item)
39+
caption = self.build_caption(item)
40+
caption["url"] = f"https://www.bilibili.com/opus/{dynamic_id}"
41+
return Illust(imgs, caption, item)
5842

5943
@staticmethod
60-
def get_images(card) -> List[Image]:
44+
def get_images(item: dict) -> List[Image]:
6145
"""Get all images in a dynamic card."""
62-
if "item" not in card or "pictures" not in card["item"]:
46+
major_items = item["modules"]["module_dynamic"]["major"]
47+
if not major_items:
48+
raise NazurinError("No image found")
49+
draw_items = major_items["draw"]["items"]
50+
if not len(draw_items):
6351
raise NazurinError("No image found")
64-
pics = card["item"]["pictures"]
6552
imgs = []
66-
for index, pic in enumerate(pics):
67-
url = pic["img_src"]
68-
destination, filename = Bilibili.get_storage_dest(card, pic, index)
69-
size = pic["img_size"] * 1024 # size returned by API is in KB
53+
for index, pic in enumerate(draw_items):
54+
url = pic["src"]
55+
destination, filename = Bilibili.get_storage_dest(item, pic, index)
56+
size = pic["size"] * 1024 # size returned by API is in KB
7057
# Sometimes it returns a wrong size that is not in whole bytes,
7158
# in this case we just ignore it.
7259
if size % 1 != 0:
@@ -78,30 +65,32 @@ def get_images(card) -> List[Image]:
7865
destination,
7966
url + "@518w.jpg",
8067
size,
81-
pic["img_width"],
82-
pic["img_height"],
68+
pic["width"],
69+
pic["height"],
8370
)
8471
)
8572
return imgs
8673

8774
@staticmethod
88-
def get_storage_dest(card: dict, pic: dict, index: int = 0) -> Tuple[str, str]:
75+
def get_storage_dest(item: dict, pic: dict, index: int = 0) -> Tuple[str, str]:
8976
"""
9077
Format destination and filename.
9178
"""
9279

93-
url = pic["img_src"]
94-
timestamp = datetime.fromtimestamp(card["timestamp"])
80+
url = pic["src"]
81+
timestamp = datetime.fromtimestamp(item["modules"]["module_author"]["pub_ts"])
9582
basename = os.path.basename(url)
9683
filename, extension = os.path.splitext(basename)
84+
user = item["modules"]["module_author"]
9785
context = {
98-
**card,
86+
"user": user,
9987
# Original filename, without extension
10088
"filename": filename,
10189
# Image index
10290
"index": index,
10391
"timestamp": timestamp,
10492
"extension": extension,
93+
"id_str": item["id_str"],
10594
"pic": pic,
10695
}
10796
return (
@@ -110,7 +99,21 @@ def get_storage_dest(card: dict, pic: dict, index: int = 0) -> Tuple[str, str]:
11099
)
111100

112101
@staticmethod
113-
def build_caption(card) -> Caption:
102+
def build_caption(item: dict) -> Caption:
103+
modules = item["modules"]
114104
return Caption(
115-
{"author": card["user"]["name"], "content": card["item"]["description"]}
105+
{
106+
"author": "#" + modules["module_author"]["name"],
107+
"content": modules["module_dynamic"]["desc"]["text"],
108+
}
116109
)
110+
111+
@staticmethod
112+
def cleanup_item(item: dict) -> dict:
113+
try:
114+
del item["basic"]
115+
del item["modules"]["module_author"]["avatar"]
116+
del item["modules"]["module_more"]
117+
except KeyError:
118+
pass
119+
return item

nazurin/sites/bilibili/config.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@
77
with env.prefixed("FILE_"):
88
DESTINATION: str = env.str("PATH", default="Bilibili")
99
FILENAME: str = env.str(
10-
"NAME", default="{dynamic_id_str}_{index} - {user[name]}({user[uid]})"
10+
"NAME", default="{id_str}_{index} - {user[name]}({user[mid]})"
1111
)

nazurin/sites/bilibili/interface.py

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
r"t\.bilibili\.com/(\d+)",
1212
# https://t.bilibili.com/h5/dynamic/detail/123456789012345678
1313
r"t\.bilibili\.com/h5/dynamic/detail/(\d+)",
14+
# https://www.bilibili.com/opus/123456789012345678
15+
r"bilibili\.com/opus/(\d+)",
1416
]
1517

1618

0 commit comments

Comments
 (0)