diff --git a/patches/expo-video/details.md b/patches/expo-video/details.md new file mode 100644 index 000000000000..d6d5a5d5a40f --- /dev/null +++ b/patches/expo-video/details.md @@ -0,0 +1,5 @@ +# `expo-video` patches + +### [expo-video+55.0.3+001+catch_play_abort_error.patch](expo-video+55.0.3+001+catch_play_abort_error.patch) + +- Reason: When rapidly seeking a video via the progress bar on web, `HTMLVideoElement.play()` returns a Promise that gets rejected with `AbortError` if `pause()` is called before it resolves. This patch wraps all 5 `video.play()` call sites in `VideoPlayer.web.js` with `.catch()` to silently swallow `AbortError` while re-throwing any other errors. This is the [standard fix recommended by Chrome](https://developer.chrome.com/blog/play-request-was-interrupted). diff --git a/patches/expo-video/expo-video+55.0.3+001+catch_play_abort_error.patch b/patches/expo-video/expo-video+55.0.3+001+catch_play_abort_error.patch new file mode 100644 index 000000000000..818a5a989f01 --- /dev/null +++ b/patches/expo-video/expo-video+55.0.3+001+catch_play_abort_error.patch @@ -0,0 +1,49 @@ +diff --git a/node_modules/expo-video/build/VideoPlayer.web.js b/node_modules/expo-video/build/VideoPlayer.web.js +index 10e49a3..52d0ab8 100644 +--- a/node_modules/expo-video/build/VideoPlayer.web.js ++++ b/node_modules/expo-video/build/VideoPlayer.web.js +@@ -224,7 +224,7 @@ export default class VideoPlayerWeb extends globalThis.expo.SharedObject { + } + play() { + this._mountedVideos.forEach((video) => { +- video.play(); ++ video.play()?.catch((e) => { if (e.name !== 'AbortError') throw e; }); + }); + } + pause() { +@@ -239,7 +239,7 @@ export default class VideoPlayerWeb extends globalThis.expo.SharedObject { + if (uri) { + video.setAttribute('src', uri); + video.load(); +- video.play(); ++ video.play()?.catch((e) => { if (e.name !== 'AbortError') throw e; }); + } + else { + video.removeAttribute('src'); +@@ -264,7 +264,7 @@ export default class VideoPlayerWeb extends globalThis.expo.SharedObject { + replay() { + this._mountedVideos.forEach((video) => { + video.currentTime = 0; +- video.play(); ++ video.play()?.catch((e) => { if (e.name !== 'AbortError') throw e; }); + }); + this.playing = true; + } +@@ -279,7 +279,7 @@ export default class VideoPlayerWeb extends globalThis.expo.SharedObject { + video.pause(); + } + else { +- video.play(); ++ video.play()?.catch((e) => { if (e.name !== 'AbortError') throw e; }); + } + video.currentTime = firstVideo.currentTime; + video.volume = firstVideo.volume; +@@ -305,7 +305,7 @@ export default class VideoPlayerWeb extends globalThis.expo.SharedObject { + this.playing = true; + this._mountedVideos.forEach((mountedVideo) => { + if (e.target !== mountedVideo) { +- mountedVideo.play(); ++ mountedVideo.play()?.catch((err) => { if (err.name !== 'AbortError') throw err; }); + } + }); + };