diff --git a/app.json b/app.json index e5eecdf8..f993a9db 100644 --- a/app.json +++ b/app.json @@ -41,7 +41,6 @@ "expo-router", "expo-font", "react-native-compressor", - "@config-plugins/ffmpeg-kit-react-native", [ "react-native-video", { @@ -54,17 +53,6 @@ } } ], - [ - "react-native-vlc-media-player", - { - "ios": { - "includeVLCKit": false - }, - "android": { - "legacyJetifier": false - } - } - ], [ "expo-build-properties", { diff --git a/app/(auth)/downloads.tsx b/app/(auth)/downloads.tsx index 115f14d1..becb26e6 100644 --- a/app/(auth)/downloads.tsx +++ b/app/(auth)/downloads.tsx @@ -15,7 +15,6 @@ import { useAtom } from "jotai"; import { runningProcesses } from "@/utils/atoms/downloads"; import { router } from "expo-router"; import { Ionicons } from "@expo/vector-icons"; -import { FFmpegKit } from "ffmpeg-kit-react-native"; const downloads: React.FC = () => { const { data: downloadedFiles, isLoading } = useQuery({ @@ -89,7 +88,6 @@ const downloads: React.FC = () => { { - FFmpegKit.cancel(); setProcess(null); }} > diff --git a/components/DownloadItem.tsx b/components/DownloadItem.tsx index fbf04d59..15a8a7ac 100644 --- a/components/DownloadItem.tsx +++ b/components/DownloadItem.tsx @@ -11,7 +11,6 @@ import { ActivityIndicator, TouchableOpacity, View } from "react-native"; import ProgressCircle from "./ProgressCircle"; import { Text } from "./common/Text"; import { useDownloadMedia } from "@/hooks/useDownloadMedia"; -import { useRemuxHlsToMp4 } from "@/hooks/useRemuxHlsToMp4"; import { getPlaybackInfo } from "@/utils/jellyfin/media/getPlaybackInfo"; type DownloadProps = { @@ -30,8 +29,6 @@ export const DownloadItem: React.FC = ({ const { downloadMedia, isDownloading, error, cancelDownload } = useDownloadMedia(api, user?.Id); - const { startRemuxing, cancelRemuxing } = useRemuxHlsToMp4(playbackURL, item); - const { data: playbackInfo, isLoading } = useQuery({ queryKey: ["playbackInfo", item.Id], queryFn: async () => getPlaybackInfo(api, item.Id, user?.Id), @@ -88,7 +85,7 @@ export const DownloadItem: React.FC = ({ {process ? ( { - cancelRemuxing(); + // cancelRemuxing(); }} className="flex flex-row items-center" > @@ -133,7 +130,7 @@ export const DownloadItem: React.FC = ({ { // downloadFile(); - startRemuxing(); + // startRemuxing(); }} > diff --git a/hooks/useRemuxHlsToMp4.ts b/hooks/useRemuxHlsToMp4.ts deleted file mode 100644 index 1ddd31ed..00000000 --- a/hooks/useRemuxHlsToMp4.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { useCallback } from "react"; -import { useAtom } from "jotai"; -import AsyncStorage from "@react-native-async-storage/async-storage"; -import * as FileSystem from "expo-file-system"; -import { FFmpegKit, FFmpegKitConfig } from "ffmpeg-kit-react-native"; -import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models"; -import { runningProcesses } from "@/utils/atoms/downloads"; -import { writeToLog } from "@/utils/log"; - -/** - * Custom hook for remuxing HLS to MP4 using FFmpeg. - * - * @param url - The URL of the HLS stream - * @param item - The BaseItemDto object representing the media item - * @returns An object with remuxing-related functions - */ -export const useRemuxHlsToMp4 = (url: string, item: BaseItemDto) => { - const [_, setProgress] = useAtom(runningProcesses); - - if (!item.Id || !item.Name) { - writeToLog("ERROR", "useRemuxHlsToMp4 ~ missing arguments"); - throw new Error("Item must have an Id and Name"); - } - - const output = `${FileSystem.documentDirectory}${item.Id}.mp4`; - const command = `-y -fflags +genpts -i ${url} -c copy -bufsize 10M -max_muxing_queue_size 4096 ${output}`; - - const startRemuxing = useCallback(async () => { - writeToLog( - "INFO", - `useRemuxHlsToMp4 ~ startRemuxing for item ${item.Name}`, - ); - - try { - setProgress({ item, progress: 0, startTime: new Date(), speed: 0 }); - - FFmpegKitConfig.enableStatisticsCallback((statistics) => { - const videoLength = - (item.MediaSources?.[0]?.RunTimeTicks || 0) / 10000000; // In seconds - const fps = item.MediaStreams?.[0]?.RealFrameRate || 25; - const totalFrames = videoLength * fps; - const processedFrames = statistics.getVideoFrameNumber(); - const speed = statistics.getSpeed(); - - const percentage = - totalFrames > 0 - ? Math.floor((processedFrames / totalFrames) * 100) - : 0; - - setProgress((prev) => - prev?.item.Id === item.Id! - ? { ...prev, progress: percentage, speed } - : prev, - ); - }); - - await FFmpegKit.executeAsync(command, async (session) => { - const returnCode = await session.getReturnCode(); - - if (returnCode.isValueSuccess()) { - await updateDownloadedFiles(item); - writeToLog( - "INFO", - `useRemuxHlsToMp4 ~ remuxing completed successfully for item: ${item.Name}`, - ); - } else if (returnCode.isValueError()) { - writeToLog( - "ERROR", - `useRemuxHlsToMp4 ~ remuxing failed for item: ${item.Name}`, - ); - } else if (returnCode.isValueCancel()) { - writeToLog( - "INFO", - `useRemuxHlsToMp4 ~ remuxing was canceled for item: ${item.Name}`, - ); - } - - setProgress(null); - }); - } catch (error) { - console.error("Failed to remux:", error); - writeToLog( - "ERROR", - `useRemuxHlsToMp4 ~ remuxing failed for item: ${item.Name}`, - ); - setProgress(null); - } - }, [output, item, command, setProgress]); - - const cancelRemuxing = useCallback(() => { - FFmpegKit.cancel(); - setProgress(null); - writeToLog( - "INFO", - `useRemuxHlsToMp4 ~ remuxing cancelled for item: ${item.Name}`, - ); - }, [item.Name, setProgress]); - - return { startRemuxing, cancelRemuxing }; -}; - -/** - * Updates the list of downloaded files in AsyncStorage. - * - * @param item - The item to add to the downloaded files list - */ -async function updateDownloadedFiles(item: BaseItemDto): Promise { - try { - const currentFiles: BaseItemDto[] = JSON.parse( - (await AsyncStorage.getItem("downloaded_files")) || "[]", - ); - const updatedFiles = [ - ...currentFiles.filter((i) => i.Id !== item.Id), - item, - ]; - await AsyncStorage.setItem( - "downloaded_files", - JSON.stringify(updatedFiles), - ); - } catch (error) { - console.error("Error updating downloaded files:", error); - writeToLog( - "ERROR", - `Failed to update downloaded files for item: ${item.Name}`, - ); - } -} diff --git a/package.json b/package.json index f2c67e95..dbb0b4f7 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,6 @@ "preset": "jest-expo" }, "dependencies": { - "@config-plugins/ffmpeg-kit-react-native": "^8.0.0", "@expo/vector-icons": "^14.0.2", "@jellyfin/sdk": "^0.10.0", "@kesha-antonov/react-native-background-downloader": "^3.2.0", @@ -40,7 +39,6 @@ "expo-status-bar": "~1.12.1", "expo-system-ui": "~3.0.7", "expo-web-browser": "~13.0.3", - "ffmpeg-kit-react-native": "^6.0.2", "jotai": "^2.9.1", "nativewind": "^2.0.11", "react": "18.2.0", @@ -59,7 +57,6 @@ "react-native-url-polyfill": "^2.0.0", "react-native-uuid": "^2.0.2", "react-native-video": "^6.4.3", - "react-native-vlc-media-player": "^1.0.67", "react-native-web": "~0.19.10", "tailwindcss": "3.3.2", "uuid": "^10.0.0",