16

我正在主持一个会议网站,如果您在中国,我想在其中嵌入优酷视频,否则嵌入 YouTube 视频。会议网站通过防火墙内的 CDN 提供服务。我得到了下面的代码来在优酷的内部和外部版本之间切换。

不幸的是,在防火墙内部似乎无法访问 ipinfo.io,因此代码在 10 秒后超时。

我考虑过重写页面以默认使用优酷视频,编写一个小的、非阻塞的 JavaScript 函数来尝试访问 YouTube。如果可以,请将优酷换成 YouTube。如果不能,请无害地退出。这样一来,YouTube 的可达性就成为关键测试,而不是您是否在中国。

或者,我考虑将视频托管在我的网站上,以便通过防火墙内的 CDN 进行复制。但是,这意味着视频将始终以全分辨率下载,即使您的连接速度很慢。

关于如何在优酷和 Youtube 之间切换,或者更一般地说有一个可以在中国境内外播放的视频,有什么更好的建议吗?

jQuery.get("https://ipinfo.io", function(response) {
    var country = response.country;

    if(country == 'CN') {
        youku.attr('src',chinaVideo)
    } else {
        youku.attr('src',generalVideo)
    }
}, "jsonp");
4

7 回答 7

6

这是我们要使用的 JavaScript:

$(document).ready(function (){
    var country = '',
    youku = $('#youku');

    $.ajax({
        url: "https://ipinfo.io",
        dataType: "jsonp",
        success: function(response){
            var country = response.country;

            if(country != 'CN') {
                youku.attr('src','https://www.youtube.com/embed/K3cEE5h7c1s')
            }
         },
         error: function(){
            console.log('sorry...')
         },
         timeout: 5000
    });     
});

如果国家/地区不是中国,我们将在 HTML 中包含优酷链接并切换到 YouTube。如果连接到ipinfo.io超时,这仍然有效,这有时会在中国发生。

编辑:修改为添加 5 秒超时。

Edit2:我们将其实现为开源 Wordpress 插件,以防其他人感兴趣。https://github.com/cncf/china-video-block

于 2018-07-24T04:55:58.540 回答
5

最好专门检查 YouTube 是否在用户的网络中被阻止,而不是根据永远 100% 可靠的 IP 过滤掉国家/地区。这样,它甚至可以在任何学校/办公室环境中工作,因为网络管理员可能出于任何原因阻止 YouTube。

是我在这方面能找到的最佳答案,它试图favicon通过 JavaScript 加载 YouTube。如果成功下载该小图像,则可以访问 YouTube。该图像只有 0.2 KB 的下载量,并且很可能已经被任何访问过 YouTube 的用户缓存。

这意味着对于拥有 YouTube 访问权限的用户来说,结果几乎是即时的,而对于防火墙被阻止的用户来说,则需要几秒钟的时间。代码很简单:

jQuery(function(){
    var youku = jQuery('#youku');
    var image = new Image();
    image.onload = function(){
        youku.attr('src','https://www.youtube.com/embed/K3cEE5h7c1s')
    };
    image.onerror = function(){
        youku.attr('src','https://www.youku.com/embed/K3cEE5h7c1s')
    };
    image.src = "https://youtube.com/favicon.ico";
});

这是一个比上述更好的解决方案,因为它不等待document.readyjQuery 事件,图像立即开始加载。

(function(){
    var image = new Image();
    image.onload = function(){
        jQuery(function(){
            jQuery('#youku').attr('src','https://www.youtube.com/embed/K3cEE5h7c1s')
        });
    };
    image.onerror = function(){
        jQuery(function(){
            jQuery('#youku').attr('src','https://www.youku.com/embed/K3cEE5h7c1s')
        });
    };
    image.src = "https://youtube.com/favicon.ico";
})();

根据评论更新:

如果图像有可能先前被缓存在用户的计算机上,将当前时间戳参数添加到图像 URL 将确保尽管先前已缓存图像仍被加载。

    image.src = "https://youtube.com/favicon.ico?_=" + Date.now();
于 2018-07-25T21:02:47.687 回答
0

使用客户端的时区怎么样?虽然并不完美,但它可以让您完全避免依赖超时或任何 geoip 服务请求。如果可能的话,我会避免可能导致从同一地址块(例如来自会议与会者)多次重复调用同一阻塞资源的方法。当我上次住在中国时,我记得从防火墙触发 TCP 重置,这将持续 30 秒或更长时间。

Intl.DateTimeFormat().resolvedOptions().timeZone在现代浏览器中得到了相当好的支持。在中国,它应该返回中国的 IANA 时区:“亚洲/上海”:

