import { TRPCError } from '@trpc/server'; import axios from 'axios'; import { z } from 'zod'; import Consola from 'consola'; import { getConfig } from '~/tools/config/getConfig'; import { createTRPCRouter, publicProcedure } from '../trpc'; import { MovieResult } from '~/modules/overseerr/Movie'; import { TvShowResult } from '~/modules/overseerr/TvShow'; export const overseerrRouter = createTRPCRouter({ all: publicProcedure .input( z.object({ configName: z.string(), query: z.string().or(z.undefined()), }) ) .query(async ({ input }) => { const config = getConfig(input.configName); const app = config.apps.find( (app) => app.integration?.type === 'overseerr' || app.integration?.type === 'jellyseerr' ); if (input.query === '' || input.query === undefined) { return []; } const apiKey = app?.integration?.properties.find((x) => x.field === 'apiKey')?.value; if (!app || !apiKey) { throw new TRPCError({ code: 'BAD_REQUEST', message: 'Wrong request', }); } const appUrl = new URL(app.url); const data = await axios .get(`${appUrl.origin}/api/v1/search?query=${input.query}`, { headers: { // Set X-Api-Key to the value of the API key 'X-Api-Key': apiKey, }, }) .then((res) => res.data); return data; }), byId: publicProcedure .input( z.object({ configName: z.string(), id: z.number(), type: z.union([z.literal('movie'), z.literal('tv')]), }) ) .query(async ({ input }) => { const config = getConfig(input.configName); const app = config.apps.find( (app) => app.integration?.type === 'overseerr' || app.integration?.type === 'jellyseerr' ); const apiKey = app?.integration?.properties.find((x) => x.field === 'apiKey')?.value; if (!apiKey) { throw new TRPCError({ code: 'BAD_REQUEST', message: 'No app found', }); } const appUrl = new URL(app.url); if (input.type === 'movie') { const movie = await axios .get(`${appUrl.origin}/api/v1/movie/${input.id}`, { headers: { // Set X-Api-Key to the value of the API key 'X-Api-Key': apiKey, }, }) .then((res) => res.data as MovieResult) .catch((err) => { Consola.error(err); throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Something went wrong', }); }); return movie; } const tv = await axios .get(`${appUrl.origin}/api/v1/tv/${input.id}`, { headers: { // Set X-Api-Key to the value of the API key 'X-Api-Key': apiKey, }, }) .then((res) => res.data as TvShowResult) .catch((err) => { Consola.error(err); throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Something went wrong', }); }); return tv; }), request: publicProcedure .input( z .object({ configName: z.string(), id: z.number(), }) .and( z .object({ seasons: z.array(z.number()), type: z.literal('tv'), }) .or( z.object({ type: z.literal('movie'), }) ) ) ) .mutation(async ({ input }) => { const config = getConfig(input.configName); const app = config.apps.find( (app) => app.integration?.type === 'overseerr' || app.integration?.type === 'jellyseerr' ); const apiKey = app?.integration?.properties.find((x) => x.field === 'apiKey')?.value; if (!apiKey) { throw new TRPCError({ code: 'BAD_REQUEST', message: 'No app found', }); } const appUrl = new URL(app.url); Consola.info('Got an Overseerr request with these arguments', { mediaType: input.type, mediaId: input.id, seasons: input.type === 'tv' ? input.seasons : undefined, }); return axios .post( `${appUrl.origin}/api/v1/request`, { mediaType: input.type, mediaId: input.id, seasons: input.type === 'tv' ? input.seasons : undefined, }, { headers: { // Set X-Api-Key to the value of the API key 'X-Api-Key': apiKey, }, } ) .then((res) => res.data) .catch((err) => { throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: err.message, }); }); }), });