Revert "Merge branch 'develop' into chore/expo-52"

This reverts commit 933f3f2f7c, reversing
changes made to f92fee4158.
This commit is contained in:
Fredrik Burmester
2025-01-23 11:34:22 +01:00
parent 933f3f2f7c
commit d5c634b74b
176 changed files with 3718 additions and 6122 deletions

View File

@@ -1,4 +1,4 @@
import {DownloadMethod, useSettings} from "@/utils/atoms/settings";
import { useSettings } from "@/utils/atoms/settings";
import { getOrSetDeviceId } from "@/utils/device";
import { useLog, writeToLog } from "@/utils/log";
import {
@@ -48,9 +48,8 @@ import useImageStorage from "@/hooks/useImageStorage";
import { storage } from "@/utils/mmkv";
import useDownloadHelper from "@/utils/download";
import { FileInfo } from "expo-file-system";
import { useHaptic } from "@/hooks/useHaptic";
import * as Haptics from "expo-haptics";
import * as Application from "expo-application";
import { useTranslation } from "react-i18next";
export type DownloadedItem = {
item: Partial<BaseItemDto>;
@@ -69,7 +68,6 @@ const DownloadContext = createContext<ReturnType<
function useDownloadProvider() {
const queryClient = useQueryClient();
const { t } = useTranslation();
const [settings] = useSettings();
const router = useRouter();
const [api] = useAtom(apiAtom);
@@ -80,8 +78,6 @@ function useDownloadProvider() {
const [processes, setProcesses] = useAtom<JobStatus[]>(processesAtom);
const successHapticFeedback = useHaptic("success");
const authHeader = useMemo(() => {
return api?.accessToken;
}, [api]);
@@ -108,7 +104,7 @@ function useDownloadProvider() {
const url = settings?.optimizedVersionsServerUrl;
if (
settings?.downloadMethod !== DownloadMethod.Optimized ||
settings?.downloadMethod !== "optimized" ||
!url ||
!deviceId ||
!authHeader
@@ -141,9 +137,9 @@ function useDownloadProvider() {
if (settings.autoDownload) {
startDownload(job);
} else {
toast.info(t("home.downloads.toasts.item_is_ready_to_be_downloaded",{item: job.item.Name}), {
toast.info(`${job.item.Name} is ready to be downloaded`, {
action: {
label: t("home.downloads.toasts.go_to_downloads"),
label: "Go to downloads",
onClick: () => {
router.push("/downloads");
toast.dismiss();
@@ -168,7 +164,7 @@ function useDownloadProvider() {
},
staleTime: 0,
refetchInterval: 2000,
enabled: settings?.downloadMethod === DownloadMethod.Optimized,
enabled: settings?.downloadMethod === "optimized",
});
useEffect(() => {
@@ -226,9 +222,9 @@ function useDownloadProvider() {
},
});
toast.info(t("home.downloads.toasts.download_stated_for_item", {item: process.item.Name}), {
toast.info(`Download started for ${process.item.Name}`, {
action: {
label: t("home.downloads.toasts.go_to_downloads"),
label: "Go to downloads",
onClick: () => {
router.push("/downloads");
toast.dismiss();
@@ -277,10 +273,10 @@ function useDownloadProvider() {
process.item,
doneHandler.bytesDownloaded
);
toast.success(t("home.downloads.toasts.download_completed_for_item", {item: process.item.Name}), {
toast.success(`Download completed for ${process.item.Name}`, {
duration: 3000,
action: {
label: t("home.downloads.toasts.go_to_downloads"),
label: "Go to downloads",
onClick: () => {
router.push("/downloads");
toast.dismiss();
@@ -302,7 +298,7 @@ function useDownloadProvider() {
if (error.errorCode === 404) {
errorMsg = "File not found on server";
}
toast.error(t("home.downloads.toasts.download_failed_for_item", {item: process.item.Name, error: errorMsg}));
toast.error(`Download failed for ${process.item.Name} - ${errorMsg}`);
writeToLog("ERROR", `Download failed for ${process.item.Name}`, {
error,
processDetails: {
@@ -359,9 +355,9 @@ function useDownloadProvider() {
throw new Error("Failed to start optimization job");
}
toast.success(t("home.downloads.toasts.queued_item_for_optimization", {item: item.Name}), {
toast.success(`Queued ${item.Name} for optimization`, {
action: {
label: t("home.downloads.toasts.go_to_downloads"),
label: "Go to download",
onClick: () => {
router.push("/downloads");
toast.dismiss();
@@ -379,21 +375,21 @@ function useDownloadProvider() {
headers: error.response?.headers,
});
toast.error(
t("home.downloads.toasts.failed_to_start_download_for_item", {item: item.Name, message: error.message})
`Failed to start download for ${item.Name}: ${error.message}`
);
if (error.response) {
toast.error(
t("home.downloads.toasts.server_responded_with_status", {statusCode: error.response.status})
`Server responded with status ${error.response.status}`
);
} else if (error.request) {
t("home.downloads.toasts.no_response_received_from_server");
toast.error("No response received from server");
} else {
toast.error("Error setting up the request");
}
} else {
console.error("Non-Axios error:", error);
toast.error(
t("home.downloads.toasts.failed_to_start_download_for_item_unexpected_error", {item: item.Name})
`Failed to start download for ${item.Name}: Unexpected error`
);
}
}
@@ -409,11 +405,11 @@ function useDownloadProvider() {
queryClient.invalidateQueries({ queryKey: ["downloadedItems"] }),
])
.then(() =>
toast.success(t("home.downloads.toasts.all_files_folders_and_jobs_deleted_successfully"))
toast.success("All files, folders, and jobs deleted successfully")
)
.catch((reason) => {
console.error("Failed to delete all files, folders, and jobs:", reason);
toast.error(t("home.downloads.toasts.an_error_occured_while_deleting_files_and_jobs"));
toast.error("An error occurred while deleting files and jobs");
});
};
@@ -536,7 +532,9 @@ function useDownloadProvider() {
if (i.Id) return deleteFile(i.Id);
return;
})
).then(() => successHapticFeedback());
).then(() =>
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success)
);
};
const cleanCacheDirectory = async () => {

View File

@@ -1,4 +1,3 @@
import "@/augmentations";
import { useInterval } from "@/hooks/useInterval";
import { storage } from "@/utils/mmkv";
import { Api, Jellyfin } from "@jellyfin/sdk";
@@ -20,9 +19,7 @@ import React, {
import { Platform } from "react-native";
import uuid from "react-native-uuid";
import { getDeviceName } from "react-native-device-info";
import { useTranslation } from "react-i18next";
import { useSettings } from "@/utils/atoms/settings";
import { JellyseerrApi, useJellyseerr } from "@/hooks/useJellyseerr";
import { toast } from "sonner-native";
interface Server {
address: string;
@@ -51,8 +48,6 @@ export const JellyfinProvider: React.FC<{ children: ReactNode }> = ({
const [jellyfin, setJellyfin] = useState<Jellyfin | undefined>(undefined);
const [deviceId, setDeviceId] = useState<string | undefined>(undefined);
const { t } = useTranslation();
useEffect(() => {
(async () => {
const id = getOrSetDeviceId();
@@ -60,7 +55,7 @@ export const JellyfinProvider: React.FC<{ children: ReactNode }> = ({
setJellyfin(
() =>
new Jellyfin({
clientInfo: { name: "Streamyfin", version: "0.25.0" },
clientInfo: { name: "Streamyfin", version: "0.23.0" },
deviceInfo: {
name: deviceName,
id,
@@ -75,14 +70,6 @@ export const JellyfinProvider: React.FC<{ children: ReactNode }> = ({
const [user, setUser] = useAtom(userAtom);
const [isPolling, setIsPolling] = useState<boolean>(false);
const [secret, setSecret] = useState<string | null>(null);
const [
settings,
updateSettings,
pluginSettings,
setPluginSettings,
refreshStreamyfinPluginSettings,
] = useSettings();
const { clearAllJellyseerData, setJellyseerrUser } = useJellyseerr();
useQuery({
queryKey: ["user", api],
@@ -105,7 +92,7 @@ export const JellyfinProvider: React.FC<{ children: ReactNode }> = ({
return {
authorization: `MediaBrowser Client="Streamyfin", Device=${
Platform.OS === "android" ? "Android" : "iOS"
}, DeviceId="${deviceId}", Version="0.25.0"`,
}, DeviceId="${deviceId}", Version="0.23.0"`,
};
}, [deviceId]);
@@ -177,14 +164,6 @@ export const JellyfinProvider: React.FC<{ children: ReactNode }> = ({
useInterval(pollQuickConnect, isPolling ? 1000 : null);
useEffect(() => {
(async () => {
await refreshStreamyfinPluginSettings();
})();
}, []);
useInterval(refreshStreamyfinPluginSettings, 60 * 5 * 1000); // 5 min
const discoverServers = async (url: string): Promise<Server[]> => {
const servers = await jellyfin?.discovery.getRecommendedServerCandidates(
url
@@ -247,39 +226,27 @@ export const JellyfinProvider: React.FC<{ children: ReactNode }> = ({
storage.set("user", JSON.stringify(auth.data.User));
setApi(jellyfin.createApi(api?.basePath, auth.data?.AccessToken));
storage.set("token", auth.data?.AccessToken);
const recentPluginSettings = await refreshStreamyfinPluginSettings();
if (recentPluginSettings?.jellyseerrServerUrl?.value) {
const jellyseerrApi = new JellyseerrApi(
recentPluginSettings.jellyseerrServerUrl.value
);
await jellyseerrApi.test().then((result) => {
if (result.isValid && result.requiresPass) {
jellyseerrApi.login(username, password).then(setJellyseerrUser);
}
});
}
}
} catch (error) {
if (axios.isAxiosError(error)) {
switch (error.response?.status) {
case 401:
throw new Error(t("login.invalid_username_or_password"));
throw new Error("Invalid username or password");
case 403:
throw new Error(t("login.user_does_not_have_permission_to_log_in"));
throw new Error("User does not have permission to log in");
case 408:
throw new Error(
t("login.server_is_taking_too_long_to_respond_try_again_later")
"Server is taking too long to respond, try again later"
);
case 429:
throw new Error(
t("login.server_received_too_many_requests_try_again_later")
"Server received too many requests, try again later"
);
case 500:
throw new Error(t("login.there_is_a_server_error"));
throw new Error("There is a server error");
default:
throw new Error(
t("login.an_unexpected_error_occured_did_you_enter_the_correct_url")
"An unexpected error occurred. Did you enter the server URL correctly?"
);
}
}
@@ -295,8 +262,6 @@ export const JellyfinProvider: React.FC<{ children: ReactNode }> = ({
mutationFn: async () => {
storage.delete("token");
setUser(null);
setPluginSettings(undefined);
await clearAllJellyseerData();
},
onError: (error) => {
console.error("Logout failed:", error);

View File

@@ -38,6 +38,7 @@ type PlaySettingsContextType = {
setPlayUrl: React.Dispatch<React.SetStateAction<string | null>>;
playSessionId?: string | null;
setOfflineSettings: (data: PlaybackType) => void;
setMusicPlaySettings: (item: BaseItemDto, url: string) => void;
};
const PlaySettingsContext = createContext<PlaySettingsContextType | undefined>(
@@ -60,6 +61,13 @@ export const PlaySettingsProvider: React.FC<{ children: React.ReactNode }> = ({
_setPlaySettings(data);
}, []);
const setMusicPlaySettings = (item: BaseItemDto, url: string) => {
setPlaySettings({
item: item,
});
setPlayUrl(url);
};
const setPlaySettings = useCallback(
async (
dataOrUpdater:
@@ -139,6 +147,7 @@ export const PlaySettingsProvider: React.FC<{ children: React.ReactNode }> = ({
setPlaySettings,
playUrl,
setPlayUrl,
setMusicPlaySettings,
setOfflineSettings,
playSessionId,
mediaSource,