mirror of
https://github.com/ajnart/homarr.git
synced 2025-11-11 16:05:47 +01:00
Hugely improve Media display by splitting it into 2 different modules
This commit is contained in:
@@ -1,72 +1,84 @@
|
|||||||
import { Indicator, Popover, Box, Center } from '@mantine/core';
|
import { Indicator, Popover, Box, Center, ScrollArea, Divider } from '@mantine/core';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { Calendar } from '@mantine/dates';
|
import { Calendar } from '@mantine/dates';
|
||||||
import MediaDisplay from './MediaDisplay';
|
import { RadarrMediaDisplay, SonarrMediaDisplay } from './MediaDisplay';
|
||||||
import { useConfig } from '../../tools/state';
|
import { useConfig } from '../../tools/state';
|
||||||
import { serviceItem } from '../../tools/types';
|
|
||||||
|
|
||||||
export default function CalendarComponent(props: any) {
|
export default function CalendarComponent(props: any) {
|
||||||
const { config } = useConfig();
|
const { config } = useConfig();
|
||||||
const [opened, setOpened] = useState(false);
|
const [opened, setOpened] = useState(false);
|
||||||
const [medias, setMedias] = useState([] as any);
|
const [sonarrMedias, setSonarrMedias] = useState([] as any);
|
||||||
if (medias === undefined) {
|
const [radarrMedias, setRadarrMedias] = useState([] as any);
|
||||||
return <div>ok</div>;
|
|
||||||
}
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Filter only sonarr and radarr services
|
// Filter only sonarr and radarr services
|
||||||
const filtered = config.services.filter(
|
const filtered = config.services.filter(
|
||||||
(service) => service.type === 'Sonarr' || service.type === 'Radarr'
|
(service) => service.type === 'Sonarr' || service.type === 'Radarr'
|
||||||
);
|
);
|
||||||
|
|
||||||
// Get the url and API key for each service
|
// Get the url and apiKey for all Sonarr and Radarr services
|
||||||
const serviceUrls = filtered.map((service: serviceItem) => ({
|
const sonarrService = filtered.filter((service) => service.type === 'Sonarr').at(0);
|
||||||
url: service.url,
|
const radarrService = filtered.filter((service) => service.type === 'Radarr').at(0);
|
||||||
apiKey: service.apiKey,
|
const nextMonth = new Date(new Date().setMonth(new Date().getMonth() + 2)).toISOString();
|
||||||
}));
|
if (sonarrService) {
|
||||||
|
fetch(
|
||||||
// Get the medias from each service
|
`${sonarrService?.url}api/calendar?apikey=${sonarrService?.apiKey}&end=${nextMonth}`
|
||||||
// With no cors
|
).then((response) => {
|
||||||
// const promises = serviceUrls.map((service) =>
|
response.json().then((data) => setSonarrMedias(data));
|
||||||
// fetch('/api/getCalendar', {
|
});
|
||||||
// method: 'POST',
|
}
|
||||||
// body: JSON.stringify({
|
if (radarrService) {
|
||||||
// apiKey: service.apiKey,
|
fetch(
|
||||||
// remoteUrl: service.url,
|
`${radarrService?.url}api/calendar?apikey=${radarrService?.apiKey}&end=${nextMonth}`
|
||||||
// }),
|
).then((response) => {
|
||||||
// }).then((response) => console.log(response.json()))
|
response.json().then((data) => setRadarrMedias(data));
|
||||||
// );
|
});
|
||||||
fetch('http://server:8989/api/calendar?apikey=ea736455118146fea297e6c7465205ce').then(
|
|
||||||
(response) => {
|
|
||||||
response.json().then((data) => setMedias(data));
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
}, [config.services]);
|
}, [config.services]);
|
||||||
|
|
||||||
if (medias === undefined) {
|
if (sonarrMedias === undefined && radarrMedias === undefined) {
|
||||||
return <div>ok</div>;
|
return <Calendar />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Calendar
|
<Calendar
|
||||||
onChange={(day: any) => {}}
|
onChange={(day: any) => {}}
|
||||||
renderDay={(renderdate) => <DayComponent renderdate={renderdate} medias={medias} />}
|
renderDay={(renderdate) => (
|
||||||
|
<DayComponent
|
||||||
|
renderdate={renderdate}
|
||||||
|
sonarrmedias={sonarrMedias}
|
||||||
|
radarrmedias={radarrMedias}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DayComponent(props: any) {
|
function DayComponent(props: any) {
|
||||||
const { renderdate, medias }: { renderdate: Date; medias: [] } = props;
|
const {
|
||||||
|
renderdate,
|
||||||
|
sonarrmedias,
|
||||||
|
radarrmedias,
|
||||||
|
}: { renderdate: Date; sonarrmedias: []; radarrmedias: [] } = props;
|
||||||
const [opened, setOpened] = useState(false);
|
const [opened, setOpened] = useState(false);
|
||||||
|
|
||||||
const day = renderdate.getDate();
|
const day = renderdate.getDate();
|
||||||
// Itterate over the medias and filter the ones that are on the same day
|
// Itterate over the medias and filter the ones that are on the same day
|
||||||
const filtered = medias.filter((media: any) => {
|
const sonarrFiltered = sonarrmedias.filter((media: any) => {
|
||||||
const date = new Date(media.airDate);
|
const date = new Date(media.airDate);
|
||||||
return date.getDate() === day;
|
// Return true if the date is renerdate without counting hours and minutes
|
||||||
|
return date.getDate() === day && date.getMonth() === renderdate.getMonth();
|
||||||
});
|
});
|
||||||
if (filtered.length === 0) {
|
const radarrFiltered = radarrmedias.filter((media: any) => {
|
||||||
|
const date = new Date(media.airDate);
|
||||||
|
// Return true if the date is renerdate without counting hours and minutes
|
||||||
|
return date.getDate() === day && date.getMonth() === renderdate.getMonth();
|
||||||
|
});
|
||||||
|
if (sonarrFiltered.length === 0 && radarrFiltered.length === 0) {
|
||||||
return <div>{day}</div>;
|
return <div>{day}</div>;
|
||||||
}
|
}
|
||||||
|
// TODO: #5 Add the ability to display multiple medias on the same day by looping over the filtered medias for each service type
|
||||||
|
// And adding a divider between the medias
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
@@ -84,7 +96,11 @@ function DayComponent(props: any) {
|
|||||||
opened={opened}
|
opened={opened}
|
||||||
target={day}
|
target={day}
|
||||||
>
|
>
|
||||||
<MediaDisplay media={filtered[0]} />
|
<ScrollArea style={{ height: 400 }}>
|
||||||
|
{sonarrFiltered.length > 0 && <SonarrMediaDisplay media={sonarrFiltered[0]} />}
|
||||||
|
<Divider my="xl" />
|
||||||
|
{radarrFiltered.length > 0 && <RadarrMediaDisplay media={radarrFiltered[0]} />}
|
||||||
|
</ScrollArea>
|
||||||
</Popover>
|
</Popover>
|
||||||
</Indicator>
|
</Indicator>
|
||||||
</Center>
|
</Center>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import MediaDisplay from './MediaDisplay';
|
import { RadarrMediaDisplay } from './MediaDisplay';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: 'Media display component',
|
title: 'Media display component',
|
||||||
@@ -64,4 +64,4 @@ export default {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Default = (args: any) => <MediaDisplay {...args} />;
|
export const Default = (args: any) => <RadarrMediaDisplay {...args} />;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Stack, Image, Group, Title, Badge, Text } from '@mantine/core';
|
import { Stack, Image, Group, Title, Badge, Text, ActionIcon, Anchor } from '@mantine/core';
|
||||||
|
import { Link } from 'tabler-icons-react';
|
||||||
|
|
||||||
export interface IMedia {
|
export interface IMedia {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -9,13 +10,16 @@ export interface IMedia {
|
|||||||
genres: string[];
|
genres: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function MediaDisplay(props: any) {
|
export function RadarrMediaDisplay(props: any) {
|
||||||
const { media }: { media: any } = props;
|
const { media }: { media: any } = props;
|
||||||
|
// Find a poster CoverType
|
||||||
|
const poster = media.series.images.find((image: any) => image.coverType === 'poster');
|
||||||
// Return a movie poster containting the title and the description
|
// Return a movie poster containting the title and the description
|
||||||
return (
|
return (
|
||||||
<Group noWrap align="self-start">
|
<Group noWrap align="self-start">
|
||||||
<Image
|
<Image
|
||||||
src={media.series.images[0].url}
|
fit="cover"
|
||||||
|
src={poster.url}
|
||||||
alt={media.series.title}
|
alt={media.series.title}
|
||||||
style={{
|
style={{
|
||||||
maxWidth: 300,
|
maxWidth: 300,
|
||||||
@@ -28,8 +32,74 @@ export default function MediaDisplay(props: any) {
|
|||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Group direction="column">
|
<Group direction="column">
|
||||||
|
<Group>
|
||||||
<Title order={3}>{media.series.title}</Title>
|
<Title order={3}>{media.series.title}</Title>
|
||||||
<Text>{media.overview}</Text>
|
<Anchor href={`https://www.imdb.com/title/${media.series.imdbId}`} target="_blank">
|
||||||
|
<ActionIcon>
|
||||||
|
<Link />
|
||||||
|
</ActionIcon>
|
||||||
|
</Anchor>
|
||||||
|
</Group>
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
textAlign: 'center',
|
||||||
|
color: '#a0aec0',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Season {media.seasonNumber} episode {media.episodeNumber}
|
||||||
|
</Text>
|
||||||
|
<Text>{media.series.overview}</Text>
|
||||||
|
</Group>
|
||||||
|
{/*Add the genres at the bottom of the poster*/}
|
||||||
|
<Group>
|
||||||
|
{media.series.genres.map((genre: string, i: number) => (
|
||||||
|
<Badge key={i}>{genre}</Badge>
|
||||||
|
))}
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</Group>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SonarrMediaDisplay(props: any) {
|
||||||
|
const { media }: { media: any } = props;
|
||||||
|
// Find a poster CoverType
|
||||||
|
const poster = media.series.images.find((image: any) => image.coverType === 'poster');
|
||||||
|
// Return a movie poster containting the title and the description
|
||||||
|
return (
|
||||||
|
<Group noWrap align="self-start">
|
||||||
|
<Image
|
||||||
|
fit="cover"
|
||||||
|
src={poster.url}
|
||||||
|
alt={media.series.title}
|
||||||
|
style={{
|
||||||
|
maxWidth: 300,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Stack
|
||||||
|
justify="space-between"
|
||||||
|
sx={(theme) => ({
|
||||||
|
height: 400,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Group direction="column">
|
||||||
|
<Group>
|
||||||
|
<Title order={3}>{media.series.title}</Title>
|
||||||
|
<Anchor href={`https://www.imdb.com/title/${media.series.imdbId}`} target="_blank">
|
||||||
|
<ActionIcon>
|
||||||
|
<Link />
|
||||||
|
</ActionIcon>
|
||||||
|
</Anchor>
|
||||||
|
</Group>
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
textAlign: 'center',
|
||||||
|
color: '#a0aec0',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Season {media.seasonNumber} episode {media.episodeNumber}
|
||||||
|
</Text>
|
||||||
|
<Text>{media.series.overview}</Text>
|
||||||
</Group>
|
</Group>
|
||||||
{/*Add the genres at the bottom of the poster*/}
|
{/*Add the genres at the bottom of the poster*/}
|
||||||
<Group>
|
<Group>
|
||||||
|
|||||||
Reference in New Issue
Block a user