コード例 #1
0
class Live():
    def __init__(self):
        self.config = Config()
        self.cookies = login()
        logger.info(self.cookies)
        self.base_path = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
                                      self.config.config['output']['path'])
        self.live_infos = Infos()
        self.display = Display()
        self.decoder = Decoder()
        self.uploader = Upload()
        self.threadRecorder = threadRecorder()
        logger.info('基路径:%s' % (self.base_path))
        self.load_room_info()
        self.get_live_url()
        logger.info('初始化完成')

    def create_duration(self, start_time, end_time):
        t = datetime.datetime.now()
        tt = t.strftime('%Y%m%d %H%M%S')
        if start_time == end_time == '0':
            return '0'
        tmp = datetime.datetime.strptime(tt.split(' ')[0] + ' %s' % start_time, '%Y%m%d %H%M%S')
        if t > tmp:
            base_time1 = tt.split(' ')[0]
            base_time2 = (t + datetime.timedelta(days=1)).strftime('%Y%m%d %H%M%S').split(' ')[0]
        else:
            base_time1 = (t - datetime.timedelta(days=1)).strftime('%Y%m%d %H%M%S').split(' ')[0]
            base_time2 = tt.split(' ')[0]
        if start_time > end_time:
            start_time = '%s %s' % (base_time1, start_time)
            end_time = '%s %s' % (base_time2, end_time)
        else:
            start_time = '%s %s' % (tt.split(' ')[0], start_time)
            end_time = '%s %s' % (tt.split(' ')[0], end_time)
        return '%s-%s' % (start_time, end_time)

    def check_live(self, key):
        duration = self.live_infos.get(key)['duration']
        if duration == '0':
            return True
        lst = duration.split('-')
        now_time = datetime.datetime.now()
        if len(lst) == 2:
            start_time = datetime.datetime.strptime(lst[0], '%Y%m%d %H%M%S')
            end_time = datetime.datetime.strptime(lst[1], '%Y%m%d %H%M%S')
            if now_time > start_time and now_time < end_time:
                return True
            else:
                logger.debug('%s[RoomID:%s]不在直播时间段' % (self.live_infos.get(key)['uname'], key))
                return False
        else:
            return False

    def load_room_info(self):
        live_infos = self.live_infos.copy()
        for lst in self.config.config['live']['room_info']:
            if lst[0] not in live_infos:
                live_info = {}
                live_info['record_start_time'] = ''
                live_info['queue_status'] = 0
                live_info['recording'] = 0
                live_info['finish_time'] = ''
            else:
                live_info = live_infos[lst[0]]
            live_info['need_rec'] = lst[1]
            live_info['need_mask'] = lst[2]
            live_info['maxsecond'] = lst[3]
            live_info['need_upload'] = lst[4]
            live_info['duration'] = self.create_duration(lst[5], lst[6])
            live_info['cookies'] = self.cookies
            live_info['base_path'] = self.base_path
            self.live_infos.update(lst[0],live_info)

    def load_realtime(self):
        '''
        实时加载配置,更新房间信息
        '''
        self.config.load_cfg()
        # logger.info(self.config.config)
        room_lst = [i[0] for i in self.config.config['live']['room_info']]
        del_lst = []
        for key in self.live_infos.copy():
            if key not in room_lst:
                del_lst.append(key)
        for key in del_lst:
            self.live_infos.delete(key)
        self.load_room_info()

    def judge_in(self, key):
        room_lst = [i[0] for i in self.config.config['live']['room_info']]
        if key not in room_lst:
            return False
        return True

    def judge_download(self,key):
        if not self.judge_in(key):
            return False
        live_info = self.live_infos.copy()[key]
        if live_info['live_status'] != 1:
            live_info['recording'] =0
            self.live_infos.update(key,live_info)
            return False
        elif not self.check_live(key) and live_info['live_status'] == 1:
            live_info['recording'] =2
            self.live_infos.update(key,live_info)
            return False
        elif self.check_live(key) and live_info['live_status'] == 1 and live_info['need_rec'] == '0':
            live_info['recording']=3
            self.live_infos.update(key,live_info)
            return False
        elif live_info['live_status'] == 1 and live_info['need_rec'] == '1':
            live_info['recording']=1
            self.live_infos.update(key,live_info)
            return True
        else:
            logger.warning('%s[RoomID:%s]进入了未知的分支呢' % (live_info['uname'],key))
            live_info['recording'] =0
            self.live_infos.update(key,live_info)
            return False

    def get_live_url(self):
        '''
        获取所有监听直播间的信息
        '''
        room_lst = [i[0] for i in self.config.config['live']['room_info']]
        for id in room_lst:
            info = None
            while info is None:
                try:
                    info = live.get_room_info(id, cookies=self.cookies)
                    time.sleep(0.3)
                except:
                    logger.error('[RoomID:%s]获取信息失败,重新尝试' % (id))
                    continue
            live_info = self.live_infos.copy()[id]
            live_info['room_id'] = id
            live_info['real_id'] = info['room_info']['room_id']
            try:
                if live_info['live_status'] != 1 and info['room_info']['live_status'] == 1:
                    logger.info('%s[RoomID:%s]开播了' % (live_info['uname'], id))
                    toaster = ToastNotifier()
                    toaster.show_toast("开播通知",
                                       '%s[RoomID:%s]开播了' % (live_info['uname'], id),
                                       icon_path=None,
                                       duration=3)
            except:
                pass
            try:
                live_info['live_status'] = info['room_info']['live_status']
                live_info['uid'] = info['room_info']['uid']
                live_info['uname'] = info['anchor_info']['base_info']['uname']
                live_info['save_name'] = '%s_%s.flv' % (
                    live_info['uname'], time.strftime("%Y%m%d%H%M%S", time.localtime()))
                live_info['title'] = info['room_info']['title']
                live_info['live_start_time'] = info['room_info']['live_start_time']
                self.live_infos.update(id,live_info)
                logger.debug(
                    '%s[RoomID:%s]直播状态\t%s' % (live_info['uname'], id, live_info['live_status']))
            except Exception as e:
                logger.critical(e)
                logger.error('[RoomID:%s]房间信息更新失败' % (id))
                logger.error(info)
        # logger.info(self.live_infos.copy())

    def get_stream(self, key):
        '''
        获取直播流
        :param key: 房间显示id
        :return: stream
        '''
        if not self.judge_in(key):
            return None
        live_info = self.live_infos.copy()[key]
        logger.info('%s[RoomID:%s]获取直播流' % (live_info['uname'], key))
        session = streamlink.Streamlink()
        session.set_option("http-cookies", self.cookies)
        session.set_option("http-headers", headers)
        log_path = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'log', 'stream.log')
        session.set_loglevel("debug")
        session.set_logoutput(open(log_path, 'a',encoding='utf-8'))
        streams = None
        while streams is None:
            try:
                streams = session.streams('https://live.bilibili.com/%s' % key)
            except:
                logger.warning('%s[RoomID:%s]获取直播流失败,正在重试' % (live_info['uname'], key))
                time.sleep(1)
        if streams == {}:
            logger.error('%s[RoomID:%s]未获取到直播流,可能是下播或者网络问题' % (live_info['uname'], key))
            return None
        if 'best' in streams:
            logger.info('%s[RoomID:%s]获取到best直播流' % (live_info['uname'], key))
            return streams['best']
        elif 'source' in streams:
            logger.info('%s[RoomID:%s]获取到source直播流' % (live_info['uname'], key))
            return streams['source']
        elif 'worst' in streams:
            logger.info('%s[RoomID:%s]获取到worst直播流' % (live_info['uname'], key))
            return streams['worst']
        else:
            logger.info('%s[RoomID:%s]未获取到直播流' % (live_info['uname'], key))
            return None

    def unlive(self, key, unlived):
        if not self.judge_in(key):
            return None
        live_info = self.live_infos.copy()[key]
        logger.info('%s[RoomID:%s]似乎下播了' % (live_info['uname'], key))
        live_info['recording'] = 0
        logger.info('%s[RoomID:%s]录制结束,录制了%.2f分钟' % (live_info['uname'], key, (
                datetime.datetime.now() - datetime.datetime.strptime(
            live_info['record_start_time'],
            '%Y-%m-%d %H:%M:%S')).total_seconds() / 60.0))
        live_info['record_start_time'] = ''
        if unlived:
            logger.info('%s[RoomID:%s]确认下播,加入转码上传队列' % (live_info['uname'], key))
            # if live_info['need_upload'] == '1':
            #     live_info['filename'] = live_info['uname'] + live_info['duration'].split('-')[0].split(' ')[0]
            #     live_info['filepath'] = os.path.join(self.base_path, live_info['uname'], '%s_%s' % (live_info['uname'], live_info['duration'].split('-')[0].split(' ')[0]))
            #     if live_info['need_mask'] == '1':
            #         live_info['filepath'] += '_mask.mp4'
            #     else:
            #         live_info['filepath'] += '.mp4'
            self.decoder.enqueue(key)
        self.live_infos.update(key,live_info)    

    def download_live(self, key):
        if not self.judge_in(key):
            return None
        save_path = os.path.join(self.base_path, self.live_infos.get(key)['uname'], 'recording')
        logger.info('%s[RoomID:%s]准备下载直播流,保存在%s' % (self.live_infos.get(key)['uname'], key, save_path))
        self.live_infos.get(key)['recording'] = 1
        if not os.path.exists(save_path):
            os.makedirs(save_path)

        stream = self.get_stream(key)
        if stream is None:
            logger.error('%s[RoomID:%s]获取直播流失败' % (self.live_infos.get(key)['uname'], key))
            self.live_infos.get(key)['record_start_time'] = ''
            self.live_infos.get(key)['recording'] = 0
            return
        filename = os.path.join(save_path, self.live_infos.get(key)['save_name'])
        self.live_infos.get(key)['record_start_time'] = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        try:
            fd = stream.open()
        except Exception as e:
            self.unlive(key,unlived=False)
            logger.critical('%s[RoomID:%s]fd open error' % (self.live_infos.get(key)['uname'], key))
            logger.error(e)
            return
        with open(filename, 'wb') as f:
            while self.judge_in(key) and self.live_infos.get(key)['live_status'] == 1 and self.live_infos.get(key)[
                'need_rec'] == '1' and self.check_live(key):
                try:
                    data = fd.read(1024 * 8)
                    if len(data) > 0:
                        f.write(data)
                    else:
                        fd.close()
                        logger.warning('%s[RoomID:%s]直播流断开,尝试重连' % (self.live_infos.get(key)['uname'], key))
                        stream = self.get_stream(key)
                        if stream is None:
                            logger.warning('%s[RoomID:%s]重连失败' % (self.live_infos.get(key)['uname'], key))
                            self.unlive(key, True)
                            return
                        else:
                            logger.info('%s[RoomID:%s]重连成功' % (self.live_infos.get(key)['uname'], key))
                            fd = stream.open()
                except Exception as e:
                    fd.close()
                    self.unlive(key,unlived=False)
                    logger.critical('%s[RoomID:%s]遇到了什么问题' % (self.live_infos.get(key)['uname'], key))
                    logger.error(e)
                    return
        fd.close()
        self.unlive(key, True)

    def run(self):
        while True:
            time.sleep(1)
            self.load_realtime()
            self.get_live_url()
            live_infos = self.live_infos.copy()
            for key in live_infos:
                if live_infos[key]['recording'] != 1 and self.judge_download(key):
                    self.threadRecorder.add('download_live_%s' % (key),self.download_live,[key,],False)
                time.sleep(0.2)

    def start(self):
        self.threadRecorder.add('display_run',self.display.run,None,False)
        self.threadRecorder.add('decoder_run',self.decoder.run,None,False)
        self.threadRecorder.add('uploader_run',self.uploader.run,None,False)
        self.threadRecorder.add('live_run',self.run,None,False)
