mirror of
https://github.com/ajnart/homarr.git
synced 2025-11-10 07:25:48 +01:00
🐛 Fix pull request issues
This commit is contained in:
@@ -5,8 +5,9 @@ import Consola from 'consola';
|
|||||||
import { NextApiRequest, NextApiResponse } from 'next';
|
import { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { AppIntegrationType } from '../../../types/app';
|
import { AppIntegrationType, IntegrationType } from '../../../types/app';
|
||||||
import { getConfig } from '../../../tools/config/getConfig';
|
import { getConfig } from '../../../tools/config/getConfig';
|
||||||
|
import { checkIntegrationsType } from '~/tools/client/app-properties';
|
||||||
|
|
||||||
export default async (req: NextApiRequest, res: NextApiResponse) => {
|
export default async (req: NextApiRequest, res: NextApiResponse) => {
|
||||||
// Filter out if the reuqest is a POST or a GET
|
// Filter out if the reuqest is a POST or a GET
|
||||||
@@ -51,14 +52,14 @@ async function Get(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
const calendar = config.widgets.find((w) => w.type === 'calendar' && w.id === widgetId);
|
const calendar = config.widgets.find((w) => w.type === 'calendar' && w.id === widgetId);
|
||||||
const useSonarrv4 = calendar?.properties.useSonarrv4 ?? false;
|
const useSonarrv4 = calendar?.properties.useSonarrv4 ?? false;
|
||||||
|
|
||||||
const mediaAppIntegrationTypes: AppIntegrationType['type'][] = [
|
const mediaAppIntegrationTypes = [
|
||||||
'sonarr',
|
'sonarr',
|
||||||
'radarr',
|
'radarr',
|
||||||
'readarr',
|
'readarr',
|
||||||
'lidarr',
|
'lidarr',
|
||||||
];
|
] as const satisfies readonly IntegrationType[];
|
||||||
const mediaApps = config.apps.filter(
|
const mediaApps = config.apps.filter((app) =>
|
||||||
(app) => app.integration && mediaAppIntegrationTypes.includes(app.integration.type)
|
checkIntegrationsType(app.integration, mediaAppIntegrationTypes)
|
||||||
);
|
);
|
||||||
|
|
||||||
const IntegrationTypeEndpointMap = new Map<AppIntegrationType['type'], string>([
|
const IntegrationTypeEndpointMap = new Map<AppIntegrationType['type'], string>([
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import {
|
|||||||
NormalizedDownloadAppStat,
|
NormalizedDownloadAppStat,
|
||||||
NormalizedDownloadQueueResponse,
|
NormalizedDownloadQueueResponse,
|
||||||
} from '../../../../types/api/downloads/queue/NormalizedDownloadQueueResponse';
|
} from '../../../../types/api/downloads/queue/NormalizedDownloadQueueResponse';
|
||||||
|
import { findAppProperty } from '~/tools/client/app-properties';
|
||||||
|
|
||||||
const Get = async (request: NextApiRequest, response: NextApiResponse) => {
|
const Get = async (request: NextApiRequest, response: NextApiResponse) => {
|
||||||
const configName = getCookie('config-name', { req: request });
|
const configName = getCookie('config-name', { req: request });
|
||||||
@@ -151,8 +152,8 @@ const GetDataFromClient = async (
|
|||||||
const options = {
|
const options = {
|
||||||
host: url.hostname,
|
host: url.hostname,
|
||||||
port: url.port,
|
port: url.port,
|
||||||
login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined,
|
login: findAppProperty(app, 'username'),
|
||||||
hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined,
|
hash: findAppProperty(app, 'password'),
|
||||||
};
|
};
|
||||||
|
|
||||||
const nzbGet = NzbgetClient(options);
|
const nzbGet = NzbgetClient(options);
|
||||||
|
|||||||
@@ -5,13 +5,14 @@ import { getConfig } from '../../../../tools/config/getConfig';
|
|||||||
|
|
||||||
import { MediaRequest } from '../../../../widgets/media-requests/media-request-types';
|
import { MediaRequest } from '../../../../widgets/media-requests/media-request-types';
|
||||||
import { MediaRequestListWidget } from '../../../../widgets/media-requests/MediaRequestListTile';
|
import { MediaRequestListWidget } from '../../../../widgets/media-requests/MediaRequestListTile';
|
||||||
|
import { checkIntegrationsType } from '~/tools/client/app-properties';
|
||||||
|
|
||||||
const Get = async (request: NextApiRequest, response: NextApiResponse) => {
|
const Get = async (request: NextApiRequest, response: NextApiResponse) => {
|
||||||
const configName = getCookie('config-name', { req: request });
|
const configName = getCookie('config-name', { req: request });
|
||||||
const config = getConfig(configName?.toString() ?? 'default');
|
const config = getConfig(configName?.toString() ?? 'default');
|
||||||
|
|
||||||
const apps = config.apps.filter((app) =>
|
const apps = config.apps.filter((app) =>
|
||||||
['overseerr', 'jellyseerr'].includes(app.integration?.type ?? '')
|
checkIntegrationsType(app.integration, ['overseerr', 'jellyseerr'])
|
||||||
);
|
);
|
||||||
|
|
||||||
Consola.log(`Retrieving media requests from ${apps.length} apps`);
|
Consola.log(`Retrieving media requests from ${apps.length} apps`);
|
||||||
@@ -24,8 +25,9 @@ const Get = async (request: NextApiRequest, response: NextApiResponse) => {
|
|||||||
})
|
})
|
||||||
.then(async (response) => {
|
.then(async (response) => {
|
||||||
const body = (await response.json()) as OverseerrResponse;
|
const body = (await response.json()) as OverseerrResponse;
|
||||||
const mediaWidget = config.widgets.find(
|
const mediaWidget = config.widgets.find((x) => x.type === 'media-requests-list') as
|
||||||
(x) => x.type === 'media-requests-list') as MediaRequestListWidget | undefined;
|
| MediaRequestListWidget
|
||||||
|
| undefined;
|
||||||
if (!mediaWidget) {
|
if (!mediaWidget) {
|
||||||
Consola.log('No media-requests-list found');
|
Consola.log('No media-requests-list found');
|
||||||
return Promise.resolve([]);
|
return Promise.resolve([]);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import {
|
|||||||
GenericSessionInfo,
|
GenericSessionInfo,
|
||||||
} from '../../../../types/api/media-server/session-info';
|
} from '../../../../types/api/media-server/session-info';
|
||||||
import { PlexClient } from '../../../../tools/server/sdk/plex/plexClient';
|
import { PlexClient } from '../../../../tools/server/sdk/plex/plexClient';
|
||||||
|
import { checkIntegrationsType, findAppProperty } from '~/tools/client/app-properties';
|
||||||
|
|
||||||
const jellyfin = new Jellyfin({
|
const jellyfin = new Jellyfin({
|
||||||
clientInfo: {
|
clientInfo: {
|
||||||
@@ -35,7 +36,7 @@ const Get = async (request: NextApiRequest, response: NextApiResponse) => {
|
|||||||
const config = getConfig(configName?.toString() ?? 'default');
|
const config = getConfig(configName?.toString() ?? 'default');
|
||||||
|
|
||||||
const apps = config.apps.filter((app) =>
|
const apps = config.apps.filter((app) =>
|
||||||
['jellyfin', 'plex'].includes(app.integration?.type ?? '')
|
checkIntegrationsType(app.integration, ['jellyfin', 'plex'])
|
||||||
);
|
);
|
||||||
|
|
||||||
const servers = await Promise.all(
|
const servers = await Promise.all(
|
||||||
@@ -66,9 +67,9 @@ const Get = async (request: NextApiRequest, response: NextApiResponse) => {
|
|||||||
const handleServer = async (app: ConfigAppType): Promise<GenericMediaServer | undefined> => {
|
const handleServer = async (app: ConfigAppType): Promise<GenericMediaServer | undefined> => {
|
||||||
switch (app.integration?.type) {
|
switch (app.integration?.type) {
|
||||||
case 'jellyfin': {
|
case 'jellyfin': {
|
||||||
const username = app.integration.properties.find((x) => x.field === 'username');
|
const username = findAppProperty(app, 'username');
|
||||||
|
|
||||||
if (!username || !username.value) {
|
if (!username) {
|
||||||
return {
|
return {
|
||||||
appId: app.id,
|
appId: app.id,
|
||||||
serverAddress: app.url,
|
serverAddress: app.url,
|
||||||
@@ -79,9 +80,9 @@ const handleServer = async (app: ConfigAppType): Promise<GenericMediaServer | un
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const password = app.integration.properties.find((x) => x.field === 'password');
|
const password = findAppProperty(app, 'password');
|
||||||
|
|
||||||
if (!password || !password.value) {
|
if (!password) {
|
||||||
return {
|
return {
|
||||||
appId: app.id,
|
appId: app.id,
|
||||||
serverAddress: app.url,
|
serverAddress: app.url,
|
||||||
@@ -94,7 +95,7 @@ const handleServer = async (app: ConfigAppType): Promise<GenericMediaServer | un
|
|||||||
|
|
||||||
const api = jellyfin.createApi(app.url);
|
const api = jellyfin.createApi(app.url);
|
||||||
const infoApi = await getSystemApi(api).getPublicSystemInfo();
|
const infoApi = await getSystemApi(api).getPublicSystemInfo();
|
||||||
await api.authenticateUserByName(username.value, password.value);
|
await api.authenticateUserByName(username, password);
|
||||||
const sessionApi = await getSessionApi(api);
|
const sessionApi = await getSessionApi(api);
|
||||||
const sessions = await sessionApi.getSessions();
|
const sessions = await sessionApi.getSessions();
|
||||||
return {
|
return {
|
||||||
@@ -166,9 +167,9 @@ const handleServer = async (app: ConfigAppType): Promise<GenericMediaServer | un
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
case 'plex': {
|
case 'plex': {
|
||||||
const apiKey = app.integration.properties.find((x) => x.field === 'apiKey');
|
const apiKey = findAppProperty(app, 'apiKey');
|
||||||
|
|
||||||
if (!apiKey || !apiKey.value) {
|
if (!apiKey) {
|
||||||
return {
|
return {
|
||||||
serverAddress: app.url,
|
serverAddress: app.url,
|
||||||
sessions: [],
|
sessions: [],
|
||||||
@@ -179,7 +180,7 @@ const handleServer = async (app: ConfigAppType): Promise<GenericMediaServer | un
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const plexClient = new PlexClient(app.url, apiKey.value);
|
const plexClient = new PlexClient(app.url, apiKey);
|
||||||
const sessions = await plexClient.getSessions();
|
const sessions = await plexClient.getSessions();
|
||||||
return {
|
return {
|
||||||
serverAddress: app.url,
|
serverAddress: app.url,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { NzbgetHistoryItem } from '../../../../server/api/routers/usenet/nzbget/
|
|||||||
import { NzbgetClient } from '../../../../server/api/routers/usenet/nzbget/nzbget-client';
|
import { NzbgetClient } from '../../../../server/api/routers/usenet/nzbget/nzbget-client';
|
||||||
import { getConfig } from '../../../../tools/config/getConfig';
|
import { getConfig } from '../../../../tools/config/getConfig';
|
||||||
import { UsenetHistoryItem } from '../../../../widgets/useNet/types';
|
import { UsenetHistoryItem } from '../../../../widgets/useNet/types';
|
||||||
|
import { findAppProperty } from '~/tools/client/app-properties';
|
||||||
|
|
||||||
dayjs.extend(duration);
|
dayjs.extend(duration);
|
||||||
|
|
||||||
@@ -40,8 +41,8 @@ async function Get(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
const options = {
|
const options = {
|
||||||
host: url.hostname,
|
host: url.hostname,
|
||||||
port: url.port || (url.protocol === 'https:' ? '443' : '80'),
|
port: url.port || (url.protocol === 'https:' ? '443' : '80'),
|
||||||
login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined,
|
login: findAppProperty(app, 'username'),
|
||||||
hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined,
|
hash: findAppProperty(app, 'password'),
|
||||||
};
|
};
|
||||||
|
|
||||||
const nzbGet = NzbgetClient(options);
|
const nzbGet = NzbgetClient(options);
|
||||||
@@ -77,7 +78,7 @@ async function Get(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
case 'sabnzbd': {
|
case 'sabnzbd': {
|
||||||
const { origin } = new URL(app.url);
|
const { origin } = new URL(app.url);
|
||||||
|
|
||||||
const apiKey = app.integration.properties.find((x) => x.field === 'apiKey')?.value;
|
const apiKey = findAppProperty(app, 'apiKey');
|
||||||
if (!apiKey) {
|
if (!apiKey) {
|
||||||
throw new Error(`API Key for app "${app.name}" is missing`);
|
throw new Error(`API Key for app "${app.name}" is missing`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { Client } from 'sabnzbd-api';
|
|||||||
import { getConfig } from '../../../../tools/config/getConfig';
|
import { getConfig } from '../../../../tools/config/getConfig';
|
||||||
import { NzbgetClient } from '../../../../server/api/routers/usenet/nzbget/nzbget-client';
|
import { NzbgetClient } from '../../../../server/api/routers/usenet/nzbget/nzbget-client';
|
||||||
import { NzbgetStatus } from '../../../../server/api/routers/usenet/nzbget/types';
|
import { NzbgetStatus } from '../../../../server/api/routers/usenet/nzbget/types';
|
||||||
|
import { findAppProperty } from '~/tools/client/app-properties';
|
||||||
|
|
||||||
dayjs.extend(duration);
|
dayjs.extend(duration);
|
||||||
|
|
||||||
@@ -39,8 +40,8 @@ async function Get(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
const options = {
|
const options = {
|
||||||
host: url.hostname,
|
host: url.hostname,
|
||||||
port: url.port || (url.protocol === 'https:' ? '443' : '80'),
|
port: url.port || (url.protocol === 'https:' ? '443' : '80'),
|
||||||
login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined,
|
login: findAppProperty(app, 'username'),
|
||||||
hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined,
|
hash: findAppProperty(app, 'password'),
|
||||||
};
|
};
|
||||||
|
|
||||||
const nzbGet = NzbgetClient(options);
|
const nzbGet = NzbgetClient(options);
|
||||||
@@ -70,7 +71,7 @@ async function Get(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'sabnzbd': {
|
case 'sabnzbd': {
|
||||||
const apiKey = app.integration.properties.find((x) => x.field === 'apiKey')?.value;
|
const apiKey = findAppProperty(app, 'apiKey');
|
||||||
if (!apiKey) {
|
if (!apiKey) {
|
||||||
throw new Error(`API Key for app "${app.name}" is missing`);
|
throw new Error(`API Key for app "${app.name}" is missing`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { NextApiRequest, NextApiResponse } from 'next';
|
|||||||
import { Client } from 'sabnzbd-api';
|
import { Client } from 'sabnzbd-api';
|
||||||
import { getConfig } from '../../../../tools/config/getConfig';
|
import { getConfig } from '../../../../tools/config/getConfig';
|
||||||
import { NzbgetClient } from '../../../../server/api/routers/usenet/nzbget/nzbget-client';
|
import { NzbgetClient } from '../../../../server/api/routers/usenet/nzbget/nzbget-client';
|
||||||
|
import { findAppProperty } from '~/tools/client/app-properties';
|
||||||
|
|
||||||
dayjs.extend(duration);
|
dayjs.extend(duration);
|
||||||
|
|
||||||
@@ -31,8 +32,8 @@ async function Post(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
const options = {
|
const options = {
|
||||||
host: url.hostname,
|
host: url.hostname,
|
||||||
port: url.port || (url.protocol === 'https:' ? '443' : '80'),
|
port: url.port || (url.protocol === 'https:' ? '443' : '80'),
|
||||||
login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined,
|
login: findAppProperty(app, 'username'),
|
||||||
hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined,
|
hash: findAppProperty(app, 'password'),
|
||||||
};
|
};
|
||||||
|
|
||||||
const nzbGet = NzbgetClient(options);
|
const nzbGet = NzbgetClient(options);
|
||||||
@@ -49,7 +50,7 @@ async function Post(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'sabnzbd': {
|
case 'sabnzbd': {
|
||||||
const apiKey = app.integration.properties.find((x) => x.field === 'apiKey')?.value;
|
const apiKey = findAppProperty(app, 'apiKey');
|
||||||
if (!apiKey) {
|
if (!apiKey) {
|
||||||
throw new Error(`API Key for app "${app.name}" is missing`);
|
throw new Error(`API Key for app "${app.name}" is missing`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { getConfig } from '../../../../tools/config/getConfig';
|
|||||||
import { UsenetQueueItem } from '../../../../widgets/useNet/types';
|
import { UsenetQueueItem } from '../../../../widgets/useNet/types';
|
||||||
import { NzbgetClient } from '../../../../server/api/routers/usenet/nzbget/nzbget-client';
|
import { NzbgetClient } from '../../../../server/api/routers/usenet/nzbget/nzbget-client';
|
||||||
import { NzbgetQueueItem, NzbgetStatus } from '../../../../server/api/routers/usenet/nzbget/types';
|
import { NzbgetQueueItem, NzbgetStatus } from '../../../../server/api/routers/usenet/nzbget/types';
|
||||||
|
import { findAppProperty } from '~/tools/client/app-properties';
|
||||||
|
|
||||||
dayjs.extend(duration);
|
dayjs.extend(duration);
|
||||||
|
|
||||||
@@ -40,8 +41,8 @@ async function Get(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
const options = {
|
const options = {
|
||||||
host: url.hostname,
|
host: url.hostname,
|
||||||
port: url.port || (url.protocol === 'https:' ? '443' : '80'),
|
port: url.port || (url.protocol === 'https:' ? '443' : '80'),
|
||||||
login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined,
|
login: findAppProperty(app, 'username'),
|
||||||
hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined,
|
hash: findAppProperty(app, 'password'),
|
||||||
};
|
};
|
||||||
|
|
||||||
const nzbGet = NzbgetClient(options);
|
const nzbGet = NzbgetClient(options);
|
||||||
@@ -91,7 +92,7 @@ async function Get(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'sabnzbd': {
|
case 'sabnzbd': {
|
||||||
const apiKey = app.integration.properties.find((x) => x.field === 'apiKey')?.value;
|
const apiKey = findAppProperty(app, 'apiKey');
|
||||||
if (!apiKey) {
|
if (!apiKey) {
|
||||||
throw new Error(`API Key for app "${app.name}" is missing`);
|
throw new Error(`API Key for app "${app.name}" is missing`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { NextApiRequest, NextApiResponse } from 'next';
|
|||||||
import { Client } from 'sabnzbd-api';
|
import { Client } from 'sabnzbd-api';
|
||||||
import { getConfig } from '../../../../tools/config/getConfig';
|
import { getConfig } from '../../../../tools/config/getConfig';
|
||||||
import { NzbgetClient } from '../../../../server/api/routers/usenet/nzbget/nzbget-client';
|
import { NzbgetClient } from '../../../../server/api/routers/usenet/nzbget/nzbget-client';
|
||||||
|
import { findAppProperty } from '~/tools/client/app-properties';
|
||||||
|
|
||||||
dayjs.extend(duration);
|
dayjs.extend(duration);
|
||||||
|
|
||||||
@@ -32,8 +33,8 @@ async function Post(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
const options = {
|
const options = {
|
||||||
host: url.hostname,
|
host: url.hostname,
|
||||||
port: url.port || (url.protocol === 'https:' ? '443' : '80'),
|
port: url.port || (url.protocol === 'https:' ? '443' : '80'),
|
||||||
login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined,
|
login: findAppProperty(app, 'username'),
|
||||||
hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined,
|
hash: findAppProperty(app, 'password'),
|
||||||
};
|
};
|
||||||
|
|
||||||
const nzbGet = NzbgetClient(options);
|
const nzbGet = NzbgetClient(options);
|
||||||
@@ -50,7 +51,7 @@ async function Post(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'sabnzbd': {
|
case 'sabnzbd': {
|
||||||
const apiKey = app.integration.properties.find((x) => x.field === 'apiKey')?.value;
|
const apiKey = findAppProperty(app, 'apiKey');
|
||||||
if (!apiKey) {
|
if (!apiKey) {
|
||||||
throw new Error(`API Key for app "${app.name}" is missing`);
|
throw new Error(`API Key for app "${app.name}" is missing`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { downloadRouter } from './routers/download';
|
|||||||
import { mediaRequestsRouter } from './routers/media-request';
|
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/router';
|
||||||
import { calendarRouter } from './routers/calendar';
|
import { calendarRouter } from './routers/calendar';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ import axios from 'axios';
|
|||||||
import Consola from 'consola';
|
import Consola from 'consola';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { getConfig } from '~/tools/config/getConfig';
|
import { getConfig } from '~/tools/config/getConfig';
|
||||||
import { AppIntegrationType } from '~/types/app';
|
import { AppIntegrationType, IntegrationType } from '~/types/app';
|
||||||
import { createTRPCRouter, publicProcedure } from '../trpc';
|
import { createTRPCRouter, publicProcedure } from '../trpc';
|
||||||
|
import { checkIntegrationsType } from '~/tools/client/app-properties';
|
||||||
|
|
||||||
export const calendarRouter = createTRPCRouter({
|
export const calendarRouter = createTRPCRouter({
|
||||||
medias: publicProcedure
|
medias: publicProcedure
|
||||||
@@ -21,14 +22,14 @@ export const calendarRouter = createTRPCRouter({
|
|||||||
const { configName, month, year, options } = input;
|
const { configName, month, year, options } = input;
|
||||||
const config = getConfig(configName);
|
const config = getConfig(configName);
|
||||||
|
|
||||||
const mediaAppIntegrationTypes: AppIntegrationType['type'][] = [
|
const mediaAppIntegrationTypes = [
|
||||||
'sonarr',
|
'sonarr',
|
||||||
'radarr',
|
'radarr',
|
||||||
'readarr',
|
'readarr',
|
||||||
'lidarr',
|
'lidarr',
|
||||||
];
|
] as const satisfies readonly IntegrationType[];
|
||||||
const mediaApps = config.apps.filter(
|
const mediaApps = config.apps.filter((app) =>
|
||||||
(app) => app.integration && mediaAppIntegrationTypes.includes(app.integration.type)
|
checkIntegrationsType(app.integration, mediaAppIntegrationTypes)
|
||||||
);
|
);
|
||||||
|
|
||||||
const integrationTypeEndpointMap = new Map<AppIntegrationType['type'], string>([
|
const integrationTypeEndpointMap = new Map<AppIntegrationType['type'], string>([
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
import { ConfigAppType, IntegrationField } from '~/types/app';
|
import { ConfigAppType, IntegrationField } from '~/types/app';
|
||||||
import { UsenetQueueItem } from '~/widgets/useNet/types';
|
import { UsenetQueueItem } from '~/widgets/useNet/types';
|
||||||
import { createTRPCRouter, publicProcedure } from '../trpc';
|
import { createTRPCRouter, publicProcedure } from '../trpc';
|
||||||
|
import { findAppProperty } from '~/tools/client/app-properties';
|
||||||
|
|
||||||
export const downloadRouter = createTRPCRouter({
|
export const downloadRouter = createTRPCRouter({
|
||||||
get: publicProcedure
|
get: publicProcedure
|
||||||
@@ -155,8 +156,8 @@ const GetDataFromClient = async (
|
|||||||
const options = {
|
const options = {
|
||||||
host: url.hostname,
|
host: url.hostname,
|
||||||
port: url.port,
|
port: url.port,
|
||||||
login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined,
|
login: findAppProperty(app, 'username'),
|
||||||
hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined,
|
hash: findAppProperty(app, 'password'),
|
||||||
};
|
};
|
||||||
|
|
||||||
const nzbGet = NzbgetClient(options);
|
const nzbGet = NzbgetClient(options);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { getConfig } from '~/tools/config/getConfig';
|
|||||||
import { MediaRequest } from '~/widgets/media-requests/media-request-types';
|
import { MediaRequest } from '~/widgets/media-requests/media-request-types';
|
||||||
import { createTRPCRouter, publicProcedure } from '../trpc';
|
import { createTRPCRouter, publicProcedure } from '../trpc';
|
||||||
import { MediaRequestListWidget } from '~/widgets/media-requests/MediaRequestListTile';
|
import { MediaRequestListWidget } from '~/widgets/media-requests/MediaRequestListTile';
|
||||||
|
import { checkIntegrationsType } from '~/tools/client/app-properties';
|
||||||
|
|
||||||
export const mediaRequestsRouter = createTRPCRouter({
|
export const mediaRequestsRouter = createTRPCRouter({
|
||||||
all: publicProcedure
|
all: publicProcedure
|
||||||
@@ -16,7 +17,7 @@ export const mediaRequestsRouter = createTRPCRouter({
|
|||||||
const config = getConfig(input.configName);
|
const config = getConfig(input.configName);
|
||||||
|
|
||||||
const apps = config.apps.filter((app) =>
|
const apps = config.apps.filter((app) =>
|
||||||
['overseerr', 'jellyseerr'].includes(app.integration?.type ?? '')
|
checkIntegrationsType(app.integration, ['overseerr', 'jellyseerr'])
|
||||||
);
|
);
|
||||||
|
|
||||||
Consola.log(`Retrieving media requests from ${apps.length} apps`);
|
Consola.log(`Retrieving media requests from ${apps.length} apps`);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { MediaServersResponseType } from '~/types/api/media-server/response';
|
|||||||
import { GenericCurrentlyPlaying, GenericSessionInfo } from '~/types/api/media-server/session-info';
|
import { GenericCurrentlyPlaying, GenericSessionInfo } from '~/types/api/media-server/session-info';
|
||||||
import { ConfigAppType } from '~/types/app';
|
import { ConfigAppType } from '~/types/app';
|
||||||
import { createTRPCRouter, publicProcedure } from '../trpc';
|
import { createTRPCRouter, publicProcedure } from '../trpc';
|
||||||
|
import { checkIntegrationsType, findAppProperty } from '~/tools/client/app-properties';
|
||||||
|
|
||||||
const jellyfin = new Jellyfin({
|
const jellyfin = new Jellyfin({
|
||||||
clientInfo: {
|
clientInfo: {
|
||||||
@@ -34,7 +35,7 @@ export const mediaServerRouter = createTRPCRouter({
|
|||||||
const config = getConfig(input.configName);
|
const config = getConfig(input.configName);
|
||||||
|
|
||||||
const apps = config.apps.filter((app) =>
|
const apps = config.apps.filter((app) =>
|
||||||
['jellyfin', 'plex'].includes(app.integration?.type ?? '')
|
checkIntegrationsType(app.integration, ['jellyfin', 'plex'])
|
||||||
);
|
);
|
||||||
|
|
||||||
const servers = await Promise.all(
|
const servers = await Promise.all(
|
||||||
@@ -68,9 +69,9 @@ export const mediaServerRouter = createTRPCRouter({
|
|||||||
const handleServer = async (app: ConfigAppType): Promise<GenericMediaServer | undefined> => {
|
const handleServer = async (app: ConfigAppType): Promise<GenericMediaServer | undefined> => {
|
||||||
switch (app.integration?.type) {
|
switch (app.integration?.type) {
|
||||||
case 'jellyfin': {
|
case 'jellyfin': {
|
||||||
const username = app.integration.properties.find((x) => x.field === 'username');
|
const username = findAppProperty(app, 'username');
|
||||||
|
|
||||||
if (!username || !username.value) {
|
if (!username) {
|
||||||
return {
|
return {
|
||||||
appId: app.id,
|
appId: app.id,
|
||||||
serverAddress: app.url,
|
serverAddress: app.url,
|
||||||
@@ -81,9 +82,9 @@ const handleServer = async (app: ConfigAppType): Promise<GenericMediaServer | un
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const password = app.integration.properties.find((x) => x.field === 'password');
|
const password = findAppProperty(app, 'password');
|
||||||
|
|
||||||
if (!password || !password.value) {
|
if (!password) {
|
||||||
return {
|
return {
|
||||||
appId: app.id,
|
appId: app.id,
|
||||||
serverAddress: app.url,
|
serverAddress: app.url,
|
||||||
@@ -96,7 +97,7 @@ const handleServer = async (app: ConfigAppType): Promise<GenericMediaServer | un
|
|||||||
|
|
||||||
const api = jellyfin.createApi(app.url);
|
const api = jellyfin.createApi(app.url);
|
||||||
const infoApi = await getSystemApi(api).getPublicSystemInfo();
|
const infoApi = await getSystemApi(api).getPublicSystemInfo();
|
||||||
await api.authenticateUserByName(username.value, password.value);
|
await api.authenticateUserByName(username, password);
|
||||||
const sessionApi = await getSessionApi(api);
|
const sessionApi = await getSessionApi(api);
|
||||||
const sessions = await sessionApi.getSessions();
|
const sessions = await sessionApi.getSessions();
|
||||||
return {
|
return {
|
||||||
@@ -168,9 +169,9 @@ const handleServer = async (app: ConfigAppType): Promise<GenericMediaServer | un
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
case 'plex': {
|
case 'plex': {
|
||||||
const apiKey = app.integration.properties.find((x) => x.field === 'apiKey');
|
const apiKey = findAppProperty(app, 'apiKey');
|
||||||
|
|
||||||
if (!apiKey || !apiKey.value) {
|
if (!apiKey) {
|
||||||
return {
|
return {
|
||||||
serverAddress: app.url,
|
serverAddress: app.url,
|
||||||
sessions: [],
|
sessions: [],
|
||||||
@@ -181,7 +182,7 @@ const handleServer = async (app: ConfigAppType): Promise<GenericMediaServer | un
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const plexClient = new PlexClient(app.url, apiKey.value);
|
const plexClient = new PlexClient(app.url, apiKey);
|
||||||
const sessions = await plexClient.getSessions();
|
const sessions = await plexClient.getSessions();
|
||||||
return {
|
return {
|
||||||
serverAddress: app.url,
|
serverAddress: app.url,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { getConfig } from '~/tools/config/getConfig';
|
|||||||
import { UsenetHistoryItem, UsenetQueueItem } from '~/widgets/useNet/types';
|
import { UsenetHistoryItem, UsenetQueueItem } from '~/widgets/useNet/types';
|
||||||
import { createTRPCRouter, publicProcedure } from '../../trpc';
|
import { createTRPCRouter, publicProcedure } from '../../trpc';
|
||||||
import { NzbgetClient } from './nzbget/nzbget-client';
|
import { NzbgetClient } from './nzbget/nzbget-client';
|
||||||
|
import { checkIntegrationsType, findAppProperty } from '~/tools/client/app-properties';
|
||||||
|
|
||||||
export const usenetRouter = createTRPCRouter({
|
export const usenetRouter = createTRPCRouter({
|
||||||
info: publicProcedure
|
info: publicProcedure
|
||||||
@@ -25,20 +26,20 @@ export const usenetRouter = createTRPCRouter({
|
|||||||
|
|
||||||
const app = config.apps.find((x) => x.id === input.appId);
|
const app = config.apps.find((x) => x.id === input.appId);
|
||||||
|
|
||||||
if (!app || (app.integration?.type !== 'nzbGet' && app.integration?.type !== 'sabnzbd')) {
|
if (!app || !checkIntegrationsType(app.integration, ['nzbGet', 'sabnzbd'])) {
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
code: 'BAD_REQUEST',
|
code: 'BAD_REQUEST',
|
||||||
message: `App with ID "${input.appId}" could not be found.`,
|
message: `App with ID "${input.appId}" could not be found.`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (app.integration?.type === 'nzbGet') {
|
if (app.integration.type === 'nzbGet') {
|
||||||
const url = new URL(app.url);
|
const url = new URL(app.url);
|
||||||
const options = {
|
const options = {
|
||||||
host: url.hostname,
|
host: url.hostname,
|
||||||
port: url.port || (url.protocol === 'https:' ? '443' : '80'),
|
port: url.port || (url.protocol === 'https:' ? '443' : '80'),
|
||||||
login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined,
|
login: findAppProperty(app, 'username'),
|
||||||
hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined,
|
hash: findAppProperty(app, 'password'),
|
||||||
};
|
};
|
||||||
|
|
||||||
const nzbGet = NzbgetClient(options);
|
const nzbGet = NzbgetClient(options);
|
||||||
@@ -70,7 +71,7 @@ export const usenetRouter = createTRPCRouter({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiKey = app.integration.properties.find((x) => x.field === 'apiKey')?.value;
|
const apiKey = findAppProperty(app, 'apiKey');
|
||||||
if (!apiKey) {
|
if (!apiKey) {
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
code: 'BAD_REQUEST',
|
code: 'BAD_REQUEST',
|
||||||
@@ -110,17 +111,17 @@ export const usenetRouter = createTRPCRouter({
|
|||||||
|
|
||||||
const app = config.apps.find((x) => x.id === input.appId);
|
const app = config.apps.find((x) => x.id === input.appId);
|
||||||
|
|
||||||
if (!app || (app.integration?.type !== 'nzbGet' && app.integration?.type !== 'sabnzbd')) {
|
if (!app || !checkIntegrationsType(app.integration, ['nzbGet', 'sabnzbd'])) {
|
||||||
throw new Error(`App with ID "${input.appId}" could not be found.`);
|
throw new Error(`App with ID "${input.appId}" could not be found.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (app.integration?.type === 'nzbGet') {
|
if (app.integration.type === 'nzbGet') {
|
||||||
const url = new URL(app.url);
|
const url = new URL(app.url);
|
||||||
const options = {
|
const options = {
|
||||||
host: url.hostname,
|
host: url.hostname,
|
||||||
port: url.port || (url.protocol === 'https:' ? '443' : '80'),
|
port: url.port || (url.protocol === 'https:' ? '443' : '80'),
|
||||||
login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined,
|
login: findAppProperty(app, 'username'),
|
||||||
hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined,
|
hash: findAppProperty(app, 'password'),
|
||||||
};
|
};
|
||||||
|
|
||||||
const nzbGet = NzbgetClient(options);
|
const nzbGet = NzbgetClient(options);
|
||||||
@@ -155,7 +156,7 @@ export const usenetRouter = createTRPCRouter({
|
|||||||
|
|
||||||
const { origin } = new URL(app.url);
|
const { origin } = new URL(app.url);
|
||||||
|
|
||||||
const apiKey = app.integration.properties.find((x) => x.field === 'apiKey')?.value;
|
const apiKey = findAppProperty(app, 'apiKey');
|
||||||
if (!apiKey) {
|
if (!apiKey) {
|
||||||
throw new Error(`API Key for app "${app.name}" is missing`);
|
throw new Error(`API Key for app "${app.name}" is missing`);
|
||||||
}
|
}
|
||||||
@@ -185,7 +186,7 @@ export const usenetRouter = createTRPCRouter({
|
|||||||
const config = getConfig(input.configName);
|
const config = getConfig(input.configName);
|
||||||
const app = config.apps.find((x) => x.id === input.appId);
|
const app = config.apps.find((x) => x.id === input.appId);
|
||||||
|
|
||||||
if (!app || (app.integration?.type !== 'nzbGet' && app.integration?.type !== 'sabnzbd')) {
|
if (!app || !checkIntegrationsType(app.integration, ['nzbGet', 'sabnzbd'])) {
|
||||||
throw new Error(`App with ID "${input.appId}" could not be found.`);
|
throw new Error(`App with ID "${input.appId}" could not be found.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,8 +195,8 @@ export const usenetRouter = createTRPCRouter({
|
|||||||
const options = {
|
const options = {
|
||||||
host: url.hostname,
|
host: url.hostname,
|
||||||
port: url.port || (url.protocol === 'https:' ? '443' : '80'),
|
port: url.port || (url.protocol === 'https:' ? '443' : '80'),
|
||||||
login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined,
|
login: findAppProperty(app, 'username'),
|
||||||
hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined,
|
hash: findAppProperty(app, 'password'),
|
||||||
};
|
};
|
||||||
|
|
||||||
const nzbGet = NzbgetClient(options);
|
const nzbGet = NzbgetClient(options);
|
||||||
@@ -211,7 +212,7 @@ export const usenetRouter = createTRPCRouter({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiKey = app.integration.properties.find((x) => x.field === 'apiKey')?.value;
|
const apiKey = findAppProperty(app, 'apiKey');
|
||||||
if (!apiKey) {
|
if (!apiKey) {
|
||||||
throw new Error(`API Key for app "${app.name}" is missing`);
|
throw new Error(`API Key for app "${app.name}" is missing`);
|
||||||
}
|
}
|
||||||
@@ -232,7 +233,7 @@ export const usenetRouter = createTRPCRouter({
|
|||||||
|
|
||||||
const app = config.apps.find((x) => x.id === input.appId);
|
const app = config.apps.find((x) => x.id === input.appId);
|
||||||
|
|
||||||
if (!app || (app.integration?.type !== 'nzbGet' && app.integration?.type !== 'sabnzbd')) {
|
if (!app || !checkIntegrationsType(app.integration, ['nzbGet', 'sabnzbd'])) {
|
||||||
throw new Error(`App with ID "${input.appId}" could not be found.`);
|
throw new Error(`App with ID "${input.appId}" could not be found.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,8 +242,8 @@ export const usenetRouter = createTRPCRouter({
|
|||||||
const options = {
|
const options = {
|
||||||
host: url.hostname,
|
host: url.hostname,
|
||||||
port: url.port || (url.protocol === 'https:' ? '443' : '80'),
|
port: url.port || (url.protocol === 'https:' ? '443' : '80'),
|
||||||
login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined,
|
login: findAppProperty(app, 'username'),
|
||||||
hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined,
|
hash: findAppProperty(app, 'password'),
|
||||||
};
|
};
|
||||||
|
|
||||||
const nzbGet = NzbgetClient(options);
|
const nzbGet = NzbgetClient(options);
|
||||||
@@ -258,7 +259,7 @@ export const usenetRouter = createTRPCRouter({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiKey = app.integration.properties.find((x) => x.field === 'apiKey')?.value;
|
const apiKey = findAppProperty(app, 'apiKey');
|
||||||
if (!apiKey) {
|
if (!apiKey) {
|
||||||
throw new Error(`API Key for app "${app.name}" is missing`);
|
throw new Error(`API Key for app "${app.name}" is missing`);
|
||||||
}
|
}
|
||||||
@@ -281,7 +282,7 @@ export const usenetRouter = createTRPCRouter({
|
|||||||
|
|
||||||
const app = config.apps.find((x) => x.id === input.appId);
|
const app = config.apps.find((x) => x.id === input.appId);
|
||||||
|
|
||||||
if (!app || (app.integration?.type !== 'nzbGet' && app.integration?.type !== 'sabnzbd')) {
|
if (!app || !checkIntegrationsType(app.integration, ['nzbGet', 'sabnzbd'])) {
|
||||||
throw new Error(`App with ID "${input.appId}" could not be found.`);
|
throw new Error(`App with ID "${input.appId}" could not be found.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,8 +291,8 @@ export const usenetRouter = createTRPCRouter({
|
|||||||
const options = {
|
const options = {
|
||||||
host: url.hostname,
|
host: url.hostname,
|
||||||
port: url.port || (url.protocol === 'https:' ? '443' : '80'),
|
port: url.port || (url.protocol === 'https:' ? '443' : '80'),
|
||||||
login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined,
|
login: findAppProperty(app, 'username'),
|
||||||
hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined,
|
hash: findAppProperty(app, 'password'),
|
||||||
};
|
};
|
||||||
|
|
||||||
const nzbGet = NzbgetClient(options);
|
const nzbGet = NzbgetClient(options);
|
||||||
@@ -340,7 +341,7 @@ export const usenetRouter = createTRPCRouter({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiKey = app.integration.properties.find((x) => x.field === 'apiKey')?.value;
|
const apiKey = findAppProperty(app, 'apiKey');
|
||||||
if (!apiKey) {
|
if (!apiKey) {
|
||||||
throw new Error(`API Key for app "${app.name}" is missing`);
|
throw new Error(`API Key for app "${app.name}" is missing`);
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,27 @@
|
|||||||
import { ConfigAppType, IntegrationField } from '../../types/app';
|
import { ConfigAppType, IntegrationField, IntegrationType } from '../../types/app';
|
||||||
|
|
||||||
export const findAppProperty = (app: ConfigAppType, key: IntegrationField) =>
|
export const findAppProperty = (app: ConfigAppType, key: IntegrationField) =>
|
||||||
app.integration?.properties.find((prop) => prop.field === key)?.value ?? '';
|
app.integration?.properties.find((prop) => prop.field === key)?.value ?? '';
|
||||||
|
|
||||||
|
/** Checks if the type of an integration is part of the TIntegrations array with propper typing */
|
||||||
|
export const checkIntegrationsType = <
|
||||||
|
TTest extends CheckIntegrationTypeInput,
|
||||||
|
TIntegrations extends readonly IntegrationType[]
|
||||||
|
>(
|
||||||
|
test: TTest | undefined | null,
|
||||||
|
integrations: TIntegrations
|
||||||
|
): test is CheckIntegrationType<TTest, TIntegrations> => {
|
||||||
|
if (!test) return false;
|
||||||
|
return integrations.includes(test.type!);
|
||||||
|
};
|
||||||
|
|
||||||
|
type CheckIntegrationTypeInput = {
|
||||||
|
type: IntegrationType | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
type CheckIntegrationType<
|
||||||
|
TInput extends CheckIntegrationTypeInput,
|
||||||
|
TIntegrations extends readonly IntegrationType[]
|
||||||
|
> = TInput & {
|
||||||
|
type: TIntegrations[number];
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user