def bilibiliStartLive(subscribe_obj, room_title, area_id=None): curSub = subscribe_obj tmp_area_id = area_id if tmp_area_id == None: tmp_area_id = curSub.get('bilibili_areaid', '199') b = getBilibiliProxy(curSub) t_room_id = b.getLiveRoomId() t_cur_blive_url = 'https://live.bilibili.com/' + t_room_id curSub['cur_blive_url'] = t_cur_blive_url # b.stopLive(t_room_id) #Just don't care the Live status, JUST STARTLIVE t_b_title = curSub.get('change_b_title') if t_b_title: b.updateRoomTitle(t_room_id, t_b_title) rtmp_link = b.startLive(t_room_id, tmp_area_id) if curSub.get( 'auto_send_dynamic' ) and rtmp_link and questInfo._getObjWithRTMPLink(rtmp_link) is None: if curSub.get('dynamic_template'): b.send_dynamic( (curSub['dynamic_template']).replace('${roomUrl}', t_cur_blive_url)) else: b.send_dynamic('转播开始了哦~') return b, t_room_id, rtmp_link
def _forwardToBilibili_Sync(channelId, link, room_title, area_id=None, isSubscribeQuest=True): resloveURLOK = False tmp_retryTime = 10 while tmp_retryTime > 0: if 'youtube.com/' in link or 'youtu.be/' in link: m3u8Link, err, errcode = _getYotube_m3u8_sync(link) if errcode == 0: link = m3u8Link resloveURLOK = True break else: tmp_retryTime -= 1 time.sleep(60) else: utitls.myLogger( '_forwardToBilibili_Sync LOG: Unsupport ForwardLink:' + link) return if resloveURLOK: b, t_room_id, rtmp_link = bilibiliStartLive(channelId, room_title, area_id) if rtmp_link: tmp_quest = questInfo._getObjWithRTMPLink(rtmp_link) if tmp_quest != None: try: os.kill(tmp_quest.get('pid', None), signal.SIGKILL) except Exception: utitls.myLogger(traceback.format_exc()) questInfo.removeQuest(rtmp_link) # force stream _forwardStream_sync(link, rtmp_link, isSubscribeQuest)
def bilibiliStartLive(channelId, room_title, area_id=None): curSub = utitls.getSubInfoWithSubChannelId(channelId) curBiliAccCookie = curSub['bilibili_cookiesStr'] tmp_area_id = area_id if tmp_area_id == None: tmp_area_id = curSub['bilibili_areaid'] b = BilibiliProxy(curBiliAccCookie) t_room_id = b.getLiveRoomId() # b.stopLive(t_room_id) #Just don't care the Live status, JUST STARTLIVE b.updateRoomTitle(t_room_id, room_title) rtmp_link = b.startLive(t_room_id, tmp_area_id) if curSub[ 'auto_send_dynamic'] and rtmp_link and questInfo._getObjWithRTMPLink( rtmp_link) is None: if curSub['dynamic_template']: b.send_dynamic(curSub['dynamic_template']).replace( '${roomUrl}', 'https://live.bilibili.com/' + t_room_id) else: b.send_dynamic('转播开始了哦~') return b, t_room_id, rtmp_link
def do_GET(self): request_path = self.path rc = 404 rb = None params = parse_qs(urlsplit(request_path).query) try: if request_path.startswith('/web/'): fname, ext = os.path.splitext(request_path) if ext in (".html", ".css", ".js"): tmp_filePath = os.path.join(os.getcwd()) for v in request_path.split('/'): tmp_filePath = os.path.join(tmp_filePath, v) print(tmp_filePath) with open(tmp_filePath, 'r', encoding='utf-8') as f: self.send_response(200) self.send_header('Content-type', types_map[ext]) self.end_headers() self.wfile.write(f.read().encode('utf-8')) return except Exception: utitls.myLogger(traceback.format_exc()) self.send_error(404) self.end_headers() return if request_path.startswith('/subscribe?'): hub_challenge_list = params.get('hub.challenge', None) if None != hub_challenge_list: rc = 202 rb = hub_challenge_list[0] elif request_path.startswith('/questlist'): rc = 200 rb = json.dumps(getQuestList_AddStarts()) elif request_path.startswith('/get_manual_json'): rc = 200 rb = json.dumps(utitls.manualJson()) elif request_path.startswith('/addRestreamSrc'): rc = 200 srcNote_list = params.get('srcNote', None) srcLink_list = params.get('srcLink', None) if srcNote_list and srcLink_list: tmp_srcNote = srcNote_list[0].strip() tmp_srcLink = srcLink_list[0].strip() utitls.addManualSrc(tmp_srcNote, tmp_srcLink) rb = json.dumps({"code": 0, "msg": "添加成功"}) elif request_path.startswith('/addRtmpDes'): rc = 200 rtmpNote_list = params.get('rtmpNote', None) rtmpLink_list = params.get('rtmpLink', None) if rtmpNote_list and rtmpLink_list: tmp_rtmpNote = rtmpNote_list[0].strip() tmp_rtmpLink = rtmpLink_list[0].strip() utitls.addManualDes(tmp_rtmpNote, tmp_rtmpLink) rb = json.dumps({"code": 0, "msg": "添加成功"}) elif request_path.startswith('/kill_quest?'): rc = 200 tmp_rtmpLink_list = params.get('rtmpLink', None) if tmp_rtmpLink_list: tmp_rtmpLink = tmp_rtmpLink_list[0].strip() tmp_quest = _getObjWithRTMPLink(tmp_rtmpLink) if tmp_quest != None: try: os.kill(tmp_quest.get('pid', None), signal.SIGKILL) rb = json.dumps({"code": 0, "msg": "操作成功"}) except Exception: utitls.myLogger(traceback.format_exc()) rb = json.dumps({"code": -2, "msg": "错误PID,操作失败!!"}) else: rb = json.dumps({ "code": -1, "msg": "查找不到对应的任务:{},操作失败!!".format(tmp_rtmpLink) }) elif request_path.startswith('/live_restream?'): forwardLink_list = params.get('forwardLink', None) restreamRtmpLink_list = params.get('restreamRtmpLink', None) if forwardLink_list and restreamRtmpLink_list: tmp_forwardLink = forwardLink_list[0].strip() tmp_rtmpLink = restreamRtmpLink_list[0].strip() isForwardLinkFormateOK = True if 'rtmp://' in tmp_rtmpLink: if 'twitcasting.tv/' in tmp_forwardLink: #('https://www.', 'twitcasting.tv/', 're2_takatsuki/fwer/aeqwet') tmp_twitcasID = tmp_forwardLink.partition( 'twitcasting.tv/')[2] tmp_twitcasID = tmp_twitcasID.split('/')[0] tmp_forwardLink = 'http://twitcasting.tv/{}/metastream.m3u8/?video=1'.format( tmp_twitcasID) elif '.m3u8' in tmp_forwardLink \ or 'youtube.com/' in tmp_forwardLink or 'youtu.be/' in tmp_forwardLink: tmp_forwardLink = tmp_forwardLink else: isForwardLinkFormateOK = False rc = 200 if isForwardLinkFormateOK: if checkIfInQuest(tmp_rtmpLink) == False: #try to restream async_forwardStream(tmp_forwardLink, tmp_rtmpLink, False) rb = json.dumps({ "code": 0, "msg": "请求成功。请等待大概30秒,网络不好时程序会自动重试30次。也可以查看任务状态看是否添加成功。\ \nRequesting ForwardLink: {},\nRequesting RestreamRtmpLink: {}\n\n当前任务:\n{}" .format(tmp_forwardLink, tmp_rtmpLink, getQuestListStr()) }) else: rb = json.dumps({ "code": 1, "msg": "当前推流已经在任务中. \nRequesting ForwardLink: {},\nRequesting RestreamRtmpLink: {}\n\n\n-----------------CurrentQuests:\n{}" .format(tmp_forwardLink, tmp_rtmpLink, getQuestListStr()) }) else: rb = json.dumps({ "code": -3, "msg": "来源地址格式错误, 请查看上面支持的格式" }) else: rc = 200 rb = json.dumps({ "code": -4, "msg": "RTMPLink格式错误!!! bilibili的RTMPLink格式是两串合起来。\nEXAMPLE:rtmp://XXXXXX.acg.tv/live-js/?streamname=live_XXXXXXX&key=XXXXXXXXXX" }) self.send_response(rc) self.send_header('Content-type', 'text/html; charset=utf-8') self.end_headers() if None != rb: try: self.wfile.write(rb.encode('utf-8')) except Exception: print(traceback.format_exc())
def do_GET(self): request_path = self.path rc = 404 rb = None sh = {'Content-Encoding': 'gzip'} params = parse_qs(urlsplit(request_path).query) try: if request_path.startswith('/web/'): request_path = request_path.split('?')[0] fname, ext = os.path.splitext(request_path) if ext in (".html", ".css", ".js"): tmp_filePath = os.path.join(os.getcwd()) for v in request_path.split('/'): tmp_filePath = os.path.join(tmp_filePath, v) with open(tmp_filePath, 'r', encoding='utf-8') as f: lastMtime = self.date_time_string( os.fstat(f.fileno()).st_mtime) if self.headers.get('If-Modified-Since') == lastMtime: self.send_response(304) self.end_headers() return self.send_response(200) sh['Content-type'] = types_map[ext] sh['Cache-Control'] = 'max-age=72000' fb = f.read() rb = self.gzip_encode(fb.encode('utf-8')) sh['Content-length'] = len(rb) sh['Last-Modified'] = lastMtime for key in sh: self.send_header(key, sh[key]) self.end_headers() self.wfile.write(rb) return except Exception: utitls.myLogger(traceback.format_exc()) self.send_error(404) self.end_headers() return if request_path.startswith('/get_manual_json'): rc = 200 ret_dic = utitls.manualJson() ret_dic['des_dict'] = [] #clear the des tmp_acc_mark_list = [] for sub in utitls.configJson().get('subscribeList', []): tmp_mark = sub.get('mark') if tmp_mark: tmp_acc_mark_list.append(tmp_mark) ret_dic['acc_mark_list'] = tmp_acc_mark_list rb = json.dumps(ret_dic) elif request_path.startswith('/questlist'): rc = 200 rb = json.dumps(getQuestList_AddStarts()) elif request_path.startswith('/live_restream?'): forwardLink_list = params.get('forwardLink', None) restreamRtmpLink_list = params.get('restreamRtmpLink', None) if forwardLink_list and restreamRtmpLink_list: tmp_forwardLink = forwardLink_list[0].strip() tmp_rtmpLink = restreamRtmpLink_list[0].strip() if 'rtmp://' in tmp_rtmpLink: if utitls.checkIsSupportForwardLink(tmp_forwardLink): isForwardLinkFormateOK = True else: isForwardLinkFormateOK = False rc = 200 if isForwardLinkFormateOK: if checkIfInQuest(tmp_rtmpLink) == False: #try to restream async_forwardStream(tmp_forwardLink, tmp_rtmpLink, False) rb = json.dumps({ "code": 0, "msg": "请求成功。请等待大概30秒,网络不好时程序会自动重试30次。也可以查看任务状态看是否添加成功。\ \nRequesting ForwardLink: {},\nRequesting RestreamRtmpLink: {}\n\n" .format(tmp_forwardLink, tmp_rtmpLink) }) else: rb = json.dumps({ "code": 1, "msg": "当前推流已经在任务中. \nRequesting ForwardLink: {},\nRequesting RestreamRtmpLink: {}\n\n\n-----------------CurrentQuests:\n{}" .format(tmp_forwardLink, tmp_rtmpLink, getQuestListStr()) }) else: rb = json.dumps({ "code": -3, "msg": "来源地址格式错误, 请查看上面支持的格式" }) elif tmp_rtmpLink.startswith('ACCMARK='): params = parse_qs(tmp_rtmpLink) acc_list = params.get('ACCMARK', None) opt_code_list = params.get('OPTC', None) is_send_dynamic_list = params.get('SEND_DYNAMIC', None) dynamic_words_list = params.get('DYNAMIC_WORDS', None) is_should_record_list = params.get('IS_SHOULD_RECORD', None) b_title_list = params.get('B_TITLE', None) rc = 200 if acc_list and opt_code_list and is_send_dynamic_list and dynamic_words_list: acc_mark = acc_list[0].strip() opt_code = opt_code_list[0].strip() is_send_dynamic = is_send_dynamic_list[0].strip() dynamic_words = dynamic_words_list[0].strip() is_should_record = is_should_record_list[0].strip() b_title = None if b_title_list: b_title = b_title_list[0].strip() tmp_is_acc_exist = False for sub in utitls.configJson().get( 'subscribeList', []): tmp_mark = sub.get('mark', "") if tmp_mark == acc_mark: if opt_code == sub.get('opt_code', ""): tmp_is_acc_exist = True sub['auto_send_dynamic'] = True if is_send_dynamic == '1' else False sub['dynamic_template'] = dynamic_words + "${roomUrl}" sub['is_should_record'] = True if is_should_record == '1' else False if b_title: sub['change_b_title'] = b_title Async_forwardToBilibili( sub, tmp_forwardLink, isSubscribeQuest=False) break if tmp_is_acc_exist: rb = json.dumps({ "code": 0, "msg": "请求成功。请等待大概30秒,网络不好时程序会自动重试30次。也可以查看任务状态看是否添加成功。\ \nRequesting ForwardLink: {},\nRequesting RestreamRtmpLink: {}\n\n" .format(tmp_forwardLink, tmp_rtmpLink) }) else: rb = json.dumps({ "code": -5, "msg": "当前账号不存在或者账号操作码错误:{}".format(acc_mark) }) else: rc = 200 rb = json.dumps({ "code": -4, "msg": "RTMPLink格式错误!!! bilibili的RTMPLink格式是两串合起来。\nEXAMPLE:rtmp://XXXXXX.acg.tv/live-js/?streamname=live_XXXXXXX&key=XXXXXXXXXX" }) elif request_path.startswith('/bilibili_opt?'): rc = 200 acc_list = params.get('acc', None) opt_code_list = params.get('opt_code', None) dynamic_words_list = params.get('sendDynamic', None) b_title_list = params.get('changeTitle', None) refreshRTMP_list = params.get('refreshRTMP', None) killRTMP_list = params.get('killRTMP', None) if acc_list and opt_code_list: acc = acc_list[0] opt_code = opt_code_list[0] curSub = utitls.getSubWithKey('mark', acc) if curSub.get('opt_code') == opt_code: if dynamic_words_list: dynamic_words = dynamic_words_list[0] b = getBilibiliProxy(curSub) t_room_id = b.getLiveRoomId() t_cur_blive_url = 'https://live.bilibili.com/' + t_room_id b.send_dynamic("{}\n{}".format(dynamic_words, t_cur_blive_url)) elif b_title_list: b_title = b_title_list[0] b = getBilibiliProxy(curSub) t_room_id = b.getLiveRoomId() b.updateRoomTitle(t_room_id, b_title) elif refreshRTMP_list: refreshRTMP = refreshRTMP_list[0] if refreshRTMP == '1': b = getBilibiliProxy(curSub) t_room_id = b.getLiveRoomId() b.startLive(t_room_id, '33') elif killRTMP_list: killRTMP = killRTMP_list[0] if killRTMP == '1': cur_quest = _getObjWithAccMark(acc) if cur_quest: updateQuestInfo('isDead', True, cur_quest.get('rtmpLink')) utitls.kill_child_processes( cur_quest.get('pid', None)) rb = json.dumps({"code": 0, "msg": "操作成功"}) else: rb = json.dumps({ "code": -5, "msg": "当前账号不存在或者账号操作码错误:{}".format(acc) }) elif request_path.startswith('/kill_quest?'): rc = 200 tmp_rtmpLink_list = params.get('rtmpLink', None) if tmp_rtmpLink_list: tmp_rtmpLink = tmp_rtmpLink_list[0].strip() tmp_quest = _getObjWithRTMPLink(tmp_rtmpLink) if tmp_quest != None: updateQuestInfo('isDead', True, tmp_rtmpLink) utitls.kill_child_processes(tmp_quest.get('pid', None)) rb = json.dumps({"code": 0, "msg": "操作成功"}) else: rb = json.dumps({ "code": -1, "msg": "查找不到对应的任务:{},操作失败!!".format(tmp_rtmpLink) }) elif request_path.startswith('/addRestreamSrc?'): rc = 200 srcNote_list = params.get('srcNote', None) srcLink_list = params.get('srcLink', None) if srcNote_list and srcLink_list: tmp_srcNote = srcNote_list[0].strip() tmp_srcLink = srcLink_list[0].strip() utitls.addManualSrc(tmp_srcNote, tmp_srcLink) rb = json.dumps({"code": 0, "msg": "添加成功"}) elif request_path.startswith('/addRtmpDes?'): rc = 200 rtmpNote_list = params.get('rtmpNote', None) rtmpLink_list = params.get('rtmpLink', None) if rtmpNote_list and rtmpLink_list: tmp_rtmpNote = rtmpNote_list[0].strip() tmp_rtmpLink = rtmpLink_list[0].strip() utitls.addManualDes(tmp_rtmpNote, tmp_rtmpLink) rb = json.dumps({"code": 0, "msg": "添加成功"}) elif request_path.startswith('/subscribe?'): hub_challenge_list = params.get('hub.challenge', None) if None != hub_challenge_list: rc = 202 rb = hub_challenge_list[0] ####### if rb: rb = self.gzip_encode(rb.encode('utf-8')) sh['Content-length'] = len(rb) self.send_response(rc) for key in sh: self.send_header(key, sh[key]) self.end_headers() if None != rb: try: self.wfile.write(rb) except Exception: print(traceback.format_exc())
def _forwardStream_sync(forwardLink, outputRTMP, isSubscribeQuest, subscribe_obj=None): tmp_quest = questInfo._getObjWithRTMPLink(outputRTMP) if tmp_quest: if tmp_quest.get('isRestart') == None: utitls.myLogger( "_forwardStream_sync ERROR: rtmp already in quest!!!!\n forwardLink:%s, \n rtmpLink:%s" % (forwardLink, outputRTMP)) return else: questInfo.addQuest(forwardLink, outputRTMP, isSubscribeQuest) if outputRTMP.startswith('rtmp://'): is_stream_playable = False tmp_title = forwardLink # default title is the forwardLink tmp_forwardLink = forwardLink if 'twitcasting.tv/' in tmp_forwardLink: #('https://www.', 'twitcasting.tv/', 're2_takatsuki/fwer/aeqwet') tmp_twitcasID = tmp_forwardLink.partition('twitcasting.tv/')[2] tmp_twitcasID = tmp_twitcasID.split('/')[0] # if using the streamlink, it should be start with hlsvariant:// tmp_forwardLink = 'hlsvariant://twitcasting.tv/{}/metastream.m3u8/?video=1'.format( tmp_twitcasID) is_stream_playable = True else: m3u8Link, tmp_title, err, errcode = resolveStreamToM3u8( tmp_forwardLink) tmp_forwardLink = forwardLink # use the orgin streamlink if errcode == 0: is_stream_playable = True else: utitls.myLogger( "_forwardStream_sync ERROR: Unsupport forwardLink:%s" % tmp_forwardLink) is_stream_playable = False if is_stream_playable == True: questInfo.updateQuestInfo('title', tmp_title, outputRTMP) if subscribe_obj: questInfo.updateQuestInfo('AccountMARK', subscribe_obj.get("mark", ""), outputRTMP) questInfo.updateQuestInfo( 'Live_URL', subscribe_obj.get("cur_blive_url", ""), outputRTMP) tmp_retryTime = 0 tmp_cmdStartTime = time.time() while tmp_retryTime <= 6: # must be <= # try to restream out, err, errcode = _forwardStreamCMD_sync( tmp_title, subscribe_obj, tmp_forwardLink, outputRTMP) out = out.decode('utf-8') if isinstance( out, (bytes, bytearray)) else out if ('[cli][info] Stream ended' in out) and ( time.time() - tmp_cmdStartTime > 180 ): # this will cause the retry out, it good as so far. utitls.myLogger( "_forwardStreamCMD_sync LOG: Stream ended=======<") break isQuestDead = questInfo._getObjWithRTMPLink(outputRTMP).get( 'isDead', False) if errcode == -9 or isQuestDead or isQuestDead == 'True': utitls.myLogger( "_forwardStreamCMD_sync LOG: Kill Current procces by rtmp:%s" % outputRTMP) break # maybe can ignore the error if ran after 2min? if time.time() - tmp_cmdStartTime < 120: tmp_retryTime += 1 # make it can exit else: tmp_retryTime = 0 # let every Connect success reset the retrytime time.sleep(10) # one m3u8 can hold 20 secounds or less tmp_cmdStartTime = time.time() #import should not miss it. utitls.myLogger( '_forwardStream_sync LOG: CURRENT RETRY TIME:%s' % tmp_retryTime) utitls.myLogger( "_forwardStream_sync LOG RETRYING___________THIS:\ninputM3U8:%s, \noutputRTMP:%s" % (forwardLink, outputRTMP)) else: utitls.myLogger("_forwardStream_sync ERROR: Invalid outputRTMP:%s" % outputRTMP) questInfo.removeQuest(outputRTMP)