mirror of
https://github.com/streamyfin/streamyfin.git
synced 2025-08-20 18:37:18 +02:00
wip
This commit is contained in:
@@ -168,6 +168,7 @@ function Layout() {
|
||||
color: "white",
|
||||
},
|
||||
}}
|
||||
closeButton
|
||||
/>
|
||||
</ThemeProvider>
|
||||
</PlaybackProvider>
|
||||
|
||||
@@ -150,10 +150,7 @@ export const DownloadItem: React.FC<DownloadProps> = ({ item, ...props }) => {
|
||||
|
||||
if (!url) throw new Error("No url");
|
||||
|
||||
if (
|
||||
settings?.optimizedVersionsServerUrl &&
|
||||
settings.optimizedVersionsServerUrl.length > 0
|
||||
) {
|
||||
if (settings?.downloadMethod === "optimized") {
|
||||
return await startBackgroundDownload(url, item);
|
||||
} else {
|
||||
return await startRemuxing(url);
|
||||
@@ -304,6 +301,13 @@ export const DownloadItem: React.FC<DownloadProps> = ({ item, ...props }) => {
|
||||
>
|
||||
Download
|
||||
</Button>
|
||||
<View className="opacity-70 text-center w-full flex items-center">
|
||||
{settings?.downloadMethod === "optimized" ? (
|
||||
<Text className="text-xs">Using optimized server</Text>
|
||||
) : (
|
||||
<Text className="text-xs">Using default method</Text>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</BottomSheetView>
|
||||
</BottomSheetModal>
|
||||
|
||||
@@ -22,7 +22,7 @@ export const ActiveDownload: React.FC<Props> = ({ ...props }) => {
|
||||
mutationFn: async () => {
|
||||
if (!process) throw new Error("No active download");
|
||||
|
||||
if (settings?.optimizedVersionsServerUrl) {
|
||||
if (settings?.downloadMethod === "optimized") {
|
||||
await axios.delete(
|
||||
settings?.optimizedVersionsServerUrl + "cancel-job/" + process.id,
|
||||
{
|
||||
@@ -45,6 +45,7 @@ export const ActiveDownload: React.FC<Props> = ({ ...props }) => {
|
||||
onError: (e) => {
|
||||
console.log(e);
|
||||
toast.error("Failed to cancel download");
|
||||
clearProcess();
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import { useState } from "react";
|
||||
import { Button } from "../Button";
|
||||
import { MediaToggles } from "./MediaToggles";
|
||||
import * as ScreenOrientation from "expo-screen-orientation";
|
||||
import { opacity } from "react-native-reanimated/lib/typescript/reanimated2/Colors";
|
||||
|
||||
interface Props extends ViewProps {}
|
||||
|
||||
@@ -458,112 +459,177 @@ export const SettingToggles: React.FC<Props> = ({ ...props }) => {
|
||||
</View>
|
||||
|
||||
<View className="mt-4">
|
||||
<Text className="text-lg font-bold mb-2">Optimized versions</Text>
|
||||
<Text className="text-lg font-bold mb-2">Downloads</Text>
|
||||
<View className="flex flex-col rounded-xl overflow-hidden divide-y-2 divide-solid divide-neutral-800">
|
||||
<View className="flex flex-col bg-neutral-900 px-4 py-4">
|
||||
<View className="flex flex-col shrink mb-2">
|
||||
<Text className="font-semibold">Optimized versions server</Text>
|
||||
<View
|
||||
className={`
|
||||
flex flex-row items-center space-x-2 justify-between bg-neutral-900 p-4
|
||||
`}
|
||||
>
|
||||
<View className="flex flex-col shrink">
|
||||
<Text className="font-semibold">Download method</Text>
|
||||
<Text className="text-xs opacity-50">
|
||||
Set the URL for the optimized versions server for downloads.
|
||||
Choose the download method to use. Optimized requires the
|
||||
optimized server.
|
||||
</Text>
|
||||
</View>
|
||||
<View className="flex flex-col">
|
||||
<Input
|
||||
placeholder="Optimized versions server URL..."
|
||||
defaultValue={
|
||||
settings.optimizedVersionsServerUrl
|
||||
? settings.optimizedVersionsServerUrl
|
||||
: ""
|
||||
}
|
||||
value={optimizedVersionsServerUrl}
|
||||
keyboardType="url"
|
||||
returnKeyType="done"
|
||||
autoCapitalize="none"
|
||||
textContentType="URL"
|
||||
onChangeText={(text) => setOptimizedVersionsServerUrl(text)}
|
||||
/>
|
||||
<Button
|
||||
color="purple"
|
||||
className="h-12 mt-2"
|
||||
onPress={() => {
|
||||
updateSettings({
|
||||
optimizedVersionsServerUrl:
|
||||
optimizedVersionsServerUrl.length === 0
|
||||
? null
|
||||
: optimizedVersionsServerUrl.endsWith("/")
|
||||
? optimizedVersionsServerUrl
|
||||
: optimizedVersionsServerUrl + "/",
|
||||
});
|
||||
}}
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
<TouchableOpacity className="bg-neutral-800 rounded-lg border-neutral-900 border px-3 py-2 flex flex-row items-center justify-between">
|
||||
<Text>
|
||||
{settings.downloadMethod === "remux"
|
||||
? "Default"
|
||||
: "Optimized"}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content
|
||||
loop={true}
|
||||
side="bottom"
|
||||
align="start"
|
||||
alignOffset={0}
|
||||
avoidCollisions={true}
|
||||
collisionPadding={8}
|
||||
sideOffset={8}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</View>
|
||||
|
||||
{settings.optimizedVersionsServerUrl && (
|
||||
<View className="p-4 bg-neutral-800 rounded-xl mt-2">
|
||||
<Text selectable>{settings.optimizedVersionsServerUrl}</Text>
|
||||
</View>
|
||||
)}
|
||||
<DropdownMenu.Label>Methods</DropdownMenu.Label>
|
||||
<DropdownMenu.Item
|
||||
key="1"
|
||||
onSelect={() => {
|
||||
updateSettings({ downloadMethod: "remux" });
|
||||
queryClient.invalidateQueries({ queryKey: ["search"] });
|
||||
}}
|
||||
>
|
||||
<DropdownMenu.ItemTitle>Default</DropdownMenu.ItemTitle>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
key="2"
|
||||
onSelect={() => {
|
||||
updateSettings({ downloadMethod: "optimized" });
|
||||
queryClient.invalidateQueries({ queryKey: ["search"] });
|
||||
}}
|
||||
>
|
||||
<DropdownMenu.ItemTitle>Optimized</DropdownMenu.ItemTitle>
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
</View>
|
||||
|
||||
<View className="flex flex-col bg-neutral-900 px-4 py-4 w-full grow-0">
|
||||
<View className="flex flex-col shrink mb-2">
|
||||
<Text className="font-semibold">
|
||||
Optimized versions auth header
|
||||
</Text>
|
||||
<Text className="text-xs opacity-50">
|
||||
The auth header for the optimized versions server.
|
||||
</Text>
|
||||
</View>
|
||||
<View className="flex flex-col w-full">
|
||||
<Input
|
||||
placeholder="Optimized versions server URL..."
|
||||
defaultValue={
|
||||
settings.optimizedVersionsAuthHeader
|
||||
? settings.optimizedVersionsAuthHeader
|
||||
: ""
|
||||
}
|
||||
value={optimizedVersionsAuthHeader}
|
||||
keyboardType="url"
|
||||
returnKeyType="done"
|
||||
autoCapitalize="none"
|
||||
textContentType="URL"
|
||||
onChangeText={(text) => setOptimizedVersionsAuthHeader(text)}
|
||||
className="w-full"
|
||||
/>
|
||||
<Button
|
||||
color="purple"
|
||||
className=" h-12 w-full mt-2"
|
||||
onPress={() => {
|
||||
updateSettings({
|
||||
optimizedVersionsAuthHeader,
|
||||
});
|
||||
}}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</View>
|
||||
|
||||
{settings.optimizedVersionsAuthHeader && (
|
||||
<View className="p-4 bg-neutral-800 rounded-xl mt-2">
|
||||
<Text className="" selectable>
|
||||
{settings.optimizedVersionsAuthHeader}
|
||||
<View
|
||||
pointerEvents={
|
||||
settings.downloadMethod === "optimized" ? "auto" : "none"
|
||||
}
|
||||
className={`
|
||||
${
|
||||
settings.downloadMethod === "optimized"
|
||||
? "opacity-100"
|
||||
: "opacity-50"
|
||||
}`}
|
||||
>
|
||||
<View className="flex flex-col bg-neutral-900 px-4 py-4">
|
||||
<View className="flex flex-col shrink mb-2">
|
||||
<Text className="font-semibold">Optimized versions server</Text>
|
||||
<Text className="text-xs opacity-50">
|
||||
Set the URL for the optimized versions server for downloads.
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
<Button
|
||||
color="red"
|
||||
className="mt-2"
|
||||
onPress={() => {
|
||||
updateSettings({
|
||||
optimizedVersionsAuthHeader: null,
|
||||
optimizedVersionsServerUrl: null,
|
||||
});
|
||||
}}
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
<View className="flex flex-col">
|
||||
<Input
|
||||
placeholder="Optimized versions server URL..."
|
||||
defaultValue={
|
||||
settings.optimizedVersionsServerUrl
|
||||
? settings.optimizedVersionsServerUrl
|
||||
: ""
|
||||
}
|
||||
value={optimizedVersionsServerUrl}
|
||||
keyboardType="url"
|
||||
returnKeyType="done"
|
||||
autoCapitalize="none"
|
||||
textContentType="URL"
|
||||
onChangeText={(text) => setOptimizedVersionsServerUrl(text)}
|
||||
/>
|
||||
<Button
|
||||
color="purple"
|
||||
className="h-12 mt-2"
|
||||
onPress={() => {
|
||||
updateSettings({
|
||||
optimizedVersionsServerUrl:
|
||||
optimizedVersionsServerUrl.length === 0
|
||||
? null
|
||||
: optimizedVersionsServerUrl.endsWith("/")
|
||||
? optimizedVersionsServerUrl
|
||||
: optimizedVersionsServerUrl + "/",
|
||||
});
|
||||
}}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</View>
|
||||
|
||||
{settings.optimizedVersionsServerUrl && (
|
||||
<View className="p-4 bg-neutral-800 rounded-xl mt-2">
|
||||
<Text selectable>{settings.optimizedVersionsServerUrl}</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
<View className="flex flex-col bg-neutral-900 px-4 py-4 w-full grow-0">
|
||||
<View className="flex flex-col shrink mb-2">
|
||||
<Text className="font-semibold">
|
||||
Optimized versions auth header
|
||||
</Text>
|
||||
<Text className="text-xs opacity-50">
|
||||
The auth header for the optimized versions server.
|
||||
</Text>
|
||||
</View>
|
||||
<View className="flex flex-col w-full">
|
||||
<Input
|
||||
placeholder="Optimized versions auth header..."
|
||||
defaultValue={
|
||||
settings.optimizedVersionsAuthHeader
|
||||
? settings.optimizedVersionsAuthHeader
|
||||
: ""
|
||||
}
|
||||
value={optimizedVersionsAuthHeader}
|
||||
keyboardType="url"
|
||||
returnKeyType="done"
|
||||
autoCapitalize="none"
|
||||
textContentType="URL"
|
||||
onChangeText={(text) => setOptimizedVersionsAuthHeader(text)}
|
||||
className="w-full"
|
||||
/>
|
||||
<Button
|
||||
color="purple"
|
||||
className=" h-12 w-full mt-2"
|
||||
onPress={() => {
|
||||
updateSettings({
|
||||
optimizedVersionsAuthHeader,
|
||||
});
|
||||
}}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</View>
|
||||
|
||||
{settings.optimizedVersionsAuthHeader && (
|
||||
<View className="p-4 bg-neutral-800 rounded-xl mt-2">
|
||||
<Text className="" selectable>
|
||||
{settings.optimizedVersionsAuthHeader}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
<Button
|
||||
color="red"
|
||||
className="mt-2"
|
||||
onPress={() => {
|
||||
updateSettings({
|
||||
optimizedVersionsAuthHeader: null,
|
||||
optimizedVersionsServerUrl: null,
|
||||
});
|
||||
}}
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -8,6 +8,7 @@ import { writeToLog } from "@/utils/log";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { toast } from "sonner-native";
|
||||
import { useDownload } from "@/providers/DownloadProvider";
|
||||
import { useRouter } from "expo-router";
|
||||
|
||||
/**
|
||||
* Custom hook for remuxing HLS to MP4 using FFmpeg.
|
||||
@@ -20,6 +21,7 @@ export const useRemuxHlsToMp4 = (item: BaseItemDto) => {
|
||||
const queryClient = useQueryClient();
|
||||
const { process, updateProcess, clearProcess, saveDownloadedItemInfo } =
|
||||
useDownload();
|
||||
const router = useRouter();
|
||||
|
||||
if (!item.Id || !item.Name) {
|
||||
writeToLog("ERROR", "useRemuxHlsToMp4 ~ missing arguments");
|
||||
@@ -32,7 +34,15 @@ export const useRemuxHlsToMp4 = (item: BaseItemDto) => {
|
||||
async (url: string) => {
|
||||
if (!item.Id) throw new Error("Item must have an Id");
|
||||
|
||||
toast.success("Download started");
|
||||
toast.success(`Download started for ${item.Name}`, {
|
||||
action: {
|
||||
label: "Go to download",
|
||||
onClick: () => {
|
||||
router.push("/downloads");
|
||||
toast.dismiss();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const command = `-y -loglevel quiet -thread_queue_size 512 -protocol_whitelist file,http,https,tcp,tls,crypto -multiple_requests 1 -tcp_nodelay 1 -fflags +genpts -i ${url} -c copy -bufsize 50M -max_muxing_queue_size 4096 ${output}`;
|
||||
|
||||
|
||||
@@ -264,6 +264,7 @@ function useDownloadProvider() {
|
||||
label: "Go to download",
|
||||
onClick: () => {
|
||||
router.push("/downloads");
|
||||
toast.dismiss();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -74,6 +74,7 @@ type Settings = {
|
||||
rewindSkipTime: number;
|
||||
optimizedVersionsServerUrl?: string | null;
|
||||
optimizedVersionsAuthHeader?: string | null;
|
||||
downloadMethod?: "optimized" | "remux";
|
||||
};
|
||||
/**
|
||||
*
|
||||
@@ -108,6 +109,9 @@ const loadSettings = async (): Promise<Settings> => {
|
||||
defaultVideoOrientation: ScreenOrientation.OrientationLock.DEFAULT,
|
||||
forwardSkipTime: 30,
|
||||
rewindSkipTime: 10,
|
||||
optimizedVersionsServerUrl: null,
|
||||
optimizedVersionsAuthHeader: null,
|
||||
downloadMethod: "remux",
|
||||
};
|
||||
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user