mirror of
https://github.com/streamyfin/streamyfin.git
synced 2025-08-20 18:37:18 +02:00
Jellyseerr
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
import { nestedTabPageScreenOptions } from "@/components/stacks/NestedTabPageStack";
|
||||
import { Stack } from "expo-router";
|
||||
import { Platform } from "react-native";
|
||||
import { t } from "i18next";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function SearchLayout() {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Stack>
|
||||
<Stack.Screen
|
||||
|
||||
@@ -13,9 +13,12 @@ import { PersonCreditCast } from "@/utils/jellyseerr/server/models/Person";
|
||||
import ParallaxSlideShow from "@/components/jellyseerr/ParallaxSlideShow";
|
||||
import JellyseerrPoster from "@/components/posters/JellyseerrPoster";
|
||||
import {MovieResult, TvResult} from "@/utils/jellyseerr/server/models/Search";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function page() {
|
||||
const local = useLocalSearchParams();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { jellyseerrApi, jellyseerrUser } = useJellyseerr();
|
||||
|
||||
const { personId } = local as { personId: string };
|
||||
@@ -58,7 +61,7 @@ export default function page() {
|
||||
<ParallaxSlideShow
|
||||
data={castedRoles}
|
||||
images={backdrops}
|
||||
listHeader="Appearances"
|
||||
listHeader={t("jellyseerr.appearances")}
|
||||
keyExtractor={(item) => item.id.toString()}
|
||||
logo={
|
||||
<Image
|
||||
@@ -85,7 +88,7 @@ export default function page() {
|
||||
{data?.details?.name}
|
||||
</Text>
|
||||
<Text className="opacity-50">
|
||||
Born{" "}
|
||||
{t("jellyseerr.born")}{" "}
|
||||
{new Date(data?.details?.birthday!!).toLocaleDateString(
|
||||
`${locale}-${region}`,
|
||||
{
|
||||
|
||||
@@ -16,9 +16,11 @@ import { useLocalSearchParams, useNavigation } from "expo-router";
|
||||
import { useAtom } from "jotai";
|
||||
import React, { useEffect, useMemo } from "react";
|
||||
import { View } from "react-native";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const page: React.FC = () => {
|
||||
const navigation = useNavigation();
|
||||
const { t } = useTranslation();
|
||||
const params = useLocalSearchParams();
|
||||
const { id: seriesId, seasonIndex } = params as {
|
||||
id: string;
|
||||
@@ -85,7 +87,7 @@ const page: React.FC = () => {
|
||||
<AddToFavorites item={item} type="series" />
|
||||
<DownloadItems
|
||||
size="large"
|
||||
title="Download Series"
|
||||
title={t("item_card.download.download_series")}
|
||||
items={allEpisodes || []}
|
||||
MissingDownloadIconComponent={() => (
|
||||
<Ionicons name="download" size={22} color="white" />
|
||||
|
||||
@@ -32,7 +32,7 @@ import { MediaSourceSelector } from "./MediaSourceSelector";
|
||||
import ProgressCircle from "./ProgressCircle";
|
||||
import { RoundButton } from "./RoundButton";
|
||||
import { SubtitleTrackSelector } from "./SubtitleTrackSelector";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { t } from "i18next";
|
||||
|
||||
interface DownloadProps extends ViewProps {
|
||||
items: BaseItemDto[];
|
||||
@@ -56,7 +56,7 @@ export const DownloadItems: React.FC<DownloadProps> = ({
|
||||
const [user] = useAtom(userAtom);
|
||||
const [queue, setQueue] = useAtom(queueAtom);
|
||||
const [settings] = useSettings();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { processes, startBackgroundDownload, downloadedFiles } = useDownload();
|
||||
const { startRemuxing } = useRemuxHlsToMp4();
|
||||
|
||||
@@ -393,7 +393,9 @@ export const DownloadSingleItem: React.FC<{
|
||||
return (
|
||||
<DownloadItems
|
||||
size={size}
|
||||
title="Download Episode"
|
||||
title={item.Type == "Episode"
|
||||
? t("item_card.download.download_episode")
|
||||
: t("item_card.download.download_movie")}
|
||||
subtitle={item.Name!}
|
||||
items={[item]}
|
||||
MissingDownloadIconComponent={() => (
|
||||
|
||||
@@ -5,15 +5,17 @@ import React from "react";
|
||||
import { FlashList } from "@shopify/flash-list";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import PersonPoster from "@/components/jellyseerr/PersonPoster";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const CastSlide: React.FC<
|
||||
{ details?: MovieDetails | TvDetails } & ViewProps
|
||||
> = ({ details, ...props }) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
details?.credits?.cast &&
|
||||
details?.credits?.cast?.length > 0 && (
|
||||
<View {...props}>
|
||||
<Text className="text-lg font-bold mb-2 px-4">Cast</Text>
|
||||
<Text className="text-lg font-bold mb-2 px-4">{t("jellyseerr.cast")}</Text>
|
||||
<FlashList
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { TmdbRelease } from "@/utils/jellyseerr/server/api/themoviedb/interfaces
|
||||
import { Ionicons, MaterialCommunityIcons } from "@expo/vector-icons";
|
||||
import CountryFlag from "react-native-country-flag";
|
||||
import { ANIME_KEYWORD_ID } from "@/utils/jellyseerr/server/api/themoviedb/constants";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
interface Release {
|
||||
certification: string;
|
||||
@@ -50,6 +51,7 @@ const DetailFacts: React.FC<
|
||||
{ details?: MovieDetails | TvDetails } & ViewProps
|
||||
> = ({ details, className, ...props }) => {
|
||||
const { jellyseerrUser } = useJellyseerr();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const locale = useMemo(() => {
|
||||
return jellyseerrUser?.settings?.locale || "en";
|
||||
@@ -144,21 +146,21 @@ const DetailFacts: React.FC<
|
||||
return (
|
||||
details && (
|
||||
<View className="p-4">
|
||||
<Text className="text-lg font-bold">Details</Text>
|
||||
<Text className="text-lg font-bold">{t("jellyseerr.details")}</Text>
|
||||
<View
|
||||
className={`${className} flex flex-col justify-center divide-y-2 divide-neutral-800`}
|
||||
{...props}
|
||||
>
|
||||
<Fact title="Status" fact={details?.status} />
|
||||
<Fact title={t("jellyseerr.status")} fact={details?.status} />
|
||||
<Fact
|
||||
title="Original Title"
|
||||
title={t("jellyseerr.original_title")}
|
||||
fact={(details as TvDetails)?.originalName}
|
||||
/>
|
||||
{details.keywords.some(
|
||||
(keyword) => keyword.id === ANIME_KEYWORD_ID
|
||||
) && <Fact title="Series Type" fact="Anime" />}
|
||||
) && <Fact title={t("jellyseerr.series_type")} fact="Anime" />}
|
||||
<Facts
|
||||
title="Release Dates"
|
||||
title={t("jellyseerr.release_dates")}
|
||||
facts={filteredReleases?.map?.((r: Release, idx) => (
|
||||
<View key={idx} className="flex flex-row space-x-2 items-center">
|
||||
{r.type === 3 ? (
|
||||
@@ -184,13 +186,13 @@ const DetailFacts: React.FC<
|
||||
</View>
|
||||
))}
|
||||
/>
|
||||
<Fact title="First Air Date" fact={firstAirDate} />
|
||||
<Fact title="Next Air Date" fact={nextAirDate} />
|
||||
<Fact title="Revenue" fact={revenue} />
|
||||
<Fact title="Budget" fact={budget} />
|
||||
<Fact title="Original Language" fact={spokenLanguage} />
|
||||
<Fact title={t("jellyseerr.first_air_date")} fact={firstAirDate} />
|
||||
<Fact title={t("jellyseerr.next_air_date")} fact={nextAirDate} />
|
||||
<Fact title={t("jellyseerr.revenue")} fact={revenue} />
|
||||
<Fact title={t("jellyseerr.budget")} fact={budget} />
|
||||
<Fact title={t("jellyseerr.original_language")} fact={spokenLanguage} />
|
||||
<Facts
|
||||
title="Production Country"
|
||||
title={t("jellyseerr.production_country")}
|
||||
facts={details?.productionCountries?.map((n, idx) => (
|
||||
<View key={idx} className="flex flex-row items-center space-x-2">
|
||||
<CountryFlag isoCode={n.iso_3166_1} size={10} />
|
||||
@@ -199,14 +201,14 @@ const DetailFacts: React.FC<
|
||||
))}
|
||||
/>
|
||||
<Facts
|
||||
title="Studios"
|
||||
title={t("jellyseerr.studios")}
|
||||
facts={uniqBy(details?.productionCompanies, "name")?.map(
|
||||
(n) => n.name
|
||||
)}
|
||||
/>
|
||||
<Facts title="Network" facts={networks?.map((n) => n.name)} />
|
||||
<Facts title={t("jellyseerr.network")}facts={networks?.map((n) => n.name)} />
|
||||
<Facts
|
||||
title="Currently Streaming on"
|
||||
title={t("jellyseerr.currently_streaming_on")}
|
||||
facts={streamingProviders?.map((s) => s.name)}
|
||||
/>
|
||||
</View>
|
||||
|
||||
@@ -10,6 +10,7 @@ import {MediaRequestBody} from "@/utils/jellyseerr/server/interfaces/api/request
|
||||
import {BottomSheetModalMethods} from "@gorhom/bottom-sheet/lib/typescript/types";
|
||||
import {Button} from "@/components/Button";
|
||||
import {Text} from "@/components/common/Text";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
interface Props {
|
||||
id: number;
|
||||
@@ -36,6 +37,8 @@ const RequestModal = forwardRef<BottomSheetModalMethods, Props & Omit<ViewProps,
|
||||
userId: jellyseerrUser?.id
|
||||
});
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [modalRequestProps, setModalRequestProps] = useState<MediaRequestBody>();
|
||||
|
||||
const {data: serviceSettings} = useQuery({
|
||||
@@ -103,7 +106,7 @@ const RequestModal = forwardRef<BottomSheetModalMethods, Props & Omit<ViewProps,
|
||||
);
|
||||
|
||||
const seasonTitle = useMemo(
|
||||
() => modalRequestProps?.seasons?.length ? `Season (${modalRequestProps?.seasons})` : undefined,
|
||||
() => modalRequestProps?.seasons?.length ? t("jellyseerr.season_x", {seasons: modalRequestProps?.seasons}) : undefined,
|
||||
[modalRequestProps?.seasons]
|
||||
);
|
||||
|
||||
@@ -148,7 +151,7 @@ const RequestModal = forwardRef<BottomSheetModalMethods, Props & Omit<ViewProps,
|
||||
return <BottomSheetView>
|
||||
<View className="flex flex-col space-y-4 px-4 pb-8 pt-2">
|
||||
<View>
|
||||
<Text className="font-bold text-2xl text-neutral-100">Advanced</Text>
|
||||
<Text className="font-bold text-2xl text-neutral-100">{t("jellyseerr.advanced")}</Text>
|
||||
{seasonTitle &&
|
||||
<Text className="text-neutral-300">{seasonTitle}</Text>
|
||||
}
|
||||
@@ -161,27 +164,27 @@ const RequestModal = forwardRef<BottomSheetModalMethods, Props & Omit<ViewProps,
|
||||
titleExtractor={(item) => item.name}
|
||||
placeholderText={defaultProfile.name}
|
||||
keyExtractor={(item) => item.id.toString()}
|
||||
label={"Quality Profile"}
|
||||
label={t("jellyseerr.quality_profile")}
|
||||
onSelected={(item) =>
|
||||
item && setRequestOverrides((prev) => ({
|
||||
...prev,
|
||||
profileId: item?.id
|
||||
}))
|
||||
}
|
||||
title={"Quality Profile"}
|
||||
title={t("jellyseerr.quality_profile")}
|
||||
/>
|
||||
<Dropdown
|
||||
data={defaultServiceDetails.rootFolders}
|
||||
titleExtractor={pathTitleExtractor}
|
||||
placeholderText={defaultFolder ? pathTitleExtractor(defaultFolder) : ""}
|
||||
keyExtractor={(item) => item.id.toString()}
|
||||
label={"Root Folder"}
|
||||
label={t("jellyseerr.root_folder")}
|
||||
onSelected={(item) =>
|
||||
item && setRequestOverrides((prev) => ({
|
||||
...prev,
|
||||
rootFolder: item.path
|
||||
}))}
|
||||
title={"Root Folder"}
|
||||
title={t("jellyseerr.root_folder")}
|
||||
/>
|
||||
<Dropdown
|
||||
multi={true}
|
||||
@@ -189,28 +192,28 @@ const RequestModal = forwardRef<BottomSheetModalMethods, Props & Omit<ViewProps,
|
||||
titleExtractor={(item) => item.label}
|
||||
placeholderText={defaultTags.map(t => t.label).join(",")}
|
||||
keyExtractor={(item) => item.id.toString()}
|
||||
label={"Tags"}
|
||||
label={t("jellyseerr.tags")}
|
||||
onSelected={(...item) =>
|
||||
item && setRequestOverrides((prev) => ({
|
||||
...prev,
|
||||
tags: item.map(i => i.id)
|
||||
}))
|
||||
}
|
||||
title={"Tags"}
|
||||
title={t("jellyseerr.tags")}
|
||||
/>
|
||||
<Dropdown
|
||||
data={users}
|
||||
titleExtractor={(item) => item.displayName}
|
||||
placeholderText={jellyseerrUser!!.displayName}
|
||||
keyExtractor={(item) => item.id.toString() || ""}
|
||||
label={"Request As"}
|
||||
label={t("jellyseerr.request_as")}
|
||||
onSelected={(item) =>
|
||||
item && setRequestOverrides((prev) => ({
|
||||
...prev,
|
||||
userId: item?.id
|
||||
}))
|
||||
}
|
||||
title={"Request As"}
|
||||
title={t("jellyseerr.request_as")}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
@@ -221,7 +224,7 @@ const RequestModal = forwardRef<BottomSheetModalMethods, Props & Omit<ViewProps,
|
||||
onPress={request}
|
||||
color="purple"
|
||||
>
|
||||
Request
|
||||
{t("jellyseerr.request_button")}
|
||||
</Button>
|
||||
</View>
|
||||
</BottomSheetView>
|
||||
|
||||
@@ -256,8 +256,8 @@ const JellyseerrSeasons: React.FC<{
|
||||
<Tags
|
||||
textClass=""
|
||||
tags={[
|
||||
`Season ${season.seasonNumber}`,
|
||||
`${season.episodeCount} Episodes`,
|
||||
t("jellyseerr.season_number", {season_number: season.seasonNumber}),
|
||||
t("jellyseerr.number_episodes", {episode_number: season.episodeCount}),
|
||||
]}
|
||||
/>
|
||||
{[0].map(() => {
|
||||
|
||||
@@ -365,6 +365,9 @@
|
||||
"none": "None",
|
||||
"download": {
|
||||
"download_season": "Download Season",
|
||||
"download_series": "Download Series",
|
||||
"download_episode": "Download Episode",
|
||||
"download_movie": "Download Movie",
|
||||
"download_x_item": "Download {{item_count}} items",
|
||||
"download_button": "Download",
|
||||
"using_optimized_server": "Using optimized server",
|
||||
@@ -397,6 +400,31 @@
|
||||
"request_button": "Request",
|
||||
"are_you_sure_you_want_to_request_all_seasons": "Are you sure you want to request all seasons?",
|
||||
"failed_to_login": "Failed to login",
|
||||
"cast": "Cast",
|
||||
"details": "Details",
|
||||
"status": "Status",
|
||||
"original_title": "Original Title",
|
||||
"series_type": "Series Type",
|
||||
"release_dates": "Release Dates",
|
||||
"first_air_date": "First Air Date",
|
||||
"next_air_date": "Next Air Date",
|
||||
"revenue": "Revenue",
|
||||
"budget": "Budget",
|
||||
"original_language": "Original Language",
|
||||
"production_country": "Production Country",
|
||||
"studios": "Studios",
|
||||
"network": "Network",
|
||||
"currently_streaming_on": "Currently Streaming on",
|
||||
"advanced": "Advanced",
|
||||
"request_as": "Request As",
|
||||
"tags": "Tags",
|
||||
"quality_profile": "Quality Profile",
|
||||
"root_folder": "Root Folder",
|
||||
"season_x": "Season {{seasons}}",
|
||||
"season_number": "Season {{season_number}}",
|
||||
"number_episodes": "{{episode_number}} Episodes",
|
||||
"born": "Born",
|
||||
"appearances": "Appearances",
|
||||
"toasts": {
|
||||
"jellyseer_does_not_meet_requirements": "Jellyseerr server does not meet minimum version requirements! Please update to at least 2.0.0",
|
||||
"jellyseerr_test_failed": "Jellyseerr test failed. Please try again.",
|
||||
|
||||
@@ -365,6 +365,9 @@
|
||||
"none": "Aucun",
|
||||
"download": {
|
||||
"download_season": "Télécharger la saison",
|
||||
"download_series": "Télécharger la série",
|
||||
"download_episode": "Télécharger l'épisode",
|
||||
"download_movie": "Télécharger le film",
|
||||
"download_x_item": "Télécharger {{item_count}} items",
|
||||
"download_button": "Télécharger",
|
||||
"using_optimized_server": "Avec le serveur de versions optimisées",
|
||||
@@ -397,6 +400,31 @@
|
||||
"request_button": "Demander",
|
||||
"are_you_sure_you_want_to_request_all_seasons": "Êtes-vous sûr de vouloir demander toutes les saisons?",
|
||||
"failed_to_login": "Échec de la connexion",
|
||||
"cast": "Distribution",
|
||||
"details": "Détails",
|
||||
"status": "Statut",
|
||||
"original_title": "Titre original",
|
||||
"series_type": "Type de série",
|
||||
"release_dates": "Dates de sortie",
|
||||
"first_air_date": "Date de première diffusion",
|
||||
"next_air_date": "Date de prochaine diffusion",
|
||||
"revenue": "Revenu",
|
||||
"budget": "Budget",
|
||||
"original_language": "Langue originale",
|
||||
"production_country": "Pays de production",
|
||||
"studios": "Studios",
|
||||
"network": "Réseaux",
|
||||
"currently_streaming_on": "En diffusion continue sur",
|
||||
"advanced": "Avancé",
|
||||
"request_as": "Demander en tant que",
|
||||
"tags": "Tags",
|
||||
"quality_profile": "Profil de qualité",
|
||||
"root_folder": "Dossier racine",
|
||||
"season_x": "Saison {{seasons}}",
|
||||
"season_number": "Saison {{season_number}}",
|
||||
"number_episodes": "{{episode_number}} épisodes",
|
||||
"born": "Né(e) le",
|
||||
"appearances": "Apparitions",
|
||||
"toasts": {
|
||||
"jellyseer_does_not_meet_requirements": "Jellyseer ne répond pas aux exigences! Veuillez mettre à jour au moins vers la version 2.0.0.",
|
||||
"jellyseerr_test_failed": "Échec du test de Jellyseerr",
|
||||
|
||||
Reference in New Issue
Block a user