134 lines
6.1 KiB
TypeScript
134 lines
6.1 KiB
TypeScript
import { Router } from 'express'
|
|
import axios from 'axios'
|
|
|
|
const router = Router()
|
|
|
|
router.get('/calendar', async (req, res) => {
|
|
const today = new Date()
|
|
const defaultStart = new Date(today.getFullYear(), today.getMonth(), 1).toISOString().slice(0, 10)
|
|
const defaultEnd = new Date(today.getFullYear(), today.getMonth() + 1, 0).toISOString().slice(0, 10)
|
|
|
|
const start = (req.query.start as string) || defaultStart
|
|
const end = (req.query.end as string) || defaultEnd
|
|
const calParams = { start, end, unmonitored: false }
|
|
|
|
const sonarrHeaders = process.env.SONARR_API_KEY ? { 'X-Api-Key': process.env.SONARR_API_KEY } : null
|
|
|
|
const results = await Promise.allSettled([
|
|
process.env.RADARR_HOST && process.env.RADARR_API_KEY
|
|
? axios.get(`${process.env.RADARR_HOST}/api/v3/calendar`, {
|
|
headers: { 'X-Api-Key': process.env.RADARR_API_KEY },
|
|
params: calParams,
|
|
})
|
|
: Promise.resolve(null),
|
|
|
|
process.env.SONARR_HOST && sonarrHeaders
|
|
? axios.get(`${process.env.SONARR_HOST}/api/v3/calendar`, {
|
|
headers: sonarrHeaders,
|
|
params: calParams,
|
|
})
|
|
: Promise.resolve(null),
|
|
|
|
process.env.SONARR_HOST && sonarrHeaders
|
|
? axios.get(`${process.env.SONARR_HOST}/api/v3/series`, {
|
|
headers: sonarrHeaders,
|
|
})
|
|
: Promise.resolve(null),
|
|
|
|
process.env.LIDARR_HOST && process.env.LIDARR_API_KEY
|
|
? axios.get(`${process.env.LIDARR_HOST}/api/v1/calendar`, {
|
|
headers: { 'X-Api-Key': process.env.LIDARR_API_KEY },
|
|
params: calParams,
|
|
})
|
|
: Promise.resolve(null),
|
|
])
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const radarrData: any[] = results[0].status === 'fulfilled' && results[0].value?.data ? results[0].value.data : []
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const sonarrData: any[] = results[1].status === 'fulfilled' && results[1].value?.data ? results[1].value.data : []
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const seriesList: any[] = results[2].status === 'fulfilled' && results[2].value?.data ? results[2].value.data : []
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const lidarrData: any[] = results[3].status === 'fulfilled' && results[3].value?.data ? results[3].value.data : []
|
|
|
|
const seriesById: Record<number, string> = {}
|
|
for (const s of seriesList) seriesById[s.id] = s.title
|
|
|
|
const items = [
|
|
...radarrData.map(m => ({
|
|
date: (m.digitalRelease ?? m.physicalRelease ?? m.inCinemas ?? '').slice(0, 10),
|
|
title: m.title,
|
|
subtitle: m.year ? String(m.year) : '',
|
|
type: 'movie' as const,
|
|
downloaded: m.hasFile ?? false,
|
|
})).filter(m => m.date),
|
|
|
|
...sonarrData.map(e => ({
|
|
date: (e.airDate ?? '').slice(0, 10),
|
|
title: seriesById[e.seriesId] ?? e.title,
|
|
subtitle: `S${String(e.seasonNumber).padStart(2,'0')}E${String(e.episodeNumber).padStart(2,'0')}${e.title && e.title !== 'TBA' ? ` · ${e.title}` : ''}`,
|
|
type: 'episode' as const,
|
|
downloaded: e.hasFile ?? false,
|
|
})).filter(e => e.date),
|
|
|
|
...lidarrData.map(a => ({
|
|
date: (a.releaseDate ?? '').slice(0, 10),
|
|
title: a.artist?.artistName ?? '',
|
|
subtitle: a.title,
|
|
type: 'album' as const,
|
|
downloaded: a.statistics?.trackFileCount > 0,
|
|
})).filter(a => a.date),
|
|
].sort((a, b) => a.date.localeCompare(b.date))
|
|
|
|
res.json({ items })
|
|
})
|
|
|
|
router.get('/stats', async (_req, res) => {
|
|
const results = await Promise.allSettled([
|
|
process.env.RADARR_HOST && process.env.RADARR_API_KEY ? Promise.all([
|
|
axios.get(`${process.env.RADARR_HOST}/api/v3/movie`, { headers: { 'X-Api-Key': process.env.RADARR_API_KEY } }),
|
|
axios.get(`${process.env.RADARR_HOST}/api/v3/queue/status`, { headers: { 'X-Api-Key': process.env.RADARR_API_KEY } }),
|
|
]) : Promise.resolve(null),
|
|
|
|
process.env.SONARR_HOST && process.env.SONARR_API_KEY ? Promise.all([
|
|
axios.get(`${process.env.SONARR_HOST}/api/v3/series`, { headers: { 'X-Api-Key': process.env.SONARR_API_KEY } }),
|
|
axios.get(`${process.env.SONARR_HOST}/api/v3/wanted/missing?pageSize=1`, { headers: { 'X-Api-Key': process.env.SONARR_API_KEY } }),
|
|
axios.get(`${process.env.SONARR_HOST}/api/v3/queue/status`, { headers: { 'X-Api-Key': process.env.SONARR_API_KEY } }),
|
|
]) : Promise.resolve(null),
|
|
|
|
process.env.LIDARR_HOST && process.env.LIDARR_API_KEY ? Promise.all([
|
|
axios.get(`${process.env.LIDARR_HOST}/api/v1/artist`, { headers: { 'X-Api-Key': process.env.LIDARR_API_KEY } }),
|
|
axios.get(`${process.env.LIDARR_HOST}/api/v1/wanted/missing?pageSize=1`, { headers: { 'X-Api-Key': process.env.LIDARR_API_KEY } }),
|
|
axios.get(`${process.env.LIDARR_HOST}/api/v1/queue/status`, { headers: { 'X-Api-Key': process.env.LIDARR_API_KEY } }),
|
|
]) : Promise.resolve(null),
|
|
])
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const radarr = results[0].status === 'fulfilled' && results[0].value ? results[0].value as any[] : null
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const sonarr = results[1].status === 'fulfilled' && results[1].value ? results[1].value as any[] : null
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const lidarr = results[2].status === 'fulfilled' && results[2].value ? results[2].value as any[] : null
|
|
|
|
res.json({
|
|
radarr: radarr ? {
|
|
movies: radarr[0].data.length,
|
|
missing: radarr[0].data.filter((m: { hasFile: boolean; monitored: boolean }) => !m.hasFile && m.monitored).length,
|
|
queue: radarr[1].data.totalCount ?? 0,
|
|
} : null,
|
|
sonarr: sonarr ? {
|
|
series: sonarr[0].data.length,
|
|
missing: sonarr[1].data.totalRecords ?? 0,
|
|
queue: sonarr[2].data.totalCount ?? 0,
|
|
} : null,
|
|
lidarr: lidarr ? {
|
|
artists: lidarr[0].data.length,
|
|
missing: lidarr[1].data.totalRecords ?? 0,
|
|
queue: lidarr[2].data.totalCount ?? 0,
|
|
} : null,
|
|
})
|
|
})
|
|
|
|
export default router
|