import type { PlayerEvent, PlayerOptions, PlayerPlugin, Source } from '@oplayer/core' import Player from '@oplayer/core' import { DependencyList, EffectCallback, forwardRef, Ref, useCallback, useEffect, useImperativeHandle, useMemo, useRef } from 'react' export interface ReactOPlayerProps extends Omit { playing?: boolean duration?: number aspectRatio?: number plugins?: PlayerPlugin[] onEvent?: (e: PlayerEvent) => void source?: Source | Promise } const ReactOPlayer = forwardRef((props: ReactOPlayerProps, ref: Ref) => { const { playing, duration, aspectRatio = 9 / 16, plugins = [], onEvent, source, ...rest } = props const onEventRef = useRef(onEvent) onEventRef.current = onEvent const player = useRef(null) const preSource = usePrevious(source) const isReady = player.current && player.current.$root const onRefChange = useCallback((node: HTMLDivElement) => { if (node !== null && !isReady) { const initialParams = source instanceof Promise ? rest : { ...rest, source } player.current = Player.make(node, initialParams).use(plugins).create() if (source instanceof Promise) player.current.changeSource(source!) if (typeof duration == 'number') player.current.seek(duration / 1000) if (onEvent) { player.current.on((payload: PlayerEvent) => onEventRef.current?.(payload)) } } }, []) useEffectIf(isReady, () => { if (playing) { if (!player.current!.isPlaying) player.current!.play() } else { if (player.current!.isPlaying) player.current!.pause() } }, [playing]) useEffectIf(isReady, () => { if ( source && (source instanceof Promise ? preSource != source : source.src && (preSource as Source)?.src !== source.src) ) { player.current!.changeSource(source) } }, [source]) useEffectIf( isReady && typeof duration === 'number', () => { player.current!.seek(duration! / 1000) }, [duration] ) useEffectIf(isReady, () => { if (rest.muted) { player.current!.mute() } else { player.current!.unmute() } }, [rest.muted]) useEffectIf(isReady, () => { player.current!.setPlaybackRate(rest.playbackRate!) }, [rest.playbackRate]) useEffect(() => { return () => { player.current?.destroy() player.current = null } }, []) useImperativeHandle(ref, () => player.current, []) return useMemo(() => { if (aspectRatio == 0) { return
} return (
) }, []) }) const useEffectIf = (where: any, cb: EffectCallback, deps?: DependencyList): void => { useEffect(() => { if (Boolean(where)) { return cb() } }, deps) } export function usePrevious(value: T): T | undefined { const ref = useRef() useEffect(() => { ref.current = value }, [value]) return ref.current } export * from '@oplayer/core' export default ReactOPlayer