Переключение между Youku и YouTube на основе того, находитесь ли вы в Китае

У меня есть сайт конференции, на котором я хочу вставить видео Youku, если вы в Китае и видео на YouTube. Веб-сайт конференции обслуживается через CDN внутри Great Firewall. Мне был предоставлен код ниже для переключения между внутренними и внешними версиями Youku.

К сожалению, ipinfo.io, похоже, не доступен в большом брандмауэре, поэтому код истекает через 10 секунд.

Я решил переписать страницу для использования видео Youku по умолчанию, написав небольшую неблокирующую функцию JavaScript, которая пытается достичь YouTube. Если это возможно, замените Youku на YouTube. Если это невозможно, выйдите безвредно. Таким образом, достижимость YouTube станет ключевым тестом, а не в Китае.

В качестве альтернативы, я подумал о размещении видео на моем сайте, чтобы он был реплицирован через CDN внутри Great Firewall. Однако это будет означать, что видео всегда будет загружаться с полным разрешением, даже если вы находитесь на медленном соединении.

Любые лучшие предложения о том, как переключаться между Youku и 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");

Ответ 1

Вот 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
    });     
});

Мы включаем ссылку Youku в HTML и переключаемся на YouTube, если страна не является Китаем. Это по-прежнему работает, если время соединения с ipinfo.io истекло, что иногда происходит в Китае.

Изменение: исправлено добавление времени ожидания 5 секунд.

Edit2: мы реализовали это как плагин Wordpress с открытым исходным кодом, на случай, если другие будут заинтересованы. https://github.com/cncf/china-video-block

Ответ 2

Лучше конкретно проверить, заблокирован ли YouTube в сети пользователя, а не отфильтровывать страну на основе IP, который никогда не бывает на 100% надежным. Таким образом, он будет работать даже в любой школьной/офисной среде, где по любой причине YouTube может быть заблокирован администратором сети.

Это лучший ответ, который я могу найти в этом отношении, который пытается загрузить favicon YouTube через JavaScript. Если вам удастся загрузить этот крошечный образ, YouTube доступен. Изображение составляет всего 0,2 килобайта от загрузки и, скорее всего, уже кэшируется любым пользователем, который когда-либо посещал 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.ready jQuery, изображение начинает загружаться мгновенно.

(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();

Ответ 3

Ваше текущее решение не является идеальным, так как оно зависит от времени ожидания запроса GET, что замедляет работу. Поскольку проблема в значительной степени связана с ipinfo.io что ipinfo.io блокируется в Китае, вероятно, эффективное решение будет включать службу идентификации IP, основанную на Китае.

Попробуйте использовать http://www.ip138.com/. Google Translate работает достаточно хорошо, чтобы читать его на английском языке. Как представляется, формальный JSON API не существует, но вы можете нажать http://www.ip138.com/ips138.asp?ip=<IP_ADDRESS_HERE> и получить информацию о местоположении.

Для этого перейдите в DOM с помощью jQuery (поскольку вы уже используете его) в строке с 本站数据:, которая будет предшествовать названию страны. Я думаю, что селектор для этого, поскольку страница в настоящее время построена, просто $( "li").first(). Извлеките строку после двоеточия и POST на API Google Translate, чтобы получить название страны на английском и вуаля! У вас есть более быстрый и надежный (если значительно более сложный) способ увидеть, есть ли посетитель в Китае или нет.

EDIT: Не совсем ясно, если вы обладаете IP-адресом пользователя заранее. Если нет, вы можете использовать аналогичный метод с https://geoiptool.com/zh/, который также находится в Китае и, таким образом, не заблокирован. Я рад, что приготовлю эту часть.

Ответ 4

Любые лучшие предложения о том, как переключаться между Youku и Youtube или, как правило, воспроизводить видео как внутри, так и за пределами Китая?

Я бы предложил взглянуть на облако Алибаба. У них есть куча услуг, но у AFAIK нет свободного плана.
Поскольку я не знаком с другими поставщиками облаков для Китая, позвольте мне описать решение для Alibaba Cloud.

Я вижу два возможных варианта для вас:

  1. используйте свою службу CDN и создайте два пакета JS - один для Китая и второй для остального мира. Первый будет включать видео от Youku, а второй - от Youtube. После загрузки их на CDN вы можете принудительно нажать их на локальные узлы в Китае/мире, поэтому для пользователей всегда есть быстрый и актуальный ответ;
  2. используйте свою службу транскодирования мультимедиа для обработки видео + Служба хранения объектов для видео-хостинга + CDN Service для распространения. Таким образом, вы можете создавать несколько видео различного качества и распространять их рядом с вашими пользователями. JS встроит видео непосредственно из CDN. Для одного видео это может быть излишним.

Ответ 5

Как насчет использования часового пояса клиента? Хотя это и не идеально, это позволит вам избегать использования тайм-аутов или любых запросов на обслуживание геоинформации. Если возможно, я бы избегал подхода, который может привести к многократным повторным вызовам одного и того же заблокированного ресурса из одного и того же блока адресов (например, от участников конференции). Когда я в последний раз жил в Китае, я помню, как запускался перезапуск TCP с Great Firewall, который длился бы 30 секунд или больше.

Intl.DateTimeFormat().resolvedOptions().timeZone достаточно хорошо поддерживается в современных браузерах. В Китае он должен вернуть часовой пояс IANA для Китая: "Азия/Шанхай":

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

Ответ 6

Вы можете использовать ffmpeg для преобразования видео в HLS-версию, сделать плейлист HLS (.m3u8) вручную на основе RFC 8216. 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, это доступно из Vista и Vista. -hls_time 2 устанавливает время фрагмента до 2 секунд на фрагмент. aac и h264 - кодеки для использования в видеофрагментах hls.

Эта команда для ffmpeg генерирует 6 уровней качества, но не создает основной список воспроизведения. Главный плейлист - это плейлист с плейлистом на полосу пропускания (см. Выше), в зависимости от скорости интернета игрок hls выбирает, какой плей-лист видеофрагментов воспроизводится.

Ответ 7

ПОЛУЧЕНИЕ ЛОКАЛЬНОЙ ИНФОРМАЦИИ ОТ БРАУЗЕРОВ С ИСПОЛЬЗОВАНИЕМ JAVASCRIPT

Чтобы ускорить процесс обнаружения, вы можете сначала попытаться извлечь локальную информацию с языка установки пакета браузера:

navigator.language
navigator.languages

а затем объединить это или, в качестве последнего ресурса, вернуться к географическому местоположению или другим средствам для обнаружения предпочтений пользовательского языка из HTTP-заголовка Accept-Language.

Ниже приведен пример внешнего сервиса для захвата заголовков браузера:

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

Другой путь, который может быть объединен с вышеупомянутым решением, - захватить некоторую строку из пользовательской среды или контекста просмотра (window.location, document.cookie, document.localStorage, Date() или Date(). ToLocaleString() и тому подобное) и сканировать эту строку для китайского кода Unicode, используя регулярные выражения Unicode Ranges.

Я считаю, что это даст вам очень хорошее приближение без дополнительных запросов. В качестве примера в моем браузере Firefox вызывается также Date().toLocaleString():

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

который легко анализируется как "итальянский" язык.

Где-то вы найдете точку Юникода китайской идеограммы/символа.