mirror of
https://github.com/zoriya/react-native-video.git
synced 2025-12-06 07:16:12 +00:00
Add error handling for the web
This commit is contained in:
@@ -4,10 +4,6 @@ import type { MixAudioMode } from "./types/MixAudioMode";
|
|||||||
import type { TextTrack } from "./types/TextTrack";
|
import type { TextTrack } from "./types/TextTrack";
|
||||||
import type { NoAutocomplete } from "./types/Utils";
|
import type { NoAutocomplete } from "./types/Utils";
|
||||||
import type { VideoConfig, VideoSource } from "./types/VideoConfig";
|
import type { VideoConfig, VideoSource } from "./types/VideoConfig";
|
||||||
import {
|
|
||||||
tryParseNativeVideoError,
|
|
||||||
VideoRuntimeError,
|
|
||||||
} from "./types/VideoError";
|
|
||||||
import type { VideoPlayerBase } from "./types/VideoPlayerBase";
|
import type { VideoPlayerBase } from "./types/VideoPlayerBase";
|
||||||
import type { VideoPlayerStatus } from "./types/VideoPlayerStatus";
|
import type { VideoPlayerStatus } from "./types/VideoPlayerStatus";
|
||||||
import { VideoPlayerEvents } from "./VideoPlayerEvents";
|
import { VideoPlayerEvents } from "./VideoPlayerEvents";
|
||||||
@@ -62,24 +58,6 @@ class VideoPlayer extends VideoPlayerEvents implements VideoPlayerBase {
|
|||||||
return this.video;
|
return this.video;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles parsing native errors to VideoRuntimeError and calling onError if provided
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
private throwError(error: unknown) {
|
|
||||||
const parsedError = tryParseNativeVideoError(error);
|
|
||||||
|
|
||||||
if (
|
|
||||||
parsedError instanceof VideoRuntimeError &&
|
|
||||||
this.triggerEvent("onError", parsedError)
|
|
||||||
) {
|
|
||||||
// We don't throw errors if onError is provided
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw parsedError;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Source
|
// Source
|
||||||
get source(): VideoPlayerSource {
|
get source(): VideoPlayerSource {
|
||||||
// TODO: properly implement this
|
// TODO: properly implement this
|
||||||
@@ -211,7 +189,8 @@ class VideoPlayer extends VideoPlayerEvents implements VideoPlayerBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
play(): void {
|
play(): void {
|
||||||
this.player.play()?.catch(this.throwError);
|
// error are already handled by the `onError` callback, no need to catch it here.
|
||||||
|
this.player.play()?.catch();
|
||||||
}
|
}
|
||||||
|
|
||||||
pause(): void {
|
pause(): void {
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ export class MediaSessionHandler {
|
|||||||
[
|
[
|
||||||
"seekbackward",
|
"seekbackward",
|
||||||
(details: MediaSessionActionDetails) => {
|
(details: MediaSessionActionDetails) => {
|
||||||
|
// @ts-expect-error ads is in an optional plugin that isn't typed.
|
||||||
if (this.player.usingPlugin("ads") && this.player.ads.inAdBreak()) {
|
if (this.player.usingPlugin("ads") && this.player.ads.inAdBreak()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -54,6 +55,7 @@ export class MediaSessionHandler {
|
|||||||
[
|
[
|
||||||
"seekforward",
|
"seekforward",
|
||||||
(details: MediaSessionActionDetails) => {
|
(details: MediaSessionActionDetails) => {
|
||||||
|
// @ts-expect-error ads is in an optional plugin that isn't typed.
|
||||||
if (this.player.usingPlugin("ads") && this.player.ads.inAdBreak()) {
|
if (this.player.usingPlugin("ads") && this.player.ads.inAdBreak()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -69,6 +71,7 @@ export class MediaSessionHandler {
|
|||||||
[
|
[
|
||||||
"seekto",
|
"seekto",
|
||||||
(details: MediaSessionActionDetails) => {
|
(details: MediaSessionActionDetails) => {
|
||||||
|
// @ts-expect-error ads is in an optional plugin that isn't typed.
|
||||||
if (this.player.usingPlugin("ads") && this.player.ads.inAdBreak()) {
|
if (this.player.usingPlugin("ads") && this.player.ads.inAdBreak()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,14 @@ import type {
|
|||||||
TimedMetadata,
|
TimedMetadata,
|
||||||
} from "../types/Events";
|
} from "../types/Events";
|
||||||
import type { TextTrack } from "../types/TextTrack";
|
import type { TextTrack } from "../types/TextTrack";
|
||||||
import type { VideoRuntimeError } from "../types/VideoError";
|
import {
|
||||||
|
type LibraryError,
|
||||||
|
type PlayerError,
|
||||||
|
type SourceError,
|
||||||
|
type UnknownError,
|
||||||
|
VideoError,
|
||||||
|
type VideoRuntimeError,
|
||||||
|
} from "../types/VideoError";
|
||||||
import type { VideoPlayerStatus } from "../types/VideoPlayerStatus";
|
import type { VideoPlayerStatus } from "../types/VideoPlayerStatus";
|
||||||
|
|
||||||
type VideoJsPlayer = ReturnType<typeof videojs>;
|
type VideoJsPlayer = ReturnType<typeof videojs>;
|
||||||
@@ -187,6 +194,26 @@ export class WebEventEmiter implements PlayerEvents {
|
|||||||
|
|
||||||
_onError() {
|
_onError() {
|
||||||
this.onStatusChange("error");
|
this.onStatusChange("error");
|
||||||
|
const err = this.player.error();
|
||||||
|
if (!err) {
|
||||||
|
console.error("Unknown error occured in player");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const codeMap = {
|
||||||
|
// @ts-expect-error Code added to html5 MediaError by videojs
|
||||||
|
[MediaError.MEDIA_ERR_CUSTOM]: "unknown/unknown",
|
||||||
|
[MediaError.MEDIA_ERR_ABORTED]: "player/asset-not-initialized",
|
||||||
|
[MediaError.MEDIA_ERR_NETWORK]: "player/network",
|
||||||
|
[MediaError.MEDIA_ERR_DECODE]: "player/invalid-source",
|
||||||
|
[MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED]:
|
||||||
|
"source/unsupported-content-type",
|
||||||
|
// @ts-expect-error Code added to html5 MediaError by videojs
|
||||||
|
[MediaError.MEDIA_ERR_ENCRYPTED]: "source/failed-to-initialize-asset",
|
||||||
|
} as Record<
|
||||||
|
number,
|
||||||
|
LibraryError | PlayerError | SourceError | UnknownError
|
||||||
|
>;
|
||||||
|
this.onError(new VideoError(codeMap[err.code]!, err.message));
|
||||||
}
|
}
|
||||||
|
|
||||||
NOOP = () => {};
|
NOOP = () => {};
|
||||||
|
|||||||
Reference in New Issue
Block a user