10 changed files with 87 additions and 21 deletions
@ -1,2 +0,0 @@
@@ -1,2 +0,0 @@
|
||||
export * from "./atoms"; |
||||
export * from "./base/Container"; |
@ -1,3 +1,2 @@
@@ -1,3 +1,2 @@
|
||||
import { ReactNode } from "react"; |
||||
export * as Atoms from "./atoms/index"; |
||||
export |
||||
export * from "./atoms"; |
||||
export * from "./base/Container"; |
||||
|
@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
|
||||
# Video player component |
||||
|
||||
Video player is quite a complex component, so here is a rundown of all the parts |
||||
|
||||
# Composable parts |
||||
These parts can be used to build any shape of a video player. |
||||
- `/atoms`- any ui element that controls the player. (Seekbar, Pause button, quality selection, etc) |
||||
- `/base` - base components that are used to build a player. Like the main container |
||||
|
||||
# internal parts |
||||
These parts are internally used, they aren't exported. Do not use them outside of player internals. |
||||
- `/display` - display interface, abstraction on how to actually play the content (e.g Video element, HLS player, Standard video element, etc) |
||||
- `/internals` - Internal components that are always rendered on every player. |
||||
- `/utils` - miscellaneous logic |
||||
- `/hooks` - hooks only used for video player |
||||
- `~/src/stores/player` - state for the video player. Should only be used by internal parts |
@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
|
||||
import { Source } from "@/components/player/hooks/usePlayer"; |
||||
|
||||
type EventMap = Record<string, any>; |
||||
type EventKey<T extends EventMap> = string & keyof T; |
||||
type EventReceiver<T> = (params: T) => void; |
||||
|
||||
export interface Emitter<T extends EventMap> { |
||||
on<K extends EventKey<T>>(eventName: K, fn: EventReceiver<T[K]>): void; |
||||
off<K extends EventKey<T>>(eventName: K, fn: EventReceiver<T[K]>): void; |
||||
emit<K extends EventKey<T>>(eventName: K, params: T[K]): void; |
||||
} |
||||
|
||||
interface Listener<T extends EventMap> { |
||||
on<K extends EventKey<T>>(eventName: K, fn: EventReceiver<T[K]>): void; |
||||
} |
||||
|
||||
export interface DisplayInterface<Events extends EventMap> |
||||
extends Listener<Events> { |
||||
play(): void; |
||||
pause(): void; |
||||
load(source: Source): void; |
||||
} |
@ -1,14 +1,36 @@
@@ -1,14 +1,36 @@
|
||||
import { useEffect, useRef } from "react"; |
||||
import { RefObject, useEffect, useRef } from "react"; |
||||
|
||||
import { MWStreamType } from "@/backend/helpers/streams"; |
||||
import { SourceSliceSource } from "@/stores/player/slices/source"; |
||||
import { AllSlices } from "@/stores/player/slices/types"; |
||||
import { usePlayerStore } from "@/stores/player/store"; |
||||
|
||||
export function VideoContainer() { |
||||
const player = usePlayerStore(); |
||||
const videoEl = useRef<HTMLVideoElement>(null); |
||||
// should this video container show right now?
|
||||
function useShouldShow(source: SourceSliceSource | null): boolean { |
||||
if (!source) return false; |
||||
if (source.type !== MWStreamType.MP4) return false; |
||||
return true; |
||||
} |
||||
|
||||
// make video element up to par with the state
|
||||
function useRestoreVideo( |
||||
videoRef: RefObject<HTMLVideoElement>, |
||||
player: AllSlices |
||||
) { |
||||
useEffect(() => { |
||||
if (videoEl.current) videoEl.current.src = player.source?.url ?? ""; |
||||
}, [player.source?.url]); |
||||
const el = videoRef.current; |
||||
const src = player.source?.url ?? ""; |
||||
if (!el) return; |
||||
if (el.src !== src) el.src = src; |
||||
}, [player.source?.url, videoRef]); |
||||
} |
||||
|
||||
export function VideoContainer() { |
||||
const videoEl = useRef<HTMLVideoElement>(null); |
||||
const player = usePlayerStore(); |
||||
useRestoreVideo(videoEl, player); |
||||
const show = useShouldShow(player.source); |
||||
|
||||
return <video controls ref={videoEl} />; |
||||
if (!show) return null; |
||||
return <video autoPlay ref={videoEl} />; |
||||
} |
||||
|
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
import { Controller } from "@/stores/player/controllers/types"; |
||||
|
||||
function useBaseController(el: HTMLVideoElement): Controller { |
||||
return {}; |
||||
} |
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
export interface Controller { |
||||
pause(): void; |
||||
play(): void; |
||||
setVolume(target: number): void; |
||||
registerVideoElement(): void; |
||||
} |
Loading…
Reference in new issue