qgyd2021 commited on
Commit
e73d172
·
1 Parent(s): f1deedf
data/porter_tasks/porter_task_chenjieshen_douyin_video_to_bilibili.json CHANGED
@@ -31,6 +31,6 @@
31
  "target_user_id": "442286660",
32
  "key_of_credentials": "bilibili_chenjiesen_credentials",
33
  "remove_after_upload": true,
34
- "min_date2": "2025-09-09 00:00:00"
35
  }
36
  ]
 
31
  "target_user_id": "442286660",
32
  "key_of_credentials": "bilibili_chenjiesen_credentials",
33
  "remove_after_upload": true,
34
+ "min_date": "2025-09-09 00:00:00"
35
  }
36
  ]
toolbox/bilibili/video/video_manager.py CHANGED
@@ -2,9 +2,7 @@
2
  # -*- coding: utf-8 -*-
3
  """
4
  https://pypi.org/project/biliupload/
5
-
6
  https://github.com/SocialSisterYi/bilibili-API-collect
7
-
8
  """
9
  import argparse
10
  import logging
@@ -31,19 +29,6 @@ class BilibiliVideoUploader(BilibiliClient):
31
  before_sleep=before_sleep_log(logger, logging.ERROR),
32
  )
33
  def preupload(self, filename, filesize):
34
- """
35
- The preupload process to get `upos_uri` and `auth` information.
36
-
37
- [Easter egg] Sometimes I'm also confused why it is called `upos`
38
- So I ask a question on the V2EX: https://v2ex.com/t/1103152
39
- Finally, the netizens reckon that may be the translation style of bilibili.
40
- :param filename: str, the name of the video to be uploaded
41
- :param filesize: str, the size of the video to be uploaded
42
- :param biz_id: int, the business id
43
- :return:
44
- upos_uri, str, the uri of the video will be stored in server
45
- auth, str, the auth information
46
- """
47
  url = "https://member.bilibili.com/preupload"
48
  params = {
49
  "name": filename,
@@ -76,12 +61,6 @@ class BilibiliVideoUploader(BilibiliClient):
76
  before_sleep=before_sleep_log(logger, logging.ERROR),
77
  )
78
  def get_upload_video_id(self, *, upos_uri, auth):
79
- """
80
- Get the `upload_id` of video.
81
- :param upos_uri: str, get from `preupload`
82
- :param auth: str, get from `preupload`
83
- :return: upload_id, str, the id of the video to be uploaded
84
- """
85
  url = f"https://upos-sz-upcdnbda2.bilivideo.com/{upos_uri}?uploads&output=json"
