forked from Ninjalama/streamyfin_mirror
wip
This commit is contained in:
@@ -23,7 +23,7 @@ export default function IndexLayout() {
|
||||
headerShadowVisible: false,
|
||||
headerRight: () => (
|
||||
<View className="flex flex-row items-center space-x-2">
|
||||
<Chromecast />
|
||||
{!Platform.isTV && <Chromecast />}
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
router.push("/(auth)/settings");
|
||||
|
||||
@@ -27,6 +27,7 @@ import { QueryFunction, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useNavigation, useRouter } from "expo-router";
|
||||
import { useAtomValue } from "jotai";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { Platform } from "react-native";
|
||||
import {
|
||||
ActivityIndicator,
|
||||
RefreshControl,
|
||||
@@ -64,11 +65,13 @@ export default function index() {
|
||||
const [isConnected, setIsConnected] = useState<boolean | null>(null);
|
||||
const [loadingRetry, setLoadingRetry] = useState(false);
|
||||
|
||||
const { downloadedFiles, cleanCacheDirectory } = useDownload();
|
||||
const navigation = useNavigation();
|
||||
|
||||
const insets = useSafeAreaInsets();
|
||||
|
||||
if (!Platform.isTV) {
|
||||
const { downloadedFiles, cleanCacheDirectory } = useDownload();
|
||||
|
||||
useEffect(() => {
|
||||
const hasDownloads = downloadedFiles && downloadedFiles.length > 0;
|
||||
navigation.setOptions({
|
||||
@@ -88,6 +91,7 @@ export default function index() {
|
||||
),
|
||||
});
|
||||
}, [downloadedFiles, navigation, router]);
|
||||
}
|
||||
|
||||
const checkConnection = useCallback(async () => {
|
||||
setLoadingRetry(true);
|
||||
@@ -107,9 +111,11 @@ export default function index() {
|
||||
setIsConnected(state.isConnected);
|
||||
});
|
||||
|
||||
if (!Platform.isTV) {
|
||||
cleanCacheDirectory().catch((e) =>
|
||||
console.error("Something went wrong cleaning cache directory")
|
||||
);
|
||||
}
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Platform } from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { ListGroup } from "@/components/list/ListGroup";
|
||||
import { ListItem } from "@/components/list/ListItem";
|
||||
@@ -13,7 +14,8 @@ import { SubtitleToggles } from "@/components/settings/SubtitleToggles";
|
||||
import { UserInfo } from "@/components/settings/UserInfo";
|
||||
import { useJellyfin } from "@/providers/JellyfinProvider";
|
||||
import { clearLogs } from "@/utils/log";
|
||||
import * as Haptics from "expo-haptics";
|
||||
// const Haptics = !Platform.isTV ? require("expo-haptics") : null;
|
||||
import * as Haptics from "@/packages/expo-haptics";
|
||||
import { useNavigation, useRouter } from "expo-router";
|
||||
import { useEffect } from "react";
|
||||
import { ScrollView, TouchableOpacity, View } from "react-native";
|
||||
@@ -26,7 +28,9 @@ export default function settings() {
|
||||
|
||||
const onClearLogsClicked = async () => {
|
||||
clearLogs();
|
||||
if (!Platform.isTV) {
|
||||
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
|
||||
}
|
||||
};
|
||||
|
||||
const navigation = useNavigation();
|
||||
|
||||
@@ -12,7 +12,7 @@ import { useQuery } from "@tanstack/react-query";
|
||||
import { router, useLocalSearchParams, useNavigation } from "expo-router";
|
||||
import { useAtom } from "jotai";
|
||||
import { useEffect, useState } from "react";
|
||||
import { ScrollView, TouchableOpacity, View } from "react-native";
|
||||
import { Platform, ScrollView, TouchableOpacity, View } from "react-native";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
|
||||
export default function page() {
|
||||
@@ -28,6 +28,7 @@ export default function page() {
|
||||
|
||||
const navigation = useNavigation();
|
||||
|
||||
if (!Platform.isTV) {
|
||||
useEffect(() => {
|
||||
navigation.setOptions({
|
||||
headerRight: () => (
|
||||
@@ -37,6 +38,7 @@ export default function page() {
|
||||
),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const { data: album } = useQuery({
|
||||
queryKey: ["album", albumId, artistId],
|
||||
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
import { FlashList } from "@shopify/flash-list";
|
||||
import { useInfiniteQuery, useQuery } from "@tanstack/react-query";
|
||||
import { useLocalSearchParams, useNavigation } from "expo-router";
|
||||
import * as ScreenOrientation from "expo-screen-orientation";
|
||||
import * as ScreenOrientation from "@/packages/expo-screen-orientation";
|
||||
import { useAtom } from "jotai";
|
||||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { FlatList, View } from "react-native";
|
||||
|
||||
@@ -34,7 +34,7 @@ import {
|
||||
IssueType,
|
||||
IssueTypeName,
|
||||
} from "@/utils/jellyseerr/server/constants/issue";
|
||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
||||
import * as DropdownMenu from "@/components/DropdownMenu";
|
||||
import { TvDetails } from "@/utils/jellyseerr/server/models/Tv";
|
||||
import JellyseerrSeasons from "@/components/series/JellyseerrSeasons";
|
||||
import { JellyserrRatings } from "@/components/Ratings";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useInfiniteQuery, useQuery } from "@tanstack/react-query";
|
||||
import { useLocalSearchParams, useNavigation } from "expo-router";
|
||||
import * as ScreenOrientation from "expo-screen-orientation";
|
||||
import * as ScreenOrientation from "@/packages/expo-screen-orientation";
|
||||
import { useAtom } from "jotai";
|
||||
import React, { useCallback, useEffect, useMemo } from "react";
|
||||
import { FlatList, useWindowDimensions, View } from "react-native";
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useSettings } from "@/utils/atoms/settings";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { Stack } from "expo-router";
|
||||
import { Platform } from "react-native";
|
||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
||||
import * as DropdownMenu from "@/components/DropdownMenu";
|
||||
|
||||
export default function IndexLayout() {
|
||||
const [settings, updateSettings] = useSettings();
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
getUserLibraryApi,
|
||||
} from "@jellyfin/sdk/lib/utils/api";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import * as Haptics from "expo-haptics";
|
||||
import * as Haptics from "@/packages/expo-haptics";
|
||||
import { useFocusEffect, useGlobalSearchParams } from "expo-router";
|
||||
import { useAtomValue } from "jotai";
|
||||
import React, {
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
getUserLibraryApi,
|
||||
} from "@jellyfin/sdk/lib/utils/api";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import * as Haptics from "expo-haptics";
|
||||
import * as Haptics from "@/packages/expo-haptics";
|
||||
import { Image } from "expo-image";
|
||||
import { useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import { useAtomValue } from "jotai";
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
getUserLibraryApi,
|
||||
} from "@jellyfin/sdk/lib/utils/api";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import * as Haptics from "expo-haptics";
|
||||
import * as Haptics from "@/packages/expo-haptics";
|
||||
import { useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import { useAtomValue } from "jotai";
|
||||
import React, {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import "@/augmentations";
|
||||
import { Platform } from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { DownloadProvider } from "@/providers/DownloadProvider";
|
||||
import {
|
||||
@@ -18,23 +19,28 @@ import { cancelJobById, getAllJobsByDeviceId } from "@/utils/optimize-server";
|
||||
import { ActionSheetProvider } from "@expo/react-native-action-sheet";
|
||||
import { BottomSheetModalProvider } from "@gorhom/bottom-sheet";
|
||||
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client";
|
||||
import {
|
||||
checkForExistingDownloads,
|
||||
completeHandler,
|
||||
download,
|
||||
} from "@kesha-antonov/react-native-background-downloader";
|
||||
// import {
|
||||
// checkForExistingDownloads,
|
||||
// completeHandler,
|
||||
// download,
|
||||
// } from "@kesha-antonov/react-native-background-downloader";
|
||||
const BackGroundDownloader = !Platform.isTV
|
||||
? require("@kesha-antonov/react-native-background-downloader")
|
||||
: null;
|
||||
import { DarkTheme, ThemeProvider } from "@react-navigation/native";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import * as BackgroundFetch from "expo-background-fetch";
|
||||
const BackgroundFetch = !Platform.isTV
|
||||
? require("expo-background-fetch")
|
||||
: null;
|
||||
import * as FileSystem from "expo-file-system";
|
||||
import { useFonts } from "expo-font";
|
||||
import { useKeepAwake } from "expo-keep-awake";
|
||||
import * as Linking from "expo-linking";
|
||||
import * as Notifications from "expo-notifications";
|
||||
const Notifications = !Platform.isTV ? require("expo-notifications") : null;
|
||||
import { router, Stack } from "expo-router";
|
||||
import * as ScreenOrientation from "expo-screen-orientation";
|
||||
import * as ScreenOrientation from "@/packages/expo-screen-orientation";
|
||||
import * as SplashScreen from "expo-splash-screen";
|
||||
import * as TaskManager from "expo-task-manager";
|
||||
const TaskManager = !Platform.isTV ? require("expo-task-manager") : null;
|
||||
import { Provider as JotaiProvider, useAtom } from "jotai";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { Appearance, AppState, TouchableOpacity } from "react-native";
|
||||
@@ -45,15 +51,19 @@ import { Toaster } from "sonner-native";
|
||||
|
||||
SplashScreen.preventAutoHideAsync();
|
||||
|
||||
Notifications.setNotificationHandler({
|
||||
if (!Platform.isTV) {
|
||||
Notifications.setNotificationHandler({
|
||||
handleNotification: async () => ({
|
||||
shouldShowAlert: true,
|
||||
shouldPlaySound: true,
|
||||
shouldSetBadge: false,
|
||||
}),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function useNotificationObserver() {
|
||||
if (Platform.isTV) return;
|
||||
|
||||
useEffect(() => {
|
||||
let isMounted = true;
|
||||
|
||||
@@ -84,7 +94,8 @@ function useNotificationObserver() {
|
||||
}, []);
|
||||
}
|
||||
|
||||
TaskManager.defineTask(BACKGROUND_FETCH_TASK, async () => {
|
||||
if (!Platform.isTV) {
|
||||
TaskManager.defineTask(BACKGROUND_FETCH_TASK, async () => {
|
||||
console.log("TaskManager ~ trigger");
|
||||
|
||||
const now = Date.now();
|
||||
@@ -117,14 +128,14 @@ TaskManager.defineTask(BACKGROUND_FETCH_TASK, async () => {
|
||||
for (let job of jobs) {
|
||||
if (job.status === "completed") {
|
||||
const downloadUrl = url + "download/" + job.id;
|
||||
const tasks = await checkForExistingDownloads();
|
||||
const tasks = await BackGroundDownloader.checkForExistingDownloads();
|
||||
|
||||
if (tasks.find((task) => task.id === job.id)) {
|
||||
console.log("TaskManager ~ Download already in progress: ", job.id);
|
||||
continue;
|
||||
}
|
||||
|
||||
download({
|
||||
BackGroundDownloader.download({
|
||||
id: job.id,
|
||||
url: downloadUrl,
|
||||
destination: `${baseDirectory}${job.item.Id}.mp4`,
|
||||
@@ -138,7 +149,7 @@ TaskManager.defineTask(BACKGROUND_FETCH_TASK, async () => {
|
||||
.done(() => {
|
||||
console.log("TaskManager ~ Download completed: ", job.id);
|
||||
saveDownloadedItemInfo(job.item);
|
||||
completeHandler(job.id);
|
||||
BackGroundDownloader.completeHandler(job.id);
|
||||
cancelJobById({
|
||||
authHeader: token,
|
||||
id: job.id,
|
||||
@@ -176,7 +187,8 @@ TaskManager.defineTask(BACKGROUND_FETCH_TASK, async () => {
|
||||
|
||||
// Be sure to return the successful result type!
|
||||
return BackgroundFetch.BackgroundFetchResult.NewData;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const checkAndRequestPermissions = async () => {
|
||||
try {
|
||||
@@ -250,6 +262,10 @@ function Layout() {
|
||||
const [orientation, setOrientation] = useAtom(orientationAtom);
|
||||
|
||||
useKeepAwake();
|
||||
|
||||
const appState = useRef(AppState.currentState);
|
||||
|
||||
if (!Platform.isTV) {
|
||||
useNotificationObserver();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -265,19 +281,20 @@ function Layout() {
|
||||
);
|
||||
}, [settings]);
|
||||
|
||||
const appState = useRef(AppState.currentState);
|
||||
|
||||
useEffect(() => {
|
||||
const subscription = AppState.addEventListener("change", (nextAppState) => {
|
||||
const subscription = AppState.addEventListener(
|
||||
"change",
|
||||
(nextAppState) => {
|
||||
if (
|
||||
appState.current.match(/inactive|background/) &&
|
||||
nextAppState === "active"
|
||||
) {
|
||||
checkForExistingDownloads();
|
||||
BackGroundDownloader.checkForExistingDownloads();
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
checkForExistingDownloads();
|
||||
BackGroundDownloader.checkForExistingDownloads();
|
||||
|
||||
return () => {
|
||||
subscription.remove();
|
||||
@@ -299,6 +316,7 @@ function Layout() {
|
||||
ScreenOrientation.removeOrientationChangeListener(subscription);
|
||||
};
|
||||
}, []);
|
||||
}
|
||||
|
||||
const url = Linking.useURL();
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { MediaSourceInfo } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import { useMemo } from "react";
|
||||
import { TouchableOpacity, View } from "react-native";
|
||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
||||
import * as DropdownMenu from "@/components/DropdownMenu";
|
||||
import { Text } from "./common/Text";
|
||||
|
||||
interface Props extends React.ComponentProps<typeof View> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { TouchableOpacity, View } from "react-native";
|
||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
||||
import * as DropdownMenu from "@/components/DropdownMenu";
|
||||
import { Text } from "./common/Text";
|
||||
import { useMemo } from "react";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as Haptics from "expo-haptics";
|
||||
import * as Haptics from "@/packages/expo-haptics";
|
||||
import React, { PropsWithChildren, ReactNode, useMemo } from "react";
|
||||
import { Text, TouchableOpacity, View } from "react-native";
|
||||
import { Loader } from "./Loader";
|
||||
|
||||
0
components/ContextMenu.native.ts
Normal file
0
components/ContextMenu.native.ts
Normal file
1
components/ContextMenu.ts
Normal file
1
components/ContextMenu.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * as ContextMenu from "zeego/context-menu";
|
||||
0
components/DropdownMenu.native.ts
Normal file
0
components/DropdownMenu.native.ts
Normal file
1
components/DropdownMenu.ts
Normal file
1
components/DropdownMenu.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * as DropdownMenu from "zeego/dropdown-menu";
|
||||
@@ -24,10 +24,10 @@ import {
|
||||
} from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import { Image } from "expo-image";
|
||||
import { useNavigation } from "expo-router";
|
||||
import * as ScreenOrientation from "expo-screen-orientation";
|
||||
import * as ScreenOrientation from "@/packages/expo-screen-orientation";
|
||||
import { useAtom } from "jotai";
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import { Platform, View } from "react-native";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import { Chromecast } from "./Chromecast";
|
||||
import { ItemHeader } from "./ItemHeader";
|
||||
@@ -81,6 +81,7 @@ export const ItemContent: React.FC<{ item: BaseItemDto }> = React.memo(
|
||||
defaultMediaSource,
|
||||
]);
|
||||
|
||||
if (!Platform.isTV) {
|
||||
useEffect(() => {
|
||||
navigation.setOptions({
|
||||
headerRight: () =>
|
||||
@@ -98,6 +99,7 @@ export const ItemContent: React.FC<{ item: BaseItemDto }> = React.memo(
|
||||
),
|
||||
});
|
||||
}, [item]);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (orientation !== ScreenOrientation.OrientationLock.PORTRAIT_UP)
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
} from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { TouchableOpacity, View } from "react-native";
|
||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
||||
import * as DropdownMenu from "@/components/DropdownMenu";
|
||||
import { Text } from "./common/Text";
|
||||
import { convertBitsToMegabitsOrGigabits } from "@/utils/bToMb";
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ import Animated, {
|
||||
import { Button } from "./Button";
|
||||
import { SelectedOptions } from "./ItemContent";
|
||||
import { chromecastProfile } from "@/utils/profiles/chromecast";
|
||||
import * as Haptics from "expo-haptics";
|
||||
import * as Haptics from "@/packages/expo-haptics";
|
||||
|
||||
interface Props extends React.ComponentProps<typeof Button> {
|
||||
item: BaseItemDto;
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
TouchableOpacity,
|
||||
TouchableOpacityProps,
|
||||
} from "react-native";
|
||||
import * as Haptics from "expo-haptics";
|
||||
import * as Haptics from "@/packages/expo-haptics";
|
||||
|
||||
interface Props extends TouchableOpacityProps {
|
||||
onPress?: () => void;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { tc } from "@/utils/textTools";
|
||||
import { MediaSourceInfo } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import { useMemo } from "react";
|
||||
import { Platform, TouchableOpacity, View } from "react-native";
|
||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
||||
import * as DropdownMenu from "@/components/DropdownMenu";
|
||||
import { Text } from "./common/Text";
|
||||
import { SubtitleHelper } from "@/utils/SubtitleHelper";
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import {useRouter, useSegments} from "expo-router";
|
||||
import React, {PropsWithChildren, useCallback, useMemo} from "react";
|
||||
import {TouchableOpacity, TouchableOpacityProps} from "react-native";
|
||||
import * as ContextMenu from "zeego/context-menu";
|
||||
import {MovieResult, TvResult} from "@/utils/jellyseerr/server/models/Search";
|
||||
import {useJellyseerr} from "@/hooks/useJellyseerr";
|
||||
import {hasPermission, Permission} from "@/utils/jellyseerr/server/lib/permissions";
|
||||
import {MediaType} from "@/utils/jellyseerr/server/constants/media";
|
||||
import { useRouter, useSegments } from "expo-router";
|
||||
import React, { PropsWithChildren, useCallback, useMemo } from "react";
|
||||
import { TouchableOpacity, TouchableOpacityProps } from "react-native";
|
||||
import * as ContextMenu from "@/components/ContextMenu";
|
||||
import { MovieResult, TvResult } from "@/utils/jellyseerr/server/models/Search";
|
||||
import { useJellyseerr } from "@/hooks/useJellyseerr";
|
||||
import {
|
||||
hasPermission,
|
||||
Permission,
|
||||
} from "@/utils/jellyseerr/server/lib/permissions";
|
||||
import { MediaType } from "@/utils/jellyseerr/server/constants/media";
|
||||
|
||||
interface Props extends TouchableOpacityProps {
|
||||
result: MovieResult | TvResult;
|
||||
@@ -26,26 +29,27 @@ export const TouchableJellyseerrRouter: React.FC<PropsWithChildren<Props>> = ({
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const segments = useSegments();
|
||||
const {jellyseerrApi, jellyseerrUser, requestMedia} = useJellyseerr()
|
||||
const { jellyseerrApi, jellyseerrUser, requestMedia } = useJellyseerr();
|
||||
|
||||
const from = segments[2];
|
||||
|
||||
const autoApprove = useMemo(() => {
|
||||
return jellyseerrUser && hasPermission(
|
||||
Permission.AUTO_APPROVE,
|
||||
jellyseerrUser.permissions,
|
||||
{type: 'or'}
|
||||
)
|
||||
}, [jellyseerrApi, jellyseerrUser])
|
||||
return (
|
||||
jellyseerrUser &&
|
||||
hasPermission(Permission.AUTO_APPROVE, jellyseerrUser.permissions, {
|
||||
type: "or",
|
||||
})
|
||||
);
|
||||
}, [jellyseerrApi, jellyseerrUser]);
|
||||
|
||||
const request = useCallback(() =>
|
||||
const request = useCallback(
|
||||
() =>
|
||||
requestMedia(mediaTitle, {
|
||||
mediaId: result.id,
|
||||
mediaType: result.mediaType
|
||||
}
|
||||
),
|
||||
mediaType: result.mediaType,
|
||||
}),
|
||||
[jellyseerrApi, result]
|
||||
)
|
||||
);
|
||||
|
||||
if (from === "(home)" || from === "(search)" || from === "(libraries)")
|
||||
return (
|
||||
@@ -55,7 +59,16 @@ export const TouchableJellyseerrRouter: React.FC<PropsWithChildren<Props>> = ({
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
// @ts-ignore
|
||||
router.push({pathname: `/(auth)/(tabs)/${from}/jellyseerr/page`, params: {...result, mediaTitle, releaseYear, canRequest, posterSrc}});
|
||||
router.push({
|
||||
pathname: `/(auth)/(tabs)/${from}/jellyseerr/page`,
|
||||
params: {
|
||||
...result,
|
||||
mediaTitle,
|
||||
releaseYear,
|
||||
canRequest,
|
||||
posterSrc,
|
||||
},
|
||||
});
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
@@ -75,12 +88,14 @@ export const TouchableJellyseerrRouter: React.FC<PropsWithChildren<Props>> = ({
|
||||
key="item-1"
|
||||
onSelect={() => {
|
||||
if (autoApprove) {
|
||||
request()
|
||||
request();
|
||||
}
|
||||
}}
|
||||
shouldDismissMenuOnSelect
|
||||
>
|
||||
<ContextMenu.ItemTitle key="item-1-title">Request</ContextMenu.ItemTitle>
|
||||
<ContextMenu.ItemTitle key="item-1-title">
|
||||
Request
|
||||
</ContextMenu.ItemTitle>
|
||||
<ContextMenu.ItemIcon
|
||||
ios={{
|
||||
name: "arrow.down.to.line",
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
import { useRouter, useSegments } from "expo-router";
|
||||
import { PropsWithChildren } from "react";
|
||||
import { TouchableOpacity, TouchableOpacityProps } from "react-native";
|
||||
import * as ContextMenu from "zeego/context-menu";
|
||||
import * as ContextMenu from "@/components/ContextMenu";
|
||||
|
||||
interface Props extends TouchableOpacityProps {
|
||||
item: BaseItemDto;
|
||||
|
||||
@@ -5,13 +5,18 @@ import { useSettings } from "@/utils/atoms/settings";
|
||||
import { JobStatus } from "@/utils/optimize-server";
|
||||
import { formatTimeString } from "@/utils/time";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { checkForExistingDownloads } from "@kesha-antonov/react-native-background-downloader";
|
||||
// import { checkForExistingDownloads } from "@kesha-antonov/react-native-background-downloader";
|
||||
const BackGroundDownloader = !Platform.isTV
|
||||
? require("@kesha-antonov/react-native-background-downloader")
|
||||
: null;
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { useRouter } from "expo-router";
|
||||
import { FFmpegKit } from "ffmpeg-kit-react-native";
|
||||
// import { FFmpegKit } from "ffmpeg-kit-react-native";
|
||||
const FFmpegKit = !Platform.isTV ? require("ffmpeg-kit-react-native") : null;
|
||||
import { useAtom } from "jotai";
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Platform,
|
||||
TouchableOpacity,
|
||||
TouchableOpacityProps,
|
||||
View,
|
||||
@@ -64,7 +69,7 @@ const DownloadCard = ({ process, ...props }: DownloadCardProps) => {
|
||||
|
||||
if (settings?.downloadMethod === "optimized") {
|
||||
try {
|
||||
const tasks = await checkForExistingDownloads();
|
||||
const tasks = await BackGroundDownloader.checkForExistingDownloads();
|
||||
for (const task of tasks) {
|
||||
if (task.id === id) {
|
||||
task.stop();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import * as Haptics from "expo-haptics";
|
||||
import * as Haptics from "@/packages/expo-haptics";
|
||||
import React, { useCallback, useMemo } from "react";
|
||||
import { TouchableOpacity, TouchableOpacityProps, View } from "react-native";
|
||||
import {
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
useActionSheet,
|
||||
} from "@expo/react-native-action-sheet";
|
||||
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import * as Haptics from "expo-haptics";
|
||||
import * as Haptics from "@/packages/expo-haptics";
|
||||
import React, { useCallback, useMemo } from "react";
|
||||
import { TouchableOpacity, View } from "react-native";
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import { itemRouter, TouchableItemRouter } from "../common/TouchableItemRouter";
|
||||
import { Loader } from "../Loader";
|
||||
import { Gesture, GestureDetector } from "react-native-gesture-handler";
|
||||
import { useRouter, useSegments } from "expo-router";
|
||||
import * as Haptics from "expo-haptics";
|
||||
import * as Haptics from "@/packages/expo-haptics";
|
||||
|
||||
interface Props extends ViewProps {}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { TouchableOpacity, View } from "react-native";
|
||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
||||
import * as DropdownMenu from "@/components/DropdownMenu";
|
||||
import { Text } from "../common/Text";
|
||||
|
||||
type Props = {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { TouchableOpacity, View, ViewProps } from "react-native";
|
||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
||||
import * as DropdownMenu from "@/components/DropdownMenu";
|
||||
import { Text } from "../common/Text";
|
||||
import { useMedia } from "./MediaContext";
|
||||
import { Switch } from "react-native-gesture-handler";
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useQueryClient } from "@tanstack/react-query";
|
||||
import { useRouter } from "expo-router";
|
||||
import React from "react";
|
||||
import { Switch, TouchableOpacity, View } from "react-native";
|
||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
||||
import * as DropdownMenu from "@/components/DropdownMenu";
|
||||
import { Text } from "../common/Text";
|
||||
import { ListGroup } from "../list/ListGroup";
|
||||
import { ListItem } from "../list/ListItem";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Platform } from "react-native";
|
||||
import { ScreenOrientationEnum, useSettings } from "@/utils/atoms/settings";
|
||||
import {
|
||||
BACKGROUND_FETCH_TASK,
|
||||
@@ -5,13 +6,15 @@ import {
|
||||
unregisterBackgroundFetchAsync,
|
||||
} from "@/utils/background-tasks";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import * as BackgroundFetch from "expo-background-fetch";
|
||||
import * as ScreenOrientation from "expo-screen-orientation";
|
||||
import * as TaskManager from "expo-task-manager";
|
||||
const BackgroundFetch = !Platform.isTV
|
||||
? require("expo-background-fetch")
|
||||
: null;
|
||||
import * as ScreenOrientation from "@/packages/expo-screen-orientation";
|
||||
const TaskManager = !Platform.isTV ? require("expo-task-manager") : null;
|
||||
import React, { useEffect } from "react";
|
||||
import { Linking, Switch, TouchableOpacity, ViewProps } from "react-native";
|
||||
import { toast } from "sonner-native";
|
||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
||||
import * as DropdownMenu from "@/components/DropdownMenu";
|
||||
import { Text } from "../common/Text";
|
||||
import { ListGroup } from "../list/ListGroup";
|
||||
import { ListItem } from "../list/ListItem";
|
||||
@@ -25,6 +28,8 @@ export const OtherSettings: React.FC = () => {
|
||||
* Background task
|
||||
*******************/
|
||||
const checkStatusAsync = async () => {
|
||||
if (Platform.isTV) return;
|
||||
|
||||
await BackgroundFetch.getStatusAsync();
|
||||
return await TaskManager.isTaskRegisteredAsync(BACKGROUND_FETCH_TASK);
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
BottomSheetView,
|
||||
} from "@gorhom/bottom-sheet";
|
||||
import { getQuickConnectApi } from "@jellyfin/sdk/lib/utils/api";
|
||||
import * as Haptics from "expo-haptics";
|
||||
import * as Haptics from "@/packages/expo-haptics";
|
||||
import { useAtom } from "jotai";
|
||||
import React, { useCallback, useRef, useState } from "react";
|
||||
import { Alert, View, ViewProps } from "react-native";
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useDownload } from "@/providers/DownloadProvider";
|
||||
import { clearLogs } from "@/utils/log";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import * as FileSystem from "expo-file-system";
|
||||
import * as Haptics from "expo-haptics";
|
||||
import * as Haptics from "@/packages/expo-haptics";
|
||||
import { View } from "react-native";
|
||||
import * as Progress from "react-native-progress";
|
||||
import { toast } from "sonner-native";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { TouchableOpacity, View, ViewProps } from "react-native";
|
||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
||||
import * as DropdownMenu from "@/components/DropdownMenu";
|
||||
import { Text } from "../common/Text";
|
||||
import { useMedia } from "./MediaContext";
|
||||
import { Switch } from "react-native-gesture-handler";
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import { View, StyleSheet } from "react-native";
|
||||
import { View, StyleSheet, Platform } from "react-native";
|
||||
import { useSharedValue } from "react-native-reanimated";
|
||||
import { Slider } from "react-native-awesome-slider";
|
||||
import { VolumeManager } from "react-native-volume-manager";
|
||||
// import { VolumeManager } from "react-native-volume-manager";
|
||||
const VolumeManager = !Platform.isTV
|
||||
? require("react-native-volume-manager")
|
||||
: null;
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
|
||||
interface AudioSliderProps {
|
||||
@@ -10,6 +13,8 @@ interface AudioSliderProps {
|
||||
}
|
||||
|
||||
const AudioSlider: React.FC<AudioSliderProps> = ({ setVisibility }) => {
|
||||
if (Platform.isTV) return;
|
||||
|
||||
const volume = useSharedValue<number>(50); // Explicitly type as number
|
||||
const min = useSharedValue<number>(0); // Explicitly type as number
|
||||
const max = useSharedValue<number>(100); // Explicitly type as number
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { View, StyleSheet } from "react-native";
|
||||
import { View, StyleSheet, Platform } from "react-native";
|
||||
import { useSharedValue } from "react-native-reanimated";
|
||||
import { Slider } from "react-native-awesome-slider";
|
||||
import * as Brightness from "expo-brightness";
|
||||
// import * as Brightness from "expo-brightness";
|
||||
const Brightness = !Platform.isTV ? require("expo-brightness") : null;
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import MaterialCommunityIcons from "@expo/vector-icons/MaterialCommunityIcons";
|
||||
|
||||
const BrightnessSlider = () => {
|
||||
if (Platform.isTV) return;
|
||||
|
||||
const brightness = useSharedValue(50);
|
||||
const min = useSharedValue(0);
|
||||
const max = useSharedValue(100);
|
||||
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
BaseItemDto,
|
||||
MediaSourceInfo,
|
||||
} from "@jellyfin/sdk/lib/generated-client";
|
||||
import * as Haptics from "expo-haptics";
|
||||
import * as Haptics from "@/packages/expo-haptics";
|
||||
import { Image } from "expo-image";
|
||||
import { useLocalSearchParams, useRouter } from "expo-router";
|
||||
import { useAtom } from "jotai";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { View, TouchableOpacity } from "react-native";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
||||
import * as DropdownMenu from "@/components/DropdownMenu";
|
||||
import { useControlContext } from "../contexts/ControlContext";
|
||||
import { useVideoContext } from "../contexts/VideoContext";
|
||||
import { EmbeddedSubtitle, ExternalSubtitle } from "../types";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useCallback, useMemo, useState } from "react";
|
||||
import { View, TouchableOpacity } from "react-native";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
||||
import * as DropdownMenu from "@/components/DropdownMenu";
|
||||
import { useControlContext } from "../contexts/ControlContext";
|
||||
import { useVideoContext } from "../contexts/VideoContext";
|
||||
import { TranscodedSubtitle } from "../types";
|
||||
|
||||
@@ -5,7 +5,7 @@ import { apiAtom } from "@/providers/JellyfinProvider";
|
||||
import { getAuthHeaders } from "@/utils/jellyfin/jellyfin";
|
||||
import { writeToLog } from "@/utils/log";
|
||||
import { msToSeconds, secondsToMs } from "@/utils/time";
|
||||
import * as Haptics from "expo-haptics";
|
||||
import * as Haptics from "@/packages/expo-haptics";
|
||||
|
||||
interface CreditTimestamps {
|
||||
Introduction: {
|
||||
|
||||
@@ -10,7 +10,9 @@ import { storage } from "@/utils/mmkv";
|
||||
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client";
|
||||
import { useAtom, useAtomValue } from "jotai";
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { getColors } from "react-native-image-colors";
|
||||
import { Platform } from "react-native";
|
||||
// import { getColors } from "react-native-image-colors";
|
||||
const getColors = !Platform.isTV ? require("react-native-image-colors") : null;
|
||||
|
||||
/**
|
||||
* Custom hook to extract and manage image colors for a given item.
|
||||
@@ -28,6 +30,8 @@ export const useImageColors = ({
|
||||
url?: string | null;
|
||||
disabled?: boolean;
|
||||
}) => {
|
||||
if (Platform.isTV) return;
|
||||
|
||||
const api = useAtomValue(apiAtom);
|
||||
const [, setPrimaryColor] = useAtom(itemThemeColorAtom);
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { apiAtom } from "@/providers/JellyfinProvider";
|
||||
import { getAuthHeaders } from "@/utils/jellyfin/jellyfin";
|
||||
import { writeToLog } from "@/utils/log";
|
||||
import { msToSeconds, secondsToMs } from "@/utils/time";
|
||||
import * as Haptics from "expo-haptics";
|
||||
import * as Haptics from "@/packages/expo-haptics";
|
||||
|
||||
interface IntroTimestamps {
|
||||
EpisodeId: string;
|
||||
|
||||
@@ -3,7 +3,7 @@ import { markAsNotPlayed } from "@/utils/jellyfin/playstate/markAsNotPlayed";
|
||||
import { markAsPlayed } from "@/utils/jellyfin/playstate/markAsPlayed";
|
||||
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import * as Haptics from "expo-haptics";
|
||||
import * as Haptics from "@/packages/expo-haptics";
|
||||
import { useAtom } from "jotai";
|
||||
|
||||
export const useMarkAsPlayed = (item: BaseItemDto) => {
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import orientationToOrientationLock from "@/utils/OrientationLockConverter";
|
||||
import * as ScreenOrientation from "expo-screen-orientation";
|
||||
import * as ScreenOrientation from "@/packages/expo-screen-orientation";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Platform } from "react-native";
|
||||
|
||||
export const useOrientation = () => {
|
||||
const [orientation, setOrientation] = useState(
|
||||
ScreenOrientation.OrientationLock.UNKNOWN
|
||||
Platform.isTV
|
||||
? ScreenOrientation.OrientationLock.LANDSCAPE
|
||||
: ScreenOrientation.OrientationLock.UNKNOWN
|
||||
);
|
||||
|
||||
if (Platform.isTV) return { orientation, setOrientation };
|
||||
|
||||
useEffect(() => {
|
||||
const orientationSubscription =
|
||||
ScreenOrientation.addOrientationChangeListener((event) => {
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { useSettings } from "@/utils/atoms/settings";
|
||||
import * as ScreenOrientation from "expo-screen-orientation";
|
||||
import * as ScreenOrientation from "@/packages/expo-screen-orientation";
|
||||
import { useEffect } from "react";
|
||||
import { Platform } from "react-native";
|
||||
|
||||
export const useOrientationSettings = () => {
|
||||
if (Platform.isTV) return;
|
||||
|
||||
const [settings] = useSettings();
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -9,7 +9,8 @@ import {
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import * as FileSystem from "expo-file-system";
|
||||
import { useRouter } from "expo-router";
|
||||
import { FFmpegKit, FFmpegSession, Statistics } from "ffmpeg-kit-react-native";
|
||||
// import { FFmpegKit, FFmpegSession, Statistics } from "ffmpeg-kit-react-native";
|
||||
const FFmpegKit = !Platform.isTV ? require("ffmpeg-kit-react-native") : null;
|
||||
import { useAtomValue } from "jotai";
|
||||
import { useCallback } from "react";
|
||||
import { toast } from "sonner-native";
|
||||
@@ -18,6 +19,7 @@ import useDownloadHelper from "@/utils/download";
|
||||
import { Api } from "@jellyfin/sdk";
|
||||
import { useSettings } from "@/utils/atoms/settings";
|
||||
import { JobStatus } from "@/utils/optimize-server";
|
||||
import { Platform } from "react-native";
|
||||
|
||||
const createFFmpegCommand = (url: string, output: string) => [
|
||||
"-y", // overwrite output files without asking
|
||||
@@ -53,7 +55,12 @@ export const useRemuxHlsToMp4 = () => {
|
||||
const [settings] = useSettings();
|
||||
const { saveImage } = useImageStorage();
|
||||
const { saveSeriesPrimaryImage } = useDownloadHelper();
|
||||
const { saveDownloadedItemInfo, setProcesses, processes, APP_CACHE_DOWNLOAD_DIRECTORY } = useDownload();
|
||||
const {
|
||||
saveDownloadedItemInfo,
|
||||
setProcesses,
|
||||
processes,
|
||||
APP_CACHE_DOWNLOAD_DIRECTORY,
|
||||
} = useDownload();
|
||||
|
||||
const onSaveAssets = async (api: Api, item: BaseItemDto) => {
|
||||
await saveSeriesPrimaryImage(item);
|
||||
@@ -78,8 +85,8 @@ export const useRemuxHlsToMp4 = () => {
|
||||
const stat = await session.getLastReceivedStatistics();
|
||||
await FileSystem.moveAsync({
|
||||
from: `${APP_CACHE_DOWNLOAD_DIRECTORY}${item.Id}.mp4`,
|
||||
to: `${FileSystem.documentDirectory}${item.Id}.mp4`
|
||||
})
|
||||
to: `${FileSystem.documentDirectory}${item.Id}.mp4`,
|
||||
});
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["downloadedItems"],
|
||||
});
|
||||
@@ -131,12 +138,16 @@ export const useRemuxHlsToMp4 = () => {
|
||||
|
||||
const startRemuxing = useCallback(
|
||||
async (item: BaseItemDto, url: string, mediaSource: MediaSourceInfo) => {
|
||||
const cacheDir = await FileSystem.getInfoAsync(APP_CACHE_DOWNLOAD_DIRECTORY);
|
||||
const cacheDir = await FileSystem.getInfoAsync(
|
||||
APP_CACHE_DOWNLOAD_DIRECTORY
|
||||
);
|
||||
if (!cacheDir.exists) {
|
||||
await FileSystem.makeDirectoryAsync(APP_CACHE_DOWNLOAD_DIRECTORY, {intermediates: true})
|
||||
await FileSystem.makeDirectoryAsync(APP_CACHE_DOWNLOAD_DIRECTORY, {
|
||||
intermediates: true,
|
||||
});
|
||||
}
|
||||
|
||||
const output = APP_CACHE_DOWNLOAD_DIRECTORY + `${item.Id}.mp4`
|
||||
const output = APP_CACHE_DOWNLOAD_DIRECTORY + `${item.Id}.mp4`;
|
||||
|
||||
if (!api) throw new Error("API is not defined");
|
||||
if (!item.Id) throw new Error("Item must have an Id");
|
||||
|
||||
0
packages/expo-haptics.native.ts
Normal file
0
packages/expo-haptics.native.ts
Normal file
1
packages/expo-haptics.ts
Normal file
1
packages/expo-haptics.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * as Haptics from "expo-haptics";
|
||||
68
packages/expo-screen-orientation.native.ts
Normal file
68
packages/expo-screen-orientation.native.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
// export { Orientation, OrientationLock } from "expo-screen-orientation";
|
||||
|
||||
export enum Orientation {
|
||||
/**
|
||||
* An unknown screen orientation. For example, the device is flat, perhaps on a table.
|
||||
*/
|
||||
UNKNOWN = 0,
|
||||
/**
|
||||
* Right-side up portrait interface orientation.
|
||||
*/
|
||||
PORTRAIT_UP = 1,
|
||||
/**
|
||||
* Upside down portrait interface orientation.
|
||||
*/
|
||||
PORTRAIT_DOWN = 2,
|
||||
/**
|
||||
* Left landscape interface orientation.
|
||||
*/
|
||||
LANDSCAPE_LEFT = 3,
|
||||
/**
|
||||
* Right landscape interface orientation.
|
||||
*/
|
||||
LANDSCAPE_RIGHT = 4,
|
||||
}
|
||||
|
||||
export enum OrientationLock {
|
||||
/**
|
||||
* The default orientation. On iOS, this will allow all orientations except `Orientation.PORTRAIT_DOWN`.
|
||||
* On Android, this lets the system decide the best orientation.
|
||||
*/
|
||||
DEFAULT = 0,
|
||||
/**
|
||||
* All four possible orientations
|
||||
*/
|
||||
ALL = 1,
|
||||
/**
|
||||
* Any portrait orientation.
|
||||
*/
|
||||
PORTRAIT = 2,
|
||||
/**
|
||||
* Right-side up portrait only.
|
||||
*/
|
||||
PORTRAIT_UP = 3,
|
||||
/**
|
||||
* Upside down portrait only.
|
||||
*/
|
||||
PORTRAIT_DOWN = 4,
|
||||
/**
|
||||
* Any landscape orientation.
|
||||
*/
|
||||
LANDSCAPE = 5,
|
||||
/**
|
||||
* Left landscape only.
|
||||
*/
|
||||
LANDSCAPE_LEFT = 6,
|
||||
/**
|
||||
* Right landscape only.
|
||||
*/
|
||||
LANDSCAPE_RIGHT = 7,
|
||||
/**
|
||||
* A platform specific orientation. This is not a valid policy that can be applied in [`lockAsync`](#screenorientationlockasyncorientationlock).
|
||||
*/
|
||||
OTHER = 8,
|
||||
/**
|
||||
* An unknown screen orientation lock. This is not a valid policy that can be applied in [`lockAsync`](#screenorientationlockasyncorientationlock).
|
||||
*/
|
||||
UNKNOWN = 9,
|
||||
}
|
||||
1
packages/expo-screen-orientation.ts
Normal file
1
packages/expo-screen-orientation.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "expo-screen-orientation";
|
||||
@@ -13,12 +13,15 @@ import {
|
||||
BaseItemDto,
|
||||
MediaSourceInfo,
|
||||
} from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import {
|
||||
checkForExistingDownloads,
|
||||
completeHandler,
|
||||
download,
|
||||
setConfig,
|
||||
} from "@kesha-antonov/react-native-background-downloader";
|
||||
// import {
|
||||
// checkForExistingDownloads,
|
||||
// completeHandler,
|
||||
// download,
|
||||
// setConfig,
|
||||
// } from "@kesha-antonov/react-native-background-downloader";
|
||||
const BackGroundDownloader = !Platform.isTV
|
||||
? require("@kesha-antonov/react-native-background-downloader")
|
||||
: null;
|
||||
import MMKV from "react-native-mmkv";
|
||||
import {
|
||||
focusManager,
|
||||
@@ -42,13 +45,14 @@ import React, {
|
||||
import { AppState, AppStateStatus, Platform } from "react-native";
|
||||
import { toast } from "sonner-native";
|
||||
import { apiAtom } from "./JellyfinProvider";
|
||||
import * as Notifications from "expo-notifications";
|
||||
// import * as Notifications from "expo-notifications";
|
||||
const Notifications = !Platform.isTV ? require("expo-notifications") : null;
|
||||
import { getItemImage } from "@/utils/getItemImage";
|
||||
import useImageStorage from "@/hooks/useImageStorage";
|
||||
import { storage } from "@/utils/mmkv";
|
||||
import useDownloadHelper from "@/utils/download";
|
||||
import { FileInfo } from "expo-file-system";
|
||||
import * as Haptics from "expo-haptics";
|
||||
import * as Haptics from "@/packages/expo-haptics";
|
||||
import * as Application from "expo-application";
|
||||
|
||||
export type DownloadedItem = {
|
||||
@@ -67,6 +71,7 @@ const DownloadContext = createContext<ReturnType<
|
||||
> | null>(null);
|
||||
|
||||
function useDownloadProvider() {
|
||||
if (Platform.isTV) return;
|
||||
const queryClient = useQueryClient();
|
||||
const [settings] = useSettings();
|
||||
const router = useRouter();
|
||||
@@ -170,7 +175,7 @@ function useDownloadProvider() {
|
||||
useEffect(() => {
|
||||
const checkIfShouldStartDownload = async () => {
|
||||
if (processes.length === 0) return;
|
||||
await checkForExistingDownloads();
|
||||
await BackGroundDownloader.checkForExistingDownloads();
|
||||
};
|
||||
|
||||
checkIfShouldStartDownload();
|
||||
@@ -214,7 +219,7 @@ function useDownloadProvider() {
|
||||
)
|
||||
);
|
||||
|
||||
setConfig({
|
||||
BackGroundDownloader.setConfig({
|
||||
isLogsEnabled: true,
|
||||
progressInterval: 500,
|
||||
headers: {
|
||||
@@ -234,7 +239,7 @@ function useDownloadProvider() {
|
||||
|
||||
const baseDirectory = FileSystem.documentDirectory;
|
||||
|
||||
download({
|
||||
BackGroundDownloader.download({
|
||||
id: process.id,
|
||||
url: settings?.optimizedVersionsServerUrl + "download/" + process.id,
|
||||
destination: `${baseDirectory}/${process.item.Id}.mp4`,
|
||||
@@ -284,7 +289,7 @@ function useDownloadProvider() {
|
||||
},
|
||||
});
|
||||
setTimeout(() => {
|
||||
completeHandler(process.id);
|
||||
BackGroundDownloader.completeHandler(process.id);
|
||||
removeProcess(process.id);
|
||||
}, 1000);
|
||||
})
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { Orientation, OrientationLock } from "expo-screen-orientation";
|
||||
import {
|
||||
Orientation,
|
||||
OrientationLock,
|
||||
} from "@/packages/expo-screen-orientation";
|
||||
|
||||
function orientationToOrientationLock(
|
||||
orientation: Orientation
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as ScreenOrientation from "expo-screen-orientation";
|
||||
import * as ScreenOrientation from "@/packages/expo-screen-orientation";
|
||||
import { atom } from "jotai";
|
||||
|
||||
export const orientationAtom = atom<number>(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { atom, useAtom } from "jotai";
|
||||
import { useEffect } from "react";
|
||||
import * as ScreenOrientation from "expo-screen-orientation";
|
||||
import * as ScreenOrientation from "@/packages/expo-screen-orientation";
|
||||
import { storage } from "../mmkv";
|
||||
import { Platform } from "react-native";
|
||||
import {
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import * as BackgroundFetch from "expo-background-fetch";
|
||||
import { Platform } from "react-native";
|
||||
const BackgroundFetch = !Platform.isTV
|
||||
? require("expo-background-fetch")
|
||||
: null;
|
||||
|
||||
export const BACKGROUND_FETCH_TASK = "background-fetch";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user