feat: feature to specify Radarr server/profile in rule #34
This commit is contained in:
@@ -58,6 +58,23 @@ When matching:
|
||||
|
||||
---
|
||||
|
||||
## Rule request options
|
||||
|
||||
It is possible to specify additional options when a movie is accepted using the `with` entry.
|
||||
|
||||
```yaml title="settings.yaml"
|
||||
- name: The rule name
|
||||
whenMatch: ...
|
||||
action: accept
|
||||
# Optional - request parameters. This must only be defined for rules with accept action
|
||||
with:
|
||||
radarr:
|
||||
server: radarr # Optional - Specify the target radarr to use in a multi radarr setup (uses default radarr when omitted)
|
||||
profile: 4K # Optional - Specify the target profile to use (uses default profile when omitted)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Ruleset extension
|
||||
|
||||
Using the `extends` property of a ruleset, you can add rules to an existing ruleset.
|
||||
@@ -71,10 +88,11 @@ config:
|
||||
- name: exclude-netflix
|
||||
rules:
|
||||
- name: Exclude netflix movies
|
||||
watchProviders:
|
||||
- region: us
|
||||
- names:
|
||||
- Netflix
|
||||
whenMatch:
|
||||
- watchProviders:
|
||||
region: us
|
||||
names:
|
||||
- Netflix
|
||||
action: reject
|
||||
- name: filter-movies
|
||||
extends: exclude-netflix # movie will be evaluated against exclude-netflix rules first
|
||||
@@ -86,6 +104,8 @@ config:
|
||||
action: accept
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Ruleset example
|
||||
|
||||
The following ruleset will:
|
||||
|
||||
@@ -1,242 +1,263 @@
|
||||
{
|
||||
"title": "Overcrawlrr configuration",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"config": {
|
||||
"type": "object",
|
||||
"required": ["overseerr", "discovery", "rulesets"],
|
||||
"properties": {
|
||||
"overseerr": { "$ref": "#/definitions/overseer" },
|
||||
"plex": { "$ref": "#/definitions/plex" },
|
||||
"discovery": { "$ref": "#/definitions/discovery"},
|
||||
"smartRecommendations": { "$ref": "#/definitions/smartRecommendations"},
|
||||
"rulesets": { "$ref": "#/definitions/rulesets"}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
|
||||
"overseer": {
|
||||
"$id": "#/definitions/overseer",
|
||||
"type": "object",
|
||||
"required": ["apiUrl", "user", "password"],
|
||||
"properties": {
|
||||
"apiUrl": { "type": "string" },
|
||||
"user": { "type": "string" },
|
||||
"password": { "type": "string" },
|
||||
"dryRunUrl": { "type": "boolean" }
|
||||
}
|
||||
},
|
||||
|
||||
"plex": {
|
||||
"$id": "#/definitions/plex",
|
||||
"type": "object",
|
||||
"required": ["apiUrl", "plexToken"],
|
||||
"properties": {
|
||||
"apiUrl": { "type": "string" },
|
||||
"plexToken": { "type": "string" }
|
||||
}
|
||||
},
|
||||
|
||||
"discovery": {
|
||||
"$id": "#/definitions/discovery",
|
||||
"type": "object",
|
||||
"required": ["cron", "streams", "ruleset"],
|
||||
"properties": {
|
||||
"cron": { "type": "string" },
|
||||
"ruleset": { "type": "string" },
|
||||
"streams": { "type": "array", "items": { "type": "string" }}
|
||||
}
|
||||
},
|
||||
|
||||
"smartRecommendations": {
|
||||
"$id": "#/definitions/smartRecommendations",
|
||||
"type": "object",
|
||||
"required": ["cron", "plexLibrary", "ruleset", "minimumRating"],
|
||||
"properties": {
|
||||
"cron": { "type": "string" },
|
||||
"plexLibrary": { "type": "string" },
|
||||
"ruleset": { "type": "string" },
|
||||
"minimumRating": { "type": "number"}
|
||||
}
|
||||
},
|
||||
|
||||
"rulesets": {
|
||||
"$id": "#/definitions/rulesets",
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/definitions/ruleset" }
|
||||
},
|
||||
|
||||
"ruleset": {
|
||||
"$id": "#/definitions/ruleset",
|
||||
"type": "object",
|
||||
"required": ["name", "rules"],
|
||||
"properties": {
|
||||
"name": { "type": "string" },
|
||||
"extends": { "type": "string" },
|
||||
"rules": { "type": "array", "items": { "$ref": "#/definitions/rule" }}
|
||||
}
|
||||
},
|
||||
|
||||
"rule": {
|
||||
"$id": "#/definitions/rule",
|
||||
"type": "object",
|
||||
"required": ["name", "whenMatch", "action"],
|
||||
"properties": {
|
||||
"name": { "type": "string" },
|
||||
"whenMatch": { "type": "array", "items": { "$ref": "#/definitions/predicate" }},
|
||||
"action": { "type": "string", "enum": ["accept", "reject", "skip"]}
|
||||
}
|
||||
},
|
||||
|
||||
"predicate": {
|
||||
"$id": "#/definitions/predicate",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"or": { "$ref": "#/definitions/orPredicate" },
|
||||
"and": { "$ref": "#/definitions/andPredicate" },
|
||||
"not": { "$ref": "#/definitions/notPredicate" },
|
||||
"adult": { "$ref": "#/definitions/adultPredicate" },
|
||||
"age": { "$ref": "#/definitions/agePredicate" },
|
||||
"score": { "$ref": "#/definitions/scorePredicate" },
|
||||
"genre": { "$ref": "#/definitions/genrePredicate" },
|
||||
"keyword": { "$ref": "#/definitions/keywordPredicate" },
|
||||
"watchProviders": { "$ref": "#/definitions/watchProvidersPredicate" },
|
||||
"voteCount": { "$ref": "#/definitions/voteCountPredicate" },
|
||||
"cast": { "$ref": "#/definitions/castPredicate" },
|
||||
"crew": { "$ref": "#/definitions/crewPredicate" },
|
||||
"released": { "$ref": "#/definitions/releasedPredicate" },
|
||||
"runtime": { "$ref": "#/definitions/runtimePredicate" },
|
||||
"productionCompany": { "$ref": "#/definitions/productionCompanyPredicate" },
|
||||
"originalLanguage": { "$ref": "#/definitions/originalLanguagePredicate" },
|
||||
"status": { "$ref": "#/definitions/statusPredicate" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"orPredicate": {
|
||||
"$id": "#/definitions/orPredicate",
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/definitions/predicate" }
|
||||
},
|
||||
|
||||
"andPredicate": {
|
||||
"$id": "#/definitions/andPredicate",
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/definitions/predicate" }
|
||||
},
|
||||
|
||||
"notPredicate": {
|
||||
"$id": "#/definitions/notPredicate",
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/definitions/predicate" }
|
||||
},
|
||||
|
||||
"adultPredicate": {
|
||||
"$id": "#/definitions/adultPredicate",
|
||||
"type": "string",
|
||||
"enum": ["yes", "no"]
|
||||
},
|
||||
|
||||
"agePredicate": {
|
||||
"$id": "#/definitions/agePredicate",
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
"releasedPredicate": {
|
||||
"$id": "#/definitions/releasedPredicate",
|
||||
"type": "string",
|
||||
"enum": ["yes", "no"]
|
||||
},
|
||||
|
||||
"scorePredicate": {
|
||||
"$id": "#/definitions/scorePredicate",
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
"voteCountPredicate": {
|
||||
"$id": "#/definitions/voteCountPredicate",
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
"genrePredicate": {
|
||||
"$id": "#/definitions/genrePredicate",
|
||||
"oneOf": [
|
||||
{ "type": "string" },
|
||||
{ "type": "array", "items": { "type": "string" }}
|
||||
]
|
||||
},
|
||||
|
||||
"keywordPredicate": {
|
||||
"$id": "#/definitions/keywordPredicate",
|
||||
"oneOf": [
|
||||
{ "type": "string" },
|
||||
{ "type": "array", "items": { "type": "string" }}
|
||||
]
|
||||
},
|
||||
|
||||
"watchProvidersPredicate": {
|
||||
"$id": "#/definitions/watchProvidersPredicate",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"region": { "type": "string"},
|
||||
"names": { "type": "array", "items": { "type": "string" }}
|
||||
}
|
||||
},
|
||||
|
||||
"castPredicate": {
|
||||
"$id": "#/definitions/castPredicate",
|
||||
"oneOf": [
|
||||
{ "type": "array", "items": { "type": "string" }},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"voice": { "type": "string", "enum": ["include", "exclude"]},
|
||||
"names": { "type": "array", "items": {"type": "string" }}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"crewPredicate": {
|
||||
"$id": "#/definitions/crewPredicate",
|
||||
"oneOf": [
|
||||
{ "type": "array", "items": { "type": "string" }},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"job": { "type": "string"},
|
||||
"names": { "type": "array", "items": {"type": "string" }}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"productionCompanyPredicate": {
|
||||
"$id": "#/definitions/productionCompanyPredicate",
|
||||
"type": "array",
|
||||
"items": {"type": "string" }
|
||||
},
|
||||
|
||||
"runtimePredicate": {
|
||||
"$id": "#/definitions/runtimePredicate",
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
"originalLanguagePredicate": {
|
||||
"$id": "#/definitions/originalLanguagePredicate",
|
||||
"oneOf": [
|
||||
{ "type": "string" },
|
||||
{ "type": "array", "items": { "type": "string" }}
|
||||
]
|
||||
},
|
||||
|
||||
"statusPredicate": {
|
||||
"$id": "#/definitions/statusPredicate",
|
||||
"oneOf": [
|
||||
{ "type": "string" },
|
||||
{ "type": "array", "items": { "type": "string" }}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
"title": "Overcrawlrr configuration",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"config": {
|
||||
"type": "object",
|
||||
"required": ["overseerr", "discovery", "rulesets"],
|
||||
"properties": {
|
||||
"overseerr": { "$ref": "#/definitions/overseer" },
|
||||
"plex": { "$ref": "#/definitions/plex" },
|
||||
"discovery": { "$ref": "#/definitions/discovery"},
|
||||
"smartRecommendations": { "$ref": "#/definitions/smartRecommendations"},
|
||||
"rulesets": { "$ref": "#/definitions/rulesets"}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
|
||||
"overseer": {
|
||||
"$id": "#/definitions/overseer",
|
||||
"type": "object",
|
||||
"required": ["apiUrl", "user", "password"],
|
||||
"properties": {
|
||||
"apiUrl": { "type": "string" },
|
||||
"user": { "type": "string" },
|
||||
"password": { "type": "string" },
|
||||
"dryRun": { "type": "boolean" }
|
||||
}
|
||||
},
|
||||
|
||||
"plex": {
|
||||
"$id": "#/definitions/plex",
|
||||
"type": "object",
|
||||
"required": ["apiUrl", "plexToken"],
|
||||
"properties": {
|
||||
"apiUrl": { "type": "string" },
|
||||
"plexToken": { "type": "string" }
|
||||
}
|
||||
},
|
||||
|
||||
"discovery": {
|
||||
"$id": "#/definitions/discovery",
|
||||
"type": "object",
|
||||
"required": ["cron", "streams", "ruleset"],
|
||||
"properties": {
|
||||
"cron": { "type": "string" },
|
||||
"ruleset": { "type": "string" },
|
||||
"streams": { "type": "array", "items": { "type": "string" }}
|
||||
}
|
||||
},
|
||||
|
||||
"smartRecommendations": {
|
||||
"$id": "#/definitions/smartRecommendations",
|
||||
"type": "object",
|
||||
"required": ["cron", "plexLibrary", "ruleset", "minimumRating"],
|
||||
"properties": {
|
||||
"cron": { "type": "string" },
|
||||
"plexLibrary": { "type": "string" },
|
||||
"ruleset": { "type": "string" },
|
||||
"minimumRating": { "type": "number"}
|
||||
}
|
||||
},
|
||||
|
||||
"rulesets": {
|
||||
"$id": "#/definitions/rulesets",
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/definitions/ruleset" }
|
||||
},
|
||||
|
||||
"ruleset": {
|
||||
"$id": "#/definitions/ruleset",
|
||||
"type": "object",
|
||||
"required": ["name", "rules"],
|
||||
"properties": {
|
||||
"name": { "type": "string" },
|
||||
"extends": { "type": "string" },
|
||||
"rules": { "type": "array", "items": { "$ref": "#/definitions/rule" }}
|
||||
}
|
||||
},
|
||||
|
||||
"rule": {
|
||||
"$id": "#/definitions/rule",
|
||||
"type": "object",
|
||||
"required": ["name", "whenMatch", "action"],
|
||||
"properties": {
|
||||
"name": { "type": "string" },
|
||||
"whenMatch": { "type": "array", "items": { "$ref": "#/definitions/predicate" }},
|
||||
"action": { "type": "string", "enum": ["accept", "reject", "skip"]},
|
||||
"with": { "$ref": "#/definitions/ruleParameters" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"ruleParameters": {
|
||||
"$id": "#/definitions/ruleParameters",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"radarr": { "$ref": "#/definitions/ruleServiceParameters"}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"ruleServiceParameters": {
|
||||
"$id": "#/definitions/ruleServiceParameters",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"server": { "type": "string"},
|
||||
"profile": { "type": "string"}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"predicate": {
|
||||
"$id": "#/definitions/predicate",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"or": { "$ref": "#/definitions/orPredicate" },
|
||||
"and": { "$ref": "#/definitions/andPredicate" },
|
||||
"not": { "$ref": "#/definitions/notPredicate" },
|
||||
"adult": { "$ref": "#/definitions/adultPredicate" },
|
||||
"age": { "$ref": "#/definitions/agePredicate" },
|
||||
"score": { "$ref": "#/definitions/scorePredicate" },
|
||||
"genre": { "$ref": "#/definitions/genrePredicate" },
|
||||
"keyword": { "$ref": "#/definitions/keywordPredicate" },
|
||||
"watchProviders": { "$ref": "#/definitions/watchProvidersPredicate" },
|
||||
"voteCount": { "$ref": "#/definitions/voteCountPredicate" },
|
||||
"cast": { "$ref": "#/definitions/castPredicate" },
|
||||
"crew": { "$ref": "#/definitions/crewPredicate" },
|
||||
"released": { "$ref": "#/definitions/releasedPredicate" },
|
||||
"runtime": { "$ref": "#/definitions/runtimePredicate" },
|
||||
"productionCompany": { "$ref": "#/definitions/productionCompanyPredicate" },
|
||||
"originalLanguage": { "$ref": "#/definitions/originalLanguagePredicate" },
|
||||
"status": { "$ref": "#/definitions/statusPredicate" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"orPredicate": {
|
||||
"$id": "#/definitions/orPredicate",
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/definitions/predicate" }
|
||||
},
|
||||
|
||||
"andPredicate": {
|
||||
"$id": "#/definitions/andPredicate",
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/definitions/predicate" }
|
||||
},
|
||||
|
||||
"notPredicate": {
|
||||
"$id": "#/definitions/notPredicate",
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/definitions/predicate" }
|
||||
},
|
||||
|
||||
"adultPredicate": {
|
||||
"$id": "#/definitions/adultPredicate",
|
||||
"type": "string",
|
||||
"enum": ["yes", "no"]
|
||||
},
|
||||
|
||||
"agePredicate": {
|
||||
"$id": "#/definitions/agePredicate",
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
"releasedPredicate": {
|
||||
"$id": "#/definitions/releasedPredicate",
|
||||
"type": "string",
|
||||
"enum": ["yes", "no"]
|
||||
},
|
||||
|
||||
"scorePredicate": {
|
||||
"$id": "#/definitions/scorePredicate",
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
"voteCountPredicate": {
|
||||
"$id": "#/definitions/voteCountPredicate",
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
"genrePredicate": {
|
||||
"$id": "#/definitions/genrePredicate",
|
||||
"oneOf": [
|
||||
{ "type": "string" },
|
||||
{ "type": "array", "items": { "type": "string" }}
|
||||
]
|
||||
},
|
||||
|
||||
"keywordPredicate": {
|
||||
"$id": "#/definitions/keywordPredicate",
|
||||
"oneOf": [
|
||||
{ "type": "string" },
|
||||
{ "type": "array", "items": { "type": "string" }}
|
||||
]
|
||||
},
|
||||
|
||||
"watchProvidersPredicate": {
|
||||
"$id": "#/definitions/watchProvidersPredicate",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"region": { "type": "string"},
|
||||
"names": { "type": "array", "items": { "type": "string" }}
|
||||
}
|
||||
},
|
||||
|
||||
"castPredicate": {
|
||||
"$id": "#/definitions/castPredicate",
|
||||
"oneOf": [
|
||||
{ "type": "array", "items": { "type": "string" }},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"voice": { "type": "string", "enum": ["include", "exclude"]},
|
||||
"names": { "type": "array", "items": {"type": "string" }}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"crewPredicate": {
|
||||
"$id": "#/definitions/crewPredicate",
|
||||
"oneOf": [
|
||||
{ "type": "array", "items": { "type": "string" }},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"job": { "type": "string"},
|
||||
"names": { "type": "array", "items": {"type": "string" }}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"productionCompanyPredicate": {
|
||||
"$id": "#/definitions/productionCompanyPredicate",
|
||||
"type": "array",
|
||||
"items": {"type": "string" }
|
||||
},
|
||||
|
||||
"runtimePredicate": {
|
||||
"$id": "#/definitions/runtimePredicate",
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
"originalLanguagePredicate": {
|
||||
"$id": "#/definitions/originalLanguagePredicate",
|
||||
"oneOf": [
|
||||
{ "type": "string" },
|
||||
{ "type": "array", "items": { "type": "string" }}
|
||||
]
|
||||
},
|
||||
|
||||
"statusPredicate": {
|
||||
"$id": "#/definitions/statusPredicate",
|
||||
"oneOf": [
|
||||
{ "type": "string" },
|
||||
{ "type": "array", "items": { "type": "string" }}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,25 @@
|
||||
import HttpApi from '@core/api/httpApi';
|
||||
import { getSettings } from '@core/lib/settings';
|
||||
import logger from '@core/log';
|
||||
import { AuthResponse, MediaRequest, MovieDetails, MovieResult, OverseerrRequestsResult, OverseerrResult } from '@core/api/overseerr/interfaces';
|
||||
import { getErrorMessage, success } from '@core/lib/utils';
|
||||
import {
|
||||
AuthResponse,
|
||||
MediaRequest,
|
||||
MovieDetails,
|
||||
MovieResult,
|
||||
OverseerrRequestsResult,
|
||||
OverseerrResult,
|
||||
RadarrProfile,
|
||||
RadarrService,
|
||||
RadarrServiceDetails,
|
||||
RequestOption,
|
||||
} from '@core/api/overseerr/interfaces';
|
||||
import { getErrorMessage, isFulfilled, success } from '@core/lib/utils';
|
||||
import NodeCache from 'node-cache';
|
||||
|
||||
class OverseerrApi extends HttpApi {
|
||||
private overseerrUser?: string;
|
||||
private overseerrPassword?: string;
|
||||
private radarrCache?: NodeCache;
|
||||
|
||||
constructor() {
|
||||
super(getSettings().overseerr.apiUrl, {});
|
||||
@@ -76,16 +89,73 @@ class OverseerrApi extends HttpApi {
|
||||
return (await this.get<OverseerrResult<MovieResult>>(`/movie/${idMovie}/recommendations`)).results;
|
||||
};
|
||||
|
||||
public requestMovie = async (idMovie: number) => {
|
||||
public requestMovie = async (idMovie: number, options: Partial<RequestOption> = {}) => {
|
||||
try {
|
||||
return await this.post(`/request`, {
|
||||
const request = {
|
||||
mediaType: 'movie',
|
||||
mediaId: idMovie,
|
||||
});
|
||||
} as Partial<MediaRequest>;
|
||||
|
||||
if (options.server) {
|
||||
const radarrServer = await this.getRadarr(options.server);
|
||||
request.serverId = radarrServer.server.id;
|
||||
}
|
||||
|
||||
if (options.profile) {
|
||||
const radarrProfile = await this.getRadarrProfile(options.server ?? `default${options.is4k ? '4k' : ''}`, options.profile);
|
||||
request.profileId = radarrProfile.id;
|
||||
}
|
||||
return await this.post(`/request`, request);
|
||||
} catch (e) {
|
||||
logger.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
private getRadarrCache = async (): Promise<NodeCache> => {
|
||||
if (!this.radarrCache) {
|
||||
this.radarrCache = new NodeCache();
|
||||
logger.info('Fetching list of Radarr services...');
|
||||
const servers = await this.get<Array<RadarrService>>(`/service/radarr`);
|
||||
|
||||
const registerServer = (service: RadarrServiceDetails) => {
|
||||
this.radarrCache!.set(`server:${service.server.name}`, service);
|
||||
if (service.server.isDefault) {
|
||||
if (service.server.is4k) {
|
||||
this.radarrCache!.set(`server:default4k`, service);
|
||||
} else {
|
||||
this.radarrCache!.set(`server:default`, service);
|
||||
}
|
||||
}
|
||||
logger.info(`Found Radarr server ${service.server.name} with profiles ${service.profiles.map((s) => s.name).join(', ')}`);
|
||||
};
|
||||
const services: Array<PromiseSettledResult<RadarrServiceDetails>> = await Promise.allSettled(
|
||||
servers.map((s) => this.get<RadarrServiceDetails>(`/service/radarr/${s.id}`))
|
||||
);
|
||||
services
|
||||
.filter(isFulfilled)
|
||||
.map((r) => r.value)
|
||||
.forEach(registerServer);
|
||||
}
|
||||
return this.radarrCache;
|
||||
};
|
||||
|
||||
public getRadarr = async (serverName: string): Promise<RadarrServiceDetails> => {
|
||||
const cache = await this.getRadarrCache();
|
||||
const fromCache = cache.get<RadarrServiceDetails>(`server:${serverName}`);
|
||||
if (fromCache) {
|
||||
return fromCache;
|
||||
}
|
||||
throw new Error(`Radarr server ${serverName} not found. Check the spelling, and make sure it exists in Overseerr.`);
|
||||
};
|
||||
|
||||
public getRadarrProfile = async (serverName: string, profileName: string): Promise<RadarrProfile> => {
|
||||
const radarr = await this.getRadarr(serverName);
|
||||
const profile = radarr.profiles.find((p) => p.name === profileName);
|
||||
if (profile) {
|
||||
return profile;
|
||||
}
|
||||
throw new Error(`Radarr profile ${profileName} not found for server ${serverName}`);
|
||||
};
|
||||
}
|
||||
|
||||
export default OverseerrApi;
|
||||
|
||||
@@ -182,3 +182,26 @@ export interface Genre {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface RadarrService {
|
||||
id: number;
|
||||
name: string;
|
||||
is4k: boolean;
|
||||
isDefault: boolean;
|
||||
}
|
||||
|
||||
export interface RadarrServiceDetails {
|
||||
server: RadarrService;
|
||||
profiles: RadarrProfile[];
|
||||
}
|
||||
|
||||
export interface RequestOption {
|
||||
server: string;
|
||||
profile: string;
|
||||
is4k: boolean;
|
||||
}
|
||||
|
||||
export interface RadarrProfile {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { MovieDetails } from '@core/api/overseerr/interfaces';
|
||||
import { PredicateOption, RuleAction } from '@core/lib/rules/interfaces';
|
||||
import { PredicateOption, RuleAction, RuleParameters } from '@core/lib/rules/interfaces';
|
||||
import { PredicateFactoryClass } from '@core/lib/rules/factory';
|
||||
|
||||
export abstract class Predicate {
|
||||
@@ -24,11 +24,13 @@ export class Rule {
|
||||
public name: string;
|
||||
public filter: Predicate[];
|
||||
public action: RuleAction;
|
||||
public with?: RuleParameters;
|
||||
|
||||
constructor(name: string, filter: Predicate[], action: RuleAction) {
|
||||
constructor(name: string, filter: Predicate[], action: RuleAction, options?: RuleParameters) {
|
||||
this.name = name;
|
||||
this.filter = filter;
|
||||
this.action = action;
|
||||
this.with = options;
|
||||
}
|
||||
|
||||
public matches(movie: MovieDetails): boolean {
|
||||
|
||||
@@ -10,6 +10,7 @@ export interface RuleOptions {
|
||||
name: string;
|
||||
whenMatch: PredicateOption[];
|
||||
action: RuleAction;
|
||||
with?: RuleParameters;
|
||||
}
|
||||
|
||||
export type PredicateOption =
|
||||
@@ -113,3 +114,12 @@ export type RuntimeOptions = {
|
||||
export type StatusOptions = {
|
||||
status: string | string[];
|
||||
};
|
||||
|
||||
export type RuleParameters = {
|
||||
radarr: RuleServiceParameters;
|
||||
};
|
||||
|
||||
export type RuleServiceParameters = {
|
||||
server?: string;
|
||||
profile?: string;
|
||||
};
|
||||
|
||||
@@ -39,7 +39,7 @@ class Ruleset {
|
||||
}
|
||||
|
||||
private buildRules(): void {
|
||||
this._rules = this._rulesetOptions.rules.map((o) => new Rule(o.name, PredicateFactory.buildPredicates(o.whenMatch), o.action));
|
||||
this._rules = this._rulesetOptions.rules.map((o) => new Rule(o.name, PredicateFactory.buildPredicates(o.whenMatch), o.action, o.with));
|
||||
}
|
||||
|
||||
public evaluateRules(movie: MovieDetails): RuleEvaluation {
|
||||
|
||||
@@ -82,7 +82,6 @@ apiRouter.use('/smartRecommendations', async (req, res) => {
|
||||
message: 'Smart recommendations complete !',
|
||||
});
|
||||
} catch (e: unknown) {
|
||||
console.log(e);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: getErrorMessage(e),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import logger from '@core/log';
|
||||
import { getSettings } from '@core/lib/settings';
|
||||
import OverseerrApi from '@core/api/overseerr';
|
||||
import { MediaStatus, MovieResult } from '@core/api/overseerr/interfaces';
|
||||
import { MediaStatus, MovieResult, RequestOption } from '@core/api/overseerr/interfaces';
|
||||
import Ruleset, { getRuleset } from '@core/lib/ruleset';
|
||||
import { color, distinctMovies, isFulfilled, isMovie, success } from '@core/lib/utils';
|
||||
import PlexApi from '@core/api/plex';
|
||||
@@ -25,7 +25,11 @@ const processMovieResult = async (movies: MovieResult[], overseerr: OverseerrApi
|
||||
if (dryRun) {
|
||||
logger.info(`Dry run - A request would have been sent to Overseerr to request movie ${movie.title}`);
|
||||
} else {
|
||||
await overseerr.requestMovie(movie.id);
|
||||
const options = {
|
||||
...(ruleResult.rule?.with?.radarr ?? {}),
|
||||
} as RequestOption;
|
||||
|
||||
await overseerr.requestMovie(movie.id, options);
|
||||
}
|
||||
} else if (ruleResult.result === 'reject') {
|
||||
logger.info(`${color.red(' Rejecting')} - "${ruleResult.movie.title}" because of rule "${color.blue(ruleResult.rule?.name ?? '')}"`);
|
||||
|
||||
Reference in New Issue
Block a user