Example #1
0
    def __init__(self, app_path: Path, base_path: Path):
        """Initialises the configuration class
        """
        _logger.debug(f'__init__ app_path "{app_path}"')

        # Initialize
        self._name = app_path.stem
        self._base_path = base_path

        # Folders
        self._data_path = Path(self._base_path, 'data').resolve()
        self._output_path = Path(self._base_path, 'output').resolve()
        self._base_data_frame_path = Path(self._output_path, 'dataframes').resolve()
        self._data_frame_path = Path(self._base_data_frame_path, date.today().strftime("%y-%m-%d")).resolve()
        self._plot_base_path = Path(self._output_path, 'plots').resolve()
        self._plot_path = Path(self._plot_base_path, date.today().strftime("%y-%m-%d")).resolve()

        # Ensure directories pre-exist
        self._data_path.mkdir(parents=True, exist_ok=True)
        self._data_frame_path.mkdir(parents=True, exist_ok=True)
        self._plot_path.mkdir(parents=True, exist_ok=True)
        _logger.debug(f'data path:       "{self._data_path}"'
                      f'data frame path: "{self._data_path}"'
                      f'plot path:       "{self._plot_path}"')

        self._config_plots = ConfigParser.parse(Path(_PLOTS_CONFIG_FILENAME))
Example #2
0
def main():
    global sPath
    global alive
    global running
    global mConfig, mMap, mExplain
    global display, display1, display2
    global log
    global nRoom
    global aColour
    global localFile
    global aBlock
    global notifyMode
    global beatClock
    # use crafted display function to ease the migration from python3 to python2 and to accommodate to different terminal coding in different system
    # display1 is normal displayer, while display2 is a separate displayer running in special thread, implementing the display interval
    # in each case, display1 shall be a instant displayer; thus, use display1 to output diagnostic message
    display1 = Displayer(0).display
    display = display1
    mConfigBak = mConfig.copy()
    try:
        parser1 = ConfigParser(mConfig, mExplain, mMap,
                               'display danmu message in bilibili live')
        useCLI = True if len(sys.argv) > 1 else False
        if (not os.path.exists(sPath)):
            sDir = os.path.split(sys.argv[0])[0]
            sFile = os.path.join(sDir, sPath)
            if (os.path.exists(sFile)):
                sPath = sFile
            else:
                display1('配置文件 {} 不存在'.format(sPath))
                sPath = None
        # parse configuration from file and from command line option
        mData = parser1.parse(sPath, useCLI)
        mConfig = mData
    except Exception as e:
        display1('读取配置出错:', e, sep='\n')
        display1('退回默认配置')
        mConfig = mConfigBak
    if (mConfig['nDelay'] > 0):
        # danmu message display interval is enabled, using threaded displayer
        display2 = Displayer(1, mConfig['nDelay']).display
        display = display2
    aColour = [(x + 30 if x < 10 else x + 80) for x in mConfig['aColour']]
    if (mConfig['verbose']):
        log = display1
    else:

        def log(*aArgs, **mArgs):
            pass

    if (mConfig['block']):
        # it seems that two format of flooding messages are existing
        aBlock = ['bilibili-(゜-゜)つロ乾杯~', '- ( ゜- ゜)つロ 乾杯~ - bilibili']
    if (mConfig['notify']):
        notifyMode = 2
    else:
        notifyMode = 1
    log(mConfig)
    nRoom = mConfig['nRoom'] or int(input('room ID:'))
    running = True
    socket.setdefaulttimeout(10)
    while running:
        try:
            try:
                sServer, nRoom, sHoster, sTitle = getRoom(nRoom)
            except urllib.error.HTTPError as e:
                if (e.code == 404):
                    display1('找不到该房间,请重新输入房间号')
                    nRoom = int(input('room ID:'))
                    continue
                else:
                    raise
            if (mConfig['write']):
                sTime = time.strftime('%m%d_%H%M%S-')
                sName = sHoster + '-' + sTitle
                sName = re.sub(r'[^\w_\-.()]', '-', sName)
                sFileName = '{}{}.txt'.format(sTime, sName)
                localFile = open(sFileName, 'a', encoding='utf-8')
            log('弹幕服务器 ' + sServer)
            aAddr1 = (sServer, 788)
            sock1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            try:
                sock1.connect(aAddr1)
            except TimeoutError as e:
                sock1.close()
                display1('到弹幕服务器的连接失败,尝试更换地址')
                if (sServer == 'livecmt-1.bilibili.com'):
                    sServer = 'livecmt-2.bilibili.com'
                else:
                    sServer = 'livecmt-1.bilibili.com'
                log('弹幕服务器 ' + sServer)
                aAddr1 = (sServer, 788)
                sock1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                sock1.connect(aAddr1)
            log('地址为 ', *sock1.getpeername())
            nUid = int(100000000000000 + 200000000000000 * random.random())
            # a random meaningless user ID
            #bPayload = b'{"roomid":%d,"uid":%d}' % (nRoom, nUid);
            bPayload = ('{"roomid":%d,"uid":%d}' %
                        (nRoom, nUid)).encode('utf-8')
            nLength = len(bPayload) + 16
            bReq = struct.pack('>IIII', nLength, 0x100001, 0x7, 0x1)
            bReq += bPayload
            sock1.sendall(bReq)
            alive = True
            bHeartBeat = struct.pack('>IIII', 0x10, 0x100001, 0x2, 0x1)
            sock1.sendall(bHeartBeat)
            # send heartbeat message per 30 seconds
            interval = SetInterval(lambda: (sock1.sendall(bHeartBeat)), 30)
            interval.start()
            # capture CR in stdin to send hearbeat in order to fetch freshed online count
            if (not beatClock):
                beatClock = interval.clock
                t = threading.Thread(target=notify)
                t.daemon = 1
                t.start()
            else:
                beatClock = interval.clock
            handler2(sock1)
        except (socket.timeout, TimeoutError) as e:
            display1('连接超时,重试...')
            continue
        except SocketDied as e:
            display1('连接被关闭,程序重启...')
            continue
        except BaseException as e:
            if (isinstance(e, KeyboardInterrupt)):
                display1('程序退出')
                running = False
            elif (sys.version[0] == '3'
                  and isinstance(e, ConnectionResetError)):
                # ConnectionResetError is not supported in python2
                display1(e)
                display1('到服务器的连接被断开,尝试重新连接...')
                continue
            else:
                with open('danmu_error.log', 'ab') as f1:
                    # record error log
                    f1.write(('\n' + (str(e))).encode('utf-8'))
                raise
        finally:
            alive = False
            if ('interval' in locals()): interval.stop()
            if ('sock1' in locals()): sock1.close()
            if (localFile):
                display1('弹幕已保存到文件 {}'.format(localFile.name))
                localFile.close()