import { NitroModules } from 'react-native-nitro-modules'; import type { MediaItem as MediaItemHybrid } from '../specs/MediaItem.nitro'; import type { MediaItemFactory } from '../specs/MediaItem.nitro'; import type { MediaItemConfig } from '../specs/types.nitro'; const factory = NitroModules.createHybridObject('MediaItemFactory'); /** * Imperative API for creating MediaItem instances. * * @example * ```ts * const item = MediaItem.create({ uri: 'https://example.com/song.mp3', title: 'My Song' }) * const item = MediaItem.fromUri('https://example.com/song.mp3') * ``` */ export const MediaItem = { /** * Create a media item from a full configuration. */ create(config: MediaItemConfig): MediaItemHybrid { return factory.create(config); }, /** * Create a media item from just a URI. * Metadata will be empty; MIME type will be inferred. */ fromUri(uri: string): MediaItemHybrid { return factory.fromUri(uri); }, }; /** * Type guard distinguishing a Nitro MediaItem HybridObject from a plain * {@link MediaItemConfig}. HybridObjects created by Nitro carry a `dispose()` * method from the HybridObject base interface; plain config objects do not. */ function isMediaItem(value: unknown): value is MediaItemHybrid { return ( typeof value === 'object' && value !== null && 'uri' in value && typeof (value as Record).dispose === 'function' ); } /** Any source form accepted by player.load / player.loadAndPlay. */ export type MediaSource = string | MediaItemConfig | MediaItemHybrid; /** * Coerce any accepted source form into a native MediaItem. * * The single normalization point for string/config/instance dispatch — * load(), loadAndPlay(), and queue application all route through here so * the coercion rules (bare URI → no metadata; config → factory; instance → * used as-is) are defined once. */ export function toMediaItem(source: MediaSource): MediaItemHybrid { if (isMediaItem(source)) return source; return typeof source === 'string' ? MediaItem.fromUri(source) : MediaItem.create(source); }