У нас есть сайт, на котором мы показываем сценическое видео для всех пользователей. Но есть конкретный клиент, который блокирует на своих устройствах все видео со статусом 403 «Запрещено», и мы хотим отображать изображение, когда замечаем, что видео заблокированы.
Мы встраиваем видео с YouTube или Vimeo.
Зависимости
HTML
Вимео
<div class = "vimeo__player js-vimeo__player embed-responsive embed-responsive-16by9"
data-video-id-16by9 = "true"
data-vimeo-autoplay = "true"
data-vimeo-loop = "true"
data-vimeo-muted = "true"
id = "unique-video-id">
</div>
YouTube
<div class = "vimeo__player js-youtube__player embed-responsive embed-responsive-16by9" id = "ytplayer">
<iframe class = "ytplayer"
src = "https://www.youtube.com/embed/<YOUTUBE_VIDEO_ID>?playlist=<YOUTUBE_VIDEO_ID>&controls=0&mute=1&autoplay=1&loop=1&modestbranding=1&showinfo=0&rel=0"
title = "YouTube video player"
frameborder = "0"
allow = "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture">
</iframe>
</div>
Есть ли способ распознать, когда видео блокируется с кодом состояния 403 запрещено?
После некоторого исследования этой проблемы мне удалось найти следующее решение:
// If there are videos (either Vimeo or YouTube) present on the page,
// initialize them
if (hasYouTubeVideo) {
initYouTubeIFrameApi();
}
if (hasVimeoVideo) {
createVimeoVideos();
}
let ytIFrameApiInitialized = false;
function initYouTubeIFrameApi(): void {
// Only run iFrame API init once
if (ytIFrameApiInitialized) {
return;
}
// This code loads the IFrame Player API code asynchronously.
const tag = document.createElement('script');
tag.onerror = () => onIFrameApiError();
tag.src = "https://www.youtube.com/iframe_api";
const firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// Set boolean to true to not initialize it more than once
ytIFrameApiInitialized = true;
}
// In case the initial script load of the YouTube iFrame API
// encounters an error, this function will be called.
function onIFrameApiError(): void {
console.error('Error occurred during YouTube iFrame API initialization');
// Then ==> Show images instead of YouTube video
// (for all YouTube videos)
}
// The onYouTubeIframeAPIReady function needs to be declared as a
// window object in TypeScript to be available when called by the
// API in another scope
declare global {
interface Window { onYouTubeIframeAPIReady: any; }
}
window.onYouTubeIframeAPIReady = function() {
onYouTubeIframeAPIReady();
}
// This function creates an <iframe> (and YouTube player) after the
// API code downloads
function onYouTubeIframeAPIReady() {
createYouTubeVideos();
}
// The actual function to create YouTube videos for multiple
// components on the page
function createYouTubeVideos(): void {
// Loop through all available YouTube video components
document.querySelectorAll(selectorOfYouTubeVideoComponent).forEach((youTubeVideo) => {
// create new YouTube player
new YT.Player(youTubePlayerId, {
videoId: youTubeVideoId,
events: {
'onReady': onPlayerReady,
'onError': onYouTubeError,
},
playerVars: {
// options ...
},
});
});
// The YouTube iFrame API will call this function when the video
// player is ready
function onPlayerReady(e) {
e.target.playVideo();
}
// The YouTube iFrame API will call this function when there's an
// error when playing the video
function onYouTubeError(e): void {
console.error('Error occurred during YouTube video player (video-ID: ' + e.target.g.id + ')');
// Then ==> Show image instead of video
// (only this specific video)
}
}
function createVimeoVideos(): void {
// Loop through all available Vimeo video components
document.querySelectorAll(selectorOfVimeoComponent).forEach((vimeoVideo) => {
const vimeoPlayer: VimeoPlayer = new VimeoPlayer(vimeoPlayerId, options);
// Catching errors of vimeo player when indicating "ready"
vimeoPlayer.ready().then(() => {
// console.info('==> Vimeo Player "ready"!');
}).catch(error => {
console.error('Error occurred on Vimeo video player during "ready" (video-ID: ' + vimeoId + '):', error);
// Then ==> Show image instead of video
// (only this specific video)
});
// Catching errors of vimeo player when indicating "play" (not required to start the player, though)
vimeoPlayer.play().then(() => {
// console.info('==> Vimeo Player "play"!');
}).catch(error => {
console.error('Error occurred on Vimeo video player during "play" (video-ID: ' + vimeoId + '):', error);
// Then ==> Show image instead of video
// (only this specific video)
});
// Catching general errors of vimeo player when indicating "error"
vimeoPlayer.on('error', (error) => {
console.error('Error occurred on Vimeo video player with "error" (video-ID: ' + vimeoId + '):', error);
// Then ==> Show image instead of video
// (only this specific video)
});
/**
* Attention: A timeout solution most likely never really is a
* good option, but in this case and with my current ability,
* it was the only solution that worked in that specific case
* where only one of the CDN of Vimeo were blocked, but not
* "vimeo.com" itself:
* - https://f.vimeocdn.com
* - https://vod-adaptive-ak.vimeocdn.com
*
* Catch instantiating error for Vimeo player if no valid
* origin URL could be set after the given timeout.
* Especially needed the specific case in which
* "https://f.vimeocdn.com" would be blocked by the user's
* system. The timeout should not be lower than 1000, as it
* might fire too early, even though the player might still
* work.
*/
setTimeout(() => {
// @ts-ignore (needed for "origin" not being present in
// the Player-class, but available on the player object)
if (vimeoPlayer.origin === '*') {
console.error('Vimeo video player (video-ID: ' + vimeoId + ') could not be initiated.');
// Then ==> Show image instead of Vimeo video
// (this specific video)
}
}, 1500);
});
}
Тогда вам, вероятно, придется перехватывать HTTP-запросы с помощью ServiceWorker, stackoverflow.com/a/43815800/1427878