弹幕大概是少数几种会让人留念 B 站的东西。
有些视频,我更愿意在原作者的 YouTube 频道或自己的高清媒体库里观看:画面更清楚,压缩更少,也可能保留了更完整的内容。但少了 B 站同一时间点飘过的一句吐槽,观看体验似乎也跟着少了一块。
有时候,真正让我笑出来的并不完全是视频本身,而是画面和弹幕共同完成的:某句似曾相识的台词、一个固定出场的道具,或者创作者刚挖完坑,观众已经提前在屏幕上报出了答案。
画面可以换一个地方看,这种共同观看的感觉却很难一起带走。
于是我做了「弹来弹去」:粘贴一个 B 站视频链接,它只获取弹幕,不下载、也不播放视频,再通过一层透明置顶窗口,把弹幕覆盖到 YouTube、Infuse、IINA、QuickTime 等播放器上。
现在它已经支持 macOS 和 Windows,并在 GitHub 开源。


画质和弹幕,为什么非要二选一?
从数据上看,视频和弹幕本来就是两套相对独立的内容。
视频负责画面与声音;弹幕只需要知道两件事:应该显示什么,以及应该在第几秒出现。既然如此,弹幕并不一定非得被锁在某个网页或某个播放器里。
只要在视频窗口上方放置一层透明、置顶的弹幕窗口,底下播放的是浏览器里的 YouTube、Infuse 中的个人媒体库,还是 IINA、QuickTime 里的本地文件,在窗口化播放场景里都没有本质区别。
我最初以为,这是一个应该早就被解决的问题。
后来搜索才发现,类似方案并非没有:弹弹play 在 Windows 上支持把弹幕覆盖到 PotPlayer、mpv、MPC 等指定播放器;Danmaku Anywhere 可以给网页视频加载弹幕;IINA 和 mpv 也有各自的弹幕插件。
但我的需求刚好落在这些方案之间:
不想为了看弹幕更换自己习惯的播放器;
不希望工具接管或重新播放视频;
既要覆盖浏览器,也要覆盖 Infuse、QuickTime 等原生应用;
既然现成方案没有完全落在这个交集里,我决定自己做一个。
一个只负责弹幕的 App
「弹来弹去」的使用流程只有四步:
粘贴 B 站视频链接,支持 BV、av、分 P 和 b23.tv 短链;
获取对应视频的弹幕;
打开透明弹幕层,并把它放到视频画面上方;
在任意播放器中打开对应的视频,完成一次时间同步。


它不读取视频内容,也不知道弹幕窗口下面正在播放什么。你可以用 Infuse 播放自己的媒体库,在 IINA 里打开本地文件,也可以直接在浏览器里观看 YouTube。只要两边是内容和时间轴大致对应的同一段视频,就能把它们组合起来。
这种设计的好处是通用:我不需要为每个播放器分别实现一套视频加载逻辑,更不会碰到画质、字幕、HDR、音轨、网盘协议或播放权限等问题。
它只做弹幕,其余事情继续交给用户已经选择好的播放器。
但这种通用性也带来了整个项目最麻烦的问题。
它怎么知道视频播放到哪里了?
答案是:它不知道。
因为「弹来弹去」不读取下方播放器的状态,所以无法自动知道视频正在播放、暂停,或者已经快进到了第几秒。
最理想的体验当然是自动同步:播放器暂停,弹幕也暂停;播放器跳转,弹幕跟着跳转;播放速度改变,两条时间轴始终保持一致。
但如果要实现这种体验,就需要分别适配浏览器、Infuse、IINA、QuickTime 以及其他播放器。有些可以通过脚本或辅助功能获取状态,有些只能间接猜测,还有些系统级全屏场景根本不允许外部窗口覆盖。
对于一个只为了解决个人观看需求的小工具来说,这很容易变成一项永远做不完的工程。
我最后选择了一个更朴素的办法:让弹幕使用自己的时间轴,再通过一次手动操作和视频完成同步。
加载弹幕后,点击「5 秒后从 0 同步」,弹幕层中央会出现倒计时。我只需要把鼠标放到播放器的播放按钮上,在倒计时归零时开始播放视频即可,这一个设计可以让用户在使用时不用受忙脚乱地去对齐进度。

如果两边相差一点,还可以使用 ±1 秒、±5 秒按钮或直接输入精确偏移进行微调。在我自己的使用中,只要两个版本没有明显的片头或剪辑差异,通常十秒左右就能对齐。
完成同步后,App 会保存这个视频的播放位置和时间偏移。下次从历史记录打开时,可以直接从上次的位置继续,不需要重新从头校准。
它没有自动同步那么优雅,但足够简单,也足够可靠。
当然,这个方案也有明确边界:如果两个版本的片头不同,可以用偏移解决;如果中间存在删减或重新剪辑,后半段仍可能再次错位。通用性并不是免费的,它只是把“适配每个播放器”的复杂度,换成了用户偶尔进行一次手动校准。
真正好用的工具,应该尽量“消失”
弹幕层位于播放器上方,但平时不应该妨碍播放器操作。
因此我加入了「鼠标穿透」:开启后,点击、拖动进度条、切换全屏等操作都会直接落到下面的播放器上;需要调整弹幕层的位置和尺寸时,再暂时关闭穿透,窗口边缘会出现提示边框,可以直接拖动和缩放。
主窗口也被压缩成两个主要步骤:第一页选择弹幕来源,可以粘贴链接或从历史记录继续观看;第二页只保留播放、暂停、进度、同步和微调。倍速、清屏、鼠标穿透和导入导出等低频操作,都收进二级菜单。
观影时,我通常不会再切回主窗口,而是使用全局快捷键控制弹幕:
播放或暂停弹幕;
前后微调 1 秒或 5 秒;
从当前时刻重新同步;
显示或隐藏弹幕层。
这看起来只是一些很小的功能,却直接决定了一个 App 是只能演示一次,还是愿意在下次看视频时重新打开。
从“能运行”到“愿意一直用”
最早的版本只完成了四件事:解析链接、获取弹幕、渲染弹幕,以及让弹幕开始或暂停。
剩下的功能,几乎都来自实际使用中的不满。
拖动进度条时,时间数字没有同步变化;点击播放后,按钮图标没有变成暂停;主窗口信息太多;开启鼠标穿透后,很难再把控制窗口找回来;长时间观看后,两边的时间轴可能产生轻微偏差。
这些问题单独看都不严重,但它们决定了一个“能运行的 Demo”能否变成真正愿意反复打开的工具。
因此,我补上了播放状态、历史记录、进度保存、全局快捷键、偏移微调、窗口位置记忆、显示区域、密度控制和过滤功能。时间轴与窗口状态也做了自动测试,避免修复一个问题时又破坏另一个使用场景。
工具类产品最容易忽略的,往往不是核心功能,而是核心功能前后的十几个小动作。
macOS 的 Liquid Glass,以及后来的 Windows 版

