forked from Ninjalama/streamyfin_mirror
fix: trailers for movies
This commit is contained in:
@@ -4,7 +4,7 @@ import { ParallaxScrollView } from "@/components/ParallaxPage";
|
||||
import { Ratings } from "@/components/Ratings";
|
||||
import { NextUp } from "@/components/series/NextUp";
|
||||
import { SeasonPicker } from "@/components/series/SeasonPicker";
|
||||
import { SeriesActions } from "@/components/series/SeriesActions";
|
||||
import { ItemActions } from "@/components/series/SeriesActions";
|
||||
import { SeriesHeader } from "@/components/series/SeriesHeader";
|
||||
import { apiAtom, userAtom } from "@/providers/JellyfinProvider";
|
||||
import { getBackdropUrl } from "@/utils/jellyfin/image/getBackdropUrl";
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import { useGlobalSearchParams, useNavigation } from "expo-router";
|
||||
import { useState, useCallback, useEffect, useMemo } from "react";
|
||||
import { Button, Dimensions } from "react-native";
|
||||
import { Alert, View } from "react-native";
|
||||
import { useGlobalSearchParams } from "expo-router";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { Alert, Dimensions, View } from "react-native";
|
||||
import YoutubePlayer, { PLAYER_STATES } from "react-native-youtube-iframe";
|
||||
|
||||
export default function page() {
|
||||
const searchParams = useGlobalSearchParams();
|
||||
const navigation = useNavigation();
|
||||
console.log(searchParams);
|
||||
|
||||
const { url } = searchParams as { url: string };
|
||||
@@ -29,15 +27,10 @@ export default function page() {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
navigation.setOptions({
|
||||
headerShown: false,
|
||||
});
|
||||
|
||||
togglePlaying();
|
||||
}, []);
|
||||
|
||||
const screenWidth = Dimensions.get("screen").width;
|
||||
const screenHeight = Dimensions.get("screen").height;
|
||||
|
||||
return (
|
||||
<View className="flex flex-col bg-black items-center justify-center h-full">
|
||||
|
||||
@@ -338,6 +338,7 @@ function Layout() {
|
||||
<Stack.Screen
|
||||
name="(auth)/trailer/page"
|
||||
options={{
|
||||
headerShown: false,
|
||||
presentation: "modal",
|
||||
title: "",
|
||||
}}
|
||||
|
||||
@@ -15,12 +15,12 @@ import useDefaultPlaySettings from "@/hooks/useDefaultPlaySettings";
|
||||
import { useImageColors } from "@/hooks/useImageColors";
|
||||
import { useOrientation } from "@/hooks/useOrientation";
|
||||
import { apiAtom } from "@/providers/JellyfinProvider";
|
||||
import { SubtitleHelper } from "@/utils/SubtitleHelper";
|
||||
import { useSettings } from "@/utils/atoms/settings";
|
||||
import { getLogoImageUrlById } from "@/utils/jellyfin/image/getLogoImageUrlById";
|
||||
import {
|
||||
BaseItemDto,
|
||||
MediaSourceInfo,
|
||||
MediaStream,
|
||||
} from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import { Image } from "expo-image";
|
||||
import { useNavigation } from "expo-router";
|
||||
@@ -31,10 +31,9 @@ import { View } from "react-native";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import { Chromecast } from "./Chromecast";
|
||||
import { ItemHeader } from "./ItemHeader";
|
||||
import { ItemTechnicalDetails } from "./ItemTechnicalDetails";
|
||||
import { MediaSourceSelector } from "./MediaSourceSelector";
|
||||
import { MoreMoviesWithActor } from "./MoreMoviesWithActor";
|
||||
import { SubtitleHelper } from "@/utils/SubtitleHelper";
|
||||
import { ItemTechnicalDetails } from "./ItemTechnicalDetails";
|
||||
|
||||
export type SelectedOptions = {
|
||||
bitrate: Bitrate;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import React from "react";
|
||||
import { View, ViewProps } from "react-native";
|
||||
import { GenreTags } from "./GenreTags";
|
||||
import { MoviesTitleHeader } from "./movies/MoviesTitleHeader";
|
||||
import { Ratings } from "./Ratings";
|
||||
import { EpisodeTitleHeader } from "./series/EpisodeTitleHeader";
|
||||
import { GenreTags } from "./GenreTags";
|
||||
import React from "react";
|
||||
import { ItemActions } from "./series/SeriesActions";
|
||||
|
||||
interface Props extends ViewProps {
|
||||
item?: BaseItemDto | null;
|
||||
@@ -27,7 +28,10 @@ export const ItemHeader: React.FC<Props> = ({ item, ...props }) => {
|
||||
return (
|
||||
<View className="flex flex-col" {...props}>
|
||||
<View className="flex flex-col" {...props}>
|
||||
<Ratings item={item} className="mb-2" />
|
||||
<View className="flex flex-row items-center justify-between">
|
||||
<Ratings item={item} className="mb-2" />
|
||||
<ItemActions item={item} />
|
||||
</View>
|
||||
{item.Type === "Episode" && (
|
||||
<>
|
||||
<EpisodeTitleHeader item={item} />
|
||||
|
||||
@@ -2,13 +2,13 @@ import { Ionicons } from "@expo/vector-icons";
|
||||
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client";
|
||||
import { useRouter } from "expo-router";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import { View, TouchableOpacity, ViewProps } from "react-native";
|
||||
import { TouchableOpacity, View, ViewProps } from "react-native";
|
||||
|
||||
interface Props extends ViewProps {
|
||||
item: BaseItemDto;
|
||||
}
|
||||
|
||||
export const SeriesActions = ({ item, ...props }: Props) => {
|
||||
export const ItemActions = ({ item, ...props }: Props) => {
|
||||
const router = useRouter();
|
||||
|
||||
const trailerLink = useMemo(() => item.RemoteTrailers?.[0]?.Url, [item]);
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Text } from "../common/Text";
|
||||
import { Ratings } from "../Ratings";
|
||||
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client";
|
||||
import { useMemo } from "react";
|
||||
import { SeriesActions } from "./SeriesActions";
|
||||
import { ItemActions } from "./SeriesActions";
|
||||
|
||||
interface Props {
|
||||
item: BaseItemDto;
|
||||
@@ -56,7 +56,7 @@ export const SeriesHeader = ({ item }: Props) => {
|
||||
<Text className="">{yearString}</Text>
|
||||
<View className="flex flex-row items-center justify-between">
|
||||
<Ratings item={item} className="mb-2" />
|
||||
<SeriesActions item={item} />
|
||||
<ItemActions item={item} />
|
||||
</View>
|
||||
<Text className="">{item?.Overview}</Text>
|
||||
</View>
|
||||
|
||||
@@ -39,7 +39,7 @@ import React, {
|
||||
useMemo,
|
||||
useState,
|
||||
} from "react";
|
||||
import {AppState, AppStateStatus, Platform} from "react-native";
|
||||
import { AppState, AppStateStatus, Platform } from "react-native";
|
||||
import { toast } from "sonner-native";
|
||||
import { apiAtom } from "./JellyfinProvider";
|
||||
import * as Notifications from "expo-notifications";
|
||||
@@ -195,7 +195,7 @@ function useDownloadProvider() {
|
||||
[settings?.optimizedVersionsServerUrl, authHeader]
|
||||
);
|
||||
|
||||
const APP_CACHE_DOWNLOAD_DIRECTORY = `${FileSystem.cacheDirectory}${Application.applicationId}/Downloads/`
|
||||
const APP_CACHE_DOWNLOAD_DIRECTORY = `${FileSystem.cacheDirectory}${Application.applicationId}/Downloads/`;
|
||||
|
||||
const startDownload = useCallback(
|
||||
async (process: JobStatus) => {
|
||||
@@ -423,32 +423,25 @@ function useDownloadProvider() {
|
||||
throw new Error("Base directory not found");
|
||||
}
|
||||
|
||||
console.log(`ignoreList length: ${ignoreList?.length}`);
|
||||
|
||||
const dirContents = await FileSystem.readDirectoryAsync(baseDirectory);
|
||||
for (const item of dirContents) {
|
||||
// Exclude mmkv directory.
|
||||
// Deleting this deletes all user information as well. Logout should handle this.
|
||||
if (
|
||||
(item == "mmkv" && !includeMMKV) ||
|
||||
ignoreList.some(i => item.includes(i))
|
||||
ignoreList.some((i) => item.includes(i))
|
||||
) {
|
||||
console.log("Skipping read for item", item)
|
||||
continue;
|
||||
}
|
||||
await FileSystem.getInfoAsync(`${baseDirectory}${item}`)
|
||||
.then((itemInfo) => {
|
||||
console.log("Loading itemInfo", itemInfo);
|
||||
|
||||
if (itemInfo.exists && !itemInfo.isDirectory) {
|
||||
callback(itemInfo);
|
||||
}
|
||||
})
|
||||
.catch(e =>
|
||||
console.error(e)
|
||||
)
|
||||
.catch((e) => console.error(e));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const deleteLocalFiles = async (): Promise<void> => {
|
||||
await forEveryDocumentDirFile(false, [], (file) => {
|
||||
@@ -545,28 +538,36 @@ function useDownloadProvider() {
|
||||
};
|
||||
|
||||
const cleanCacheDirectory = async () => {
|
||||
const cacheDir = await FileSystem.getInfoAsync(APP_CACHE_DOWNLOAD_DIRECTORY);
|
||||
const cacheDir = await FileSystem.getInfoAsync(
|
||||
APP_CACHE_DOWNLOAD_DIRECTORY
|
||||
);
|
||||
if (cacheDir.exists) {
|
||||
const cachedFiles = await FileSystem.readDirectoryAsync(APP_CACHE_DOWNLOAD_DIRECTORY)
|
||||
let position = 0
|
||||
const batchSize = 3
|
||||
const cachedFiles = await FileSystem.readDirectoryAsync(
|
||||
APP_CACHE_DOWNLOAD_DIRECTORY
|
||||
);
|
||||
let position = 0;
|
||||
const batchSize = 3;
|
||||
|
||||
// batching promise.all to avoid OOM
|
||||
while (position < cachedFiles.length) {
|
||||
const itemsForBatch = cachedFiles.slice(position, position + batchSize)
|
||||
await Promise.all(itemsForBatch.map(async file => {
|
||||
const info = await FileSystem.getInfoAsync(`${APP_CACHE_DOWNLOAD_DIRECTORY}${file}`)
|
||||
if (info.exists) {
|
||||
await FileSystem.deleteAsync(info.uri, { idempotent: true })
|
||||
return Promise.resolve(file)
|
||||
}
|
||||
return Promise.reject()
|
||||
}))
|
||||
const itemsForBatch = cachedFiles.slice(position, position + batchSize);
|
||||
await Promise.all(
|
||||
itemsForBatch.map(async (file) => {
|
||||
const info = await FileSystem.getInfoAsync(
|
||||
`${APP_CACHE_DOWNLOAD_DIRECTORY}${file}`
|
||||
);
|
||||
if (info.exists) {
|
||||
await FileSystem.deleteAsync(info.uri, { idempotent: true });
|
||||
return Promise.resolve(file);
|
||||
}
|
||||
return Promise.reject();
|
||||
})
|
||||
);
|
||||
|
||||
position += batchSize
|
||||
position += batchSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const deleteFileByType = async (type: BaseItemDto["Type"]) => {
|
||||
await Promise.all(
|
||||
@@ -583,20 +584,22 @@ function useDownloadProvider() {
|
||||
};
|
||||
|
||||
const appSizeUsage = useMemo(async () => {
|
||||
const sizes: number[] = downloadedFiles?.map(d => {
|
||||
return getDownloadedItemSize(d.item.Id!!)
|
||||
}) || [];
|
||||
const sizes: number[] =
|
||||
downloadedFiles?.map((d) => {
|
||||
return getDownloadedItemSize(d.item.Id!!);
|
||||
}) || [];
|
||||
|
||||
await forEveryDocumentDirFile(
|
||||
true,
|
||||
getAllDownloadedItems().map(d => d.item.Id!!),
|
||||
getAllDownloadedItems().map((d) => d.item.Id!!),
|
||||
(file) => {
|
||||
if (file.exists) {
|
||||
sizes.push(file.size);
|
||||
}
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
})
|
||||
}
|
||||
).catch((e) => {
|
||||
console.error(e);
|
||||
});
|
||||
|
||||
return sizes.reduce((sum, size) => sum + size, 0);
|
||||
}, [logs, downloadedFiles, forEveryDocumentDirFile]);
|
||||
@@ -690,7 +693,7 @@ function useDownloadProvider() {
|
||||
appSizeUsage,
|
||||
getDownloadedItemSize,
|
||||
APP_CACHE_DOWNLOAD_DIRECTORY,
|
||||
cleanCacheDirectory
|
||||
cleanCacheDirectory,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user