HoneyTian commited on
Commit
3e3e219
·
1 Parent(s): 21d84e1
toolbox/bilibili/bilibili_client.py CHANGED
@@ -14,17 +14,17 @@ import subprocess
14
  import time
15
  from urllib.parse import urlencode, urlparse
16
 
 
 
17
  import qrcode
18
  import requests
19
  import requests.utils
 
20
 
21
  from project_settings import project_path
22
  from toolbox.design_patterns.singleton import ParamsSingleton
23
 
24
 
25
- logger = logging.getLogger("toolbox")
26
-
27
-
28
  class BilibiliUtils(object):
29
  app_key = "4409e2ce8ffd12b8"
30
  app_sec = "59b43e04ad6965f34319062b478f83dd"
@@ -167,6 +167,11 @@ class BilibiliClient(BilibiliUtils, ParamsSingleton):
167
  logger.error(f"Check failed, please check the info; status_code: {response.status_code}, text: {response.text}")
168
  return False
169
 
 
 
 
 
 
170
  def get_now(self):
171
  url = "https://api.bilibili.com/x/report/click/now"
172
 
@@ -179,6 +184,11 @@ class BilibiliClient(BilibiliUtils, ParamsSingleton):
179
  js = response.json()
180
  return js
181
 
 
 
 
 
 
182
  def get_version(self):
183
  url = "https://api.live.bilibili.com/xlive/app-blink/v1/liveVersionInfo/getHomePageLiveVersion"
184
 
 
14
  import time
15
  from urllib.parse import urlencode, urlparse
16
 
17
+ logger = logging.getLogger("toolbox")
18
+
19
  import qrcode
20
  import requests
21
  import requests.utils
22
+ from tenacity import before_sleep_log, retry, retry_if_exception_type, stop_after_attempt, wait_fixed
23
 
24
  from project_settings import project_path
25
  from toolbox.design_patterns.singleton import ParamsSingleton
26
 
27
 
 
 
 
28
  class BilibiliUtils(object):
29
  app_key = "4409e2ce8ffd12b8"
30
  app_sec = "59b43e04ad6965f34319062b478f83dd"
 
167
  logger.error(f"Check failed, please check the info; status_code: {response.status_code}, text: {response.text}")
168
  return False
169
 
170
+ @retry(
171
+ wait=wait_fixed(10),
172
+ stop=stop_after_attempt(3),
173
+ before_sleep=before_sleep_log(logger, logging.ERROR),
174
+ )
175
  def get_now(self):
176
  url = "https://api.bilibili.com/x/report/click/now"
177
 
 
184
  js = response.json()
185
  return js
186
 
187
+ @retry(
188
+ wait=wait_fixed(10),
189
+ stop=stop_after_attempt(3),
190
+ before_sleep=before_sleep_log(logger, logging.ERROR),
191
+ )
192
  def get_version(self):
193
  url = "https://api.live.bilibili.com/xlive/app-blink/v1/liveVersionInfo/getHomePageLiveVersion"
194
 
toolbox/bilibili/live/live_manager.py CHANGED
@@ -8,16 +8,10 @@ https://github.com/ChaceQC/bilibili_live_stream_code/blob/master/main/bilibili_l
8
  """
9
  import argparse
10
  import logging
11
- import math
12
- from pathlib import Path
13
- import re
14
- import json
15
  import urllib
16
  import urllib.parse
17
  import hashlib
18
 
19
- import requests
20
- import requests.utils
21
  from tenacity import before_sleep_log, retry, retry_if_exception_type, stop_after_attempt, wait_fixed
22
 
23
  logger = logging.getLogger("toolbox")
@@ -26,22 +20,6 @@ from project_settings import project_path
26
  from toolbox.bilibili.bilibili_client import BilibiliClient
27
 
28
 
29
- def appsign(params, appkey, appsec):
30
- """
31
- 为请求参数进行app签名
32
- :param params: 原参数
33
- :param appkey: key
34
- :param appsec: key对应的secret
35
- :return:
36
- """
37
- params.update({'appkey': appkey})
38
- params = dict(sorted(params.items())) # 按照 key 重排参数
39
- query = urllib.parse.urlencode(params) # 序列化参数
40
- sign = hashlib.md5((query + appsec).encode()).hexdigest() # 计算 api 签名
41
- params.update({'sign': sign})
42
- return params
43
-
44
-
45
  class RtmpPublishCMD(object):
46
  def __init__(self, cmd_list: list, cmd_str: str):
47
  self.cmd_list = cmd_list
@@ -52,6 +30,11 @@ class BilibiliLiveManager(BilibiliClient):
52
  def __init__(self):
53
  super().__init__()
54
 
 
 
 
 
 
55
  def set_live_title(self, title: str):
56
  """
