diff --git a/front/packages/ui/src/player/react-native-video.d.ts b/front/packages/ui/src/player/react-native-video.d.ts deleted file mode 100644 index eae2a736..00000000 --- a/front/packages/ui/src/player/react-native-video.d.ts +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Kyoo - A portable and vast media library solution. - * Copyright (c) Kyoo. - * - * See AUTHORS.md and LICENSE file in the project root for full license information. - * - * Kyoo is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * Kyoo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Kyoo. If not, see . - */ - -// Type definitions for react-native-video 5.0 -// Project: https://github.com/react-native-community/react-native-video, https://github.com/brentvatne/react-native-video -// Definitions by: HuHuanming -// Nekith -// Philip Frank -// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.8 - -declare module "react-native-video" { - import * as React from "react"; - import { ViewProps } from "react-native"; - - export interface OnLoadData { - canPlayFastForward: boolean; - canPlayReverse: boolean; - canPlaySlowForward: boolean; - canPlaySlowReverse: boolean; - canStepBackward: boolean; - canStepForward: boolean; - currentPosition: number; - currentTime: number; - duration: number; - naturalSize: { - height: number; - width: number; - orientation: "portrait" | "landscape"; - }; - videoTracks: Array<{ - bitrate: number; - codecs: string; - width: number; - height: number; - trackId: string; - }>; - audioTracks: Array<{ - index: number; - title: string; - language: string; - type: string; - }>; - textTracks: Array<{ - index: number; - title: string; - language: string; - type: string; - }>; - } - - export interface OnProgressData { - currentTime: number; - playableDuration: number; - seekableDuration: number; - } - - export interface OnBandwidthUpdateData { - bitrate: number; - } - - export interface LoadError { - error: { - "": string; - errorString: string; - }; - } - - export interface OnSeekData { - currentTime: number; - seekTime: number; - target?: number | undefined; - } - - export interface OnPlaybackRateData { - playbackRate: number; - } - - export interface OnPictureInPictureStatusData { - isActive: boolean; - } - - export interface OnExternalPlaybackChangeData { - isExternalPlaybackActive: boolean; - } - - export interface OnBufferData { - isBuffering: boolean; - } - - export interface DRMSettings { - type: DRMType; - licenseServer?: string | undefined; - headers?: { [key: string]: string } | undefined; - contentId?: string | undefined; - certificateUrl?: string | undefined; - base64Certificate?: boolean | undefined; - getLicense?(spcString: string): Promise; - } - - export const TextTrackType: { - SRT: "application/x-subrip"; - TTML: "application/ttml+xml"; - VTT: "text/vtt"; - }; - - export enum FilterType { - NONE = "", - INVERT = "CIColorInvert", - MONOCHROME = "CIColorMonochrome", - POSTERIZE = "CIColorPosterize", - FALSE = "CIFalseColor", - MAXIMUMCOMPONENT = "CIMaximumComponent", - MINIMUMCOMPONENT = "CIMinimumComponent", - CHROME = "CIPhotoEffectChrome", - FADE = "CIPhotoEffectFade", - INSTANT = "CIPhotoEffectInstant", - MONO = "CIPhotoEffectMono", - NOIR = "CIPhotoEffectNoir", - PROCESS = "CIPhotoEffectProcess", - TONAL = "CIPhotoEffectTonal", - TRANSFER = "CIPhotoEffectTransfer", - SEPIA = "CISepiaTone", - } - - export enum DRMType { - WIDEVINE = "widevine", - PLAYREADY = "playready", - CLEARKEY = "clearkey", - FAIRPLAY = "fairplay", - } - - export interface VideoProperties extends ViewProps { - filter?: FilterType | undefined; - filterEnabled?: boolean | undefined; - - /* Native only */ - src?: any; - seek?: number | undefined; - fullscreen?: boolean | undefined; - fullscreenOrientation?: "all" | "landscape" | "portrait" | undefined; - fullscreenAutorotate?: boolean | undefined; - onVideoLoadStart?(): void; - onVideoLoad?(): void; - onVideoBuffer?(): void; - onVideoError?(): void; - onVideoProgress?(): void; - onVideoSeek?(): void; - onVideoEnd?(): void; - onTimedMetadata?(): void; - onVideoFullscreenPlayerWillPresent?(): void; - onVideoFullscreenPlayerDidPresent?(): void; - onVideoFullscreenPlayerWillDismiss?(): void; - onVideoFullscreenPlayerDidDismiss?(): void; - - /* Wrapper component */ - // Opaque type returned by require('./video.mp4') - source: - | { - uri?: string | undefined; - headers?: { [key: string]: string } | undefined; - type?: string | undefined; - } - | number; - minLoadRetryCount?: number | undefined; - maxBitRate?: number | undefined; - resizeMode?: "stretch" | "contain" | "cover" | "none" | undefined; // via Image#resizeMode - posterResizeMode?: "stretch" | "contain" | "cover" | "none" | undefined; // via Image#resizeMode - poster?: string | undefined; - repeat?: boolean | undefined; - automaticallyWaitsToMinimizeStalling?: boolean | undefined; - paused?: boolean | undefined; - muted?: boolean | undefined; - volume?: number | undefined; - bufferConfig?: - | { - minBufferMs?: number | undefined; - maxBufferMs?: number | undefined; - bufferForPlaybackMs?: number | undefined; - bufferForPlaybackAfterRebufferMs?: number | undefined; - } - | undefined; - stereoPan?: number | undefined; - rate?: number | undefined; - pictureInPicture?: boolean | undefined; - playInBackground?: boolean | undefined; - playWhenInactive?: boolean | undefined; - ignoreSilentSwitch?: "ignore" | "obey" | undefined; - mixWithOthers?: "inherit" | "mix" | "duck" | undefined; - reportBandwidth?: boolean | undefined; - disableFocus?: boolean | undefined; - controls?: boolean | undefined; - currentTime?: number | undefined; - progressUpdateInterval?: number | undefined; - useTextureView?: boolean | undefined; - hideShutterView?: boolean | undefined; - shutterColor?: string; - frameQuality?: number; - onFrameChange?: (base64ImageString: string) => void; - allowsExternalPlayback?: boolean | undefined; - audioOnly?: boolean | undefined; - preventsDisplaySleepDuringVideoPlayback?: boolean | undefined; - drm?: DRMSettings | undefined; - preferredForwardBufferDuration?: number | undefined; - - onLoadStart?(): void; - onLoad?(data: OnLoadData): void; - onBuffer?(data: OnBufferData): void; - onError?(error: LoadError): void; - onProgress?(data: OnProgressData): void; - onBandwidthUpdate?(data: OnBandwidthUpdateData): void; - onSeek?(data: OnSeekData): void; - onEnd?(): void; - onFullscreenPlayerWillPresent?(): void; - onFullscreenPlayerDidPresent?(): void; - onFullscreenPlayerWillDismiss?(): void; - onFullscreenPlayerDidDismiss?(): void; - onReadyForDisplay?(): void; - onPlaybackStalled?(): void; - onPlaybackResume?(): void; - onPlaybackRateChange?(data: OnPlaybackRateData): void; - onAudioFocusChanged?(): void; - onAudioBecomingNoisy?(): void; - onPictureInPictureStatusChanged?(data: OnPictureInPictureStatusData): void; - onRestoreUserInterfaceForPictureInPictureStop?(): void; - onExternalPlaybackChange?(data: OnExternalPlaybackChangeData): void; - selectedAudioTrack?: - | { - type: "system" | "disabled" | "title" | "language" | "index"; - value?: string | number | undefined; - } - | undefined; - selectedTextTrack?: - | { - type: "system" | "disabled" | "title" | "language" | "index"; - value?: string | number | undefined; - } - | undefined; - selectedVideoTrack?: - | { - type: "auto" | "disabled" | "resolution" | "index"; - value?: string | number | undefined; - } - | undefined; - textTracks?: - | Array<{ - title?: string | undefined; - language?: string | undefined; - type: "application/x-subrip" | "application/ttml+xml" | "text/vtt"; - uri: string; - }> - | undefined; - - /* Required by react-native */ - scaleX?: number | undefined; - scaleY?: number | undefined; - translateX?: number | undefined; - translateY?: number | undefined; - rotation?: number | undefined; - } - - export default class Video extends React.Component { - presentFullscreenPlayer(): void; - dismissFullscreenPlayer(): void; - restoreUserInterfaceForPictureInPictureStopCompleted(restored: boolean): void; - save(): Promise; - seek(time: number, tolerance?: number): void; - } -} diff --git a/front/packages/ui/src/player/state.tsx b/front/packages/ui/src/player/state.tsx index 63cfdf75..5df8e813 100644 --- a/front/packages/ui/src/player/state.tsx +++ b/front/packages/ui/src/player/state.tsx @@ -22,7 +22,7 @@ import { Audio, Episode, Subtitle, useAccount } from "@kyoo/models"; import { atom, useAtom, useAtomValue, useSetAtom } from "jotai"; import { useAtomCallback } from "jotai/utils"; import { ElementRef, memo, useEffect, useLayoutEffect, useRef, useState, useCallback } from "react"; -import NativeVideo, { VideoProperties as VideoProps } from "./video"; +import NativeVideo, { VideoProps } from "./video"; import { Platform } from "react-native"; export const playAtom = atom(true); diff --git a/front/packages/ui/src/player/video.tsx b/front/packages/ui/src/player/video.tsx index 9f65d143..9a8221b7 100644 --- a/front/packages/ui/src/player/video.tsx +++ b/front/packages/ui/src/player/video.tsx @@ -18,17 +18,17 @@ * along with Kyoo. If not, see . */ -import "./react-native-video.d.ts"; +import "react-native-video"; declare module "react-native-video" { - interface VideoProperties { + interface ReactVideoProps { fonts?: string[]; subtitles?: Subtitle[]; onPlayPause: (isPlaying: boolean) => void; onMediaUnsupported?: () => void; } - export type VideoProps = Omit & { - source: { uri: string; hls: string | null; startPosition?: number | null }; + export type VideoProps = Omit & { + source: { uri: string; hls: string | null; startPosition?: number }; }; } @@ -38,7 +38,13 @@ import { Audio, Subtitle, getToken } from "@kyoo/models"; import { IconButton, Menu } from "@kyoo/primitives"; import { ComponentProps, forwardRef, useEffect, useRef } from "react"; import { atom, useAtom, useAtomValue, useSetAtom } from "jotai"; -import NativeVideo, { OnLoadData, VideoProps } from "react-native-video"; +import NativeVideo, { + VideoRef, + OnLoadData, + VideoProps, + SelectedTrackType, + SelectedVideoTrackType, +} from "react-native-video"; import { useTranslation } from "react-i18next"; import { PlayMode, audioAtom, playModeAtom, subtitleAtom } from "./state"; import uuid from "react-native-uuid"; @@ -57,7 +63,7 @@ const videoAtom = atom(0); const clientId = uuid.v4() as string; -const Video = forwardRef(function Video( +const Video = forwardRef(function Video( { onLoad, onBuffer, source, onPointerDown, subtitles, ...props }, ref, ) { @@ -92,21 +98,25 @@ const Video = forwardRef(function Video( onLoad?.(info); }} onBuffer={onBuffer} - selectedVideoTrack={video === -1 ? { type: "auto" } : { type: "resolution", value: video }} - selectedAudioTrack={{ type: "index", value: audio.index }} + selectedVideoTrack={ + video === -1 + ? { type: SelectedVideoTrackType.AUDO } + : { type: SelectedVideoTrackType.RESOLUTION, value: video } + } + selectedAudioTrack={{ type: SelectedTrackType.INDEX, value: audio.index }} textTracks={subtitles?.map((x) => ({ type: MimeTypes.get(x.codec) as any, uri: x.link!, title: x.title ?? "Unknown", - language: x.language ?? "Unknown", + language: x.language ?? ("Unknown" as any), }))} selectedTextTrack={ subtitle ? { - type: "index", + type: SelectedTrackType.INDEX, value: subtitles?.indexOf(subtitle), } - : { type: "disabled" } + : { type: SelectedTrackType.DISABLED } } {...props} /> @@ -128,7 +138,7 @@ export const AudiosMenu = ({ audios, ...props }: CustomMenu & { audios?: Audio[] {info.audioTracks.map((x) => ( setAudio(x as any)} /> diff --git a/front/packages/ui/src/player/video.web.tsx b/front/packages/ui/src/player/video.web.tsx index 1165c4a5..dfdc55ad 100644 --- a/front/packages/ui/src/player/video.web.tsx +++ b/front/packages/ui/src/player/video.web.tsx @@ -170,7 +170,7 @@ const Video = forwardRef<{ seek: (value: number) => void }, VideoProps>(function if (!d.fatal || !hls?.media) return; console.warn("Hls error", d); onError?.call(null, { - error: { "": "", errorString: d.reason ?? d.error?.message ?? "Unknown hls error" }, + error: { errorString: d.reason ?? d.error?.message ?? "Unknown hls error" }, }); }); } @@ -230,7 +230,7 @@ const Video = forwardRef<{ seek: (value: number) => void }, VideoProps>(function onMediaUnsupported?.call(undefined); else { onError?.call(null, { - error: { "": "", errorString: ref.current?.error?.message ?? "Unknown error" }, + error: { errorString: ref.current?.error?.message ?? "Unknown error" }, }); } }}