Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Console error when loading PlayerAPI in React #10

Open
stephenhamm opened this issue Sep 22, 2021 · 15 comments
Open

Console error when loading PlayerAPI in React #10

stephenhamm opened this issue Sep 22, 2021 · 15 comments

Comments

@stephenhamm
Copy link

My team is having an issue with the Player API loading in React 16. This console error is showing whenever the player is loaded.

Screen Shot 2021-09-22 at 9 43 28 AM

Recently someone from my team created an issue here (#6) and it was resolved. This ticket saw the introduction of the 'api-target-origin' parameter for the player's iframe. While my colleague was able to get this to work in Angular, the issue is still persisting in React.

The Player API is imported into our component
Screen Shot 2021-09-22 at 9 48 25 AM

The api-target-origin is included in the source, as well as the rootUrl (which in our case is http://localhost:3000).
Screen Shot 2021-09-22 at 9 48 55 AM

The iframe's source is set.
Screen Shot 2021-09-22 at 9 49 53 AM

The request being sent to Watson is as follows, which includes the api-target-origin.
https://video.ibm.com/embed/recorded/130908580?html5ui&api-target-origin=http://localhost:3000&showtitle=true&allowfullscreen=false&volume=50

In my colleagues notes in the previous ticket, the 'html5ui=' parameter comes after the 'api-target-origin' param, so even trying this as a hardcoded value still produces the error.
Screen Shot 2021-09-22 at 9 53 18 AM

He mentions that the error happens when the SSO dialogue window is present, but i'm seeing the error in the console even when already signed in.

I also noticed that there are two requests sent, one coming back with a 301 and another with 200.

The full file contents are as follows.

import PlayerAPI from 'ibm-video-streaming-web-player-api';
import React, { useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';

type WMPlayerErrorEvent = { name: 'autoplayRejected'; message: string };

type Props = {
  id: string;
  src?: string;
  thumbnail?: string;
  pauseVideo?: boolean;
  seekToTimestamp?: number;
  onVideoProgress?: (progressInSec: number) => void;
  onVideoPlayClicked?: (isPlaying: boolean) => void;
};

const T_NS = 'MediaPlayer';

const MediaPlayer = (props: Props): JSX.Element => {
  const { id, src, thumbnail, pauseVideo, seekToTimestamp, onVideoProgress, onVideoPlayClicked } =
    props;
  const { t } = useTranslation(T_NS);

  const playerRef = useRef<HTMLIFrameElement>(null);

  const rootUrl = encodeURIComponent(window.location.origin);
  const srcUpdated = src
    ? `${src}&api-target-origin=${rootUrl}&showtitle=true&allowfullscreen=false&volume=50`
    : '';

  const [playerContentAvailable, setPlayerContentAvailable] = useState(false);
  const [videoIsPlaying, setVideoIsPlaying] = useState(false);
  const playerSourceAvailable = !!(srcUpdated && srcUpdated.length > 0);
  const playerReady = playerRef && !!playerRef.current;

  // add media player handlers
  useEffect(() => {
    try {
      if (!playerSourceAvailable || !playerReady) {
        return;
      }

      const onError = (event: WMPlayerErrorEvent): void => {
        const { name, message } = event;

        switch (name) {
          case 'autoplayRejected':
            throw new Error(message);
        }
      };

      const onContentAvailable = (data: string): void => {
        if (data === 'contentAvailable') {
          setPlayerContentAvailable(true);
        }
      };

      const onPlaying = (viewer: any, isPlaying: boolean): void => {
        setVideoIsPlaying(isPlaying);

        if (onVideoPlayClicked) {
          onVideoPlayClicked(isPlaying);
        }

        viewer.getProperty('progress', (progressInSec: number) => {
          if (!isPlaying && onVideoProgress) {
            onVideoProgress(progressInSec);
          }
        });
      };

      const onSeekStarted = (data: {
        from: number;
        to: number;
        initiator: 'user' | 'system';
      }): void => {
        const { to: progressInSec } = data;
        if (onVideoProgress) {
          onVideoProgress(progressInSec);
        }
      };

      const viewer = PlayerAPI(playerRef.current?.id);

      if (videoIsPlaying && pauseVideo) {
        viewer.callMethod('pause');
      } else if (!videoIsPlaying && !pauseVideo) {
        viewer.callMethod('play');
      }

      viewer.addListener('error', onError);

      viewer.addListener('contentAvailable', onContentAvailable);

      viewer.addListener('playing', (type: 'playing', isPlaying: boolean) =>
        onPlaying(viewer, isPlaying),
      );

      viewer.addListener(
        'seekStarted',
        (type: 'seekStarted', data: { from: number; to: number; initiator: 'user' | 'system' }) =>
          onSeekStarted(data),
      );

      return () => {
        viewer.removeListener('error', onError);
        viewer.removeListener('contentAvailable', onContentAvailable);
        viewer.removeListener('playing', onPlaying);
        viewer.removeListener('seekStarted', onSeekStarted);
      };
    } catch (error) {
      throw new Error(error.message);
    }
    /* eslint-disable react-hooks/exhaustive-deps */
  }, [id, onVideoProgress, playerSourceAvailable, playerReady, pauseVideo]);

  // on edit comment the player seeks to time of comment and pauses.
  useEffect(() => {
    if (!playerSourceAvailable || !playerReady || !seekToTimestamp) {
      return;
    }

    const viewer = PlayerAPI(playerRef.current?.id);
    viewer.callMethod('seek', seekToTimestamp);
    viewer.callMethod('pause');
  }, [playerSourceAvailable, playerReady, seekToTimestamp]);

  return (
    <div className='media-player'>
      {!playerSourceAvailable && (
        <div className='container'>
          <div className='image-container'>
            <img
              className='img'
              src={thumbnail}
              alt={t('Video content is not available for playback at this moment')}
            />
          </div>
          <div className='play-container'>
            {t('Video content is not available for playback at this moment')}
          </div>
        </div>
      )}
      {playerSourceAvailable && !playerContentAvailable && (
        <div className='loading-video'>{t('Loading video')}</div>
      )}
      {playerSourceAvailable && (
        <iframe
          ref={playerRef}
          id={id}
          title={id}
          src={srcUpdated}
          allowFullScreen={false}
          frameBorder='0'
          sandbox='allow-forms allow-popups allow-same-origin allow-scripts allow-top-navigation-by-user-activation'
          width='100%'
          height='100%'
        />
      )}
    </div>
  );
};

export default MediaPlayer;

Any further help with this would be very much appreciated. Thanks!

@jungdaniel
Copy link
Contributor

Hi @stephenhamm,
Sorry for the late response and thank you for the detailed description. I started working on this, I let you know if I have something.

@jungdaniel
Copy link
Contributor

👋 Hi again,

I put together a little project with create-react-app based on your use-case here:
https://github.com/jungdaniel/ibm-video-streaming-web-player-api-issue-10

Apart from seeing that error message does the api work? I couldn't consistently reproduce that error message, but when I saw it, the api still worked for me after the sso process finished. I tested it in chrome and firefox, both on localhost:3000 and on gh-pages. We are executing some code when the videos' iframe loads and in case of SSO it can happen a few times. I suspect that the error happens when the postMessage is called during the SSO.

Here you can check the example in action:
https://jungdaniel.github.io/ibm-video-streaming-web-player-api-issue-10/

@pooshonbanerjee
Copy link

Yes @jungdaniel , the API works even when that message shows up. And you are also right when you say that the message shows up sometimes, and sometimes doesn't.
The reason why we opened this ticket is because this application where we are using this SDK is a production level application, to be used company-wide. So we are trying to avoid these errors showing up on this console.
Do you think something can be done about this?

@jungdaniel
Copy link
Contributor

Yes, I see your point. I guess we can wrap the postMessage call in a try catch block to suppress this "false positive" error. I'll discuss it with the team, maybe we can find something even better.

@pooshonbanerjee
Copy link

Thanks a lot @jungdaniel for looking into this and possibly closing in on a resolution.

@pooshonbanerjee
Copy link

Hi @jungdaniel , any luck with this?

@pooshonbanerjee
Copy link

Hi @jungdaniel , any update?

@jungdaniel
Copy link
Contributor

Hi @pooshonbanerjee,
It seems that with a try catch block we won't be able to suppress this kind of message. I am looking for another solution right now.

@pooshonbanerjee
Copy link

pooshonbanerjee commented Oct 13, 2021 via email

@jungdaniel
Copy link
Contributor

@pooshonbanerjee @stephenhamm,

Unfortunatelly we couldn't find a solution for this issue. I couldn't catch these errors neither with try catch nor with window.onerror. The only thing I found, suggested to delay the postMessage call with setTimeout and clear the timeout if another load event is triggered on the iframe. Seems like a hack and we would rather not rely on timers in this case.

@stephenhamm
Copy link
Author

stephenhamm commented Oct 28, 2021

Thanks @jungdaniel for the reply. Would this timeout be built-in on your end or is it something we have to implement?

@jungdaniel
Copy link
Contributor

Would be built in this lib.

@pooshonbanerjee
Copy link

Thanks @jungdaniel

@pooshonbanerjee
Copy link

Hi @jungdaniel , any idea when this new update will be released?

@pooshonbanerjee
Copy link

Hi @jungdaniel , any update on this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants