diff --git a/Common.py b/Common.py index 265d968..6f11bd6 100644 --- a/Common.py +++ b/Common.py @@ -255,7 +255,6 @@ def appendError(obj): class downloader(XiGuaLiveApi): - files = [] playlist = None def updRoomInfo(self): @@ -270,18 +269,20 @@ class downloader(XiGuaLiveApi): forceNotDownload = False forceNotBroadcasting = False self.playlist = False - self.files = [] def updPlayList(self): global streamUrl if self.isLive: if "stream_url" in self._rawRoomInfo: if self.playlist is None: - self.playlist = False + self.playlist = None else: self.playlist = self._rawRoomInfo["stream_url"]["flv_pull_url"] self.playlist = self.playlist.replace("_uhd", "").replace("_sd", "").replace("_ld", "") streamUrl = self.playlist + else: + streamUrl = None + self.playlist = None def onLike(self, user): pass diff --git a/api.py b/api.py index d644e5f..4f1163d 100644 --- a/api.py +++ b/api.py @@ -32,11 +32,11 @@ class XiGuaLiveApi: self.name = name self.updRoomInfo() - def _updateRoomInfo(self, json): + def _updateRoomPopularity(self, json): """ 更新房间人气的方法 Update Room Popularity - :param json: Recived Message + :param json: Received Message """ if "extra" in json: if "member_count" in json["extra"] and json["extra"]["member_count"] > 0: @@ -60,7 +60,7 @@ class XiGuaLiveApi: """ 礼物连击中的消息 Message On Sending Presents - :param gift: Struct of Gift Messsage + :param gift: Struct of Gift Message """ print("礼物连击 :", gift) @@ -68,14 +68,14 @@ class XiGuaLiveApi: """ 礼物送完了的提示信息 Message On Finished Send Present - :param gift: Struct of Gift Messsage + :param gift: Struct of Gift Message """ print("感谢", gift) def onAd(self, i): """ 全局广播 - All Channel Boardcasting Message( Just An Ad ) + All Channel Broadcasting Message( Just An Ad ) :param i: JSON DATA if you wanna using it """ # print(i) @@ -85,7 +85,7 @@ class XiGuaLiveApi: """ 聊天信息 On Chatting - :param chat: Struct of Chat Messsage + :param chat: Struct of Chat Message """ if not chat.isFiltered: print(chat) @@ -94,7 +94,7 @@ class XiGuaLiveApi: """ 进入房间消息 On Entering Room - :param msg: Struct of Member Messsage + :param msg: Struct of Member Message """ print("提示 :", msg) @@ -102,7 +102,7 @@ class XiGuaLiveApi: """ 关注主播时的消息 On Subscribe - :param user: Struct of User Messsage + :param user: Struct of User Message """ print("消息 :", user, "关注了主播") @@ -131,80 +131,93 @@ class XiGuaLiveApi: """ print("中奖消息 :", i) + def _checkUsernameIsMatched(self): + """ + 验证主播名字是自己想要的那个 + :return: bool: 是否匹配 + """ + if self.name is None or self.roomLiver is None: + return False + #验证主播名字是自己想要的那个 + return True + + def _forceSearchUser(self): + """ + 搜索主播名 + :return: + """ + try: + p = s.get("https://security.snssdk.com/video/app/search/live/?version_code=730&device_platform=android" + "&format=json&keyword={}".format(self.name)) + d = p.json() + except json.decoder.JSONDecodeError as e: + self.apiChangedError("搜索接口错误", e.__str__()) + return + if "data" in d and d["data"] is not None: + for i in d["data"]: + if i["block_type"] != 0: + continue + if "cells" not in i or len(i["cells"]) == 0: + return + self.isValidRoom = True + if "is_living" in i["cells"][0]["anchor"]["user_info"]: + self.isLive = i["cells"][0]["anchor"]["user_info"]["is_living"] + else: + self.isLive = False + if "room_id" in i["cells"][0]["anchor"]: + self.roomID = int(i["cells"][0]["anchor"]["room_id"]) + else: + self.isLive = False + self.roomLiver = User(i["cells"][0]) + if self.isLive: + return self.updRoomInfo() + else: + return False + + def _updateRoomOnly(self): + """ + 仅更新房间,不重新获取信息 + :return: + """ + try: + p = s.post("https://i.snssdk.com/videolive/room/enter?version_code=730" + "&device_platform=android", + data="room_id={roomID}&version_code=730" + "&device_platform=android".format(roomID=self.roomID), + headers={"Content-Type": "application/x-www-form-urlencoded"}) + d = p.json() + except Exception as e: + self.apiChangedError("更新房间接口错误", e.__str__()) + return False + self.isValidRoom = d["base_resp"]["status_code"] == 0 + if d["base_resp"]["status_code"] != 0: + self.apiChangedError("更新房间信息接口返回非0状态值", d) + return False + if "room" not in d and d["room"] is None: + self.apiChangedError("Api发生改变,请及时联系我", d) + return False + self.roomLiver = User(d) + if not self._checkUsernameIsMatched(): + self.isLive = False + return False + self._rawRoomInfo = d["room"] + self.isLive = d["room"]["status"] == 2 + self.roomTitle = d["room"]["title"] + self.roomPopularity = d["room"]["user_count"] + l = Lottery(d) + if l.isActive: + self.lottery = l + return True + def updRoomInfo(self): """ 更新房间信息(可能写的很垃圾) :return: """ if self.isLive: - try: - p = s.post("https://i.snssdk.com/videolive/room/enter?version_code=730" - "&device_platform=android", - data="room_id={roomID}&version_code=730" - "&device_platform=android".format(roomID=self.roomID), - headers={"Content-Type":"application/x-www-form-urlencoded"}) - d = p.json() - except Exception as e: - if DEBUG: - print("ReqError@UpdRoomInfo") - print(e.__str__()) - if p: - print(p.status_code) - print(p.text) - return False - self.isValidRoom = d["base_resp"]["status_code"] == 0 - if d["base_resp"]["status_code"] != 0: - if DEBUG: - print("CodeIsnot0@UpdRoomInfo") - print(d) - return False - if "room" not in d and d["room"] is None: - self.apiChangedError("Api发生改变,请及时联系我", d) - return False - self.roomLiver = User(d) - if self.name not in str(self.roomLiver): - self.isLive = False - return False - self._rawRoomInfo = d["room"] - self.isLive = d["room"]["status"] == 2 - self.roomTitle = d["room"]["title"] - self.roomPopularity = d["room"]["user_count"] - l = Lottery(d) - if l.isActive: - self.lottery = l - return True + return self._updateRoomOnly() else: - try: - p = s.get("https://security.snssdk.com/video/app/search/live/?version_code=730&device_platform=android" - "&format=json&keyword={}".format(self.name)) - d = p.json() - except json.decoder.JSONDecodeError as e: - if DEBUG: - print(e.__str__()) - if p: - print(p.status_code) - print(p.text) - return - if "data" in d and d["data"] is not None: - for i in d["data"]: - if i["block_type"] != 0: - continue - if "cells" not in i or len(i["cells"]) == 0: - return - self.isValidRoom = True - if "is_living" in i["cells"][0]["anchor"]["user_info"]: - self.isLive = i["cells"][0]["anchor"]["user_info"]["is_living"] - else: - self.isLive = False - if "room_id" in i["cells"][0]["anchor"]: - self.roomID = int(i["cells"][0]["anchor"]["room_id"]) - else: - self.isLive = False - self.roomLiver = User(i["cells"][0]) - if self.isLive: - return self.updRoomInfo() - else: - return False + return self._forceSearchUser() @staticmethod def findRoomByUserId(userId:int): @@ -281,8 +294,8 @@ class XiGuaLiveApi: elif i["common"]['method'] == "VideoLiveChatMessage": self.onChat(Chat(i, self.lottery)) elif i["common"]['method'] == "VideoLiveMemberMessage": - self._updateRoomInfo(i) self.onEnter(MemberMsg(i)) + self._updateRoomPopularity(i) elif i["common"]['method'] == "VideoLiveSocialMessage": self.onSubscribe(User(i)) elif i["common"]['method'] == "VideoLiveJoinDiscipulusMessage": diff --git a/liveDownloader.py b/liveDownloader.py index ff6a461..d5fd125 100644 --- a/liveDownloader.py +++ b/liveDownloader.py @@ -12,42 +12,43 @@ isEncode = False isDownload = False -def download(url): +def download(): global isDownload - path = datetime.strftime(datetime.now(), "%Y%m%d_%H%M.flv") - p = requests.get(url, stream=True) - if p.status_code != 200: - Common.appendDownloadStatus("Download with Response 404, maybe broadcaster is not broadcasting") - return True - isDownload = True - Common.appendDownloadStatus("Download >{}< Start".format(path)) - f = open(path, "wb") - try: - for t in p.iter_content(chunk_size=64 * 1024): - if t: + while Common.api.isLive and not Common.forceNotDownload: + if not Common.streamUrl: + Common.appendError("Download with No StreamUrl Specific") + break + path = datetime.strftime(datetime.now(), "%Y%m%d_%H%M.flv") + p = requests.get(Common.streamUrl, stream=True) + if p.status_code != 200: + Common.appendDownloadStatus("Download with Response {}".format(p.status_code)) + break + isDownload = True + Common.appendDownloadStatus("Download >{}< Start".format(path)) + f = open(path, "wb") + try: + _size = 0 + for t in p.iter_content(chunk_size=64 * 1024): + if Common.forceNotDownload: + Common.modifyLastDownloadStatus("Force Stop Download".format(path)) + return f.write(t) - else: - raise Exception("`t` is not valid") - _size = os.path.getsize(path) - Common.modifyLastDownloadStatus("Downloading >{}< @ {:.2f}%".format(path, 100.0 * _size/Common.config["p_s"])) - if _size > Common.config["p_s"] or Common.forceNotDownload: - Common.modifyLastDownloadStatus("Download >{}< Exceed MaxSize".format(path)) - break - except Exception as e: - Common.appendError("Download >{}< With Exception {}".format(path, e.__str__())) - f.close() - isDownload = False - Common.modifyLastDownloadStatus("Download >{}< Finished".format(path)) - if os.path.getsize(path) < 1024 * 1024: - Common.modifyLastDownloadStatus("Downloaded File >{}< is too small, will ignore it".format(path)) - os.remove(path) - return False - if Common.forceNotDownload: - Common.modifyLastDownloadStatus("设置了不下载,所以[{}]不会下载".format(path)) - return - else: + _size += len(t) + Common.modifyLastDownloadStatus("Downloading >{}< @ {:.2f}%".format(path, 100.0 * _size/Common.config["p_s"])) + if _size > Common.config["p_s"]: + Common.modifyLastDownloadStatus("Download >{}< Exceed MaxSize".format(path)) + break + Common.modifyLastDownloadStatus("Download >{}< Finished".format(path)) + except Exception as e: + Common.appendError("Download >{}< With Exception {}".format(path, e.__str__())) + f.close() + isDownload = False + if os.path.getsize(path) < 1024 * 1024: + Common.modifyLastDownloadStatus("Downloaded File >{}< is too small, will ignore it".format(path)) + os.remove(path) + return False Common.encodeQueue.put(path) - download(url) + Common.api.updRoomInfo() def encode(): @@ -106,52 +107,58 @@ def upload(date=datetime.strftime(datetime.now(), "%Y_%m_%d")): b = Bilibili() b.login(Common.config["b_u"], Common.config["b_p"]) - +t = threading.Thread(target=download, args=()) +ut = threading.Thread(target=upload, args=()) et = threading.Thread(target=encode, args=()) -et.setDaemon(True) -et.start() + + +def awakeEncode(): + global et + if et.is_alive(): + return True + et = threading.Thread(target=encode, args=()) + et.setDaemon(True) + et.start() + return False + + +def awakeDownload(): + global t + if t.is_alive(): + return True + t = threading.Thread(target=download, args=()) + t.setDaemon(True) + t.start() + return False + + +def awakeUpload(): + global ut + if ut.is_alive(): + return True + ut = threading.Thread(target=upload, args=()) + ut.setDaemon(True) + ut.start() + return False def run(): - global isEncode, isDownload, et + global isEncode, isDownload, et, t, ut Common.refreshDownloader() if not Common.api.isValidRoom: Common.appendError("[{}]房间未找到".format(Common.config["l_u"])) return - d = None - t = threading.Thread(target=download) - ut = threading.Thread(target=upload, args=(d,)) + awakeEncode() _count = 0 - _count_error = 0 while True: if Common.api.isLive and not Common.forceNotBroadcasting: - if d is None: - d = datetime.strftime(datetime.now(), "%Y_%m_%d") if not t.is_alive() and not Common.forceNotDownload: - try: - Common.api.updRoomInfo() - _count = 0 - _count_error = 0 - except Exception as e: - Common.appendError(e.__str__()) - continue - _count_error += 1 - _preT = Common.api.playlist - if not _preT: - Common.api.updRoomInfo() - continue - t = threading.Thread(target=download, args=(_preT,)) - t.setDaemon(True) - t.start() + awakeDownload() if not ut.is_alive(): - ut = threading.Thread(target=upload, args=(d,)) - ut.setDaemon(True) - ut.start() + awakeUpload() if not et.is_alive(): - et = threading.Thread(target=encode, args=()) - et.setDaemon(True) - et.start() - if _count % 15 == 0: + awakeEncode() + if _count % 15 == 14: try: Common.api.updRoomInfo() _count = 0 @@ -159,24 +166,16 @@ def run(): except Exception as e: Common.appendError(e.__str__()) time.sleep(20) - _count_error += 1 continue - if _count_error > 15: - Common.api.isLive = False - _count += 1 time.sleep(20) else: - if d is not None: - d = None if not isEncode and not isDownload: Common.uploadQueue.put(True) isEncode = True isDownload = True - # print("主播未开播,等待1分钟后重试") time.sleep(60) try: Common.api.updRoomInfo() - _count_error = 0 except Exception as e: Common.appendError(e.__str__()) Common.refreshDownloader()