🏗️ Migrate calendar to tRPC

This commit is contained in:
Meier Lukas
2023-06-10 18:00:24 +02:00
parent 696da5dbec
commit bef6c56aeb
3 changed files with 111 additions and 18 deletions

View File

@@ -11,6 +11,7 @@ import { mediaRequestsRouter } from './routers/media-request';
import { mediaServerRouter } from './routers/media-server'; import { mediaServerRouter } from './routers/media-server';
import { overseerrRouter } from './routers/overseerr'; import { overseerrRouter } from './routers/overseerr';
import { usenetRouter } from './routers/usenet/route'; import { usenetRouter } from './routers/usenet/route';
import { calendarRouter } from './routers/calendar';
/** /**
* This is the primary router for your server. * This is the primary router for your server.
@@ -30,6 +31,7 @@ export const rootRouter = createTRPCRouter({
mediaServer: mediaServerRouter, mediaServer: mediaServerRouter,
overseerr: overseerrRouter, overseerr: overseerrRouter,
usenet: usenetRouter, usenet: usenetRouter,
calendar: calendarRouter,
}); });
// export type definition of API // export type definition of API

View File

@@ -0,0 +1,95 @@
import axios from 'axios';
import Consola from 'consola';
import { z } from 'zod';
import { getConfig } from '~/tools/config/getConfig';
import { AppIntegrationType } from '~/types/app';
import { createTRPCRouter, publicProcedure } from '../trpc';
export const calendarRouter = createTRPCRouter({
medias: publicProcedure
.input(
z.object({
configName: z.string(),
month: z.number().min(1).max(12),
year: z.number().min(1900).max(2300),
options: z.object({
useSonarrv4: z.boolean().optional().default(false),
}),
})
)
.query(async ({ input }) => {
const { configName, month, year, options } = input;
const config = getConfig(configName);
const mediaAppIntegrationTypes: AppIntegrationType['type'][] = [
'sonarr',
'radarr',
'readarr',
'lidarr',
];
const mediaApps = config.apps.filter(
(app) => app.integration && mediaAppIntegrationTypes.includes(app.integration.type)
);
const integrationTypeEndpointMap = new Map<AppIntegrationType['type'], string>([
['sonarr', input.options.useSonarrv4 ? '/api/v3/calendar' : '/api/calendar'],
['radarr', '/api/v3/calendar'],
['lidarr', '/api/v1/calendar'],
['readarr', '/api/v1/calendar'],
]);
const promises = mediaApps.map(async (app) => {
const integration = app.integration!;
const endpoint = integrationTypeEndpointMap.get(integration.type);
if (!endpoint) {
return {
type: integration.type,
items: [],
success: false,
};
}
// Get the origin URL
let { href: origin } = new URL(app.url);
if (origin.endsWith('/')) {
origin = origin.slice(0, -1);
}
const start = new Date(year, month - 1, 1); // First day of month
const end = new Date(year, month, 0); // Last day of month
const apiKey = integration.properties.find((x) => x.field === 'apiKey')?.value;
if (!apiKey) return { type: integration.type, items: [], success: false };
return axios
.get(
`${origin}${endpoint}?apiKey=${apiKey}&end=${end.toISOString()}&start=${start.toISOString()}&includeSeries=true&includeEpisodeFile=true&includeEpisodeImages=true`
)
.then((x) => ({ type: integration.type, items: x.data as any[], success: true }))
.catch((err) => {
Consola.error(
`failed to process request to app '${integration.type}' (${app.id}): ${err}`
);
return {
type: integration.type,
items: [],
success: false,
};
});
});
const medias = await Promise.all(promises);
const countFailed = medias.filter((x) => !x.success).length;
if (countFailed > 0) {
Consola.warn(`A total of ${countFailed} apps for the calendar widget failed`);
}
return {
tvShows: medias.filter((m) => m.type === 'sonarr').flatMap((m) => m.items),
movies: medias.filter((m) => m.type === 'radarr').flatMap((m) => m.items),
books: medias.filter((m) => m.type === 'readarr').flatMap((m) => m.items),
musics: medias.filter((m) => m.type === 'lidarr').flatMap((m) => m.items),
totalCount: medias.reduce((p, c) => p + c.items.length, 0),
};
}),
});

View File

@@ -1,16 +1,16 @@
import { useMantineTheme } from '@mantine/core'; import { useMantineTheme } from '@mantine/core';
import { Calendar } from '@mantine/dates'; import { Calendar } from '@mantine/dates';
import { IconCalendarTime } from '@tabler/icons-react'; import { IconCalendarTime } from '@tabler/icons-react';
import { useQuery } from '@tanstack/react-query';
import { i18n } from 'next-i18next'; import { i18n } from 'next-i18next';
import { useState } from 'react'; import { useState } from 'react';
import { api } from '~/utils/api';
import { useEditModeStore } from '../../components/Dashboard/Views/useEditModeStore';
import { useConfigContext } from '../../config/provider'; import { useConfigContext } from '../../config/provider';
import { defineWidget } from '../helper'; import { defineWidget } from '../helper';
import { IWidget } from '../widgets'; import { IWidget } from '../widgets';
import { CalendarDay } from './CalendarDay'; import { CalendarDay } from './CalendarDay';
import { getBgColorByDateAndTheme } from './bg-calculator'; import { getBgColorByDateAndTheme } from './bg-calculator';
import { MediasType } from './type'; import { MediasType } from './type';
import { useEditModeStore } from '../../components/Dashboard/Views/useEditModeStore';
const definition = defineWidget({ const definition = defineWidget({
id: 'calendar', id: 'calendar',
@@ -55,22 +55,18 @@ function CalendarTile({ widget }: CalendarTileProps) {
const [month, setMonth] = useState(new Date()); const [month, setMonth] = useState(new Date());
const isEditMode = useEditModeStore((x) => x.enabled); const isEditMode = useEditModeStore((x) => x.enabled);
const { data: medias } = useQuery({ const { data: medias } = api.calendar.medias.useQuery(
queryKey: [ {
'calendar/medias', configName: configName!,
{ month: month.getMonth(), year: month.getFullYear(), v4: widget.properties.useSonarrv4 }, month: month.getMonth() + 1,
], year: month.getFullYear(),
options: { useSonarrv4: widget.properties.useSonarrv4 },
},
{
staleTime: 1000 * 60 * 60 * 5, staleTime: 1000 * 60 * 60 * 5,
enabled: isEditMode === false, enabled: isEditMode === false,
queryFn: async () => }
(await ( );
await fetch(
`/api/modules/calendar?year=${month.getFullYear()}&month=${
month.getMonth() + 1
}&configName=${configName}&widgetId=${widget.id}`
)
).json()) as MediasType,
});
return ( return (
<Calendar <Calendar