diff --git a/GLOBAL_MODAL_GUIDE.md b/GLOBAL_MODAL_GUIDE.md index 5426ca722..11a05f105 100644 --- a/GLOBAL_MODAL_GUIDE.md +++ b/GLOBAL_MODAL_GUIDE.md @@ -143,14 +143,6 @@ interface ModalOptions { } ``` -## Examples - -See `components/ExampleGlobalModalUsage.tsx` for comprehensive examples including: -- Simple content modal -- Modal with custom snap points -- Complex component in modal -- Success/error modals triggered from functions - ## Default Styling The modal uses these default styles (can be overridden via options): diff --git a/augmentations/index.ts b/augmentations/index.ts index abec02c9d..0c193e831 100644 --- a/augmentations/index.ts +++ b/augmentations/index.ts @@ -1,4 +1,3 @@ export * from "./api"; export * from "./mmkv"; export * from "./number"; -export * from "./string"; diff --git a/augmentations/number.ts b/augmentations/number.ts index bef44ac58..c8146d659 100644 --- a/augmentations/number.ts +++ b/augmentations/number.ts @@ -3,7 +3,6 @@ declare global { bytesToReadable(decimals?: number): string; secondsToMilliseconds(): number; minutesToMilliseconds(): number; - hoursToMilliseconds(): number; } } @@ -28,8 +27,4 @@ Number.prototype.minutesToMilliseconds = function () { return this.valueOf() * (60).secondsToMilliseconds(); }; -Number.prototype.hoursToMilliseconds = function () { - return this.valueOf() * (60).minutesToMilliseconds(); -}; - export {}; diff --git a/augmentations/string.ts b/augmentations/string.ts deleted file mode 100644 index f4a50b55c..000000000 --- a/augmentations/string.ts +++ /dev/null @@ -1,14 +0,0 @@ -declare global { - interface String { - toTitle(): string; - } -} - -String.prototype.toTitle = function () { - return this.replaceAll("_", " ").replace( - /\w\S*/g, - (text) => text.charAt(0).toUpperCase() + text.substring(1).toLowerCase(), - ); -}; - -export {}; diff --git a/components/ContextMenu.tv.ts b/components/ContextMenu.tv.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/components/ExampleGlobalModalUsage.tsx b/components/ExampleGlobalModalUsage.tsx deleted file mode 100644 index ccebb823d..000000000 --- a/components/ExampleGlobalModalUsage.tsx +++ /dev/null @@ -1,203 +0,0 @@ -/** - * Example Usage of Global Modal - * - * This file demonstrates how to use the global modal system from anywhere in your app. - * You can delete this file after understanding how it works. - */ - -import { Ionicons } from "@expo/vector-icons"; -import { TouchableOpacity, View } from "react-native"; -import { Text } from "@/components/common/Text"; -import { useGlobalModal } from "@/providers/GlobalModalProvider"; - -/** - * Example 1: Simple Content Modal - */ -export const SimpleModalExample = () => { - const { showModal } = useGlobalModal(); - - const handleOpenModal = () => { - showModal( - - Simple Modal - - This is a simple modal with just some text content. - - - Swipe down or tap outside to close. - - , - ); - }; - - return ( - - Open Simple Modal - - ); -}; - -/** - * Example 2: Modal with Custom Snap Points - */ -export const CustomSnapPointsExample = () => { - const { showModal } = useGlobalModal(); - - const handleOpenModal = () => { - showModal( - - - Custom Snap Points - - - This modal has custom snap points (25%, 50%, 90%). - - - - Try dragging the modal to different heights! - - - , - { - snapPoints: ["25%", "50%", "90%"], - enableDynamicSizing: false, - }, - ); - }; - - return ( - - Custom Snap Points - - ); -}; - -/** - * Example 3: Complex Component in Modal - */ -const SettingsModalContent = () => { - const { hideModal } = useGlobalModal(); - - const settings = [ - { - id: 1, - title: "Notifications", - icon: "notifications-outline" as const, - enabled: true, - }, - { id: 2, title: "Dark Mode", icon: "moon-outline" as const, enabled: true }, - { - id: 3, - title: "Auto-play", - icon: "play-outline" as const, - enabled: false, - }, - ]; - - return ( - - Settings - - {settings.map((setting, index) => ( - - - - {setting.title} - - - - - - ))} - - - Close - - - ); -}; - -export const ComplexModalExample = () => { - const { showModal } = useGlobalModal(); - - const handleOpenModal = () => { - showModal(); - }; - - return ( - - Complex Component - - ); -}; - -/** - * Example 4: Modal Triggered from Function (e.g., API response) - */ -export const useShowSuccessModal = () => { - const { showModal } = useGlobalModal(); - - return (message: string) => { - showModal( - - - - - Success! - {message} - , - ); - }; -}; - -/** - * Main Demo Component - */ -export const GlobalModalDemo = () => { - const showSuccess = useShowSuccessModal(); - - return ( - - - Global Modal Examples - - - - - - - showSuccess("Operation completed successfully!")} - className='bg-orange-600 px-4 py-2 rounded-lg' - > - Show Success Modal - - - ); -}; diff --git a/components/common/LargePoster.tsx b/components/common/LargePoster.tsx deleted file mode 100644 index ab3b16fb4..000000000 --- a/components/common/LargePoster.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { Image } from "expo-image"; -import { View } from "react-native"; - -export const LargePoster: React.FC<{ url?: string | null }> = ({ url }) => { - if (!url) - return ( - - - - ); - - return ( - - - - ); -}; diff --git a/components/common/VerticalSkeleton.tsx b/components/common/VerticalSkeleton.tsx deleted file mode 100644 index 02a8a2567..000000000 --- a/components/common/VerticalSkeleton.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { View, type ViewProps } from "react-native"; - -interface Props extends ViewProps { - index: number; -} - -export const VerticalSkeleton: React.FC = ({ index, ...props }) => { - return ( - - - - - - - ); -}; diff --git a/components/navigation/TabBarIcon.tsx b/components/navigation/TabBarIcon.tsx deleted file mode 100644 index a28bba840..000000000 --- a/components/navigation/TabBarIcon.tsx +++ /dev/null @@ -1,12 +0,0 @@ -// You can explore the built-in icon families and icons on the web at https://icons.expo.fyi/ - -import type { IconProps } from "@expo/vector-icons/build/createIconSet"; -import Ionicons from "@expo/vector-icons/Ionicons"; -import type { ComponentProps } from "react"; - -export function TabBarIcon({ - style, - ...rest -}: IconProps["name"]>) { - return ; -} diff --git a/components/posters/EpisodePoster.tsx b/components/posters/EpisodePoster.tsx deleted file mode 100644 index af42989b9..000000000 --- a/components/posters/EpisodePoster.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import type { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models"; -import { Image } from "expo-image"; -import { useAtom } from "jotai"; -import { useMemo, useState } from "react"; -import { View } from "react-native"; -import { WatchedIndicator } from "@/components/WatchedIndicator"; -import { apiAtom } from "@/providers/JellyfinProvider"; - -type MoviePosterProps = { - item: BaseItemDto; - showProgress?: boolean; -}; - -export const EpisodePoster: React.FC = ({ - item, - showProgress = false, -}) => { - const [api] = useAtom(apiAtom); - - const url = useMemo(() => { - if (item.Type === "Episode") { - return `${api?.basePath}/Items/${item.ParentBackdropItemId}/Images/Thumb?fillHeight=389&quality=80&tag=${item.ParentThumbImageTag}`; - } - }, [item]); - - const [progress, _setProgress] = useState( - item.UserData?.PlayedPercentage || 0, - ); - - const blurhash = useMemo(() => { - const key = item.ImageTags?.Primary as string; - return item.ImageBlurHashes?.Primary?.[key]; - }, [item]); - - return ( - - - - {showProgress && progress > 0 && ( - - )} - - ); -}; diff --git a/components/posters/ParentPoster.tsx b/components/posters/ParentPoster.tsx deleted file mode 100644 index 47b62e4c3..000000000 --- a/components/posters/ParentPoster.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { Image } from "expo-image"; -import { useAtom } from "jotai"; -import { useMemo } from "react"; -import { View } from "react-native"; -import { apiAtom } from "@/providers/JellyfinProvider"; - -type PosterProps = { - id?: string; - showProgress?: boolean; -}; - -const ParentPoster: React.FC = ({ id }) => { - const [api] = useAtom(apiAtom); - - const url = useMemo( - () => `${api?.basePath}/Items/${id}/Images/Primary`, - [id], - ); - - if (!url || !id) - return ( - - ); - - return ( - - - - ); -}; - -export default ParentPoster; diff --git a/components/settings/Dashboard.tsx b/components/settings/Dashboard.tsx deleted file mode 100644 index d41de0086..000000000 --- a/components/settings/Dashboard.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { useTranslation } from "react-i18next"; -import { View } from "react-native"; -import useRouter from "@/hooks/useAppRouter"; -import { useSessions, type useSessionsProps } from "@/hooks/useSessions"; -import { useSettings } from "@/utils/atoms/settings"; -import { ListGroup } from "../list/ListGroup"; -import { ListItem } from "../list/ListItem"; - -export const Dashboard = () => { - const { settings } = useSettings(); - const { sessions = [] } = useSessions({} as useSessionsProps); - const router = useRouter(); - - const { t } = useTranslation(); - - if (!settings) return null; - return ( - - - router.push("/settings/dashboard/sessions")} - title={t("home.settings.dashboard.sessions_title")} - showArrow - /> - - - ); -}; diff --git a/components/settings/DownloadSettings.tsx b/components/settings/DownloadSettings.tsx deleted file mode 100644 index 3a0017ac5..000000000 --- a/components/settings/DownloadSettings.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function DownloadSettings() { - return null; -} diff --git a/components/settings/DownloadSettings.tv.tsx b/components/settings/DownloadSettings.tv.tsx deleted file mode 100644 index 3a0017ac5..000000000 --- a/components/settings/DownloadSettings.tv.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function DownloadSettings() { - return null; -} diff --git a/constants/Languages.ts b/constants/Languages.ts deleted file mode 100644 index 8014e3800..000000000 --- a/constants/Languages.ts +++ /dev/null @@ -1,39 +0,0 @@ -import type { DefaultLanguageOption } from "@/utils/atoms/settings"; - -export const LANGUAGES: DefaultLanguageOption[] = [ - { label: "English", value: "eng" }, - { label: "Spanish", value: "spa" }, - { label: "Chinese (Mandarin)", value: "cmn" }, - { label: "Hindi", value: "hin" }, - { label: "Arabic", value: "ara" }, - { label: "French", value: "fra" }, - { label: "Russian", value: "rus" }, - { label: "Portuguese", value: "por" }, - { label: "Japanese", value: "jpn" }, - { label: "German", value: "deu" }, - { label: "Italian", value: "ita" }, - { label: "Korean", value: "kor" }, - { label: "Turkish", value: "tur" }, - { label: "Dutch", value: "nld" }, - { label: "Polish", value: "pol" }, - { label: "Vietnamese", value: "vie" }, - { label: "Thai", value: "tha" }, - { label: "Indonesian", value: "ind" }, - { label: "Greek", value: "ell" }, - { label: "Swedish", value: "swe" }, - { label: "Danish", value: "dan" }, - { label: "Norwegian", value: "nor" }, - { label: "Finnish", value: "fin" }, - { label: "Czech", value: "ces" }, - { label: "Hungarian", value: "hun" }, - { label: "Romanian", value: "ron" }, - { label: "Ukrainian", value: "ukr" }, - { label: "Hebrew", value: "heb" }, - { label: "Bengali", value: "ben" }, - { label: "Punjabi", value: "pan" }, - { label: "Tagalog", value: "tgl" }, - { label: "Swahili", value: "swa" }, - { label: "Malay", value: "msa" }, - { label: "Persian", value: "fas" }, - { label: "Urdu", value: "urd" }, -]; diff --git a/hooks/useControlsVisibility.ts b/hooks/useControlsVisibility.ts deleted file mode 100644 index caca0d842..000000000 --- a/hooks/useControlsVisibility.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { useCallback, useEffect, useRef } from "react"; -import { useSharedValue } from "react-native-reanimated"; - -export const useControlsVisibility = (timeout = 3000) => { - const opacity = useSharedValue(1); - - const hideControlsTimerRef = useRef | null>( - null, - ); - - const showControls = useCallback(() => { - opacity.value = 1; - if (hideControlsTimerRef.current) { - clearTimeout(hideControlsTimerRef.current); - } - hideControlsTimerRef.current = setTimeout(() => { - opacity.value = 0; - }, timeout); - }, [timeout]); - - const hideControls = useCallback(() => { - opacity.value = 0; - if (hideControlsTimerRef.current) { - clearTimeout(hideControlsTimerRef.current); - } - }, []); - - useEffect(() => { - return () => { - if (hideControlsTimerRef.current) { - clearTimeout(hideControlsTimerRef.current); - } - }; - }, []); - - return { opacity, showControls, hideControls }; -}; diff --git a/hooks/useDownloadedFileOpener.ts b/hooks/useDownloadedFileOpener.ts deleted file mode 100644 index 845161a19..000000000 --- a/hooks/useDownloadedFileOpener.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { BaseItemDto } from "@jellyfin/sdk/lib/generated-client"; -import { useCallback } from "react"; -import useRouter from "@/hooks/useAppRouter"; -import { usePlaySettings } from "@/providers/PlaySettingsProvider"; -import { writeToLog } from "@/utils/log"; - -export const useDownloadedFileOpener = () => { - const router = useRouter(); - const { setPlayUrl, setOfflineSettings } = usePlaySettings(); - - const openFile = useCallback( - async (item: BaseItemDto) => { - if (!item.Id) { - writeToLog("ERROR", "Attempted to open a file without an ID."); - console.error("Attempted to open a file without an ID."); - return; - } - const queryParams = new URLSearchParams({ - itemId: item.Id, - offline: "true", - playbackPosition: - item.UserData?.PlaybackPositionTicks?.toString() ?? "0", - }); - try { - router.push(`/player/direct-player?${queryParams.toString()}`); - } catch (error) { - writeToLog("ERROR", "Error opening file", error); - console.error("Error opening file:", error); - } - }, - [setOfflineSettings, setPlayUrl, router], - ); - - return { openFile }; -}; diff --git a/hooks/useImageColors.ts b/hooks/useImageColors.ts deleted file mode 100644 index 4d8a01369..000000000 --- a/hooks/useImageColors.ts +++ /dev/null @@ -1,120 +0,0 @@ -import type { BaseItemDto } from "@jellyfin/sdk/lib/generated-client"; -import { useAtom, useAtomValue } from "jotai"; -import { useEffect, useMemo } from "react"; -import { Platform } from "react-native"; -import type * as ImageColorsType from "react-native-image-colors"; -import { apiAtom } from "@/providers/JellyfinProvider"; - -// Conditionally import react-native-image-colors only on non-TV platforms -const ImageColors = Platform.isTV - ? null - : (require("react-native-image-colors") as typeof ImageColorsType); - -import { - adjustToNearBlack, - calculateTextColor, - isCloseToBlack, - itemThemeColorAtom, -} from "@/utils/atoms/primaryColor"; -import { getItemImage } from "@/utils/getItemImage"; -import { storage } from "@/utils/mmkv"; - -/** - * Custom hook to extract and manage image colors for a given item. - * - * @param item - The BaseItemDto object representing the item. - * @param disabled - A boolean flag to disable color extraction. - * - */ -export const useImageColors = ({ - item, - url, - disabled, -}: { - item?: BaseItemDto | null; - url?: string | null; - disabled?: boolean; -}) => { - const api = useAtomValue(apiAtom); - const [, setPrimaryColor] = useAtom(itemThemeColorAtom); - - const isTv = Platform.isTV; - - const source = useMemo(() => { - if (!api) return; - if (url) return { uri: url }; - if (item) - return getItemImage({ - item, - api, - variant: "Primary", - quality: 80, - width: 300, - }); - return null; - }, [api, item, url]); - - useEffect(() => { - if (isTv) return; - if (disabled) return; - if (source?.uri) { - const _primary = storage.getString(`${source.uri}-primary`); - const _text = storage.getString(`${source.uri}-text`); - - if (_primary && _text) { - setPrimaryColor({ - primary: _primary, - text: _text, - }); - return; - } - - // Extract colors from the image - if (!ImageColors?.getColors) return; - - ImageColors.getColors(source.uri, { - fallback: "#fff", - cache: false, - }) - .then((colors: ImageColorsType.ImageColorsResult) => { - let primary = "#fff"; - let text = "#000"; - let backup = "#fff"; - - // Select the appropriate color based on the platform - if (colors.platform === "android") { - primary = colors.dominant; - backup = colors.vibrant; - } else if (colors.platform === "ios") { - primary = colors.detail; - backup = colors.primary; - } - - // Adjust the primary color if it's too close to black - if (primary && isCloseToBlack(primary)) { - if (backup && !isCloseToBlack(backup)) primary = backup; - primary = adjustToNearBlack(primary); - } - - // Calculate the text color based on the primary color - if (primary) text = calculateTextColor(primary); - - setPrimaryColor({ - primary, - text, - }); - - // Cache the colors in storage - if (source.uri && primary) { - storage.set(`${source.uri}-primary`, primary); - storage.set(`${source.uri}-text`, text); - } - }) - .catch((error: any) => { - console.error("Error getting colors", error); - }); - } - }, [isTv, source?.uri, setPrimaryColor, disabled]); - - if (isTv) return; -}; diff --git a/utils/bToMb.ts b/utils/bToMb.ts deleted file mode 100644 index 79b7caf45..000000000 --- a/utils/bToMb.ts +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Convert bits to megabits or gigabits - * - * Return nice looking string - * If under 1000Mb, return XXXMB, else return X.XGB - */ - -export function convertBitsToMegabitsOrGigabits(bits?: number | null): string { - if (!bits) return "0MB"; - - const megabits = bits / 1000000; - - if (megabits < 1000) { - return `${Math.round(megabits)}MB`; - } - const gigabits = megabits / 1000; - return `${gigabits.toFixed(1)}GB`; -} diff --git a/utils/collectionTypeToItemType.ts b/utils/collectionTypeToItemType.ts deleted file mode 100644 index 0889b8d61..000000000 --- a/utils/collectionTypeToItemType.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { - BaseItemKind, - CollectionType, -} from "@jellyfin/sdk/lib/generated-client"; - -/** - * Converts a ColletionType to a BaseItemKind (also called ItemType) - * - * CollectionTypes - * readonly Unknown: "unknown"; - readonly Movies: "movies"; - readonly Tvshows: "tvshows"; - readonly Trailers: "trailers"; - readonly Homevideos: "homevideos"; - readonly Boxsets: "boxsets"; - readonly Books: "books"; - readonly Photos: "photos"; - readonly Livetv: "livetv"; - readonly Playlists: "playlists"; - readonly Folders: "folders"; - */ -export const colletionTypeToItemType = ( - collectionType?: CollectionType | null, -): BaseItemKind | undefined => { - if (!collectionType) return undefined; - - switch (collectionType) { - case CollectionType.Movies: - return BaseItemKind.Movie; - case CollectionType.Tvshows: - return BaseItemKind.Series; - case CollectionType.Homevideos: - return BaseItemKind.Video; - case CollectionType.Books: - return BaseItemKind.Book; - case CollectionType.Playlists: - return BaseItemKind.Playlist; - case CollectionType.Folders: - return BaseItemKind.Folder; - case CollectionType.Photos: - return BaseItemKind.Photo; - case CollectionType.Trailers: - return BaseItemKind.Trailer; - } - - return undefined; -}; diff --git a/utils/hls/parseM3U8ForSubtitles.ts b/utils/hls/parseM3U8ForSubtitles.ts deleted file mode 100644 index 5e0ad3826..000000000 --- a/utils/hls/parseM3U8ForSubtitles.ts +++ /dev/null @@ -1,56 +0,0 @@ -import axios from "axios"; - -export interface SubtitleTrack { - index: number; - name: string; - uri: string; - language: string; - default: boolean; - forced: boolean; - autoSelect: boolean; -} - -export async function parseM3U8ForSubtitles( - url: string, -): Promise { - try { - const response = await axios.get(url, { responseType: "text" }); - const lines = response.data.split(/\r?\n/); - const subtitleTracks: SubtitleTrack[] = []; - let index = 0; - - lines.forEach((line: string) => { - if (line.startsWith("#EXT-X-MEDIA:TYPE=SUBTITLES")) { - const attributes = parseAttributes(line); - const track: SubtitleTrack = { - index: index++, - name: attributes.NAME || "", - uri: attributes.URI || "", - language: attributes.LANGUAGE || "", - default: attributes.DEFAULT === "YES", - forced: attributes.FORCED === "YES", - autoSelect: attributes.AUTOSELECT === "YES", - }; - subtitleTracks.push(track); - } - }); - - return subtitleTracks; - } catch (error) { - console.error("Failed to fetch or parse the M3U8 file:", error); - throw error; - } -} - -function parseAttributes(line: string): { [key: string]: string } { - const attributes: { [key: string]: string } = {}; - const regex = /([A-Z-]+)=(?:"([^"]*)"|([^,]*))/g; - - for (const match of line.matchAll(regex)) { - const key = match[1]; - const value = match[2] ?? match[3]; // quoted or unquoted - attributes[key] = value; - } - - return attributes; -} diff --git a/utils/jellyfin/session/capabilities.ts b/utils/jellyfin/session/capabilities.ts deleted file mode 100644 index 4e4f20747..000000000 --- a/utils/jellyfin/session/capabilities.ts +++ /dev/null @@ -1,56 +0,0 @@ -import type { Api } from "@jellyfin/sdk"; -import type { AxiosResponse } from "axios"; -import type { Settings } from "../../atoms/settings"; -import { generateDeviceProfile } from "../../profiles/native"; -import { getAuthHeaders } from "../jellyfin"; - -interface PostCapabilitiesParams { - api: Api | null | undefined; - itemId: string | null | undefined; - sessionId: string | null | undefined; - deviceProfile: Settings["deviceProfile"]; -} - -/** - * Marks a media item as not played for a specific user. - * - * @param params - The parameters for marking an item as not played - * @returns A promise that resolves to true if the operation was successful, false otherwise - */ -export const postCapabilities = async ({ - api, - itemId, - sessionId, -}: PostCapabilitiesParams): Promise => { - if (!api || !itemId || !sessionId) { - throw new Error("Missing parameters for marking item as not played"); - } - - try { - const d = api.axiosInstance.post( - `${api.basePath}/Sessions/Capabilities/Full`, - { - playableMediaTypes: ["Audio", "Video"], - supportedCommands: [ - "PlayState", - "Play", - "ToggleFullscreen", - "DisplayMessage", - "Mute", - "Unmute", - "SetVolume", - "ToggleMute", - ], - supportsMediaControl: true, - id: sessionId, - DeviceProfile: generateDeviceProfile(), - }, - { - headers: getAuthHeaders(api), - }, - ); - return d; - } catch (_error) { - throw new Error("Failed to mark as not played"); - } -}; diff --git a/utils/jellyfin/tvshows/nextUp.ts b/utils/jellyfin/tvshows/nextUp.ts deleted file mode 100644 index 414a47a79..000000000 --- a/utils/jellyfin/tvshows/nextUp.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { Api } from "@jellyfin/sdk"; -import type { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models"; -import { getAuthHeaders } from "../jellyfin"; - -interface NextUpParams { - itemId?: string | null; - userId?: string | null; - api?: Api | null; -} - -/** - * Fetches the next up episodes for a series or all series for a user. - * - * @param params - The parameters for fetching next up episodes - * @returns A promise that resolves to an array of BaseItemDto representing the next up episodes - */ -export const nextUp = async ({ - itemId, - userId, - api, -}: NextUpParams): Promise => { - if (!userId || !api) { - console.error("Invalid parameters for nextUp: missing userId or api"); - return []; - } - - try { - const response = await api.axiosInstance.get<{ Items: BaseItemDto[] }>( - `${api.basePath}/Shows/NextUp`, - { - params: { - SeriesId: itemId || undefined, - UserId: userId, - Fields: "MediaSourceCount", - }, - headers: getAuthHeaders(api), - }, - ); - - return response.data.Items; - } catch (_error) { - return []; - } -}; diff --git a/utils/jellyfin/user-library/getItemById.ts b/utils/jellyfin/user-library/getItemById.ts deleted file mode 100644 index 261733b69..000000000 --- a/utils/jellyfin/user-library/getItemById.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { Api } from "@jellyfin/sdk"; -import type { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models"; -import { getUserLibraryApi } from "@jellyfin/sdk/lib/utils/api"; - -/** - * Retrieves an item by its ID from the API. - * - * @param api - The Jellyfin API instance. - * @param itemId - The ID of the item to retrieve. - * @returns The item object or undefined if no item matches the ID. - */ -export const getItemById = async ( - api?: Api | null | undefined, - itemId?: string | null | undefined, -): Promise => { - if (!api || !itemId) { - return undefined; - } - - try { - const itemData = await getUserLibraryApi(api).getItem({ itemId }); - - const item = itemData.data; - if (!item) { - console.error("No items found with the specified ID:", itemId); - return undefined; - } - - return item; - } catch (error) { - console.error("Failed to retrieve the item:", error); - throw new Error(`Failed to retrieve the item due to an error: ${error}`); - } -}; diff --git a/utils/secondsToTicks.ts b/utils/secondsToTicks.ts deleted file mode 100644 index df13813e6..000000000 --- a/utils/secondsToTicks.ts +++ /dev/null @@ -1,5 +0,0 @@ -// seconds to ticks util - -export function secondsToTicks(seconds: number): number { - return seconds * 10000000; -}