console.log(Intl.DateTimeFormat().resolvedOptions().timeZone)

还有一些库(jsTimezoneDetectmoment-timezone)将上述内容与跨多个时间点的getTimezoneOffset功能结合起来Date,对时区进行有根据的猜测,这可能会在旧浏览器上产生更好的结果:

console.log(jstz.determine().name());
console.log(moment.tz.guess());
<script src="//cdnjs.cloudflare.com/ajax/libs/jstimezonedetect/1.0.6/jstz.min.js"></script>

<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.5/moment-timezone-with-data-2010-2020.min.js"></script>

就我而言,我可能会尝试将时区检测为“亚洲/上海”并回退到“UTC + 8”的时区偏移量(仅时区偏移量就会比中国大陆更多,但我想这是可以接受的后备策略的过度使用),例如:

var ianaTz = Intl.DateTimeFormat().resolvedOptions().timeZone;
var offset = new Date().getTimezoneOffset();

if (ianaTz === "Asia/Shanghai" || (ianaTz == null && offset/60 == -8)) {
  console.log("We'll assume China");
} else {
  console.log("not China");
}

于 2018-07-25T21:42:34.853 回答
0

您当前的解决方案并不理想,因为它取决于 GET 请求超时,这会减慢速度。由于该问题主要围绕ipinfo.io在中国被屏蔽,因此有效的解决方案可能涉及基于中国的 IP 识别服务。

尝试使用http://www.ip138.com/. 谷歌翻译工作得很好,可以用英文阅读。似乎没有正式的 JSON API,但您可以点击http://www.ip138.com/ips138.asp?ip=<IP_ADDRESS_HERE>并获取位置信息。

为此,请使用 jQuery(因为您已经在使用它)将 DOM 导航到带有 的行本站数据:,该行将位于国家/地区名称之前。我认为当前构建页面时的选择器很简单$( "li" ).first()。提取冒号后面的字符串并将其发布到 Google Translate API 以获取英文国家名称,瞧!您有一种更快、更可靠(如果要复杂得多)的方式来查看访问者是否在中国。

编辑:如果您事先拥有用户的 IP 地址,尚不完全清楚。如果没有,您可以使用与 类似的方法https://geoiptool.com/zh/,该方法也位于中国境内,因此不会被阻止。我很高兴根据需要充实这部分。

于 2018-07-25T18:26:38.717 回答
0

使用 JAVASCRIPT 从浏览器获取区域信息

为了使检测过程更快,您可以首先尝试从浏览器包安装语言中提取语言环境信息:

navigator.language
navigator.languages

然后结合该资源,或者作为最后一个资源,回退到地理位置或其他方式,以从Accept-LanguageHTTP 标头中检测用户语言偏好。

以下是获取浏览器标头的外部服务示例:

https://ajaxhttpheaders1.appspot.com/?callback=getHeaders

可能与上述解决方案相结合的另一条路径是从用户环境或浏览上下文中获取一些字符串(window.location、document.cookie、document.localStorage、Date() 或 Date().toLocaleString() 等)并使用正则表达式 Unicode 范围扫描这些字符串以查找中文 Unicode 代码点。

我相信这会让你得到一个非常好的近似值,而无需提出额外的要求。作为我的 Firefox 浏览器中的示例,调用也会Date().toLocaleString()产生:

"Mon Jul 30 2018 01:35:38 GMT+0200 (Ora legale dell’Europa centrale)"

可以很容易地将其解析为“意大利”语言环境。

您会在某个地方找到中文表意文字/符号的 Unicode 点。

于 2018-07-29T23:53:00.343 回答
0

关于如何在优酷和 Youtube 之间切换,或者更一般地说有一个可以在中国境内外播放的视频,有什么更好的建议吗?

我建议看看阿里云。他们有很多服务,但 AFAIK 没有免费计划。
由于我不熟悉中国其他云提供商,让我描述一个阿里云的解决方案。

我为您看到了两种可能的选择:

  1. 使用他们的CDN 服务并创建两个 JS 包 - 一个用于中国,第二个用于世界其他地区。第一个将嵌入优酷的视频,第二个 - 来自 Youtube。上传到CDN后,可以强制推送到中国/世界的本地节点,让用户始终有快速、最新的响应;
  2. 使用他们的媒体转码服务进行视频处理 +对象存储服务进行视频托管 + CDN 服务进行分发。通过这种方式,您可以创建多个不同质量的视频并将它们分发到您的用户附近。JS 将直接从 CDN 嵌入视频。对于一个视频,这可能是一种矫枉过正。
