Есть ли способ распознать, когда видеоплееры (YouTube + Vimeo) блокируются с помощью 403 Forbidden для отображения изображения?

У нас есть сайт, на котором мы показываем сценическое видео для всех пользователей. Но есть конкретный клиент, который блокирует на своих устройствах все видео со статусом 403 «Запрещено», и мы хотим отображать изображение, когда замечаем, что видео заблокированы.

Мы встраиваем видео с YouTube или Vimeo.

Зависимости

  • "@vimeo/player": "^2.13.0"

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 запрещено?

Тогда вам, вероятно, придется перехватывать HTTP-запросы с помощью ServiceWorker, stackoverflow.com/a/43815800/1427878

CBroe 18.04.2024 15:15
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Введение в CSS
Введение в CSS
CSS является неотъемлемой частью трех основных составляющих front-end веб-разработки.
Как выровнять Div по центру?
Как выровнять Div по центру?
Чтобы выровнять элемент <div>по горизонтали и вертикали с помощью CSS, можно использовать комбинацию свойств и значений CSS. Вот несколько методов,...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Travel Booking Angular Template один из лучших Travel & Tour booking template in the world. 30+ валидированных HTML5 страниц, которые помогут...
0
1
155
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

После некоторого исследования этой проблемы мне удалось найти следующее решение:

Общая инициализация

// If there are videos (either Vimeo or YouTube) present on the page,
// initialize them
if (hasYouTubeVideo) {
    initYouTubeIFrameApi();
}
if (hasVimeoVideo) {
    createVimeoVideos();
}

Реализация YouTube (iFrame API)

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)
    }
}

Реализация Vimeo ("@vimeo/player": "^2.13.0")

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

Другие вопросы по теме