异地远程一起看视频(VideoTogether本地实现方式)

linken 849 2023-05-29

一、背景与需求

现今很多人都有异地远程一起看电影、视频、番剧的需求,但实际上无论是手机app还是各种电脑端软件都不能很好的达到我的需求。我作为问题的提出方,对此类情景的要求如下:

  • 对方使用方便、简洁,无需太多设置,不限客户端,最好做到开箱即用;
  • 对方无需提前准备,无需下载视频;
  • 使用时做到简单优雅,部署和准备阶段不至于过分繁琐。

在以上条件的约束下,我目前有两个较为稳定的解决方案:

  • 其一是直接使用我自己本地现成的Jellyfin。它本身自带一个SyncPlay功能,只要两个用户同时加入一个组就可以共享进度,但偶尔好像有些不稳定。
  • 其二就是接下来要详细说的VideoTogether。它最主要的功能是作为浏览器插件来使用,但由于作者的辛勤努力和对各种情况及需求的适配更新,让我们能配合一些其他的操作来做到足以满足上面提出的三点需求。

二、前置要求及工具介绍

首先需要判断你是否具备一下任意一项条件:

  • 本地网络拥有公网IP,且上传带宽不低于10Mbps;
  • 可以做到内网穿透,且上传带宽不低于10Mbps;
  • 拥有一台具备公网IP,带宽不低于5Mbps,且流量充足的VPS服务器;

这里强调一下,如果不满足上述任一一条前置要求,那此篇文章中的实现方式是不可行的。

项目官方地址:Github仓库官方网站

最初我是在v2ex上看到作者发的帖子,了解到这个解决方式。

但作者当时是以浏览器插件的形式实现的,这就需要观看双方都进行同样的配置、安装同样的插件,然后打开同样的视频页面才可以自动同步播放进度。这其实是不符合我在文章开头提到的要求的。

回过头来,我发现作者提供了一个为视频网站添加一起看功能的解决办法,如此一来异地的两方在观看时都可以作为网站的用户直接打开浏览器,而不需要再做诸如安装插件、配置环境、配置代理什么的繁琐方式。并且如果可以实现此类方式,那理论上无论任何种类的客户端只要使用浏览器就可以同步观看。

并且在之后的更新中,作者已经开始测试简单分享功能,就是单方面安装插件后直接将链接分享给对方,对方可做到无需安装插件直接点击进行同步观看,这应该会是一个更加便利的解决方式。但即便目前还没有实装这一功能,我们也可以用此篇文章中将要介绍的方法来让对方便利的加入和观看我们提供的视频。

在文章的最后,我还会简单介绍一下省去过多Web代理服务器的配置,直接配合AList进行更简洁流畅的同步观看的办法。

接下来是正文。

三、具体实现方式

1、准备Web服务器

任意Web服务器都可以,比如Nginx、caddy、httpd等等,因为我们只需要搭建一个最简单的视频网站。这里我使用的是Nginx,如果你那里只有Windows环境我也建议选择Nginx来进行操作。

以Windows环境为例,只需要去官方网站下载Nginx的压缩包,解压后就是Nginx的工作目录,只要把准备好的网站文件、视频和字幕文件都按照路径放在www下,然后双击nginx.exe,一个最简单的视频播放网站就准备好了。

好了,这部分内容只是一个提示,具体的操作教程有非常多,并且我们在这里只需要最简单最基础的功能,所以为了节省篇幅,大家有需要可以去搜索一下其他的教程。

2、网页代码文件

接下来是重点(但不是什么难点),即编写网页源文件使指定的视频可以直接通过浏览器进行播放,这里将example.test.com:8181作为你对外提供服务的Web服务器的访问地址与端口,理论上在这里使用IP:端口域名:端口都可以,可以按需修改。

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>一起看</title> 
  <script src="https://2gether.video/release/extension.website.user.js"/></script>
</head>
<style>
  ::cue {
    background: none;
    color: #fff;
    text-shadow: 0 1px #000, 1px 0 #000, -1px 0 #000, 0 -1px #000;
    font-size: 48px;
  }
</style>

<body style="background-color:rgba(38, 52, 68, 0.89)">
  <div id="main">
    <h1>一起看</h1>
    <div id="body">
      <div id="effect" class="part">
        <div class="show">
          <div class="demo">
            <video id="video" preload="auto" width="100%" height="100%" autobuffer controls>
              <source src="http://example.test.com:8181/111/video.mp4" type="video/mp4">
              <source src="http://example.test.com:8181/1111/video.mp4" type="video/ogg">
              <source src="http://example.test.com:8181/1111/video.mp4" type="video/webm">
              <object data="http://example.test.com:8181/1111/video.mp4" width="100%" height="100%">
                <embed src="http://example.test.com:8181/1111/video.mp4" width="100%" height="100%">
              </object>
              <track src="http://example.test.com:8181/1111/cc.vtt" kind="subtitles" label="中文字幕" srclang="zh" default>
            </video>
          </div>
        </div>
      </div>
    </div>
  </div>
</body>

在上面的这个index.html文件内容中可以看出,我们将需要播放的视频文件命名为video.mp4,字幕文件命名为cc.vtt,并一同放在网站根目录下的/111这个目录下。

至此,网站页面文件也准备好了。

3、视频文件处理