57
  :return
@@ -95,6 +78,11 @@ class BilibiliLiveManager(BilibiliClient):
95
  # print(json.dumps(js, ensure_ascii=False, indent=4))
96
  return js
97
 
 
 
 
 
 
98
  def get_room_id_by_uid(self):
99
  dede_user_id = self.cookies.get("DedeUserID")
100
 
@@ -280,6 +268,32 @@ class BilibiliLiveManager(BilibiliClient):
280
  js = response.json()
281
  return js
282
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
283
 
284
  def get_args():
285
  parser = argparse.ArgumentParser()
@@ -311,8 +325,9 @@ def main():
311
 
312
  # result = client.get_room_id()
313
  # result = client.stop_live()
314
- result = client.start_live_by_flv_file(args.room_id)
315
  # result = client.set_live_title("设置直播标题")
 
316
  print(result)
317
  return
318
 
 
8
  """
9
  import argparse
10
  import logging
 
 
 
 
11
  import urllib
12
  import urllib.parse
13
  import hashlib
14
 
 
 
15
  from tenacity import before_sleep_log, retry, retry_if_exception_type, stop_after_attempt, wait_fixed
16
 
17
  logger = logging.getLogger("toolbox")
 
20
  from toolbox.bilibili.bilibili_client import BilibiliClient
21
 
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  class RtmpPublishCMD(object):
24
  def __init__(self, cmd_list: list, cmd_str: str):
25
  self.cmd_list = cmd_list
 
30
  def __init__(self):
31
  super().__init__()
32
 
33
+ @retry(
34
+ wait=wait_fixed(10),
35
+ stop=stop_after_attempt(3),
36
+ before_sleep=before_sleep_log(logger, logging.ERROR),
37
+ )
38
  def set_live_title(self, title: str):
39
  """
40
  :return
 
78
  # print(json.dumps(js, ensure_ascii=False, indent=4))
79
  return js
80
 
81
+ @retry(
82
+ wait=wait_fixed(10),
83
+ stop=stop_after_attempt(3),
84
+ before_sleep=before_sleep_log(logger, logging.ERROR),
85
+ )
86
  def get_room_id_by_uid(self):
87
  dede_user_id = self.cookies.get("DedeUserID")
88
 
 
268
  js = response.json()
269
  return js
270
 
271
+ @retry(
272
+ wait=wait_fixed(10),
273
+ stop=stop_after_attempt(3),
274
+ before_sleep=before_sleep_log(logger, logging.ERROR),
275
+ )
276
+ def get_live_status(self):
277
+ js = self.get_room_id_by_uid()
278
+ room_id = js["data"]["room_id"]
279
+
280
+ url = f"https://api.live.bilibili.com/room/v1/Room/get_info?room_id={room_id}"
281
+
282
+ response = self.session.get(
283
+ url,
284
+ headers=self.headers,
285
+ )
286
+ if response.status_code != 200:
287
+ raise AssertionError(f"request failed; status_code: {response.status_code}, text: {response.text}")
288
+ js = response.json()
289
+ return js
290
+
291
+ def is_living(self):
292
+ js = self.get_live_status()
293
+ live_status = js["data"]["live_status"]
294
+ flag = live_status == 1
295
+ return flag
296
+
297
 
298
  def get_args():
299
  parser = argparse.ArgumentParser()
 
325
 
326
  # result = client.get_room_id()
327
  # result = client.stop_live()
328
+ # result = client.start_live_by_flv_file(args.room_id)
329
  # result = client.set_live_title("设置直播标题")
330
+ result = client.is_living()
331
  print(result)
332
  return
333
 
toolbox/bilibili/video/video_manager.py CHANGED
@@ -14,6 +14,8 @@ import re
14
 
15
  logger = logging.getLogger("toolbox")
16
 
 
 
17
  from project_settings import project_path
18
  from toolbox.bilibili.bilibili_client import BilibiliClient
19
 
@@ -22,6 +24,11 @@ class BilibiliVideoUploader(BilibiliClient):
22
  def __init__(self):
23
  super().__init__()
