diff --git "a/DD\347\233\221\346\216\247\345\256\244.py" "b/DD\347\233\221\346\216\247\345\256\244.py" index 77706d0..50137c1 100644 --- "a/DD\347\233\221\346\216\247\345\256\244.py" +++ "b/DD\347\233\221\346\216\247\345\256\244.py" @@ -96,8 +96,7 @@ def __init__(self, title): self.setWindowTitle(title) self.setObjectName(f'dock-{title}') self.setFloating(False) - self.setAllowedAreas(Qt.LeftDockWidgetArea | - Qt.RightDockWidgetArea | Qt.TopDockWidgetArea) + self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea | Qt.TopDockWidgetArea) class StartLiveWindow(QWidget): @@ -149,8 +148,7 @@ def __init__(self): layout.addWidget(okButton, 2, 3, 1, 1) def selectCopyPath(self): - savePath = QFileDialog.getExistingDirectory( - self, "选择备份缓存路径", None, QFileDialog.ShowDirsOnly) + savePath = QFileDialog.getExistingDirectory(self, "选择备份缓存路径", None, QFileDialog.ShowDirsOnly) if savePath: self.savePathEdit.setText(savePath) @@ -167,9 +165,9 @@ def __init__(self): self.resize(350, 150) self.setWindowTitle('当前版本') layout = QGridLayout(self) - layout.addWidget(QLabel('DD监控室 v2.6正式版'), 0, 0, 1, 2) + layout.addWidget(QLabel('DD监控室 v2.8正式版'), 0, 0, 1, 2) layout.addWidget(QLabel('by 神君Channel'), 1, 0, 1, 2) - layout.addWidget(QLabel('特别鸣谢:大锅饭 美东矿业 inkydragon'), 2, 0, 1, 2) + layout.addWidget(QLabel('特别鸣谢:大锅饭 美东矿业 inkydragon 聪_哥'), 2, 0, 1, 2) releases_url = QLabel('') releases_url.setOpenExternalLinks(True) releases_url.setText(_translate("MainWindow", "

\ @@ -182,8 +180,7 @@ def __init__(self): layout.addWidget(checkButton, 0, 2, 1, 1) def checkUpdate(self): - QDesktopServices.openUrl( - QUrl(r'https://github.com/zhimingshenjun/DD_Monitor/releases/tag/DD_Monitor')) + QDesktopServices.openUrl(QUrl(r'https://github.com/zhimingshenjun/DD_Monitor/releases/tag/DD_Monitor')) class HotKey(QWidget): @@ -209,16 +206,14 @@ def __init__(self, config): def run(self): try: - configJSONPath = os.path.join( - application_path, r'utils/config.json') + configJSONPath = os.path.join(application_path, r'utils/config.json') with codecs.open(configJSONPath, 'w', encoding='utf-8') as f: f.write(json.dumps(self.config, ensure_ascii=False)) except: logging.exception('config.json 写入失败') try: # 备份 防止存储config时崩溃 - configJSONPath = os.path.join( - application_path, r'utils/config_备份%d.json' % self.backupNumber) + configJSONPath = os.path.join(application_path, r'utils/config_备份%d.json' % self.backupNumber) self.backupNumber += 1 if self.backupNumber == 4: self.backupNumber = 1 @@ -234,12 +229,11 @@ class CheckDanmmuProvider(QThread): """检查弹幕服务器域名解析状态""" def __init__(self): - super(CheckDanmmuProvider, self).__init__() - + super(CheckDanmmuProvider,self).__init__() + def run(self): try: - anwsers = dns.resolver.resolve( - 'broadcastlv.chat.bilibili.com', 'A') + anwsers = dns.resolver.resolve('broadcastlv.chat.bilibili.com', 'A') danmu_ip = anwsers[0].to_text() logging.info("弹幕IP: %s" % danmu_ip) except Exception as e: @@ -381,7 +375,7 @@ def __init__(self, cacheFolder, progressBar, progressText): vlcProgressCounter = 1 for i in range(16): if len(self.config['danmu'][i]) < 8: - self.config['danmu'][i].append(0) + self.config['danmu'][i].append(3) volume = self.config['volume'][i] progressText.setText('设置第%s个主层播放器...' % str(i + 1)) self.videoWidgetList.append(VideoWidget(i, volume, cacheFolder, textSetting=self.config['danmu'][i], diff --git a/VideoWidget_vlc.py b/VideoWidget_vlc.py index 94ce753..ebddbc4 100644 --- a/VideoWidget_vlc.py +++ b/VideoWidget_vlc.py @@ -407,7 +407,7 @@ def __init__(self, id, volume, cacheFolder, top=False, title='', resize=[], # 关闭窗口 self.stop = PushButton(self.style().standardIcon( QStyle.SP_DialogCancelButton)) - self.stop.clicked.connect(self.mediaStop) + self.stop.clicked.connect(self._mediaStop) frameLayout.addWidget(self.stop) # ---- IO 交互设置 ---- @@ -431,6 +431,10 @@ def __init__(self, id, volume, cacheFolder, top=False, title='', resize=[], self.moveTimer.timeout.connect(self.initTextPos) self.moveTimer.start(50) + # self.reloadDanmuTimer = QTimer() + # self.reloadDanmuTimer.timeout.connect(self.reloadDanmu) + # self.reloadDanmuTimer.start(10000) + # 检查播放卡住的定时器 self.checkPlaying = QTimer() self.checkPlaying.timeout.connect(self.checkPlayStatus) @@ -892,11 +896,7 @@ def closeDanmu(self): # self.setTranslator.emit([self.id, False]) def stopDanmuMessage(self): - try: - self.danmu.message.disconnect(self.playDanmu) - except: - logging.exception('停止弹幕出错') - self.danmu.terminate() + self.stopDanmu() def showDanmu(self): if self.textBrowser.isHidden(): @@ -986,6 +986,9 @@ def mediaReload(self): else: self.mediaStop() + def _mediaStop(self): + self.mediaStop() + def mediaStop(self, deleteMedia=True): # self.userPause = True self.oldTitle, self.oldUname = '', '' @@ -997,17 +1000,27 @@ def mediaStop(self, deleteMedia=True): self.play.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) if deleteMedia: self.deleteMedia.emit(self.id) - try: - self.danmu.message.disconnect(self.playDanmu) - except: - logging.exception('停止弹幕出错') self.getMediaURL.recordToken = False self.getMediaURL.checkTimer.stop() self.checkPlaying.stop() + self.stopDanmu() + + def stopDanmu(self): + # try: + try: + self.danmu.message.disconnect(self.playDanmu) + except: + pass self.danmu.terminate() self.danmu.quit() self.danmu.wait() + def reloadDanmu(self): + self.stopDanmu() + self.danmu.setRoomID(self.roomID) + self.danmu.message.connect(self.playDanmu) + self.danmu.start() + def setMedia(self, cacheName): self.retryTimes = 0 self.cacheName = cacheName @@ -1016,7 +1029,8 @@ def setMedia(self, cacheName): try: self.danmu.message.disconnect(self.playDanmu) except: - logging.exception('停止弹幕出错') + pass + # logging.exception('停止弹幕出错') if self.startWithDanmu: self.danmu.message.connect(self.playDanmu) self.danmu.terminate() @@ -1126,7 +1140,7 @@ def playDanmu(self, message): self.textBrowser.msgsBrowser.append(message) return for symbol in self.filters: - if symbol in message[message.find(': ')+2:]: + if symbol in message: self.textBrowser.transBrowser.append(message) token = True break diff --git a/remote.py b/remote.py index ff2731d..6a5c66a 100644 --- a/remote.py +++ b/remote.py @@ -6,15 +6,22 @@ import zlib import json import requests -from aiowebsocket.converses import AioWebSocket +# from aiowebsocket.converses import AioWebSocket from PyQt5.QtCore import QThread, pyqtSignal import logging +from bilibili_api import live + + +class Live(live.LiveDanmaku): + + def __init__(self, room_display_id): + super().__init__(room_display_id) + + def register(self, event: str, func: callable): + self.__getattribute__("_LiveDanmaku__event_handlers")[event].append(func) class remoteThread(QThread): - """ - TODO: 换用 bilibili_api.live.LiveDanmaku(room_display_id) - """ message = pyqtSignal(str) def __init__(self, roomID): @@ -31,32 +38,38 @@ def __init__(self, roomID): if '"roomid":' in line: self.roomID = line.split('"roomid":')[1].split(',')[0] - async def startup(self, url): - logging.info('尝试打开 %s 的弹幕Socket' % self.roomID) - data_raw = '000000{headerLen}0010000100000007000000017b22726f6f6d6964223a{roomid}7d' - data_raw = data_raw.format(headerLen=hex(27 + len(self.roomID))[2:], - roomid=''.join(map(lambda x: hex(ord(x))[2:], list(self.roomID)))) - async with AioWebSocket(url) as aws: - try: - converse = aws.manipulator - await converse.send(bytes.fromhex(data_raw)) - tasks = [self.receDM(converse), self.sendHeartBeat(converse)] - await asyncio.wait(tasks) - except: - logging.exception('弹幕Socket打开失败') + async def startup(self): + self.roomID = int(self.roomID) + self.room = Live(self.roomID) + self.room.add_event_listener('DANMU_MSG', self.danmu) # 用户发送弹幕 + # self.room.add_event_listener('SEND_GIFT', self.gift) # 礼物 + # self.room.add_event_listener('COMBO_SEND', self.combo_gift) # 礼物连击 + # self.room.add_event_listener('GUARD_BUY', self.guard) # 续费大航海 + self.room.add_event_listener('SUPER_CHAT_MESSAGE', self.sc) # 醒目留言(SC) + # self.room.add_event_listener('INTERACT_WORD', self.enter) # 用户进入直播间 + await self.room.connect() + # await asyncio.wait([self.room.connect()]) - async def sendHeartBeat(self, websocket): - logging.debug("向%s发送心跳包" % self.roomID) - hb = '00000010001000010000000200000001' - while True: - await asyncio.sleep(30) - await websocket.send(bytes.fromhex(hb)) + async def danmu(self, jd): + self.message.emit(jd['data']['info'][1]) - async def receDM(self, websocket): - while True: - recv_text = await websocket.receive() - logging.debug("从%s接收到DM" % self.roomID) - self.printDM(recv_text) + async def gift(self, event): + print(event) + + async def combo_gift(self, event): + print(event) + + async def guard(self, event): + print(event) + + async def sc(self, jd): + jd = jd['data'] + self.message.emit( + f"【SC(¥{jd['data']['price']}) {jd['data']['user_info']['uname']}: {jd['data']['message']}】" + ) + + async def enter(self, event): + print(event) def printDM(self, data): packetLen = int(data[:4].hex(), 16) @@ -118,11 +131,12 @@ def getMetal(jd): jd = json.loads(data[16:].decode('utf-8', errors='ignore')) if jd['cmd'] == 'DANMU_MSG': self.message.emit( - f"{userType[jd['info'][2][7]]}{adminType[jd['info'][2][2]]}{getMetal(jd)} {jd['info'][2][1]}: {jd['info'][1]}" + # f"{userType[jd['info'][2][7]]}{adminType[jd['info'][2][2]]}{getMetal(jd)} {jd['info'][2][1]}: {jd['info'][1]}" + f"{jd['info'][1]}" ) elif jd['cmd'] == 'SUPER_CHAT_MESSAGE': self.message.emit( - f"SC(¥{jd['data']['price']}) {getMetal(jd)} {jd['data']['user_info']['uname']}: {jd['data']['message']}" + f"【SC(¥{jd['data']['price']}) {getMetal(jd)} {jd['data']['user_info']['uname']}: {jd['data']['message']}】" ) elif jd['cmd'] == 'SEND_GIFT': if jd['data']['coin_type'] == "gold": @@ -153,12 +167,8 @@ def getMetal(jd): logging.exception('弹幕输出失败') def setRoomID(self, roomID): - self.roomID = roomID + self.roomID = int(roomID) def run(self): - remote = r'wss://broadcastlv.chat.bilibili.com:2245/sub' - try: - asyncio.set_event_loop(asyncio.new_event_loop()) - asyncio.get_event_loop().run_until_complete(self.startup(remote)) - except: - logging.exception('弹幕主循环出错') + asyncio.set_event_loop(asyncio.new_event_loop()) + asyncio.get_event_loop().run_until_complete(self.startup())