fregante / iphone-inline-video

📱 Make videos playable inline on the iPhone (prevents automatic fullscreen)
https://npm.im/iphone-inline-video
MIT License
2.05k stars 300 forks source link

Error DOMException #138

Closed ghost closed 6 years ago

ghost commented 6 years ago

Hello mate. I am using react and I have this error. Does anyone know what is going on ?

:3000/#:1 Uncaught (in promise) DOMException: Failed to load because no supported source was found.

fregante commented 6 years ago

I’d need your full code. Are you using <source> and/or changing the src after initialization?

jsiebern commented 6 years ago

I found it to not work with react when I tried it a while back, my solution was to create a div and manually create the video element and inserting it into the react div. It's a bit dirty but it did the trick just fine.

fregante commented 6 years ago

If anyone provides a repro I can look into it.

There are other issues opened by people trying it with react, maybe they have the solution.

jsiebern commented 6 years ago

I just remembered, I needed this workaround as React doesn't pass on the muted prop as expected.

So this is what I did (simplified):

class Player extends React.Component {
  // Dom References
  video;
  videoContainer;

  addVideoToContainer = div => {
    const { url, mutedDefault = true } = this.props;

    // Doing the ref stuff unfortunately requires some workarounds
    if (div === null) {
      return;
    }

    this.videoContainer = div;
    // Unfortunately we need to hack our way around React not passing on the "muted" prop as expected, without it iOS ( and Android ) won't allow autoplay at all
    this.videoContainer.innerHTML = `
            <video src="${url}" autoplay ${mutedDefault
      ? "muted"
      : ""} playsinline id="video_1" style="width: 100%; height: 100%; z-index: 2; position: absolute; top: 0; left: 0;"></video>
        `;

    const video = this.videoContainer.querySelector("video");
    if (!video || !(video instanceof HTMLVideoElement)) {
      throw new Error("Expected Video Element");
    }
    this.video = video;

    this.video.addEventListener("loadedmetadata", this.videoMetadata, false);
    this.video.addEventListener("play", this.videoPlay, false);
    this.video.addEventListener("timeupdate", this.videoTimeUpdate, false);
    this.video.addEventListener("pause", this.videoPaused, false);
    this.video.addEventListener("ended", this.videoEnded, false);
    this.video.addEventListener("contextmenu", this.videoContextmenu, false);
    this.video.addEventListener("click", this.videoContextmenu, false);
    this.video.addEventListener("seeking", this.videoSeeking, false);
    this.video.addEventListener("waiting", this.videoMetadata, false);
    this.video.addEventListener("playing", this.videoMetadata, false);
  };

  videoMetadata = () => {};

  videoPlay = () => {};

  videoTimeUpdate = () => {};

  videoPaused = () => {};

  videoEnded = () => {};

  videoContextmenu = () => {};

  render() {
    const { state, mutedDefault = true } = this.props;

    return <div ref={this.addVideoToContainer} />;
  }
}

This works perfectly fine for me in production

fregante commented 6 years ago

I’m sure that’s unnecessary, you need to IIV on the real dom element, not on the react component. IIV should not go through React so there’s no prop that it wouldn’t “pass”

montogeek commented 6 years ago

We do it like this:

 initPolyfill(this.video, {
        iPad: true,
        muted: this.state.muted
      })

Where this.video is a ref

fregante commented 6 years ago

A ref to what? I’d need more of the code to understand where it’s being called.

Muted isn’t a parameter anymore, it just reads the attribute.

montogeek commented 6 years ago

@bfred-it https://reactjs.org/docs/refs-and-the-dom.html, I am not the original issue autor, just trying to help how to integrate your library with React.

fregante commented 6 years ago

@montogeek Thanks, the sounds like the correct way.