mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-01-15 23:59:08 +00:00
Compare commits
2 Commits
remove-opt
...
refactor/d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad751fd2c8 | ||
|
|
42e66b39cc |
@@ -13,7 +13,7 @@ import { orientationAtom } from "@/utils/atoms/orientation";
|
|||||||
import { Settings, useSettings } from "@/utils/atoms/settings";
|
import { Settings, useSettings } from "@/utils/atoms/settings";
|
||||||
import { BACKGROUND_FETCH_TASK } from "@/utils/background-tasks";
|
import { BACKGROUND_FETCH_TASK } from "@/utils/background-tasks";
|
||||||
import { LogProvider, writeToLog } from "@/utils/log";
|
import { LogProvider, writeToLog } from "@/utils/log";
|
||||||
import { storage } from "@/utils/mmkv";
|
import { formatItemName, storage } from "@/utils/mmkv";
|
||||||
import { cancelJobById, getAllJobsByDeviceId } from "@/utils/optimize-server";
|
import { cancelJobById, getAllJobsByDeviceId } from "@/utils/optimize-server";
|
||||||
import { ActionSheetProvider } from "@expo/react-native-action-sheet";
|
import { ActionSheetProvider } from "@expo/react-native-action-sheet";
|
||||||
import { BottomSheetModalProvider } from "@gorhom/bottom-sheet";
|
import { BottomSheetModalProvider } from "@gorhom/bottom-sheet";
|
||||||
@@ -385,18 +385,15 @@ function Layout() {
|
|||||||
function saveDownloadedItemInfo(item: BaseItemDto) {
|
function saveDownloadedItemInfo(item: BaseItemDto) {
|
||||||
try {
|
try {
|
||||||
const downloadedItems = storage.getString("downloadedItems");
|
const downloadedItems = storage.getString("downloadedItems");
|
||||||
let items: BaseItemDto[] = downloadedItems
|
let items: { [key: string]: BaseItemDto } = downloadedItems
|
||||||
? JSON.parse(downloadedItems)
|
? JSON.parse(downloadedItems)
|
||||||
: [];
|
: {};
|
||||||
|
|
||||||
const existingItemIndex = items.findIndex((i) => i.Id === item.Id);
|
if (item.Id) {
|
||||||
if (existingItemIndex !== -1) {
|
item.Path = `${FileSystem.documentDirectory}${formatItemName(item)}.mp4`;
|
||||||
items[existingItemIndex] = item;
|
items[item.Id] = item;
|
||||||
} else {
|
storage.set("downloadedItems", JSON.stringify(items));
|
||||||
items.push(item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
storage.set("downloadedItems", JSON.stringify(items));
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
writeToLog("ERROR", "Failed to save downloaded item information:", error);
|
writeToLog("ERROR", "Failed to save downloaded item information:", error);
|
||||||
console.error("Failed to save downloaded item information:", error);
|
console.error("Failed to save downloaded item information:", error);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { usePlaySettings } from "@/providers/PlaySettingsProvider";
|
import { usePlaySettings } from "@/providers/PlaySettingsProvider";
|
||||||
import { writeToLog } from "@/utils/log";
|
import { writeToLog } from "@/utils/log";
|
||||||
|
import { getFilePathFromItemId } from "@/utils/mmkv";
|
||||||
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client";
|
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client";
|
||||||
import * as FileSystem from "expo-file-system";
|
import * as FileSystem from "expo-file-system";
|
||||||
import { useRouter } from "expo-router";
|
import { useRouter } from "expo-router";
|
||||||
@@ -17,13 +18,13 @@ export const getDownloadedFileUrl = async (itemId: string): Promise<string> => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const files = await FileSystem.readDirectoryAsync(directory);
|
const files = await FileSystem.readDirectoryAsync(directory);
|
||||||
const path = itemId!;
|
const filePath = getFilePathFromItemId(itemId);
|
||||||
const matchingFile = files.find((file) => file.startsWith(path));
|
|
||||||
|
const matchingFile = files.find((file) => file === filePath);
|
||||||
|
|
||||||
if (!matchingFile) {
|
if (!matchingFile) {
|
||||||
throw new Error(`No file found for item ${path}`);
|
throw new Error(`No file found for item ${filePath}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return `${directory}${matchingFile}`;
|
return `${directory}${matchingFile}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import useDownloadHelper from "@/utils/download";
|
|||||||
import { Api } from "@jellyfin/sdk";
|
import { Api } from "@jellyfin/sdk";
|
||||||
import { useSettings } from "@/utils/atoms/settings";
|
import { useSettings } from "@/utils/atoms/settings";
|
||||||
import { JobStatus } from "@/utils/optimize-server";
|
import { JobStatus } from "@/utils/optimize-server";
|
||||||
|
import { formatItemName } from "@/utils/mmkv";
|
||||||
|
|
||||||
const createFFmpegCommand = (url: string, output: string) => [
|
const createFFmpegCommand = (url: string, output: string) => [
|
||||||
"-y", // overwrite output files without asking
|
"-y", // overwrite output files without asking
|
||||||
@@ -53,7 +54,12 @@ export const useRemuxHlsToMp4 = () => {
|
|||||||
const [settings] = useSettings();
|
const [settings] = useSettings();
|
||||||
const { saveImage } = useImageStorage();
|
const { saveImage } = useImageStorage();
|
||||||
const { saveSeriesPrimaryImage } = useDownloadHelper();
|
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) => {
|
const onSaveAssets = async (api: Api, item: BaseItemDto) => {
|
||||||
await saveSeriesPrimaryImage(item);
|
await saveSeriesPrimaryImage(item);
|
||||||
@@ -73,13 +79,12 @@ export const useRemuxHlsToMp4 = () => {
|
|||||||
try {
|
try {
|
||||||
console.log("completeCallback");
|
console.log("completeCallback");
|
||||||
const returnCode = await session.getReturnCode();
|
const returnCode = await session.getReturnCode();
|
||||||
|
|
||||||
if (returnCode.isValueSuccess()) {
|
if (returnCode.isValueSuccess()) {
|
||||||
const stat = await session.getLastReceivedStatistics();
|
const stat = await session.getLastReceivedStatistics();
|
||||||
await FileSystem.moveAsync({
|
await FileSystem.moveAsync({
|
||||||
from: `${APP_CACHE_DOWNLOAD_DIRECTORY}${item.Id}.mp4`,
|
from: `${APP_CACHE_DOWNLOAD_DIRECTORY}${item.Id}.mp4`,
|
||||||
to: `${FileSystem.documentDirectory}${item.Id}.mp4`
|
to: `${FileSystem.documentDirectory}${formatItemName(item)}.mp4`,
|
||||||
})
|
});
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: ["downloadedItems"],
|
queryKey: ["downloadedItems"],
|
||||||
});
|
});
|
||||||
@@ -131,12 +136,16 @@ export const useRemuxHlsToMp4 = () => {
|
|||||||
|
|
||||||
const startRemuxing = useCallback(
|
const startRemuxing = useCallback(
|
||||||
async (item: BaseItemDto, url: string, mediaSource: MediaSourceInfo) => {
|
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) {
|
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 (!api) throw new Error("API is not defined");
|
||||||
if (!item.Id) throw new Error("Item must have an Id");
|
if (!item.Id) throw new Error("Item must have an Id");
|
||||||
|
|||||||
@@ -19,14 +19,7 @@ import {
|
|||||||
download,
|
download,
|
||||||
setConfig,
|
setConfig,
|
||||||
} from "@kesha-antonov/react-native-background-downloader";
|
} from "@kesha-antonov/react-native-background-downloader";
|
||||||
import MMKV from "react-native-mmkv";
|
import { focusManager, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import {
|
|
||||||
focusManager,
|
|
||||||
QueryClient,
|
|
||||||
QueryClientProvider,
|
|
||||||
useQuery,
|
|
||||||
useQueryClient,
|
|
||||||
} from "@tanstack/react-query";
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import * as FileSystem from "expo-file-system";
|
import * as FileSystem from "expo-file-system";
|
||||||
import { useRouter } from "expo-router";
|
import { useRouter } from "expo-router";
|
||||||
@@ -45,7 +38,7 @@ import { apiAtom } from "./JellyfinProvider";
|
|||||||
import * as Notifications from "expo-notifications";
|
import * as Notifications from "expo-notifications";
|
||||||
import { getItemImage } from "@/utils/getItemImage";
|
import { getItemImage } from "@/utils/getItemImage";
|
||||||
import useImageStorage from "@/hooks/useImageStorage";
|
import useImageStorage from "@/hooks/useImageStorage";
|
||||||
import { storage } from "@/utils/mmkv";
|
import { formatItemName, saveItemMapping, storage } from "@/utils/mmkv";
|
||||||
import useDownloadHelper from "@/utils/download";
|
import useDownloadHelper from "@/utils/download";
|
||||||
import { FileInfo } from "expo-file-system";
|
import { FileInfo } from "expo-file-system";
|
||||||
import * as Haptics from "expo-haptics";
|
import * as Haptics from "expo-haptics";
|
||||||
@@ -54,8 +47,11 @@ import * as Application from "expo-application";
|
|||||||
export type DownloadedItem = {
|
export type DownloadedItem = {
|
||||||
item: Partial<BaseItemDto>;
|
item: Partial<BaseItemDto>;
|
||||||
mediaSource: MediaSourceInfo;
|
mediaSource: MediaSourceInfo;
|
||||||
|
fileSize: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type DownloadedItem2 = {};
|
||||||
|
|
||||||
export const processesAtom = atom<JobStatus[]>([]);
|
export const processesAtom = atom<JobStatus[]>([]);
|
||||||
|
|
||||||
function onAppStateChange(status: AppStateStatus) {
|
function onAppStateChange(status: AppStateStatus) {
|
||||||
@@ -512,8 +508,10 @@ function useDownloadProvider() {
|
|||||||
|
|
||||||
const downloadedItems = storage.getString("downloadedItems");
|
const downloadedItems = storage.getString("downloadedItems");
|
||||||
if (downloadedItems) {
|
if (downloadedItems) {
|
||||||
let items = JSON.parse(downloadedItems) as DownloadedItem[];
|
let items: { [key: string]: BaseItemDto } = downloadedItems
|
||||||
items = items.filter((item) => item.item.Id !== id);
|
? JSON.parse(downloadedItems)
|
||||||
|
: {};
|
||||||
|
delete items[id];
|
||||||
storage.set("downloadedItems", JSON.stringify(items));
|
storage.set("downloadedItems", JSON.stringify(items));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -586,7 +584,7 @@ function useDownloadProvider() {
|
|||||||
const appSizeUsage = useMemo(async () => {
|
const appSizeUsage = useMemo(async () => {
|
||||||
const sizes: number[] =
|
const sizes: number[] =
|
||||||
downloadedFiles?.map((d) => {
|
downloadedFiles?.map((d) => {
|
||||||
return getDownloadedItemSize(d.item.Id!!);
|
return d.fileSize;
|
||||||
}) || [];
|
}) || [];
|
||||||
|
|
||||||
await forEveryDocumentDirFile(
|
await forEveryDocumentDirFile(
|
||||||
@@ -608,8 +606,10 @@ function useDownloadProvider() {
|
|||||||
try {
|
try {
|
||||||
const downloadedItems = storage.getString("downloadedItems");
|
const downloadedItems = storage.getString("downloadedItems");
|
||||||
if (downloadedItems) {
|
if (downloadedItems) {
|
||||||
const items: DownloadedItem[] = JSON.parse(downloadedItems);
|
const items: { [key: string]: BaseItemDto } = downloadedItems
|
||||||
const item = items.find((i) => i.item.Id === itemId);
|
? JSON.parse(downloadedItems)
|
||||||
|
: {};
|
||||||
|
const item = items[itemId] as DownloadedItem;
|
||||||
return item || null;
|
return item || null;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -623,7 +623,7 @@ function useDownloadProvider() {
|
|||||||
try {
|
try {
|
||||||
const downloadedItems = storage.getString("downloadedItems");
|
const downloadedItems = storage.getString("downloadedItems");
|
||||||
if (downloadedItems) {
|
if (downloadedItems) {
|
||||||
return JSON.parse(downloadedItems) as DownloadedItem[];
|
return Object.values(JSON.parse(downloadedItems)) as DownloadedItem[];
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -636,11 +636,11 @@ function useDownloadProvider() {
|
|||||||
function saveDownloadedItemInfo(item: BaseItemDto, size: number = 0) {
|
function saveDownloadedItemInfo(item: BaseItemDto, size: number = 0) {
|
||||||
try {
|
try {
|
||||||
const downloadedItems = storage.getString("downloadedItems");
|
const downloadedItems = storage.getString("downloadedItems");
|
||||||
let items: DownloadedItem[] = downloadedItems
|
const items: { [key: string]: BaseItemDto } = downloadedItems
|
||||||
? JSON.parse(downloadedItems)
|
? JSON.parse(downloadedItems)
|
||||||
: [];
|
: {};
|
||||||
|
|
||||||
const existingItemIndex = items.findIndex((i) => i.item.Id === item.Id);
|
const chosenItem = items[item.Id!] || {};
|
||||||
|
|
||||||
const data = getDownloadItemInfoFromDiskTmp(item.Id!);
|
const data = getDownloadItemInfoFromDiskTmp(item.Id!);
|
||||||
|
|
||||||
@@ -651,12 +651,6 @@ function useDownloadProvider() {
|
|||||||
|
|
||||||
const newItem = { item, mediaSource: data.mediaSource };
|
const newItem = { item, mediaSource: data.mediaSource };
|
||||||
|
|
||||||
if (existingItemIndex !== -1) {
|
|
||||||
items[existingItemIndex] = newItem;
|
|
||||||
} else {
|
|
||||||
items.push(newItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteDownloadItemInfoFromDiskTmp(item.Id!);
|
deleteDownloadItemInfoFromDiskTmp(item.Id!);
|
||||||
|
|
||||||
storage.set("downloadedItems", JSON.stringify(items));
|
storage.set("downloadedItems", JSON.stringify(items));
|
||||||
|
|||||||
@@ -1,3 +1,30 @@
|
|||||||
|
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client";
|
||||||
import { MMKV } from "react-native-mmkv";
|
import { MMKV } from "react-native-mmkv";
|
||||||
|
|
||||||
export const storage = new MMKV();
|
const storage = new MMKV();
|
||||||
|
|
||||||
|
const saveItemMapping = (itemId: string | undefined, fileName: string) => {
|
||||||
|
if (!itemId) return;
|
||||||
|
storage.set(itemId, fileName);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getFilePathFromItemId = (itemId: string): string | undefined => {
|
||||||
|
return storage.getString(itemId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatItemName = (item: BaseItemDto) => {
|
||||||
|
if (item.Type === "Episode") {
|
||||||
|
const formattedParentIndexNumber = (item.ParentIndexNumber ?? 0)
|
||||||
|
.toString()
|
||||||
|
.padStart(2, "0");
|
||||||
|
const formattedIndexNumber = (item.IndexNumber ?? 0)
|
||||||
|
.toString()
|
||||||
|
.padStart(2, "0");
|
||||||
|
|
||||||
|
const formattedString = `S${formattedParentIndexNumber}E${formattedIndexNumber}`;
|
||||||
|
return `${item.SeriesName} - ${formattedString} - ${item.Name}`;
|
||||||
|
}
|
||||||
|
return item.Name;
|
||||||
|
};
|
||||||
|
|
||||||
|
export { saveItemMapping, getFilePathFromItemId, storage, formatItemName };
|
||||||
|
|||||||
Reference in New Issue
Block a user