86
  response = self.session.post(
87
  url,
@@ -189,7 +168,6 @@ class BilibiliVideoUploader(BilibiliClient):
189
  def publish_video(self, bilibili_filename, metadata: dict):
190
  """
191
  publish the uploaded video
192
-
193
  https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/creativecenter/upload.md
194
  :param bilibili_filename:
195
  :param metadata:
 
2
  # -*- coding: utf-8 -*-
3
  """
4
  https://pypi.org/project/biliupload/
 
5
  https://github.com/SocialSisterYi/bilibili-API-collect
 
6
  """
7
  import argparse
8
  import logging
 
29
  before_sleep=before_sleep_log(logger, logging.ERROR),
30
  )
31
  def preupload(self, filename, filesize):
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  url = "https://member.bilibili.com/preupload"
33
  params = {
34
  "name": filename,
 
61
  before_sleep=before_sleep_log(logger, logging.ERROR),
62
  )
63
  def get_upload_video_id(self, *, upos_uri, auth):
 
 
 
 
 
 
64
  url = f"https://upos-sz-upcdnbda2.bilivideo.com/{upos_uri}?uploads&output=json"
65
  response = self.session.post(
66
  url,
 
168
  def publish_video(self, bilibili_filename, metadata: dict):
169
  """
170
  publish the uploaded video
 
171
  https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/creativecenter/upload.md
172
  :param bilibili_filename:
173
  :param metadata:
toolbox/bilibili/video/video_manager2.py ADDED
@@ -0,0 +1,475 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ https://pypi.org/project/biliupload/
5
+
6
+ https://github.com/SocialSisterYi/bilibili-API-collect
7
+
8
+ """
9
+ import argparse
10
+ import json
11
+ import logging
12
+ import math
13
+ from pathlib import Path
14
+ import re
15
+
16
+ logger = logging.getLogger("toolbox")
17
+
18
+ from tenacity import before_sleep_log, retry, retry_if_exception_type, stop_after_attempt, wait_fixed
19
+ from tqdm import tqdm
20
+
21
+ from project_settings import project_path
22
+ from toolbox.bilibili.bilibili_client import BilibiliClient
23
+
24
+
25
+ class BilibiliVideoUploader(BilibiliClient):
26
+ def __init__(self):
27
+ super().__init__()
28
+
29
+ @retry(
30
+ wait=wait_fixed(10),
31
+ stop=stop_after_attempt(3),
32
+ before_sleep=before_sleep_log(logger, logging.ERROR),
33
+ )
34
+ def preupload_mp4(self, filename, filesize):
35
+ """
36
+ The preupload process to get `upos_uri` and `auth` information.
37
+
38
+ [Easter egg] Sometimes I'm also confused why it is called `upos`
39
+ So I ask a question on the V2EX: https://v2ex.com/t/1103152
40
+ Finally, the netizens reckon that may be the translation style of bilibili.
41
+ :param filename: str, the name of the video to be uploaded
42
+ :param filesize: str, the size of the video to be uploaded
43
+ :param biz_id: int, the business id
44
+ :return:
45
+ upos_uri, str, the uri of the video will be stored in server
46
+ auth, str, the auth information
47
+ """
48
+ url = "https://member.bilibili.com/preupload"
49
+ params = {
50
+ "probe_version": "20221109",
51
+ "upcdn": "bldsa",
52
+ "zone": "cs",
53
+ "name": filename,
54
+ "r": "upos",
55
+ "profile": "ugcfx/bup",
56
+ "ssl": 0,
57
+ "version": "2.14.0.0",
58
+ "build": "2140000",
59
+ "size": filesize,
60
+ }
61
+ # params = {
62
+ # "name": filename,
63
+ # "size": filesize,
64
+ # # The parameters below are fixed
65
+ # "r": "upos",
66
+ # "profile": "ugcupos/bup",
67
+ # "ssl": 0,
68
+ # "version": "2.8.9",
69
+ # "build": "2080900",
70
+ # "upcdn": "bda2",
71
+ # "probe_version": "20200810"
72
+ # }
73
+ response = self.session.get(
74
+ url,
75
+ params=params,
76
+ headers={"TE": "Trailers"}
77
+ )
78
+
79
+ if response.status_code != 200:
80
+ raise AssertionError(f"request failed; status_code: {response.status_code}, text: {response.text}")
81
+ js = response.json()
82
+ if js["OK"] != 1:
83
+ raise AssertionError(f"request failed;")
84
+ return js
85
+
86
+ @retry(
87
+ wait=wait_fixed(10),
88
+ stop=stop_after_attempt(3),
89
+ before_sleep=before_sleep_log(logger, logging.ERROR),
90
+ )
91
+ def preupload_txt(self, filename, filesize):
92
+ """
93
+ The preupload process to get `upos_uri` and `auth` information.
94
+
95
+ [Easter egg] Sometimes I'm also confused why it is called `upos`
96
+ So I ask a question on the V2EX: https://v2ex.com/t/1103152
97
+ Finally, the netizens reckon that may be the translation style of bilibili.
98
+ :param filename: str, the name of the video to be uploaded
99
+ :param filesize: str, the size of the video to be uploaded
100
+ :param biz_id: int, the business id
101
+ :return:
102
+ upos_uri, str, the uri of the video will be stored in server
103
+ auth, str, the auth information
104
+ """
105
+ url = "https://member.bilibili.com/preupload"
106
+ params = {
107
+ "name": "file_meta.txt",
108
+ "size": 2000,
109
+ "r": "upos",
110
+ "profile": "fxmeta/bup",
111
+ "ssl": 0,
112
+ "version": "2.14.0.0",
113
+ "build": "2140000",
114
+ "webVersion": "2.14.0",
115
+ }
116
+ response = self.session.get(
117
+ url,
118
+ params=params,
119
+ headers=self.headers,
120
+ )
121
+ if response.status_code != 200:
122
+ raise AssertionError(f"request failed; status_code: {response.status_code}, text: {response.text}")
123
+ js = response.json()
124
+ if js["OK"] != 1:
125
+ raise AssertionError(f"request failed;")
126
+ return js
127
+
128
+ @retry(
129
+ wait=wait_fixed(10),
130
+ stop=stop_after_attempt(3),
131
+ before_sleep=before_sleep_log(logger, logging.ERROR),
132
+ )
133
+ def get_upload_video_id(self, *, endpoint, upos_uri, auth,
134
+ filesize, chunk_size, biz_id,
135
+ # txt_upos_uri
136
+ ):
137
+ # endpoint = "//upos-sz-upcdnbda2.bilivideo.com"
138
+ url = f"https:{endpoint}/{upos_uri}?uploads&output=json&"
139
+ # url = f"https://upos-sz-upcdnbda2.bilivideo.com/{upos_uri}?uploads&output=json"
140
+
141
+ params = {
142
+ "profile": "ugcfx/bup",
143
+ "filesize": filesize,
144
+ "partsize": chunk_size,
145
+ "biz_id": biz_id,
146
+ # "meta_upos_uri": txt_upos_uri,
147
+
148
+ }
149
+ response = self.session.post(
150
+ url,
151
+ headers={"X-Upos-Auth": auth},
152
+ params=params,
153
+ )
154
+ if response.status_code != 200:
155
+ raise AssertionError(f"request failed; status_code: {response.status_code}, text: {response.text}")
156
+ js = response.json()
157
+ if js["OK"] != 1:
158
+ raise AssertionError(f"request failed;")
159
+ return js
160
+
161
+ def upload_video_in_chunks(self, *, endpoint, upos_uri, auth, upload_id, fileio, filesize, chunk_size, chunks):
162
+ """
163
+ Upload the video in chunks.
164
+ :param upos_uri: str, get from `preupload`
165
+ :param auth: str, get from `preupload`
166
+ :param upload_id: str, get from `get_upload_video_id`
167
+ :param fileio: io.BufferedReader, the io stream of the video to be uploaded
168
+ :param filesize: int, the size of the video to be uploaded
169
+ :param chunk_size: int, the size of each chunk to be uploaded
170
+ :param chunks: int, the number of chunks to be uploaded
171
+ :return:
172
+ """
173
+ # endpoint = "//upos-sz-upcdnbda2.bilivideo.com"
174
+ url = f"https:{endpoint}/{upos_uri}"
175
+
176
+ params = {
177
+ "partNumber": None, # start from 1
178
+ "uploadId": upload_id,
179
+ "chunk": None, # start from 0
180
+ "chunks": chunks,
181
+ "size": None, # current batch size
182
+ "start": None,
183
+ "end": None,
184
+ "total": filesize,
185
+ }
186
+ process_bar = tqdm(desc="bilibili_upload_video", total=chunks)
187
+ for chunknum in range(chunks):
188
+ start = fileio.tell()
189
+ batchbytes = fileio.read(chunk_size)
190
+ params["partNumber"] = chunknum + 1
191
+ params["chunk"] = chunknum
192
+ params["size"] = len(batchbytes)
193
+ params["start"] = start
194
+ params["end"] = fileio.tell()
195
+ response = self.session.options(
196
+ url,
197
+ params=params,
198
+ data=batchbytes,
199
+ headers={"X-Upos-Auth": auth}
200
+ )
201
+ if response.status_code != 200:
202
+ raise AssertionError(f"request failed; status_code: {response.status_code}, text: {response.text}")
203
+ process_bar.update(1)
204
+
205
+ @retry(
206
+ wait=wait_fixed(10),
207
+ stop=stop_after_attempt(3),
208
+ before_sleep=before_sleep_log(logger, logging.ERROR),
209
+ )
210
+ def finish_upload(self, *, endpoint, upos_uri, auth, filename, upload_id, biz_id, chunks):
211
+ # endpoint = "//upos-sz-upcdnbda2.bilivideo.com"
212
+ url = f"https:{endpoint}/{upos_uri}"
213
+
214
+ params = {
215
+ "output": "json",
216
+ "name": filename,
217
+ "profile" : "ugcfx/bup",
218
+ "uploadId": upload_id,
219
+ "biz_id": biz_id
220
+ }
221
+ print(params)
222
+ data = {
223
+ "parts": [
224
+ {"partNumber": i+1, "eTag": "etag"}
225
+ for i in range(chunks)
226
+ ]
227
+ }
228
+ print(data)
229
+ response = self.session.post(
230
+ url,
231
+ params=params,
232
+ data=json.dumps(data),
233
+ headers={
234
+ "X-Upos-Auth": auth,
235
+ "Content-Type": "application/json",
236
+ "referer": "https://member.bilibili.com/",
237
+ "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36"
238
+ }
239
+ )
240
+ if response.status_code != 200:
241
+ raise AssertionError(f"request failed; status_code: {response.status_code}, text: {response.text}")
242
+ js = response.json()
243
+ if js["OK"] != 1:
244
+ raise AssertionError(f"request failed;")
245
+ return js
246
+
247
+ @retry(
248
+ wait=wait_fixed(10),
249
+ stop=stop_after_attempt(3),
250
+ before_sleep=before_sleep_log(logger, logging.ERROR),
251
+ )
252
+ def publish_video(self, bilibili_filename, metadata: dict):
253
+ """
254
+ publish the uploaded video
255
+
256
+ https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/creativecenter/upload.md
257
+ :param bilibili_filename:
258
+ :param metadata:
259
+ :return:
260
+ """
261
+ url = f'https://member.bilibili.com/x/vu/web/add?csrf={self.cookies["bili_jct"]}'
262
+
263
+ data = {
264
+ "copyright": metadata["copyright"],
265
+ "videos": [
266
+ {
267
+ "filename": bilibili_filename,
268
+ "title": metadata["title"],
269
+ "desc": metadata["desc"]
270
+ }
271
+ ],
272
+ "source": metadata["source"],
273
+ "tid": metadata["tid"],
274
+ "title": metadata["title"],
275
+ "cover": metadata["cover"],
276
+ "tag": metadata["tag"],
277
+ "desc_format_id": 0,
278
+ "desc": metadata["desc"],
279
+ "dynamic": metadata["dynamic"],
280
+ "subtitle": {"open": 0, "lan": ""},
281
+
282
+ }
283
+
284
+ if metadata["copyright"] != 2:
285
+ del data["source"]
286
+ # copyright: 1 original 2 reprint
287
+ data["copyright"] = 1
288
+
289
+ response = self.session.post(
290
+ url,
291
+ json=data,
292
+ headers={"TE": "Trailers"}
293
+ )
294
+ if response.status_code != 200:
295
+ raise AssertionError(f"request failed; status_code: {response.status_code}, text: {response.text}")
296
+ js = response.json()
297
+ return js
298
+
299
+ def upload_video_file(self, filename):
300
+ filename = Path(filename)
301
+ filesize = filename.stat().st_size
302
+
303
+ js = self.preupload_mp4(filename=filename, filesize=filesize)
304
+ endpoint = js["endpoint"]
305
+ upos_uri = js["upos_uri"].split("//")[-1]
306
+ auth = js["auth"]
307
+ biz_id = js["biz_id"]
308
+ chunk_size = js["chunk_size"]
309
+ chunks = math.ceil(filesize / chunk_size)
310
+
311
+ # js = self.preupload_txt(filename=filename, filesize=filesize)
312
+ # endpoint = js["endpoint"]
313
+ # txt_upos_uri = js["upos_uri"]
314
+ # auth = js["auth"]
315
+ # biz_id = js["biz_id"]
316
+ # chunk_size = js["chunk_size"]
317
+ # chunks = math.ceil(filesize / chunk_size)
318
+
319
+ upload_video_id_response = self.get_upload_video_id(
320
+ endpoint=endpoint,
321
+ upos_uri=upos_uri,
322
+ auth=auth,
323
+ filesize=filesize,
324
+ chunk_size=chunk_size,
325
+ biz_id=biz_id,
326
+ # txt_upos_uri=txt_upos_uri,
327
+
328
+ )
329
+ upload_id = upload_video_id_response["upload_id"]
330
+ key = upload_video_id_response["key"]
331
+
332
+ bilibili_filename = re.search(r"/(.*)\.", key).group(1)
333
+ fileio = filename.open(mode="rb")
334
+ self.upload_video_in_chunks(
335
+ endpoint=endpoint,
336
+ upos_uri=upos_uri,
337
+ auth=auth,
338
+ upload_id=upload_id,
339
+ fileio=fileio,
340
+ filesize=filesize,
341
+ chunk_size=chunk_size,
342
+ chunks=chunks
343
+ )
344
+ fileio.close()
345
+
346
+ # notify the all chunks have been uploaded
347
+ self.finish_upload(
348
+ endpoint=endpoint,
349
+ upos_uri=upos_uri, auth=auth, filename=filename.name,
350
+ upload_id=upload_id, biz_id=biz_id, chunks=chunks
351
+ )
352
+
353
+ return biz_id, upload_id, bilibili_filename
354
+
355
+ def upload_video_and_publish(self, filename: str, metadata: dict):
356
+ _, upload_id, bilibili_filename = self.upload_video_file(filename)
357
+ logger.info(f"finish uploading, upload_id: {upload_id}, bilibili_filename: {bilibili_filename}, filename: {filename}")
358
+ tid = self.predict_tid(
359
+ title=metadata["title"],
360
+ upload_id=upload_id,
361
+ bilibili_filename=bilibili_filename,
362
+ )
363
+ metadata["tid"] = tid
364
+ logger.info(f"predict tid, tid: {tid}, filename: {filename}")
365
+ publish_video_response = self.publish_video(bilibili_filename=bilibili_filename, metadata=metadata)
366
+
367
+ bvid = None
368
+ status_code = publish_video_response["code"]
369
+ if status_code == 137022:
370
+ message = publish_video_response["message"]
371
+ logger.info(f"publish_video failed; code: {status_code}, message: {message}")
372
+ else:
373
+ bvid = publish_video_response["data"]["bvid"]
374
+ return bvid
375
+
376
+ @retry(
377
+ wait=wait_fixed(10),
378
+ stop=stop_after_attempt(3),
379
+ before_sleep=before_sleep_log(logger, logging.ERROR),
380
+ )
381
+ def predict_tid(self, title: str, upload_id: str, bilibili_filename: str):
382
+ csrf = self.cookies["bili_jct"]
383
+ url = f"https://member.bilibili.com/x/vupre/web/archive/types/predict"
384
+ params = {
385
+ "csrf": csrf,
386
+ }
387
+ data = {
388
+ "title": title,
389
+ "upload_id": upload_id,
390
+ "filename": bilibili_filename,
391
+ }
392
+ response = self.session.post(
393
+ url,
394
+ params=params,
395
+ json=data,
396
+ headers=self.headers,
397
+ )
398
+ if response.status_code != 200:
399
+ raise AssertionError(f"request failed; status_code: {response.status_code}, text: {response.text}")
400
+ js = response.json()
401
+ return js
402
+
403
+
404
+ def get_args():
405
+ parser = argparse.ArgumentParser()
406
+ parser.add_argument(
407
+ "--key_of_credentials",
408
+ default="bilibili_chenjiesen_credentials",
409
+ type=str
410
+ )
411
+ parser.add_argument(
412
+ "--filename",
413
+ default=(project_path / "data/tasks/chenjieshen_douyin_video_to_bilibili/video/douyin/陈杰森/7548332163859533083_20250910T170000_千万不要帮朋友担保!否则你可能背上一身债!.mp4").as_posix(),
414
+ type=str
415
+ )
416
+ args = parser.parse_args()
417
+ return args
418
+
419
+
420
+ def main():
421
+ import log
422
+ from project_settings import project_path, log_directory, environment
423
+
424
+ log.setup_size_rotating(log_directory=log_directory)
425
+
426
+ args = get_args()
427
+
428
+ client = BilibiliVideoUploader()
429
+
430
+ flag = client.check_login()
431
+ print(f"flag: {flag}")
432
+ credentials = environment.get(args.key_of_credentials, dtype=json.loads)
433
+ client.login_with_credentials_info(credentials)
434
+ flag = client.check_login()
435
+ print(f"flag: {flag}")
436
+
437
+ tags = [
438
+ "阅兵",
439
+ "商机",
440
+ "干货分享",
441
+ "金融",
442
+ "商业"
443
+ ]
444
+ metadata = {
445
+ "title": "九三阅兵的意义有多重大。 为什么说这次阅兵是“雷军式BOSS直销”?来的是客户,更是未来的“合伙人”!",
446
+ "desc": "九三阅兵的意义有多重大。 为什么说这次阅兵是“雷军式BOSS直销”?来的是客户,更是未来的“合伙人”!#阅兵 #金融 #商业 #商机 #干货分享",
447
+ "tag": ",".join(tags),
448
+
449
+ "copyright": 1,
450
+ "source": None,
451
+ "tid": 138,
452
+ "cover": "",
453
+ "dynamic": "",
454
+ }
455
+
456
+ bvid = client.upload_video_and_publish(
457
+ filename=args.filename,
458
+ metadata={
459
+ "title": "九三阅兵的意义有多重大。 为什么说这次阅兵是“雷军式BOSS直销”?来的是客户,更是未来的“合伙人”!",
460
+ "desc": "九三阅兵的意义有多重大。 为什么说这次阅兵是“雷军式BOSS直销”?来的是客户,更是未来的“合伙人”!#阅兵 #金融 #商业 #商机 #干货分享",
461
+ "tag": ",".join(tags),
462
+
463
+ "copyright": 1,
464
+ "source": None,
465
+ "tid": 138,
466
+ "cover": "",
467
+ "dynamic": "",
468
+ }
469
+ )
470
+ print(f"bvid: {bvid}")
471
+ return
472
+
473
+
474
+ if __name__ == "__main__":
475
+ main()