macOS 版采用原生 AppKit 开发,并使用了 macOS 26 Tahoe 的 Liquid Glass 界面。主控制窗口使用玻璃材质卡片和按钮,深色模式下则选择了偏粉色的强调色,希望它看起来像一个系统工具,而不是套着网页外壳的播放器。
使用新系统 API 的代价也很直接:目前 macOS 版要求 macOS 26 或更高版本。为了兼容更旧的系统重新实现整套界面,会让这个个人项目多出不少维护成本,因此第一阶段我选择先把体验做好。
后来我又做了 Windows 10/11 x64 原生版本。它采用 .NET 8 和 WPF,同样包含透明置顶弹幕层、鼠标穿透、分 P、时间轴同步、过滤、历史记录和全局快捷键。安装包是自包含版本,用户不需要额外安装 .NET Runtime。
两个版本没有追求界面上的完全一致,但核心工作方式相同:视频由原来的播放器负责,弹幕由一层独立窗口负责。
弹幕也可以不挡住画面
一位朋友试用后,向我提到了另一个起初没有想到的使用场景。
看经典电影,或者摄影、作画特别出色的动画时,人会更想好好欣赏完整的构图、光影和细节。弹幕依然有趣,但让文字从人物面前和精心设计的画面上不断飘过,有时也会破坏观看体验。
在站内播放器里,弹幕终究与视频共用同一块画面。即使可以调整透明度和显示区域,想在关键镜头完全不受遮挡,往往还是需要手动打开和关闭弹幕。
但「弹来弹去」的弹幕层本身就是一个可以自由移动、缩放的独立窗口,你想调整成任何比例,放在任何位置都可以,因此弹幕并不一定要盖在视频上。
只有一块屏幕时,可以把视频窗口放在屏幕上半部分,把弹幕层放在下半部分:上面只保留完整画面,下面继续显示观众在同一时间点留下的反应,两边互不遮挡。
如果有两块显示器,还可以把视频放在主屏,把弹幕层单独放到副屏。主屏用来专心看电影,副屏则像一条与影片同步的观众席——想看时转一下视线,不想看时也不会干扰画面。
这也是独立窗口带来的另一个价值:它不只是把 B 站弹幕带到其他播放器,也让画面和弹幕可以在空间上彼此分离。弹幕既可以覆盖在视频上,也可以退到画面之外,成为一条独立的观看层。

像播客类的节目,本身画面就不重要,你甚至可以一边开着弹幕一边查阅其他资料,比如这样:

下载、限制与边界
「弹来弹去」目前已经在 GitHub 开源,采用 GPL-3.0 许可证:
目前有几项限制需要提前说明:
macOS 版要求 macOS 26 Tahoe 或更高版本;Windows 版支持 Windows 10/11 x64;
工具仅使用无需登录即可访问的公开接口,不携带 Cookie,因此获取到的是当前公开弹幕池,不一定包含全部历史弹幕;
当前支持 BV、av、分 P 和 b23.tv 短链,暂不支持番剧 ep/ss 链接与互动视频;
工具不下载视频,也不会绕过视频平台的播放权限;
独立弹幕层在系统原生独占全屏下可能无法显示,可改用窗口最大化,或导出 ASS 字幕作为兜底;
视频版本存在中途删减或重新剪辑时,弹幕可能需要再次校准。
这是一个独立第三方开源工具,与哔哩哔哩没有关联、授权或合作关系。弹幕内容的权利归原发送用户及平台所有,请仅用于个人观看辅助,不要用于批量抓取或商业用途。
还想继续做什么
现在的版本已经解决了我最初的问题:在 Infuse 中播放自己的高清媒体库,或者在 YouTube 上观看创作者发布的版本时,仍然能够保留 B 站弹幕。
但还有一些方向值得继续尝试。
比如把弹幕密度显示成时间轴热力图。弹幕数量往往能反映视频的情绪高点,即使不读取具体内容,也可以提前知道接下来哪里可能发生有趣的事情。
我也考虑过制作一个浏览器扩展,用来读取 YouTube 等网页播放器的当前进度,再与桌面 App 通过本地连接自动同步。它会让网页观看体验更加完整,不过也意味着需要针对不同网站持续适配。
至少在现在,我仍然更愿意先保持这个工具的简单:
视频归播放器管,弹幕归「弹来弹去」管。
我们早已习惯把视频、字幕和音轨自由组合。也许弹幕同样不应该永远被锁在某一个网站里。
有些视频值得用最好的画质观看,而有些梗,确实需要大家一起笑才完整。

我的其他文章(另一个账号发的):
