cookpete / react-player

A React component for playing a variety of URLs, including file paths, YouTube, Facebook, Twitch, SoundCloud, Streamable, Vimeo, Wistia and DailyMotion
https://cookpete.github.io/react-player
MIT License
9.26k stars 1.15k forks source link

Can It play a blob file? #114

Closed jeanmichelcote closed 7 years ago

jeanmichelcote commented 7 years ago

Should the player be able to play a blob file?

I am trying to download 2 vimeo clips from my vimeo account both with vanilla XHR and with axios, then make them into their respective blob in order to have 'em ready to play without having to load first. I need really quick response and no loading time.

So when I call this.load(url), can url be a blob file?

At the moment, I can't make it work. Here is the code that I have to fetch the clips. With axios:

  const endpoint = '/oembed.json';

  function fetchRessource(url) {
    return axios(endpoint, {
      method: 'GET',
      baseURL: 'https://vimeo.com/api/',
      params: { url: url, },
      responseType: 'blob',
      onDownloadProgress: event => console.log('Downloading... -> ', event)
    })
      .then(blob => { return blobUtil.createObjectURL(new Blob([blob])) })
      .catch(err => `Could not create the objectURL from the arrayBuffer - ${err}`); // IE10+
  }

  return axios.all([
    fetchRessource(url1),
    fetchRessource(url2)
  ])
  .then(axios.spread((url1, url2) => {
    return [url1, url2];
  }));

This gives me back the blobURLs but throws this when I am trying to play them: onError Event {isTrusted: true, type: "error", target: video, currentTarget: video, eventPhase: 2…}bubbles: falsecancelBubble: falsecancelable: truecomposed: falsecurrentTarget: nulldefaultPrevented: falseeventPhase: 0isTrusted: truepath: Array[10]returnValue: truesrcElement: videotarget: videotimeStamp: 9187.02type: "error"__proto__: Event Looks like a Media error: code 4

With XHR:

function loadIt(file) {
  const req = new XMLHttpRequest();
  req.onload = () => { return URL.createObjectURL(req.response) };
  req.open("GET", file);
  req.setRequestHeader('Access-Control-Allow-Origin', '*');
  req.responseType = "blob";
  req.send();
}

This throws another error and is not even able to get anything from the server: XMLHttpRequest cannot load https://vimeo.com/187265782/83876b2cdc. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.

cookpete commented 7 years ago

Have you tried copying and pasting the resulting blob string into a new tab to see if the file plays? ReactPlayer should play blob strings fine as long as the HTML5 media player can handle it when set as the src. I have tested playing a blob string from a simple <input type='file' /> and it seemed to work ok.

jeanmichelcote commented 7 years ago

Yeah, it seems to be working when uploading a file through the input form but what I am trying to do is to download an entire vimeo clip from my account (about 17 seconds), store it in a blob and then have it play instantly when needed, without having to spend 1 or 2 seconds of loading time.

And no, the blob that I've gotten from the XHR call to vimeo does not play on its own when url is copy/pasted in an empty browser tab.

Not sure what to do next...

jeanmichelcote commented 7 years ago

Oh, actually, when I copy/paste the blobURL in the address bar, this is what I appears, as is, straight in the browser window, without any styling:

[object Object]

But when I try to play it, I get the Media error: code 4 message.

Means anything to you?

cookpete commented 7 years ago

Is there any reason you aren't just rendering a player and waiting for the onReady callback instead of waiting for an XHR to complete?

// state = { playing: false }
<ReactPlayer
  url='http://vimeo.com/blah'
  playing={this.state.playing}
  onReady={() => {
    // Video is loaded and ready to play now
    // To start playing:
    this.setState({ playing: true })
  }}
/>

Seems like it would get the same result without the blob weirdness.

jeanmichelcote commented 7 years ago

I am building an app in which I work clips by 3's; a question clip, a right answer clip and a wrong answer clip. When the question clip is loaded and fires the onReady event, I want to load both answer clips in blobs so that when the question clip offers a set of choices, and the user clicks on one, either the right or wrong answer clips are ready to fire off without any delay.

So the onReady event of the question clip is used to make 2 ajax calls to vimeo to get the 2 answer clips.

cookpete commented 7 years ago

I would simply render three ReactPlayers with the question and answer clips all loaded (with playing set to false for the answer clips), then just hide/show/play the relevant player depending on the answer. You would be waiting the same amount of time (probably longer) to load in blob strings compared to waiting for each iframe to call onReady.

jeanmichelcote commented 7 years ago

That is a considerable suggestion, thank you. I'll see how I can implement that in my project.

x-yuri commented 6 years ago

@CookPete From what I can see, react-player no longer plays blobs, does it? I'm trying to feed it a file from <input type="file"... if anything. And it plays the video when I paste the URL into another tab. Am I missing something?

cookpete commented 6 years ago

@x-yuri ReactPlayer will fall back to the FilePlayer if it cannot play the URL with other players. Playing blobs should still work. It works for me in this fiddle using URL.createObjectURL():

https://jsfiddle.net/0pn9avov/

i7N3 commented 4 years ago

@CookPete Is it possible to do the same with the hls (.m3u8) video file?