2022-06-01 15:32:29 +02:00
|
|
|
import axios from 'axios';
|
2023-02-18 15:02:39 +01:00
|
|
|
|
2023-01-10 20:55:35 +01:00
|
|
|
import Consola from 'consola';
|
2023-02-18 15:02:39 +01:00
|
|
|
|
2022-06-01 15:32:29 +02:00
|
|
|
import { NextApiRequest, NextApiResponse } from 'next';
|
2023-02-18 15:02:39 +01:00
|
|
|
|
2022-12-18 22:27:01 +01:00
|
|
|
import { AppIntegrationType } from '../../../types/app';
|
2023-02-18 15:02:39 +01:00
|
|
|
import { getConfig } from '../../../tools/config/getConfig';
|
2022-06-01 15:32:29 +02:00
|
|
|
|
|
|
|
|
export default async (req: NextApiRequest, res: NextApiResponse) => {
|
|
|
|
|
// Filter out if the reuqest is a POST or a GET
|
2022-12-11 14:11:25 +01:00
|
|
|
if (req.method === 'GET') {
|
|
|
|
|
return Get(req, res);
|
2022-06-01 15:32:29 +02:00
|
|
|
}
|
|
|
|
|
return res.status(405).json({
|
|
|
|
|
statusCode: 405,
|
|
|
|
|
message: 'Method not allowed',
|
|
|
|
|
});
|
|
|
|
|
};
|
2022-12-11 14:11:25 +01:00
|
|
|
|
|
|
|
|
async function Get(req: NextApiRequest, res: NextApiResponse) {
|
2022-12-18 22:27:01 +01:00
|
|
|
// Parse req.body as a AppItem
|
2022-12-11 14:11:25 +01:00
|
|
|
const {
|
|
|
|
|
month: monthString,
|
|
|
|
|
year: yearString,
|
|
|
|
|
configName,
|
|
|
|
|
} = req.query as { month: string; year: string; configName: string };
|
|
|
|
|
|
2022-12-17 00:28:46 +09:00
|
|
|
const month = parseInt(monthString, 10);
|
|
|
|
|
const year = parseInt(yearString, 10);
|
2022-12-11 14:11:25 +01:00
|
|
|
|
2022-12-17 00:28:46 +09:00
|
|
|
if (Number.isNaN(month) || Number.isNaN(year) || !configName) {
|
2022-12-11 14:11:25 +01:00
|
|
|
return res.status(400).json({
|
|
|
|
|
statusCode: 400,
|
|
|
|
|
message: 'Missing required parameter in url: year, month or configName',
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const config = getConfig(configName);
|
|
|
|
|
|
2023-02-06 01:09:11 +09:00
|
|
|
// Find the calendar widget in the config
|
|
|
|
|
const calendar = config.widgets.find((w) => w.id === 'calendar');
|
|
|
|
|
const useSonarrv4 = calendar?.properties.useSonarrv4 ?? false;
|
|
|
|
|
|
2022-12-18 22:27:01 +01:00
|
|
|
const mediaAppIntegrationTypes: AppIntegrationType['type'][] = [
|
2022-12-11 14:11:25 +01:00
|
|
|
'sonarr',
|
|
|
|
|
'radarr',
|
|
|
|
|
'readarr',
|
|
|
|
|
'lidarr',
|
|
|
|
|
];
|
2022-12-18 22:27:01 +01:00
|
|
|
const mediaApps = config.apps.filter(
|
2022-12-20 11:45:33 +09:00
|
|
|
(app) => app.integration && mediaAppIntegrationTypes.includes(app.integration.type)
|
2022-12-11 14:11:25 +01:00
|
|
|
);
|
|
|
|
|
|
2023-02-06 01:09:11 +09:00
|
|
|
const IntegrationTypeEndpointMap = new Map<AppIntegrationType['type'], string>([
|
2023-03-03 12:40:49 +09:00
|
|
|
['sonarr', useSonarrv4 ? '/api/v3/calendar' : '/api/calendar'],
|
2023-02-06 01:09:11 +09:00
|
|
|
['radarr', '/api/v3/calendar'],
|
|
|
|
|
['lidarr', '/api/v1/calendar'],
|
|
|
|
|
['readarr', '/api/v1/calendar'],
|
|
|
|
|
]);
|
|
|
|
|
|
2023-01-10 20:55:35 +01:00
|
|
|
try {
|
|
|
|
|
const medias = await Promise.all(
|
|
|
|
|
await mediaApps.map(async (app) => {
|
|
|
|
|
const integration = app.integration!;
|
|
|
|
|
const endpoint = IntegrationTypeEndpointMap.get(integration.type);
|
|
|
|
|
if (!endpoint) {
|
|
|
|
|
return {
|
|
|
|
|
type: integration.type,
|
|
|
|
|
items: [],
|
2023-01-22 00:01:05 +01:00
|
|
|
success: false,
|
2023-01-10 20:55:35 +01:00
|
|
|
};
|
|
|
|
|
}
|
2022-12-11 14:11:25 +01:00
|
|
|
|
2023-01-10 20:55:35 +01:00
|
|
|
// Get the origin URL
|
|
|
|
|
let { href: origin } = new URL(app.url);
|
|
|
|
|
if (origin.endsWith('/')) {
|
|
|
|
|
origin = origin.slice(0, -1);
|
|
|
|
|
}
|
2022-12-11 14:11:25 +01:00
|
|
|
|
2023-01-10 20:55:35 +01:00
|
|
|
const start = new Date(year, month - 1, 1); // First day of month
|
|
|
|
|
const end = new Date(year, month, 0); // Last day of month
|
2022-12-11 14:11:25 +01:00
|
|
|
|
2023-01-10 20:55:35 +01:00
|
|
|
const apiKey = integration.properties.find((x) => x.field === 'apiKey')?.value;
|
2023-01-22 00:01:05 +01:00
|
|
|
if (!apiKey) return { type: integration.type, items: [], success: false };
|
2023-01-10 20:55:35 +01:00
|
|
|
return axios
|
|
|
|
|
.get(
|
2023-02-06 01:09:11 +09:00
|
|
|
`${origin}${endpoint}?apiKey=${apiKey}&end=${end.toISOString()}&start=${start.toISOString()}&includeSeries=true&includeEpisodeFile=true&includeEpisodeImages=true`
|
2023-01-10 20:55:35 +01:00
|
|
|
)
|
2023-01-22 00:01:05 +01:00
|
|
|
.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,
|
|
|
|
|
};
|
|
|
|
|
});
|
2023-01-10 20:55:35 +01:00
|
|
|
})
|
|
|
|
|
);
|
2022-12-11 14:11:25 +01:00
|
|
|
|
2023-02-06 01:09:11 +09:00
|
|
|
const countFailed = medias.filter((x) => !x.success).length;
|
2023-01-22 00:01:05 +01:00
|
|
|
if (countFailed > 0) {
|
|
|
|
|
Consola.warn(`A total of ${countFailed} apps for the calendar widget failed`);
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-10 20:55:35 +01:00
|
|
|
return res.status(200).json({
|
|
|
|
|
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),
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
Consola.error(`Error while requesting media from your app. Check your configuration. ${error}`);
|
|
|
|
|
|
|
|
|
|
return res.status(500).json({
|
|
|
|
|
tvShows: [],
|
|
|
|
|
movies: [],
|
|
|
|
|
books: [],
|
|
|
|
|
musics: [],
|
|
|
|
|
totalCount: 0,
|
|
|
|
|
});
|
|
|
|
|
}
|
2022-12-11 14:11:25 +01:00
|
|
|
}
|