24
 
 
 
 
 
 
25
  def preupload(self, filename, filesize):
26
  """
27
  The preupload process to get `upos_uri` and `auth` information.
@@ -62,6 +69,11 @@ class BilibiliVideoUploader(BilibiliClient):
62
  raise AssertionError(f"request failed;")
63
  return js
64
 
 
 
 
 
 
65
  def get_upload_video_id(self, *, upos_uri, auth):
66
  """
67
  Get the `upload_id` of video.
@@ -120,10 +132,14 @@ class BilibiliVideoUploader(BilibiliClient):
120
  data=batchbytes,
121
  headers={"X-Upos-Auth": auth}
122
  )
123
- assert response.status_code == 200
124
- # logger.debug(f'Completed chunk{chunknum+1} uploading')
125
- # print(res)
126
 
 
 
 
 
 
127
  def finish_upload(self, *, upos_uri, auth, filename, upload_id, biz_id, chunks):
128
  """
129
  Notify the all chunks have been uploaded.
@@ -162,6 +178,11 @@ class BilibiliVideoUploader(BilibiliClient):
162
  raise AssertionError(f"request failed;")
163
  return js
164
 
 
 
 
 
 
165
  def publish_video(self, bilibili_filename, metadata: dict):
166
  """
167
  publish the uploaded video
 
14
 
15
  logger = logging.getLogger("toolbox")
16
 
17
+ from tenacity import before_sleep_log, retry, retry_if_exception_type, stop_after_attempt, wait_fixed
18
+
19
  from project_settings import project_path
20
  from toolbox.bilibili.bilibili_client import BilibiliClient
21
 
 
24
  def __init__(self):
25
  super().__init__()
26
 
27
+ @retry(
28
+ wait=wait_fixed(10),
29
+ stop=stop_after_attempt(3),
30
+ before_sleep=before_sleep_log(logger, logging.ERROR),
31
+ )
32
  def preupload(self, filename, filesize):
33
  """
34
  The preupload process to get `upos_uri` and `auth` information.
 
69
  raise AssertionError(f"request failed;")
70
  return js
71
 
72
+ @retry(
73
+ wait=wait_fixed(10),
74
+ stop=stop_after_attempt(3),
75
+ before_sleep=before_sleep_log(logger, logging.ERROR),
76
+ )
77
  def get_upload_video_id(self, *, upos_uri, auth):
78
  """
79
  Get the `upload_id` of video.
 
132
  data=batchbytes,
133
  headers={"X-Upos-Auth": auth}
134
  )
135
+ if response.status_code != 200:
136
+ raise AssertionError(f"request failed; status_code: {response.status_code}, text: {response.text}")
 
137
 
138
+ @retry(
139
+ wait=wait_fixed(10),
140
+ stop=stop_after_attempt(3),
141
+ before_sleep=before_sleep_log(logger, logging.ERROR),
142
+ )
143
  def finish_upload(self, *, upos_uri, auth, filename, upload_id, biz_id, chunks):
144
  """
145
  Notify the all chunks have been uploaded.
 
178
  raise AssertionError(f"request failed;")
179
  return js
180
 
181
+ @retry(
182
+ wait=wait_fixed(10),
183
+ stop=stop_after_attempt(3),
184
+ before_sleep=before_sleep_log(logger, logging.ERROR),
185
+ )
186
  def publish_video(self, bilibili_filename, metadata: dict):
187
  """
188
  publish the uploaded video
toolbox/douyin/homepage/follow.py CHANGED
@@ -16,7 +16,7 @@ class FollowManager(DouyinClient):
16
  def __init__(self):
17
  super().__init__()
18
 
19
- @async_cache_decorator(60)
20
  async def get_living_list(self):
21
  url = "https://www.douyin.com/webcast/web/feed/follow/"
22
 
 
16
  def __init__(self):
17
  super().__init__()
18
 
19
+ @async_cache_decorator(600)
20
  async def get_living_list(self):
21
  url = "https://www.douyin.com/webcast/web/feed/follow/"
22
 
toolbox/douyin/live/live_recording.py CHANGED
@@ -158,7 +158,7 @@ class LiveRecording(FollowManager):
158
  break
159
  return result
160
 
161
- @async_cache_decorator(60)
162
  async def get_live_info_by_follow(self, room_id: str):
163
  result = None
164
  live_info_list: List[dict] = await self.get_living_list()
 
158
  break
159
  return result
