mirror of
https://github.com/fallenbagel/jellyseerr.git
synced 2025-12-24 02:39:18 -05:00
* fix: handle status badge for season packs When a series is downloaded with a season pack, the status tooltip displays only the name of the first episode as a title, and displays a list of all episodes as a description, with the same file being repeated for each episode. This PR fixes this, using the season number as the tooltip title and showing only the season pack file currently being downloaded. * fix: add missing i18n translation
225 lines
6.4 KiB
TypeScript
225 lines
6.4 KiB
TypeScript
import RadarrAPI from '@server/api/servarr/radarr';
|
|
import SonarrAPI from '@server/api/servarr/sonarr';
|
|
import { MediaType } from '@server/constants/media';
|
|
import { getSettings } from '@server/lib/settings';
|
|
import logger from '@server/logger';
|
|
import { uniqWith } from 'lodash';
|
|
|
|
interface EpisodeNumberResult {
|
|
seasonNumber: number;
|
|
episodeNumber: number;
|
|
absoluteEpisodeNumber: number;
|
|
id: number;
|
|
}
|
|
export interface DownloadingItem {
|
|
mediaType: MediaType;
|
|
externalId: number;
|
|
size: number;
|
|
sizeLeft: number;
|
|
status: string;
|
|
timeLeft: string;
|
|
estimatedCompletionTime: Date;
|
|
title: string;
|
|
downloadId: string;
|
|
episode?: EpisodeNumberResult;
|
|
}
|
|
|
|
class DownloadTracker {
|
|
private radarrServers: Record<number, DownloadingItem[]> = {};
|
|
private sonarrServers: Record<number, DownloadingItem[]> = {};
|
|
|
|
public getMovieProgress(
|
|
serverId: number,
|
|
externalServiceId: number
|
|
): DownloadingItem[] {
|
|
if (!this.radarrServers[serverId]) {
|
|
return [];
|
|
}
|
|
|
|
return this.radarrServers[serverId].filter(
|
|
(item) => item.externalId === externalServiceId
|
|
);
|
|
}
|
|
|
|
public getSeriesProgress(
|
|
serverId: number,
|
|
externalServiceId: number
|
|
): DownloadingItem[] {
|
|
if (!this.sonarrServers[serverId]) {
|
|
return [];
|
|
}
|
|
|
|
return this.sonarrServers[serverId].filter(
|
|
(item) => item.externalId === externalServiceId
|
|
);
|
|
}
|
|
|
|
public async resetDownloadTracker() {
|
|
this.radarrServers = {};
|
|
}
|
|
|
|
public updateDownloads() {
|
|
this.updateRadarrDownloads();
|
|
this.updateSonarrDownloads();
|
|
}
|
|
|
|
private async updateRadarrDownloads() {
|
|
const settings = getSettings();
|
|
|
|
// Remove duplicate servers
|
|
const filteredServers = uniqWith(settings.radarr, (radarrA, radarrB) => {
|
|
return (
|
|
radarrA.hostname === radarrB.hostname &&
|
|
radarrA.port === radarrB.port &&
|
|
radarrA.baseUrl === radarrB.baseUrl
|
|
);
|
|
});
|
|
|
|
// Load downloads from Radarr servers
|
|
Promise.all(
|
|
filteredServers.map(async (server) => {
|
|
if (server.syncEnabled) {
|
|
const radarr = new RadarrAPI({
|
|
apiKey: server.apiKey,
|
|
url: RadarrAPI.buildUrl(server, '/api/v3'),
|
|
});
|
|
|
|
try {
|
|
const queueItems = await radarr.getQueue();
|
|
|
|
this.radarrServers[server.id] = queueItems.map((item) => ({
|
|
externalId: item.movieId,
|
|
estimatedCompletionTime: new Date(item.estimatedCompletionTime),
|
|
mediaType: MediaType.MOVIE,
|
|
size: item.size,
|
|
sizeLeft: item.sizeleft,
|
|
status: item.status,
|
|
timeLeft: item.timeleft,
|
|
title: item.title,
|
|
downloadId: item.downloadId,
|
|
}));
|
|
|
|
if (queueItems.length > 0) {
|
|
logger.debug(
|
|
`Found ${queueItems.length} item(s) in progress on Radarr server: ${server.name}`,
|
|
{ label: 'Download Tracker' }
|
|
);
|
|
}
|
|
} catch {
|
|
logger.error(
|
|
`Unable to get queue from Radarr server: ${server.name}`,
|
|
{
|
|
label: 'Download Tracker',
|
|
}
|
|
);
|
|
}
|
|
|
|
// Duplicate this data to matching servers
|
|
const matchingServers = settings.radarr.filter(
|
|
(rs) =>
|
|
rs.hostname === server.hostname &&
|
|
rs.port === server.port &&
|
|
rs.baseUrl === server.baseUrl &&
|
|
rs.id !== server.id
|
|
);
|
|
|
|
if (matchingServers.length > 0) {
|
|
logger.debug(
|
|
`Matching download data to ${matchingServers.length} other Radarr server(s)`,
|
|
{ label: 'Download Tracker' }
|
|
);
|
|
}
|
|
|
|
matchingServers.forEach((ms) => {
|
|
if (ms.syncEnabled) {
|
|
this.radarrServers[ms.id] = this.radarrServers[server.id];
|
|
}
|
|
});
|
|
}
|
|
})
|
|
);
|
|
}
|
|
|
|
private async updateSonarrDownloads() {
|
|
const settings = getSettings();
|
|
|
|
// Remove duplicate servers
|
|
const filteredServers = uniqWith(settings.sonarr, (sonarrA, sonarrB) => {
|
|
return (
|
|
sonarrA.hostname === sonarrB.hostname &&
|
|
sonarrA.port === sonarrB.port &&
|
|
sonarrA.baseUrl === sonarrB.baseUrl
|
|
);
|
|
});
|
|
|
|
// Load downloads from Sonarr servers
|
|
Promise.all(
|
|
filteredServers.map(async (server) => {
|
|
if (server.syncEnabled) {
|
|
const sonarr = new SonarrAPI({
|
|
apiKey: server.apiKey,
|
|
url: SonarrAPI.buildUrl(server, '/api/v3'),
|
|
});
|
|
|
|
try {
|
|
const queueItems = await sonarr.getQueue();
|
|
|
|
this.sonarrServers[server.id] = queueItems.map((item) => ({
|
|
externalId: item.seriesId,
|
|
estimatedCompletionTime: new Date(item.estimatedCompletionTime),
|
|
mediaType: MediaType.TV,
|
|
size: item.size,
|
|
sizeLeft: item.sizeleft,
|
|
status: item.status,
|
|
timeLeft: item.timeleft,
|
|
title: item.title,
|
|
episode: item.episode,
|
|
downloadId: item.downloadId,
|
|
}));
|
|
|
|
if (queueItems.length > 0) {
|
|
logger.debug(
|
|
`Found ${queueItems.length} item(s) in progress on Sonarr server: ${server.name}`,
|
|
{ label: 'Download Tracker' }
|
|
);
|
|
}
|
|
} catch {
|
|
logger.error(
|
|
`Unable to get queue from Sonarr server: ${server.name}`,
|
|
{
|
|
label: 'Download Tracker',
|
|
}
|
|
);
|
|
}
|
|
|
|
// Duplicate this data to matching servers
|
|
const matchingServers = settings.sonarr.filter(
|
|
(ss) =>
|
|
ss.hostname === server.hostname &&
|
|
ss.port === server.port &&
|
|
ss.baseUrl === server.baseUrl &&
|
|
ss.id !== server.id
|
|
);
|
|
|
|
if (matchingServers.length > 0) {
|
|
logger.debug(
|
|
`Matching download data to ${matchingServers.length} other Sonarr server(s)`,
|
|
{ label: 'Download Tracker' }
|
|
);
|
|
}
|
|
|
|
matchingServers.forEach((ms) => {
|
|
if (ms.syncEnabled) {
|
|
this.sonarrServers[ms.id] = this.sonarrServers[server.id];
|
|
}
|
|
});
|
|
}
|
|
})
|
|
);
|
|
}
|
|
}
|
|
|
|
const downloadTracker = new DownloadTracker();
|
|
|
|
export default downloadTracker;
|