diff --git a/README.md b/README.md index 4f3857e..423ef97 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ Plugin repository for [Macast](https://github.com/xfangfang/Macast/). | PotPlayer | | | ☑️ | PotPlayer support for Macast | [potplayer.py](https://raw.githubusercontent.com/xfangfang/Macast-plugins/main/potplayer/potplayer.py) [README](https://github.com/xfangfang/Macast-plugins/tree/main/potplayer) | | PI-FM-RDS | | ☑️ (Only for RaspberryPi) | | Use this to send MP3 music in the form of FM broadcast | [pi_fm.py](https://raw.githubusercontent.com/xfangfang/Macast-plugins/main/pi-fm-rds/pi_fm.py) [README](https://github.com/xfangfang/Macast-plugins/tree/main/pi-fm-rds) | | WebBrowser | ☑️ | ☑️ | ☑️ | This can be used to download media files or get some m3u8 played | [web.py](https://raw.githubusercontent.com/xfangfang/Macast-plugins/main/web/web.py) [README](https://github.com/xfangfang/Macast-plugins/tree/main/web) | +| BiliBrowser | ☑️ | ☑️ | ☑️ | Open Bilibili videos in the default browser (depends on NVA to get BV id) | [bilibrowser.py](https://raw.githubusercontent.com/pasical/Macast-plugins/main/bilibrowser/bilibrowser.py) [README](https://github.com/pasical/Macast-plugins/tree/main/bilibrowser) | | Nirvana(Protocol) | ☑️ | ☑️ | ☑️ | A protocol created by Bilibili. | [nirvana.py](https://raw.githubusercontent.com/xfangfang/Macast-plugins/main/nirvana/nirvana.py) [README](https://github.com/xfangfang/Macast-plugins/tree/main/nirvana) | diff --git a/README_ZH.md b/README_ZH.md index a50ef5d..535bfc7 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -31,6 +31,7 @@ | PotPlayer | | | ☑️ | PotPlayer 适配插件 | [potplayer.py](https://gitee.com/xfangfang/Macast-plugins/raw/main/potplayer/potplayer.py) [README](https://gitee.com/xfangfang/Macast-plugins/tree/main/potplayer) |image | PI-FM-RDS | | ☑️ (只能用在树莓派上) | | 使用这个插件接收mp3媒体链接并用pi-fm-rds以fm广播的形式发送 | [pi_fm.py](https://gitee.com/xfangfang/Macast-plugins/raw/main/pi-fm-rds/pi_fm.py) [README](https://gitee.com/xfangfang/Macast-plugins/tree/main/pi-fm-rds) | | WebBrowser | ☑️ | ☑️ | ☑️ | 这个插件可以用于使用浏览器下载媒体文件,或播放某些不受mpv支持的m3u8文件 | [web.py](https://gitee.com/xfangfang/Macast-plugins/raw/main/web/web.py) [README](https://gitee.com/xfangfang/Macast-plugins/tree/main/web) | +| BiliBrowser | ☑️ | ☑️ | ☑️ | 在默认浏览器打开 B 站视频(依赖 NVA 协议获取 BV 号) | [bilibrowser.py](https://raw.githubusercontent.com/pasical/Macast-plugins/main/bilibrowser/bilibrowser.py) [README](https://github.com/pasical/Macast-plugins/tree/main/bilibrowser) | | Nirvana(协议) | ☑️ | ☑️ | ☑️ | 这个插件用于适配B站的私有协议,仅用于编程学习使用,禁止用做商业用途,如有侵权,请联系作者删除。 | [nirvana.py](https://gitee.com/xfangfang/Macast-plugins/raw/main/nirvana/nirvana.py) [README](https://gitee.com/xfangfang/Macast-plugins/tree/main/nirvana) | diff --git a/bilibrowser/README.md b/bilibrowser/README.md new file mode 100644 index 0000000..bfd5836 --- /dev/null +++ b/bilibrowser/README.md @@ -0,0 +1,33 @@ +# BiliBrowser + +## English + +BiliBrowser renderer for Macast. It opens the original Bilibili video in your default browser. + +### Platform + +darwin win32 linux + +### Dependence + +Requires [NVA (Nirvana) Protocol](https://github.com/xfangfang/Macast-plugins/blob/main/nirvana/README.md) plugin to resolve aid/cid. **After installing, switch the adapter to NVA in Macast settings.** + +### Help + +Download the plugin to the renderer folder, enable BiliBrowser in Macast. When you cast a Bilibili stream to Macast, the plugin opens ```https://www.bilibili.com/video/BV...```. Make sure to manually switch the adapter option to NVA; otherwise, your browser will open an m3u8 player. + +## 中文 + +BiliBrowser 是为 Macast 开发的播放器插件,会在默认浏览器中打开哔哩哔哩视频源链接。 + +### 平台 + +darwin win32 linux + +### 依赖 + +依赖 [NVA 协议](https://github.com/xfangfang/Macast-plugins/blob/main/nirvana/README.md) 用于解析 aid/cid。**安装后请在 Macast 的适配器设置中手动切换为 NVA。** + +### 使用帮助 + +将插件放在 renderer 文件夹,在 Macast 中启用 "BiliBrowser"。当向 Macast 投送 B 站内容时,插件会在浏览器打开 ```https://www.bilibili.com/video/BV...```。请务必手动将适配器选项切换为 NVA,否则浏览器会直接打开 m3u8 播放器。 \ No newline at end of file diff --git a/bilibrowser/bilibrowser.py b/bilibrowser/bilibrowser.py new file mode 100644 index 0000000..aa7a06b --- /dev/null +++ b/bilibrowser/bilibrowser.py @@ -0,0 +1,131 @@ + +# BiliBrowser +# +# Macast Metadata +# BiliBrowser +# BiliBrowserRenderer +# darwin,linux,win32 +# 0.2 +# 0.7 +# Pasical +# Open the stream source BV video in browser. Dependence on NVA Protocol + +import re +import time +import threading +import webbrowser +import subprocess +import sys +import cherrypy + +from macast import gui, Setting +from macast.renderer import Renderer + +class BiliBrowserRenderer(Renderer): + # AV转BV常量 + XOR_CODE = 23442827791579 + MASK_CODE = 2251799813685247 + MAX_AID = 1 << 51 + ALPHABET = "FcwAPNKTMug3GV5Lj7EJnHpWsx4tb8haYeviqBz6rkCy12mUSDQX9RdoZf" + ENCODE_MAP = (8, 7, 0, 5, 1, 3, 2, 4, 6) + BASE = len(ALPHABET) + PREFIX = "BV1" + + def __init__(self): + super(BiliBrowserRenderer, self).__init__() + self.start_position = 0 + self.position_thread_running = True + self.position_thread = threading.Thread(target=self.position_tick, daemon=True) + self.position_thread.start() + + def position_tick(self): + while self.position_thread_running: + time.sleep(1) + self.start_position += 1 + sec = self.start_position + position = '%d:%02d:%02d' % (sec // 3600, (sec % 3600) // 60, sec % 60) + self.set_state_position(position) + + # 从NVA协议获取aid + def get_video_info_from_nva(self, url=None): + try: + target_cid = None + if url: + match = re.search(r'upgcxcode/\d+/\d+/(\d+)', url) + target_cid = match.group(1) if match else None + + protocols = cherrypy.engine.publish('get_protocol') + if protocols and hasattr(protocols[0], 'clients'): + for handler in protocols[0].clients.values(): + if hasattr(handler, 'aid') and handler.aid: + if target_cid and hasattr(handler, 'cid') and str(handler.cid) == str(target_cid): + return handler.aid + elif not target_cid: + return handler.aid + except: + pass + return None + + # AV号转BV号 + def av2bv(self, aid): + try: + aid = int(aid) + bvid = [""] * 9 + tmp = (self.MAX_AID | aid) ^ self.XOR_CODE + for i in range(len(self.ENCODE_MAP)): + bvid[self.ENCODE_MAP[i]] = self.ALPHABET[tmp % self.BASE] + tmp //= self.BASE + return self.PREFIX + "".join(bvid) + except: + return None + + # 在默认浏览器中打开URL + def open_browser(self, url): + try: + if sys.platform == 'darwin': + subprocess.Popen(['open', url]) + elif sys.platform == 'win32': + webbrowser.open(url) + else: + env = Setting.get_system_env() + toDelete = [] + for (k, v) in env.items(): + if k != 'PATH' and 'tmp' in v: + toDelete.append(k) + for k in toDelete: + env.pop(k, None) + subprocess.Popen(["xdg-open", url], env=env) + return True + except: + return False + + def set_media_stop(self): + self.set_state_transport('STOPPED') + cherrypy.engine.publish('renderer_av_stop') + + def set_media_url(self, url, start=0): + self.set_media_stop() + self.start_position = 0 + + aid = self.get_video_info_from_nva(url) + if aid: + bvid = self.av2bv(aid) + video_url = f"https://www.bilibili.com/video/{bvid}" if bvid else f"https://www.bilibili.com/video/av{aid}" + self.open_browser(video_url) + self.set_state_transport("PLAYING") + cherrypy.engine.publish('renderer_av_uri', video_url) + return + + # 如果NVA协议无法获取信息,直接打开原始链接 + self.open_browser(url) + self.set_state_transport("PLAYING") + cherrypy.engine.publish('renderer_av_uri', url) + + def stop(self): + super(BiliBrowserRenderer, self).stop() + self.set_media_stop() + self.position_thread_running = False + + +if __name__ == '__main__': + gui(BiliBrowserRenderer())