Fix react-native-video typescript

This commit is contained in:
Zoe Roux 2024-01-30 17:49:34 +01:00
parent ecc2b70e43
commit 93608c9549
4 changed files with 25 additions and 301 deletions

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
// 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 <https://github.com/huhuanming>
// Nekith <https://github.com/Nekith>
// Philip Frank <https://github.com/bananer>
// 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<string>;
}
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<VideoProperties> {
presentFullscreenPlayer(): void;
dismissFullscreenPlayer(): void;
restoreUserInterfaceForPictureInPictureStopCompleted(restored: boolean): void;
save(): Promise<void>;
seek(time: number, tolerance?: number): void;
}
}

View File

@ -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);

View File

@ -18,17 +18,17 @@
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
*/
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<VideoProperties, "source"> & {
source: { uri: string; hls: string | null; startPosition?: number | null };
export type VideoProps = Omit<ReactVideoProps, "source"> & {
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<NativeVideo, VideoProps>(function Video(
const Video = forwardRef<VideoRef, VideoProps>(function Video(
{ onLoad, onBuffer, source, onPointerDown, subtitles, ...props },
ref,
) {
@ -92,21 +98,25 @@ const Video = forwardRef<NativeVideo, VideoProps>(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) => (
<Menu.Item
key={x.index}
label={audios?.[x.index].displayName ?? x.title}
label={audios?.[x.index].displayName ?? x.title ?? x.language ?? "Unknown"}
selected={audio!.index === x.index}
onSelect={() => setAudio(x as any)}
/>

View File

@ -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" },
});
}
}}