160
 
161
+ @async_cache_decorator(600)
162
  async def get_live_info_by_follow(self, room_id: str):
163
  result = None
164
  live_info_list: List[dict] = await self.get_living_list()
toolbox/douyin/video/download.py CHANGED
@@ -12,6 +12,7 @@ from tenacity import before_sleep_log, retry, retry_if_exception_type, stop_afte
12
  from project_settings import project_path
13
  from toolbox.douyin.douyin_client import DouyinClient
14
  from toolbox.exception import ExpectedError
 
15
 
16
  logger = logging.getLogger("toolbox")
17
 
@@ -48,11 +49,7 @@ class VideoDownload(DouyinClient):
48
  else:
49
  raise AssertionError(f"Got status code {response.status_code}")
50
 
51
- # @retry(
52
- # wait=wait_fixed(10),
53
- # stop=stop_after_attempt(3),
54
- # before_sleep=before_sleep_log(logger, logging.ERROR),
55
- # )
56
  async def get_video_list_by_user_id(self, sec_user_id: str, max_cursor: int = 0, count: int = 18):
57
  url = "https://www.douyin.com/aweme/v1/web/aweme/post/"
58
 
 
12
  from project_settings import project_path
13
  from toolbox.douyin.douyin_client import DouyinClient
14
  from toolbox.exception import ExpectedError
15
+ from toolbox.asyncio.cacheout import async_cache_decorator
16
 
17
  logger = logging.getLogger("toolbox")
18
 
 
49
  else:
50
  raise AssertionError(f"Got status code {response.status_code}")
51
 
52
+ @async_cache_decorator(600)
 
 
 
 
53
  async def get_video_list_by_user_id(self, sec_user_id: str, max_cursor: int = 0, count: int = 18):
54
  url = "https://www.douyin.com/aweme/v1/web/aweme/post/"
55
 
toolbox/porter/manager.py CHANGED
@@ -23,7 +23,7 @@ class PorterManager(object):
23
 
24
  if not enable:
25
  continue
26
- task_cls = BaseTask.by_name(task_type)
27
  task_obj = task_cls(**task)
28
 
29
  coro_task_set.add(task_obj.start())
 
23
 
24
  if not enable:
25
  continue
26
+ task_cls: BaseTask = BaseTask.by_name(task_type)
27
  task_obj = task_cls(**task)
28
 
29
  coro_task_set.add(task_obj.start())
toolbox/porter/tasks/douyin_live_to_bilibili_live_task.py CHANGED
@@ -162,14 +162,17 @@ class DouyinLiveToBilibiliLiveTask(BaseTask):
162
  input_source=live_url,
163
  do_copy=True
164
  )
165
- await asyncio.to_thread(
166
  self.blocking_stream, cmd
167
  )
168
- # 每次开直播后须暂停一段时间,以避免频繁操作。
169
- await asyncio.sleep(3600 * 1)
 
 
170
 
171
  def blocking_stream(self, cmd: RtmpPublishCMD):
172
- _ = self.bilibili_client.stop_live()
 
173
 
174
  logger.info(f"{self.flag}开始推流命令: \n{cmd.cmd_str}")
175
 
@@ -209,7 +212,7 @@ async def main():
209
 
210
  log.setup_size_rotating(log_directory=log_directory)
211
 
212
- task = DouyinLiveToBilibiliTask(
213
  room_name="清源第一帅",
214
  room_id="139751520143",
215
  check_interval=10,
 
162
  input_source=live_url,
163
  do_copy=True
164
  )
165
+ return_code = await asyncio.to_thread(
166
  self.blocking_stream, cmd
167
  )
168
+ if return_code != 0:
169
+ interval = self.check_interval * 360
170
+ logger.info(f"{self.flag}推流进程异常结束,sleep {interval}s 以避免频繁调用。")
171
+ await asyncio.sleep(interval)
172
 
173
  def blocking_stream(self, cmd: RtmpPublishCMD):
174
+ if self.bilibili_client.is_living():
175
+ _ = self.bilibili_client.stop_live()
176
 
177
  logger.info(f"{self.flag}开始推流命令: \n{cmd.cmd_str}")
178
 
 
212
 
213
  log.setup_size_rotating(log_directory=log_directory)
214
 
215
+ task = DouyinLiveToBilibiliLiveTask(
216
  room_name="清源第一帅",
217
  room_id="139751520143",
218
  check_interval=10,