于 2018-07-25T21:11:05.800 回答
0

您可以使用 ffmpeg 将视频转换为 HLS 版本,根据 RFC 8216 手动制作 HLS 播放列表(.m3u8)。ffmpeg 不会为您创建主播放列表。HLS 有助于使分辨率适应互联网速度。如果您将它与免费的hls.js javascript媒体播放器结合使用,您可以将其托管在您自己的网站上,以便通过中国的防火墙,并支持自适应分辨率。

这是一个示例 HLS 主播放列表,因此您不一定需要阅读 RFC 8216,该文件将称为 Video.m3u8:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080
Video_1080p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=9000000,RESOLUTION=2560x1440
Video_1440p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=16000000,RESOLUTION=3840x2160
Video_4k.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2800000,RESOLUTION=1280x720
Video_720p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1400000,RESOLUTION=842x480
Video_480p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=640x360
Video_360p.m3u8

带宽以每秒比特数指定,质量顺序无关紧要,因为媒体播放器选择播放哪种分辨率。

您可以在命令提示符下用于 ffmpeg 的命令是:

ffmpeg -hwaccel dxva2 -hide_banner -y -i "C:\input\Video.mp4" -vf scale=1920:1080 -c:a aac -ar 48000 -c:v h264 -profile:v main -crf 20 -r 30 -sc_threshold 0 -g 48 -keyint_min 48 -hls_time 2 -hls_playlist_type vod -b:v 5000k -maxrate 5350k -bufsize 7500k -b:a 192k -hls_segment_filename "C:\output\Video_1080p_%03d.ts" "C:\output\Video_1080p.m3u8" -vf scale=2560:1440 -c:a aac -ar 48000 -c:v h264 -profile:v main -crf 20 -r 30 -sc_threshold 0 -g 48 -keyint_min 48 -hls_time 2 -hls_playlist_type vod -b:v 9000k -maxrate 10350k -bufsize 14500k -b:a 192k -hls_segment_filename "C:\output\Video_1440p_%03d.ts" "C:\output\Video_1440p.m3u8" -vf scale=3840:2160 -c:a aac -ar 48000 -c:v h264 -profile:v main -crf 20 -r 30 -sc_threshold 0 -g 48 -keyint_min 48 -hls_time 2 -hls_playlist_type vod -b:v 16000k -maxrate 20350k -bufsize 26000k -b:a 192k -hls_segment_filename "C:\output\Video_4k_%03d.ts" "C:\output\Video_4k.m3u8" -vf scale=1280:720 -c:a aac -ar 48000 -c:v h264 -profile:v main -crf 20 -r 30 -sc_threshold 0 -g 48 -keyint_min 48 -hls_time 2 -hls_playlist_type vod -b:v 2800k -maxrate 2996k -bufsize 4200k -b:a 128k -hls_segment_filename "C:\output\Video_720p_%03d.ts" "C:\output\Video_720p.m3u8" -vf scale=842:480 -c:a aac -ar 48000 -c:v h264 -profile:v main -crf 20 -r 30 -sc_threshold 0 -g 48 -keyint_min 48 -hls_time 2 -hls_playlist_type vod -b:v 1400k -maxrate 1498k -bufsize 2100k -b:a 128k -hls_segment_filename "C:\output\Video_480p_%03d.ts" "C:\output\Video_480p.m3u8" -vf scale=640:360 -c:a aac -ar 48000 -c:v h264 -profile:v main -crf 20 -r 30 -sc_threshold 0 -g 48 -keyint_min 48 -hls_time 2 -hls_playlist_type vod -b:v 800k -maxrate 865k -bufsize 1200k -b:a 96k -hls_segment_filename "C:\output\Video_360p_%03d.ts" "C:\output\Video_360p.m3u8"

您唯一需要做的是将 C:\input\Video.mp4 替换为您的视频,并将所有 C:\output\Video 替换为视频的输出名称。360p 代表输出视频文件名中指定的分辨率,它不影响实际分辨率,%03d 是一个命令,它被解析为视频片段一个数字,例如 001 到 999。下划线用于可读性。

注释解释: -hwaccel dxva2 表示 ffmpeg 将使用 Directx 进行硬件加速,这在 windows vista 及以上版本中可用。-hls_time 2 将片段时间设置为每个片段 2 秒。aac 和 h264 是在 hls 视频片段中使用的编解码器。

ffmpeg 的此命令会生成 6 个质量级别,但不会创建主播放列表。主播放列表是每个带宽的播放列表(见上文),取决于互联网速度,hls 播放器选择要播放的视频片段的播放列表。

于 2018-07-26T09:50:44.717 回答