コード例 #2
0
class History():
    def __init__(self):
        self._lock = threading.Lock()
        self.live_infos = Infos()
        self.base_path = os.path.join(
            os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
            'history')
        self.init()
        logger.debug('History模块初始化完成')

    def init(self):
        if not os.path.exists(self.base_path):
            os.mkdir(self.base_path)
        for key in self.live_infos.copy():
            history_file = os.path.join(
                self.base_path,
                '%s_%s' % (key, self.live_infos.get(key)['uname']))
            if not os.path.exists(history_file):
                with open(history_file, 'w', encoding='utf-8') as a:
                    pass

    def add_info(self, key, para, output):
        self.init()
        history_file = os.path.join(
            self.base_path, '%s_%s' % (key, self.live_infos.get(key)['uname']))
        with self._lock:
            with open(history_file, 'a', encoding='utf-8') as a:
                a.write(
                    '####📢 %s, 当前%s状态为: %s, 当前时间: %s\n' %
                    (output, para, self.live_infos.get(key)[para],
                     datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')))

    def heartbeat(self):
        while True:
            try:
                time.sleep(600)
                self.init()
                for key in self.live_infos.copy():
                    history_file = os.path.join(
                        self.base_path,
                        '%s_%s' % (key, self.live_infos.get(key)['uname']))
                    with self._lock:
                        with open(history_file, 'a', encoding='utf-8') as a:
                            a.write('####✨ 当前时间: %s\n' %
                                    (datetime.datetime.now().strftime(
                                        '%Y-%m-%d %H:%M:%S')))
                            a.write('录制时段: %s\n' %
                                    (self.live_infos.get(key)['duration']))
                            a.write('直播状态: %s\n' %
                                    (self.live_infos.get(key)['live_status']))
                            a.write('录制状态: %s\n' %
                                    (self.live_infos.get(key)['recording']))
                            a.write('是否录制: %s\n' %
                                    (self.live_infos.get(key)['need_rec']))
                            a.write('是否遮挡: %s\n' %
                                    (self.live_infos.get(key)['need_mask']))
                            a.write('是否上传: %s\n' %
                                    (self.live_infos.get(key)['need_upload']))
            except Exception as e:
                logger.critical(e)
                continue