目前我经过测试,大部分浏览器对视频编码的兼容基本无碍,但音频基本只支持acc格式,而大部分清晰度较高的视频文件尤其是电影都不是以此种音频编码格式保存的,这也是很多人在用浏览器播放某些视频资源时没有声音的原因。因此我们需要在本地手动进行转码,不过不用担心,因为我们仅是重新对音频进行转码,视频格式不需要动,所以这个转码的速度还是很快的。

这里需要用到ffmpeg,具体安装不再说明。由于ffmpeg支持多平台并且全平台命令语法保持一致,所以之后的命令不会对此进行区分,如在Windows平台下请将ffmpeg自行转换为ffmpeg.exe,并注意执行路径。

视频转码命令如下:

ffmpeg -i video_file.mkv -c:v copy -c:a aac video.mp4

这条命令中,仅保留了原视频文件中的视频流和音频流,并重新进行打包,理论上使用.mp4.mkv无差异。

4、字幕文件处理

因为html5自带的播放器仅支持.vtt格式字幕,并不支持内嵌字幕,故在处理原视频时,原字幕不再保留。

需要去射手网下载电影对应的字幕文件,格式一般为.ass.srt,然后用ffmpeg进行格式转换:

ffmpeg -i sub_file.ass cc.vtt

如果原视频中的字幕文件是text格式的,那也可以直接将其中的字幕取出并转换为单独的.vtt格式文件:

ffmpeg -i video_file.mkv -map 0:s:0 cc.vtt

这里如果原视频中有多条字幕,需要自行确认你所需要转出的字幕对应的流的序号,并在命令中进行调整。

5、特殊问题和说明

在linux系统或VPS下,基本上做到这一步就算是成功了,双方应该已经可以正常同步观影。但如果部署方使用的是自己的Windows电脑,并且外部在路由器等设备上映射后对方访问不到对应页面,那可能需要调整本地的防火墙设置和映射。

注:除非确实有访问不到的异常,并且确认已经对防火墙进行了关闭或开启了放通策略,不然请尽量不要设置此部分内容。

假设我们使用的对外端口是8181,那么将Nginx的配置文件中的端口设置为80,并进行下述设置。

本机127.0.0.1上的80端口映射到8181端口对外(并需要开启防火墙上的对应端口或关闭防火墙):

netsh interface portproxy add v4tov4 listenport=8181 connectport=80 connectaddress=127.0.0.1

查看映射情况,确认是否生效:

netsh interface portproxy show all

理论上此操作只需设置一次即可永久生效。

四、将功能集成至AList

1、介绍

AList是一个支持多种存储的文件列表程序,它可以将你本地或者网盘中的文件以面板的方式展示出来。作为一个文件管理工具,它支持多个存储提供商,包括本地存储、阿里云盘、OneDrive、Google Drive 等,且易于拓展。

并且最重要的是它还提供了常见文件的在线预览功能,比如我们需要的视频的预览功能。

AList内置了ArtPlayer播放器作为网页视频播放器,可以在线直接对视频进行播放,并且默认会加载与视频文件同目录下的同名字幕文件,官方说明是支持asssrtvtt三种格式,但经过我自己测试以及在Github的讨论区中调研发现前两种格式并不是完全兼容,所以将字幕转为vtt格式还是很有必要的。

同样,在AList的讨论区中,关于视频播放提到的最多的问题就是视频没有声音或者播放异常,这也都是由于浏览器播放的方式只能解析一部分视频编码和声音编码格式,所以我们前面提到的视频准备流程和字幕准备流程仍旧是必不可少的一项工作。另外,如果遇到视频画面直接黑屏的问题,建议是重新换源下载,因为对视频重编码的时间一般都大于重新下载的时间。

另外,笔者使用的是本地存储,所以没有测试将阿里云盘、夸克网盘等国内便利性较高的网盘挂到AList上之后,是否可以降低对本地上传带宽的要求,做到白嫖公有网盘带宽的效果。

所以这一点的明确信息容我日后测试完毕再来更新,但据推测应该是可行的。不过如果采取这种方式,是需要将本地转码好的视频上传到公有网盘,准备时间和准备步骤会增加。

2、为AList添加一起看功能

在官方的为视频网站添加一起看功能这个教程页面中,已经更新了将一起看功能添加到AList的教程说明,具体教程页面可以点击跳转,其中包括了部署AList的步骤以及添加一起看功能和优化的方法。我这里为了自己留一份备份,也在下面简单把需要调整的位置及代码记录一下,但详细说明就不全篇复制了。

以下设置皆在AList的“全局”设置中。

自定义头部:

添加videotogether功能,并调整默认按钮位置:

<script src="https://polyfill.io/v3/polyfill.min.js?features=String.prototype.replaceAll"></script>
<script src="https://2gether.video/release/extension.website.user.js"></script>
<script>
document.addEventListener("DOMContentLoaded", () => {
  const seAList = document.createElement("style");

  seAList.innerHTML = `
    .left-toolbar-box {
        left: var(--hope-space-5);
        right: auto;
    }
`;

  document.body.appendChild(seAList);
});
</script>

自定义内容:

由于内置ArtPlayer播放器加载字幕后,页面字幕过小影响观看,可以在这里调整字幕的显示大小,具体数值可自由尝试并修改:

<style>
.art-subtitle {
  font-size: 40px !important;
}
</style>

将这些配置全部调整完毕后,将视频以及与其同名的字幕文件放在AList下,即可直接使用一起看的方式进行播放观看。