From bc060c668f8e46f1e45285039d97a216cd77791d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Moska=C5=82a?= Date: Wed, 25 Mar 2026 08:58:58 +0100 Subject: [PATCH] feat(web): add supportedFeatures and __DEV__ warnings for unsupported methods --- .../src/core/VideoPlayer.ts | 36 +++++++++++++++---- .../src/core/VideoPlayer.web.ts | 9 +++++ .../src/core/types/SupportedFeatures.ts | 19 ++++++++++ .../src/core/types/VideoPlayerBase.ts | 14 ++++++++ packages/react-native-video/src/index.tsx | 1 + 5 files changed, 73 insertions(+), 6 deletions(-) create mode 100644 packages/react-native-video/src/core/types/SupportedFeatures.ts diff --git a/packages/react-native-video/src/core/VideoPlayer.ts b/packages/react-native-video/src/core/VideoPlayer.ts index e7f2a2a8..edbeb111 100644 --- a/packages/react-native-video/src/core/VideoPlayer.ts +++ b/packages/react-native-video/src/core/VideoPlayer.ts @@ -19,6 +19,16 @@ import { VideoPlayerEvents } from "./VideoPlayerEvents"; import type { AudioTrack } from "./types/AudioTrack"; import type { VideoTrack } from "./types/VideoTrack"; import type { QualityLevel } from "./types/QualityLevel"; +import type { SupportedFeatures } from "./types/SupportedFeatures"; + +function warnUnsupported(method: string, feature: keyof SupportedFeatures) { + if (__DEV__) { + console.warn( + `[react-native-video] ${method}() is not yet implemented on native platforms. ` + + `Check player.supportedFeatures.${feature} before calling.`, + ); + } +} class VideoPlayer extends VideoPlayerEvents implements VideoPlayerBase { private _player: VideoPlayerImpl | undefined; @@ -334,34 +344,40 @@ class VideoPlayer extends VideoPlayerEvents implements VideoPlayerBase { return this.player.selectedTrack; } - // TODO: implement this getAvailableAudioTracks(): AudioTrack[] { + warnUnsupported("getAvailableAudioTracks", "audioTrackSelection"); return []; } - selectAudioTrack(_: AudioTrack | null): void {} + selectAudioTrack(_: AudioTrack | null): void { + warnUnsupported("selectAudioTrack", "audioTrackSelection"); + } get selectedAudioTrack(): AudioTrack | undefined { return undefined; } getAvailableVideoTracks(): VideoTrack[] { + warnUnsupported("getAvailableVideoTracks", "videoTrackSelection"); return []; } - selectVideoTrack(_: VideoTrack | null): void {} + selectVideoTrack(_: VideoTrack | null): void { + warnUnsupported("selectVideoTrack", "videoTrackSelection"); + } get selectedVideoTrack(): VideoTrack | undefined { return undefined; } - // quality - getAvailableQualities(): QualityLevel[] { + warnUnsupported("getAvailableQualities", "qualitySelection"); return []; } - selectQuality(_: QualityLevel | null): void {} + selectQuality(_: QualityLevel | null): void { + warnUnsupported("selectQuality", "qualitySelection"); + } get currentQuality(): QualityLevel | undefined { return undefined; @@ -370,6 +386,14 @@ class VideoPlayer extends VideoPlayerEvents implements VideoPlayerBase { get autoQualityEnabled(): boolean { return true; } + + get supportedFeatures(): SupportedFeatures { + return { + audioTrackSelection: false, + videoTrackSelection: false, + qualitySelection: false, + }; + } } export { VideoPlayer }; diff --git a/packages/react-native-video/src/core/VideoPlayer.web.ts b/packages/react-native-video/src/core/VideoPlayer.web.ts index e1b2a851..e6dfac1c 100644 --- a/packages/react-native-video/src/core/VideoPlayer.web.ts +++ b/packages/react-native-video/src/core/VideoPlayer.web.ts @@ -17,6 +17,7 @@ import { MediaSessionHandler } from "./web/MediaSession"; import { WebEventEmitter } from "./web/WebEventEmitter"; import type { VideoTrack } from "./types/VideoTrack"; import type { QualityLevel } from "./types/QualityLevel"; +import type { SupportedFeatures } from "./types/SupportedFeatures"; import { mapVideoJsTracks, type VideoJsPlayer, @@ -397,6 +398,14 @@ class VideoPlayer extends VideoPlayerEvents implements VideoPlayerBase { } return true; } + + get supportedFeatures(): SupportedFeatures { + return { + audioTrackSelection: true, + videoTrackSelection: true, + qualitySelection: true, + }; + } } export { VideoPlayer }; diff --git a/packages/react-native-video/src/core/types/SupportedFeatures.ts b/packages/react-native-video/src/core/types/SupportedFeatures.ts new file mode 100644 index 00000000..904ab759 --- /dev/null +++ b/packages/react-native-video/src/core/types/SupportedFeatures.ts @@ -0,0 +1,19 @@ +/** + * Describes which optional features are supported by the current player platform. + * Use this to check feature availability before calling platform-specific methods. + * + * @example + * ```ts + * if (player.supportedFeatures.audioTrackSelection) { + * const tracks = player.getAvailableAudioTracks(); + * } + * ``` + */ +export interface SupportedFeatures { + /** Whether audio track listing and selection is supported. @platform web */ + audioTrackSelection: boolean; + /** Whether video track listing and selection is supported. @platform web */ + videoTrackSelection: boolean; + /** Whether quality level listing and selection is supported. @platform web */ + qualitySelection: boolean; +} diff --git a/packages/react-native-video/src/core/types/VideoPlayerBase.ts b/packages/react-native-video/src/core/types/VideoPlayerBase.ts index 8167877d..b1d38a30 100644 --- a/packages/react-native-video/src/core/types/VideoPlayerBase.ts +++ b/packages/react-native-video/src/core/types/VideoPlayerBase.ts @@ -1,5 +1,6 @@ import type { IgnoreSilentSwitchMode } from './IgnoreSilentSwitchMode'; import type { MixAudioMode } from './MixAudioMode'; +import type { SupportedFeatures } from './SupportedFeatures'; import type { TextTrack } from './TextTrack'; import type { VideoPlayerSourceBase } from './VideoPlayerSourceBase'; import type { VideoPlayerStatus } from './VideoPlayerStatus'; @@ -171,4 +172,17 @@ export interface VideoPlayerBase { * @returns The currently selected text track, or undefined if none is selected */ readonly selectedTrack?: TextTrack; + + /** + * Describes which optional features are supported on the current platform. + * Use this to check availability before calling platform-specific methods. + * + * @example + * ```ts + * if (player.supportedFeatures.qualitySelection) { + * const qualities = player.getAvailableQualities(); + * } + * ``` + */ + readonly supportedFeatures: SupportedFeatures; } diff --git a/packages/react-native-video/src/index.tsx b/packages/react-native-video/src/index.tsx index 7886416d..b216dee0 100644 --- a/packages/react-native-video/src/index.tsx +++ b/packages/react-native-video/src/index.tsx @@ -8,6 +8,7 @@ export type { TextTrack } from "./core/types/TextTrack"; export type { AudioTrack } from "./core/types/AudioTrack"; export type { VideoTrack } from "./core/types/VideoTrack"; export type { QualityLevel } from "./core/types/QualityLevel"; +export type { SupportedFeatures } from "./core/types/SupportedFeatures"; export type { VideoConfig, VideoSource } from "./core/types/VideoConfig"; export type { LibraryError,