🏗️ Migrate overseerr search to tRPC

This commit is contained in:
Meier Lukas
2023-06-10 15:01:56 +02:00
parent ed5e548257
commit f57d91123e
3 changed files with 73 additions and 26 deletions

View File

@@ -13,10 +13,9 @@ import {
import { useDebouncedValue, useHotkeys } from '@mantine/hooks';
import { showNotification } from '@mantine/notifications';
import { IconBrandYoutube, IconDownload, IconMovie, IconSearch } from '@tabler/icons-react';
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';
import { useTranslation } from 'next-i18next';
import React, { forwardRef, useEffect, useRef, useState } from 'react';
import { api } from '~/utils/api';
import { useConfigContext } from '../../../config/provider';
import { OverseerrMediaDisplay } from '../../../modules/common';
import { IModule } from '../../../modules/ModuleTypes';
@@ -141,26 +140,12 @@ export function Search() {
const openTarget = getOpenTarget(config);
const [opened, setOpened] = useState(false);
const {
data: OverseerrResults,
isLoading,
error,
} = useQuery(
['overseerr', debounced],
async () => {
const res = await axios.get(`/api/modules/overseerr?query=${debounced}`);
return res.data.results ?? [];
},
{
enabled:
const isOverseerrSearchEnabled =
isOverseerrEnabled === true &&
selectedSearchEngine.value === 'overseerr' &&
debounced.length > 3,
refetchOnWindowFocus: false,
refetchOnMount: false,
refetchInterval: false,
}
);
debounced.length > 3;
const { data: overseerrResults } = useOverseerrSearchQuery(debounced, isOverseerrSearchEnabled);
const isModuleEnabled = config?.settings.customization.layout.enabledSearchbar;
if (!isModuleEnabled) {
@@ -173,7 +158,7 @@ export function Search() {
<Box style={{ width: '100%', maxWidth: 400 }}>
<Popover
opened={
(OverseerrResults && OverseerrResults.length > 0 && opened && searchQuery.length > 3) ??
(overseerrResults && overseerrResults.length > 0 && opened && searchQuery.length > 3) ??
false
}
position="bottom"
@@ -224,11 +209,11 @@ export function Search() {
</Popover.Target>
<Popover.Dropdown>
<ScrollArea style={{ height: '80vh', maxWidth: '90vw' }} offsetScrollbars>
{OverseerrResults &&
OverseerrResults.slice(0, 4).map((result: any, index: number) => (
{overseerrResults &&
overseerrResults.slice(0, 4).map((result: any, index: number) => (
<React.Fragment key={index}>
<OverseerrMediaDisplay key={result.id} media={result} />
{index < OverseerrResults.length - 1 && index < 3 && (
{index < overseerrResults.length - 1 && index < 3 && (
<Divider variant="dashed" my="xs" />
)}
</React.Fragment>
@@ -312,3 +297,19 @@ const getOpenTarget = (config: ConfigType | undefined): '_blank' | '_self' => {
return config.settings.common.searchEngine.properties.openInNewTab ? '_blank' : '_self';
};
const useOverseerrSearchQuery = (query: string, isEnabled: boolean) => {
const { name: configName } = useConfigContext();
return api.overseerr.all.useQuery(
{
query,
configName: configName!,
},
{
enabled: isEnabled,
refetchOnWindowFocus: false,
refetchOnMount: false,
refetchInterval: false,
}
);
};

View File

@@ -9,6 +9,7 @@ import { dnsHoleRouter } from './routers/dns-hole';
import { downloadRouter } from './routers/download';
import { mediaRequestsRouter } from './routers/media-request';
import { mediaServerRouter } from './routers/media-server';
import { overseerrRouter } from './routers/overseerr';
/**
* This is the primary router for your server.
@@ -26,6 +27,7 @@ export const rootRouter = createTRPCRouter({
download: downloadRouter,
mediaRequest: mediaRequestsRouter,
mediaServer: mediaServerRouter,
overseerr: overseerrRouter,
});
// export type definition of API

View File

@@ -0,0 +1,44 @@
import { TRPCError } from '@trpc/server';
import axios from 'axios';
import { z } from 'zod';
import { getConfig } from '~/tools/config/getConfig';
import { createTRPCRouter, publicProcedure } from '../trpc';
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;
}),
});