Переключение между Youku и YouTube в зависимости от того, находитесь ли вы в Китае
У меня есть веб-сайт конференции, на котором я хочу добавить видео Youku, если вы находитесь в Китае, и видео на YouTube в противном случае. Веб-сайт конференции обслуживается через CDN внутри Большого межсетевого экрана. Мне был дан код ниже для переключения между внутренней и внешней версиями Youku.
К сожалению, ipinfo.io, по-видимому, недоступен внутри Большого межсетевого экрана, поэтому время ожидания кода истекает через 10 секунд.
Я решил переписать страницу, чтобы использовать видео Youku по умолчанию, написать небольшую неблокирующую функцию JavaScript, которая пытается связаться с YouTube. Если это возможно, замените Youku на YouTube. Если нет, выходите безобидно. Таким образом, доступность YouTube становится ключевым тестом, а не в Китае.
В качестве альтернативы я подумал о размещении видео на моем сайте, чтобы оно было реплицировано через CDN внутри Большого межсетевого экрана. Однако это будет означать, что видео всегда будет загружаться в полном разрешении, даже если у вас медленное соединение.
Какие-нибудь лучшие предложения о том, как переключаться между 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");
7 ответов
Вот 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 секунд тайм-аут.
Лучше конкретно проверить, заблокирован ли 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();
Как насчет использования часового пояса клиента? Хотя он и не идеален, он позволит вам полностью отказаться от тайм-аутов или любых запросов на обслуживание геоипа. Если возможно, я бы избегал подхода, который мог бы привести ко многим повторным вызовам к одному и тому же заблокированному ресурсу из одного и того же блока адресов (например, от участников конференции). Когда я в последний раз жил в Китае, я помню, как инициировал сброс TCP с Большого Брандмауэра, который длился бы добрых 30 секунд или больше.
Intl.DateTimeFormat().resolvedOptions().timeZone
достаточно хорошо поддерживается в современных браузерах. В Китае он должен вернуть часовой пояс IANA для Китая: "Азия / Шанхай":
console.log(Intl.DateTimeFormat().resolvedOptions().timeZone)
Есть также библиотеки ( jsTimezoneDetect и https://momentjs.com/time zone), которые сочетают в себе вышеуказанное и 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");
}
Вы можете использовать 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, это доступно из Windows Vista и выше. -hls_time 2 устанавливает время фрагмента равным 2 секундам на фрагмент. aac и h264 - это кодеки для использования во фрагментах видео hls.
Эта команда для ffmpeg генерирует 6 уровней качества, но не создает основной список воспроизведения. Главный список воспроизведения - это список воспроизведения с списком воспроизведения на полосу пропускания (см. Выше), в зависимости от скорости интернета, который игрок hls выбирает, какой список фрагментов видео воспроизводить.
Ваше текущее решение не является идеальным, так как оно зависит от тайм-аута запроса GET, что замедлит работу. Поскольку проблема в основном вращается вокруг 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()
, Извлеките строку после двоеточия и отправьте ее в API Google Translate, чтобы получить название страны на английском языке и вуаля! У вас есть более быстрый и надежный (если значительно более сложный) способ узнать, находится ли посетитель в Китае или нет.
РЕДАКТИРОВАТЬ: не совсем ясно, если у вас есть IP-адрес пользователя заранее. Если нет, вы можете использовать аналогичный метод с https://geoiptool.com/zh/
, который также базируется в Китае и, таким образом, не заблокирован. Я рад дополнить эту часть по мере необходимости.
ПОЛУЧЕНИЕ МЕСТНОЙ ИНФОРМАЦИИ ОТ БРАУЗЕРОВ, ИСПОЛЬЗУЮЩИХ JAVASCRIPT
Чтобы ускорить процесс обнаружения, вы можете сначала попытаться извлечь информацию о локали из языка установки пакета браузера:
navigator.language
navigator.languages
а затем объединить этот или, как последний ресурс, откат к географическому местоположению или другие средства для обнаружения языковых предпочтений пользователя из Accept-Language
HTTP заголовок.
Ниже приведен пример внешнего сервиса для захвата заголовков браузера:
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 китайской идеограммы / символа.
Какие-нибудь лучшие предложения о том, как переключаться между Youku и Youtube, или, в более общем смысле, воспроизводить видео как внутри, так и за пределами Китая?
Я бы посоветовал взглянуть на облако Alibaba. У них есть куча услуг, но у AFAIK нет бесплатного плана.
Поскольку я не знаком с другими облачными провайдерами для Китая, позвольте мне описать решение для Alibaba Cloud.
Я вижу два возможных варианта для вас:
- воспользуйтесь услугой CDN и создайте два пакета JS - один для Китая и второй для остального мира. Первый будет вставлять видео с Youku, а второй - с Youtube. После загрузки их в CDN вы можете принудительно отправить их на локальные узлы в Китае / мире, чтобы у пользователей всегда был быстрый и актуальный ответ;
- используйте их Media Transcoding Service для обработки видео + Object Storage Service для видеохостинга + CDN Service для распространения. Таким образом, вы можете создавать несколько видео разного качества и распространять их среди своих пользователей. JS будет вставлять видео прямо из CDN. Для одного видео это может быть излишним.