Merge pull request #10 from psyko-gh/feature-voice-cast
Added voice option in cast predicate + Docs lint
This commit is contained in:
2
.github/workflows/contribution.yaml
vendored
2
.github/workflows/contribution.yaml
vendored
@@ -24,6 +24,8 @@ jobs:
|
|||||||
run: npm run lint
|
run: npm run lint
|
||||||
- name: Format
|
- name: Format
|
||||||
run: npm run format
|
run: npm run format
|
||||||
|
- name: Docs format
|
||||||
|
run: npm run format-docs
|
||||||
- name: Build
|
- name: Build
|
||||||
run: npm run build
|
run: npm run build
|
||||||
- name: Tests
|
- name: Tests
|
||||||
|
|||||||
@@ -67,21 +67,23 @@ config:
|
|||||||
- name: Accept favorites actors
|
- name: Accept favorites actors
|
||||||
whenMatch:
|
whenMatch:
|
||||||
- cast:
|
- cast:
|
||||||
- Jenna Ortega
|
voice: exclude
|
||||||
- Michael Keaton
|
names:
|
||||||
- Denzel Washington
|
- Jenna Ortega
|
||||||
- Keanu Reeves
|
- Michael Keaton
|
||||||
- Jessica Alba
|
- Denzel Washington
|
||||||
- Halle Berry
|
- Keanu Reeves
|
||||||
- Sydney Sweeney
|
- Jessica Alba
|
||||||
- Tom Hanks
|
- Halle Berry
|
||||||
- Samuel L. Jackson
|
- Sydney Sweeney
|
||||||
- Morgan Freeman
|
- Tom Hanks
|
||||||
- Anthony Hopkins
|
- Samuel L. Jackson
|
||||||
- Gal Gadot
|
- Morgan Freeman
|
||||||
- Tom Cruise
|
- Anthony Hopkins
|
||||||
- Brad Pitt
|
- Gal Gadot
|
||||||
- Matt Damon
|
- Tom Cruise
|
||||||
|
- Brad Pitt
|
||||||
|
- Matt Damon
|
||||||
action: accept
|
action: accept
|
||||||
- name: Reject declining actors
|
- name: Reject declining actors
|
||||||
whenMatch:
|
whenMatch:
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# Schema
|
# Schema
|
||||||
|
|
||||||
The JSON Schema is available here: https://github.com/psyko-gh/overcrawlrr/blob/master/schema/schema.json
|
The JSON Schema is available here: https://github.com/psyko-gh/overcrawlrr/blob/master/schema/schema.json
|
||||||
|
|||||||
@@ -9,25 +9,27 @@ Overcrawlrr configuration is defined in the `settings.yaml` searched by default
|
|||||||
---
|
---
|
||||||
|
|
||||||
### Overseerr authentication
|
### Overseerr authentication
|
||||||
|
|
||||||
Overcrawlrr need to authenticate to Overseerr to fetch movie information and create movie requests.
|
Overcrawlrr need to authenticate to Overseerr to fetch movie information and create movie requests.
|
||||||
|
|
||||||
It is recommended to create a [local user in Overseerr](https://docs.overseerr.dev/using-overseerr/users#creating-local-users) dedicated to Overcrawlrr.
|
It is recommended to create a [local user in Overseerr](https://docs.overseerr.dev/using-overseerr/users#creating-local-users) dedicated to Overcrawlrr.
|
||||||
Doing so, you can have fine-grained control on its permissions:
|
Doing so, you can have fine-grained control on its permissions:
|
||||||
|
|
||||||
- Allow/deny automatic requests validation,
|
- Allow/deny automatic requests validation,
|
||||||
- Allow/deny to request in 4K,
|
- Allow/deny to request in 4K,
|
||||||
- Specify the languages and the region when discovering movies,
|
- Specify the languages and the region when discovering movies,
|
||||||
- And more...
|
- And more...
|
||||||
|
|
||||||
Once the user is created, you can fill these value in Overcrawlrr `settings.yaml`:
|
Once the user is created, you can fill these value in Overcrawlrr `settings.yaml`:
|
||||||
|
|
||||||
```yaml title="settings.yaml"
|
```yaml title="settings.yaml"
|
||||||
config:
|
config:
|
||||||
overseerr:
|
overseerr:
|
||||||
apiUrl: xxx # required
|
apiUrl: xxx # required
|
||||||
user: xxx # required
|
user: xxx # required
|
||||||
password: xxx # required
|
password: xxx # required
|
||||||
dryRun: true # Optional - dryRun will not send requests to Overseerr
|
dryRun: true # Optional - dryRun will not send requests to Overseerr
|
||||||
# allowing you to test your rules
|
# allowing you to test your rules
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -39,37 +41,38 @@ Once the user is created, you can fill these value in Overcrawlrr `settings.yaml
|
|||||||
This authentication is optional and only required if you're using the Smart Recommendations job
|
This authentication is optional and only required if you're using the Smart Recommendations job
|
||||||
|
|
||||||
To read data from your Plex library, you have to specify your Plex URL and token in `settings.yaml`:
|
To read data from your Plex library, you have to specify your Plex URL and token in `settings.yaml`:
|
||||||
|
|
||||||
```yaml title="settings.yaml"
|
```yaml title="settings.yaml"
|
||||||
config:
|
config:
|
||||||
# Only required when using Smart recommendations job
|
# Only required when using Smart recommendations job
|
||||||
plex:
|
plex:
|
||||||
apiUrl: xxx
|
apiUrl: xxx
|
||||||
plexToken: xxx
|
plexToken: xxx
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Using environment variables
|
### Using environment variables
|
||||||
|
|
||||||
You can refer to environment variables using the `{{ key }}` syntax.
|
You can refer to environment variables using the `{{ key }}` syntax.
|
||||||
|
|
||||||
```yaml title="settings.yaml"
|
```yaml title="settings.yaml"
|
||||||
config:
|
config:
|
||||||
overseerr:
|
overseerr:
|
||||||
apiUrl: xxx
|
apiUrl: xxx
|
||||||
user: '{{ OVERSEERR_USER }}'
|
user: '{{ OVERSEERR_USER }}'
|
||||||
password: '{{ OVERSEERR_PASSWORD }}'
|
password: '{{ OVERSEERR_PASSWORD }}'
|
||||||
```
|
```
|
||||||
|
|
||||||
These variables can be defined in the `docker-compose.yaml`
|
These variables can be defined in the `docker-compose.yaml`
|
||||||
|
|
||||||
```yaml title="docker-compose.yaml"
|
```yaml title="docker-compose.yaml"
|
||||||
services:
|
services:
|
||||||
overcrawlrr:
|
overcrawlrr:
|
||||||
# ...
|
# ...
|
||||||
environment:
|
environment:
|
||||||
- OVERSEERR_USER=
|
- OVERSEERR_USER=
|
||||||
- OVERSEERR_PASSWORD=
|
- OVERSEERR_PASSWORD=
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -4,23 +4,21 @@
|
|||||||
|
|
||||||
Using Overcrawlrr requires you to have a running instance of Overseerr
|
Using Overcrawlrr requires you to have a running instance of Overseerr
|
||||||
|
|
||||||
|
|
||||||
With docker-compose
|
With docker-compose
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
services:
|
services:
|
||||||
overcrawlrr:
|
overcrawlrr:
|
||||||
image: ghcr.io/psyko-gh/overcrawlrr:latest
|
image: ghcr.io/psyko-gh/overcrawlrr:latest
|
||||||
container_name: overcrawlrr
|
container_name: overcrawlrr
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- 5056:5056
|
- 5056:5056
|
||||||
environment:
|
environment:
|
||||||
- OVERSEERR_USER=
|
- OVERSEERR_USER=
|
||||||
- OVERSEERR_PASSWORD=
|
- OVERSEERR_PASSWORD=
|
||||||
volumes:
|
volumes:
|
||||||
- /path/to/config:/config
|
- /path/to/config:/config
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
With docker cli
|
With docker cli
|
||||||
|
|||||||
67
docs/jobs.md
67
docs/jobs.md
@@ -10,19 +10,19 @@ It will fetch movies from Overseerr _(from the upcoming/popular/trending section
|
|||||||
|
|
||||||
```yaml title="settings.yaml"
|
```yaml title="settings.yaml"
|
||||||
config:
|
config:
|
||||||
overseer:
|
overseer:
|
||||||
# ....
|
# ....
|
||||||
discovery:
|
discovery:
|
||||||
# Required
|
# Required
|
||||||
cron: '30 3 * * *'
|
cron: '30 3 * * *'
|
||||||
# Required - the overseer streams to search through
|
# Required - the overseer streams to search through
|
||||||
# Possible values: upcoming, popular, trending
|
# Possible values: upcoming, popular, trending
|
||||||
streams:
|
streams:
|
||||||
- upcoming
|
- upcoming
|
||||||
- popular
|
- popular
|
||||||
- trending
|
- trending
|
||||||
# Required - the name of the ruleset used to evaluate movies
|
# Required - the name of the ruleset used to evaluate movies
|
||||||
ruleset: Ruleset name
|
ruleset: Ruleset name
|
||||||
```
|
```
|
||||||
|
|
||||||
## Smart recommendations
|
## Smart recommendations
|
||||||
@@ -37,19 +37,38 @@ Considering the movie you liked, it will crawl their recommended movies and appl
|
|||||||
|
|
||||||
```yaml title="settings.yaml"
|
```yaml title="settings.yaml"
|
||||||
config:
|
config:
|
||||||
plex:
|
plex:
|
||||||
# ....
|
# ....
|
||||||
smartRecommendations:
|
smartRecommendations:
|
||||||
# Required
|
# Required
|
||||||
cron: '1 14 * * *'
|
cron: '1 14 * * *'
|
||||||
# The name of the plex library to use as a seed
|
# The name of the plex library to use as a seed
|
||||||
plexLibrary: Films
|
plexLibrary: Films
|
||||||
# Your minimum personal rating to consider
|
# Your minimum personal rating to consider
|
||||||
minimumRating: 6.9
|
minimumRating: 6.9
|
||||||
ruleset: Ruleset name
|
ruleset: Ruleset name
|
||||||
```
|
```
|
||||||
|
|
||||||
## Checking output
|
## Testing jobs
|
||||||
|
|
||||||
|
### Evaluating a ruleset
|
||||||
|
|
||||||
|
You can also evaluate a ruleset against a specific movie, using the following URL:
|
||||||
|
|
||||||
|
```
|
||||||
|
http://localhost:5056/api/movies/<id_movie>/evaluate/<ruleset_name>
|
||||||
|
```
|
||||||
|
|
||||||
|
Simply replace `<id_movie>` and `<rulest_name>` by the values matching your needs.
|
||||||
|
|
||||||
|
To find the ID of a movie, navigate to the movie in Overseerr. The ID is the number is the URL.
|
||||||
|
|
||||||
|
### Manually triggering jobs
|
||||||
|
|
||||||
|
You can manually trigger the job by accessing the following URL (assuming Overcrawlrr is accessible at `http://localhost:5056`):
|
||||||
|
|
||||||
|
- Discover job: `http://localhost:5056/api/discover`
|
||||||
|
- Smart recommendations job: `http://localhost:5056/api/smartRecommendations`
|
||||||
|
|
||||||
Evaluation of the jobs are displayed in the container log. If you named your service `overcrawlrr`, you can see it with the following command:
|
Evaluation of the jobs are displayed in the container log. If you named your service `overcrawlrr`, you can see it with the following command:
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
Filters on the adult status of the movie.
|
Filters on the adult status of the movie.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- adult: yes
|
- adult: yes
|
||||||
# or
|
# or
|
||||||
- adult: no
|
- adult: no
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -19,25 +19,27 @@ Filters on the age of the movie.
|
|||||||
See [Duration expressions](#duration-expressions) for more details
|
See [Duration expressions](#duration-expressions) for more details
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- age: less than 2 years
|
- age: less than 2 years
|
||||||
# or
|
# or
|
||||||
- age: more than 6 months
|
- age: more than 6 months
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `and`
|
### `and`
|
||||||
|
|
||||||
Predicate that will match if all of its predicate matches
|
Predicate that will match if all of its predicate matches
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# Will match if the movie is less than 2 years old AND if the movie genre is 'animation'
|
# Will match if the movie is less than 2 years old AND if the movie genre is 'animation'
|
||||||
- and:
|
- and:
|
||||||
- age: less than 2 years
|
- age: less than 2 years
|
||||||
- genre:
|
- genre:
|
||||||
- animation
|
- animation
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `cast`
|
### `cast`
|
||||||
|
|
||||||
Filters based on the cast of the movie. Will match when one or more of the listed name matches.
|
Filters based on the cast of the movie. Will match when one or more of the listed name matches.
|
||||||
@@ -45,12 +47,22 @@ Filters based on the cast of the movie. Will match when one or more of the liste
|
|||||||
**Case insensitive**
|
**Case insensitive**
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- cast:
|
- cast:
|
||||||
- Denzel Washington
|
- Denzel Washington
|
||||||
- Jessica Alba
|
- Jessica Alba
|
||||||
|
```
|
||||||
|
|
||||||
|
It is also possible to exclude an cast when it's performing voice only (in animation movies for example)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- cast:
|
||||||
|
voice: exclude
|
||||||
|
names:
|
||||||
|
- Scarlett Johansson
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `crew`
|
### `crew`
|
||||||
|
|
||||||
Filters based on the crew of the movie. Will match when one or more of the listed name matches.
|
Filters based on the crew of the movie. Will match when one or more of the listed name matches.
|
||||||
@@ -58,21 +70,23 @@ Filters based on the crew of the movie. Will match when one or more of the liste
|
|||||||
**Case insensitive**
|
**Case insensitive**
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- crew:
|
- crew:
|
||||||
- James Cameron
|
- James Cameron
|
||||||
- Hans Zimmer
|
- Hans Zimmer
|
||||||
```
|
```
|
||||||
|
|
||||||
It is also possible to specify the job
|
It is also possible to specify the job
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- crew:
|
- crew:
|
||||||
job: director
|
job: director
|
||||||
names:
|
names:
|
||||||
- James Cameron
|
- James Cameron
|
||||||
- Steven Spielberg
|
- Steven Spielberg
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `genre`
|
### `genre`
|
||||||
|
|
||||||
Filters on the genre of the movie. Will match when one or more of the listed genres matches the genre of the movie.
|
Filters on the genre of the movie. Will match when one or more of the listed genres matches the genre of the movie.
|
||||||
@@ -80,25 +94,27 @@ Filters on the genre of the movie. Will match when one or more of the listed gen
|
|||||||
**Case insensitive**
|
**Case insensitive**
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- genre: musical
|
- genre: musical
|
||||||
# or with an array of values
|
# or with an array of values
|
||||||
- genre:
|
- genre:
|
||||||
- animation
|
- animation
|
||||||
- romance
|
- romance
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `not`
|
### `not`
|
||||||
|
|
||||||
Predicate that invert the result of its child predicate
|
Predicate that invert the result of its child predicate
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- not:
|
- not:
|
||||||
- genre:
|
- genre:
|
||||||
- animation
|
- animation
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `originalLanguage`
|
### `originalLanguage`
|
||||||
|
|
||||||
Filters on the original language of the movie
|
Filters on the original language of the movie
|
||||||
@@ -106,27 +122,29 @@ Filters on the original language of the movie
|
|||||||
**Case insensitive**
|
**Case insensitive**
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# ISO 639-1 format of the language (de, au, us, fr...)
|
# ISO 639-1 format of the language (de, au, us, fr...)
|
||||||
- originalLanguage: en
|
- originalLanguage: en
|
||||||
# or with an array of values
|
# or with an array of values
|
||||||
- originalLanguage:
|
- originalLanguage:
|
||||||
- en
|
- en
|
||||||
- fr
|
- fr
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `or`
|
### `or`
|
||||||
|
|
||||||
Predicate that will match if any of its predicate matches
|
Predicate that will match if any of its predicate matches
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# Will match if the movie is less than 2 years old OR if the movie score is above 8
|
# Will match if the movie is less than 2 years old OR if the movie score is above 8
|
||||||
- or:
|
- or:
|
||||||
- age: less than 2 years
|
- age: less than 2 years
|
||||||
- score: above 8
|
- score: above 8
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `productionCompany`
|
### `productionCompany`
|
||||||
|
|
||||||
Filters based on the production companies of the movie. Will match when one or more of the listed company matches.
|
Filters based on the production companies of the movie. Will match when one or more of the listed company matches.
|
||||||
@@ -134,24 +152,26 @@ Filters based on the production companies of the movie. Will match when one or m
|
|||||||
**Case insensitive**
|
**Case insensitive**
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- productionCompany:
|
- productionCompany:
|
||||||
- 20th Century Fox
|
- 20th Century Fox
|
||||||
- Warner Bros. Pictures
|
- Warner Bros. Pictures
|
||||||
- Twisted Pictures
|
- Twisted Pictures
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `released`
|
### `released`
|
||||||
|
|
||||||
Filters on the released status of the movie.
|
Filters on the released status of the movie.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- released: yes
|
- released: yes
|
||||||
# or
|
# or
|
||||||
- released: no
|
- released: no
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `runtime`
|
### `runtime`
|
||||||
|
|
||||||
Filters on the runtime _(duration)_ of the movie.
|
Filters on the runtime _(duration)_ of the movie.
|
||||||
@@ -159,12 +179,13 @@ Filters on the runtime _(duration)_ of the movie.
|
|||||||
See [Duration expressions](#duration-expressions) for more details
|
See [Duration expressions](#duration-expressions) for more details
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- runtime: less than 2.5 hours
|
- runtime: less than 2.5 hours
|
||||||
# or
|
# or
|
||||||
- runtime: more than 120 minutes
|
- runtime: more than 120 minutes
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `score`
|
### `score`
|
||||||
|
|
||||||
Filters on the score of the movie.
|
Filters on the score of the movie.
|
||||||
@@ -172,12 +193,13 @@ Filters on the score of the movie.
|
|||||||
Overseerr score is expressed between 0 to 10, but to make things clear, it is possible to pass the score as a fractional number.
|
Overseerr score is expressed between 0 to 10, but to make things clear, it is possible to pass the score as a fractional number.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- score: above 6.5
|
- score: above 6.5
|
||||||
# or
|
# or
|
||||||
- score: below 75/100 # Would be the same as 7.5, 7.5/10 or even 750/1000
|
- score: below 75/100 # Would be the same as 7.5, 7.5/10 or even 750/1000
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `status`
|
### `status`
|
||||||
|
|
||||||
Filters on the status of the movie.
|
Filters on the status of the movie.
|
||||||
@@ -187,24 +209,24 @@ The possible values are the one provided by [TMDB](https://www.themoviedb.org/):
|
|||||||
**Case insensitive**
|
**Case insensitive**
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- status: released
|
- status: released
|
||||||
# or with an array of values
|
# or with an array of values
|
||||||
- status:
|
- status:
|
||||||
- released
|
- released
|
||||||
- post production
|
- post production
|
||||||
- planned
|
- planned
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `voteCount`
|
### `voteCount`
|
||||||
|
|
||||||
Filters on the vote count of the movie.
|
Filters on the vote count of the movie.
|
||||||
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- voteCount: above 1000
|
- voteCount: above 1000
|
||||||
# or
|
# or
|
||||||
- voteCount: below 100
|
- voteCount: below 100
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -216,11 +238,11 @@ Filters based on the available Streaming/VOD platforms. Will match when one or m
|
|||||||
**Case insensitive**
|
**Case insensitive**
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# This predicate will match when the movie is available in Germany on Netflix or Amazon Prime
|
# This predicate will match when the movie is available in Germany on Netflix or Amazon Prime
|
||||||
- watchProviders:
|
- watchProviders:
|
||||||
# ISO 3166-1 alpha-2 format of the region (de, au, us, fr...)
|
# ISO 3166-1 alpha-2 format of the region (de, au, us, fr...)
|
||||||
- region: de
|
- region: de
|
||||||
- names:
|
- names:
|
||||||
- Netflix
|
- Netflix
|
||||||
- Amazon Prime
|
- Amazon Prime
|
||||||
```
|
```
|
||||||
@@ -231,12 +253,12 @@ Filters based on the available Streaming/VOD platforms. Will match when one or m
|
|||||||
|
|
||||||
Duration expressions, like the one used in the `age` or `runtime` predicate can be expressed in the following way:
|
Duration expressions, like the one used in the `age` or `runtime` predicate can be expressed in the following way:
|
||||||
|
|
||||||
- an **operator**: `less than` or `more than`
|
- an **operator**: `less than` or `more than`
|
||||||
- a integer or decimal **number**: `2` or `2.5`
|
- a integer or decimal **number**: `2` or `2.5`
|
||||||
- a **unit**: one of the following `year`, `month`, `week`, `day`, `hour`, `minute`. Singular or plural doesn't matter, so `hour` is the same as `hours`
|
- a **unit**: one of the following `year`, `month`, `week`, `day`, `hour`, `minute`. Singular or plural doesn't matter, so `hour` is the same as `hours`
|
||||||
|
|
||||||
The following expressions are valid:
|
The following expressions are valid:
|
||||||
|
|
||||||
- `less than 1 hour`/`less than 1 hours`/`less than 60 minutes`
|
- `less than 1 hour`/`less than 1 hours`/`less than 60 minutes`
|
||||||
- `less than 3 hours`/`less than 3 hour`/`less than 180 minute`
|
- `less than 3 hours`/`less than 3 hour`/`less than 180 minute`
|
||||||
- `more than 6 month`
|
- `more than 6 month`
|
||||||
|
|||||||
111
docs/rulesets.md
111
docs/rulesets.md
@@ -8,24 +8,24 @@ A ruleset is a named group of rules.
|
|||||||
|
|
||||||
```yaml title="settings.yaml"
|
```yaml title="settings.yaml"
|
||||||
config:
|
config:
|
||||||
# ...
|
# ...
|
||||||
rulesets:
|
rulesets:
|
||||||
# Required - the name of the ruleset
|
# Required - the name of the ruleset
|
||||||
- name: Ruleset name
|
- name: Ruleset name
|
||||||
# Optional - the name of another ruleset.
|
# Optional - the name of another ruleset.
|
||||||
# This ruleset will apply all the rules in the extended ruleset
|
# This ruleset will apply all the rules in the extended ruleset
|
||||||
# before applying its own rules
|
# before applying its own rules
|
||||||
extends: Another ruleset
|
extends: Another ruleset
|
||||||
# Required - An array defining the rules of the ruleset
|
# Required - An array defining the rules of the ruleset
|
||||||
rules:
|
rules:
|
||||||
- # rule 1
|
- # rule 1
|
||||||
- # rule 2
|
- # rule 2
|
||||||
- # rule ...
|
- # rule ...
|
||||||
```
|
```
|
||||||
|
|
||||||
- The rules are applied in the declared order,
|
- The rules are applied in the declared order,
|
||||||
- When a rule matches, the rule's `action` is applied, and the evaluation of the ruleset stops.
|
- When a rule matches, the rule's `action` is applied, and the evaluation of the ruleset stops.
|
||||||
- If a rule doesn't match, it is ignored, and the next rule is evaluated.
|
- If a rule doesn't match, it is ignored, and the next rule is evaluated.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -36,25 +36,25 @@ A rule is a named group of predicates.
|
|||||||
A predicate is a simple operation allowing to test the property of a movie.
|
A predicate is a simple operation allowing to test the property of a movie.
|
||||||
|
|
||||||
```yaml title="settings.yaml"
|
```yaml title="settings.yaml"
|
||||||
# Required - the name of the rule
|
# Required - the name of the rule
|
||||||
- name: The rule name
|
- name: The rule name
|
||||||
# Required - an array defining the predicates used in the rule
|
# Required - an array defining the predicates used in the rule
|
||||||
whenMatch:
|
whenMatch:
|
||||||
- # predicate 1
|
- # predicate 1
|
||||||
- # predicate 2
|
- # predicate 2
|
||||||
- # ...
|
- # ...
|
||||||
- # predicate n
|
- # predicate n
|
||||||
# Required - the action to apply when the rule matches
|
# Required - the action to apply when the rule matches
|
||||||
# Possible values: accept or reject
|
# Possible values: accept or reject
|
||||||
action: accept
|
action: accept
|
||||||
```
|
```
|
||||||
|
|
||||||
The rule will match if **all the predicates** in the `whenMatch` match.
|
The rule will match if **all the predicates** in the `whenMatch` match.
|
||||||
|
|
||||||
When matching:
|
When matching:
|
||||||
|
|
||||||
- If `action: accept`, a request is sent to Overseerr to add the movie,
|
- If `action: accept`, a request is sent to Overseerr to add the movie,
|
||||||
- If `action: reject`, the movie is ignored, and the evaluation of the ruleset stops for this movie.
|
- If `action: reject`, the movie is ignored, and the evaluation of the ruleset stops for this movie.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -66,25 +66,26 @@ This is particularly useful for common rejection rules.
|
|||||||
|
|
||||||
```yaml title="settings.yaml"
|
```yaml title="settings.yaml"
|
||||||
config:
|
config:
|
||||||
# ...
|
# ...
|
||||||
rulesets:
|
rulesets:
|
||||||
- name: exclude-netflix
|
- name: exclude-netflix
|
||||||
rules:
|
rules:
|
||||||
- name: Exclude netflix movies
|
- name: Exclude netflix movies
|
||||||
watchProviders:
|
watchProviders:
|
||||||
- region: us
|
- region: us
|
||||||
- names:
|
- names:
|
||||||
- Netflix
|
- Netflix
|
||||||
action: reject
|
action: reject
|
||||||
- name: filter-movies
|
- name: filter-movies
|
||||||
extends: exclude-netflix # movie will be evaluated against exclude-netflix rules first
|
extends: exclude-netflix # movie will be evaluated against exclude-netflix rules first
|
||||||
rules:
|
rules:
|
||||||
- name: High score
|
- name: High score
|
||||||
whenMatch:
|
whenMatch:
|
||||||
- age: less than 1 year
|
- age: less than 1 year
|
||||||
- score: above 9/10
|
- score: above 9/10
|
||||||
action: accept
|
action: accept
|
||||||
```
|
```
|
||||||
|
|
||||||
## Ruleset example
|
## Ruleset example
|
||||||
|
|
||||||
The following ruleset will:
|
The following ruleset will:
|
||||||
@@ -93,18 +94,18 @@ The following ruleset will:
|
|||||||
2. Request all movies _(that went through rule 1)_ released in the past year, with a score above 7
|
2. Request all movies _(that went through rule 1)_ released in the past year, with a score above 7
|
||||||
|
|
||||||
```yaml title="settings.yaml"
|
```yaml title="settings.yaml"
|
||||||
rulesets:
|
rulesets:
|
||||||
- name: New great movie
|
- name: New great movie
|
||||||
rules:
|
rules:
|
||||||
- name: Reject less wanted genres
|
- name: Reject less wanted genres
|
||||||
whenMatch:
|
whenMatch:
|
||||||
- genre:
|
- genre:
|
||||||
- animation
|
- animation
|
||||||
- romance
|
- romance
|
||||||
action: reject
|
action: reject
|
||||||
- name: New great movies
|
- name: New great movies
|
||||||
whenMatch:
|
whenMatch:
|
||||||
- age: less than 1 years
|
- age: less than 1 years
|
||||||
- score: above 7
|
- score: above 7
|
||||||
action: accept
|
action: accept
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
"lint": "eslint \"./**/*.ts\"",
|
"lint": "eslint \"./**/*.ts\"",
|
||||||
"format:fix": "prettier ./src --write --cache",
|
"format:fix": "prettier ./src --write --cache",
|
||||||
"format": "prettier ./src --check --cache",
|
"format": "prettier ./src --check --cache",
|
||||||
|
"format-docs": "prettier ./docs --check --cache",
|
||||||
|
"format-docs:fix": "prettier ./docs --write --cache",
|
||||||
"start": "tsx src/index.ts",
|
"start": "tsx src/index.ts",
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -218,7 +218,18 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["cast"],
|
"required": ["cast"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"cast": { "type": "array", "items": {"type": "string" }}
|
"cast": {
|
||||||
|
"oneOf": [
|
||||||
|
{ "type": "array", "items": { "type": "string" }},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"voice": { "type": "string", "enum": ["include", "exclude"]},
|
||||||
|
"names": { "type": "array", "items": {"type": "string" }}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -157,6 +157,36 @@ describe('castPredicate', () => {
|
|||||||
const rule = testRule(new CastPredicate({ cast: ['Jessica Alba'] }));
|
const rule = testRule(new CastPredicate({ cast: ['Jessica Alba'] }));
|
||||||
assertRuleDoesntMatch(rule, movie);
|
assertRuleDoesntMatch(rule, movie);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should match with voice field', async () => {
|
||||||
|
const ruleIncludeVoice = testRule(
|
||||||
|
new CastPredicate({
|
||||||
|
cast: {
|
||||||
|
voice: 'include',
|
||||||
|
names: ['Bob Sherman'],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const ruleExcludeVoice = testRule(
|
||||||
|
new CastPredicate({
|
||||||
|
cast: {
|
||||||
|
voice: 'exclude',
|
||||||
|
names: ['Bob Sherman'],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const ruleExcludeVoice2 = testRule(
|
||||||
|
new CastPredicate({
|
||||||
|
cast: {
|
||||||
|
voice: 'exclude',
|
||||||
|
names: ['Bob Sherman', 'Sigourney Weaver'],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
assertRuleMatches(ruleIncludeVoice, movie);
|
||||||
|
assertRuleMatches(ruleExcludeVoice2, movie);
|
||||||
|
assertRuleDoesntMatch(ruleExcludeVoice, movie);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('crewPredicate', () => {
|
describe('crewPredicate', () => {
|
||||||
|
|||||||
@@ -52,7 +52,12 @@ export type AgeOptions = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type CastOptions = {
|
export type CastOptions = {
|
||||||
cast: string[];
|
cast: string[] | CastWithVoiceOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CastWithVoiceOptions = {
|
||||||
|
voice: 'include' | 'exclude';
|
||||||
|
names: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type GenreOptions = {
|
export type GenreOptions = {
|
||||||
|
|||||||
@@ -4,10 +4,13 @@ import { PredicateBuilder } from '@core/lib/rules';
|
|||||||
import { CastOptions } from '@core/lib/rules/interfaces';
|
import { CastOptions } from '@core/lib/rules/interfaces';
|
||||||
|
|
||||||
export class CastPredicate extends TagsPredicate {
|
export class CastPredicate extends TagsPredicate {
|
||||||
|
private excludeVoice: boolean = false;
|
||||||
|
|
||||||
constructor(options: CastOptions) {
|
constructor(options: CastOptions) {
|
||||||
super({
|
super({
|
||||||
terms: options.cast,
|
terms: Array.isArray(options.cast) ? options.cast : options.cast.names,
|
||||||
});
|
});
|
||||||
|
this.excludeVoice = Array.isArray(options.cast) ? false : options.cast.voice?.toLowerCase() === 'exclude';
|
||||||
}
|
}
|
||||||
|
|
||||||
getTags(movie: MovieDetails): string[] {
|
getTags(movie: MovieDetails): string[] {
|
||||||
@@ -16,7 +19,9 @@ export class CastPredicate extends TagsPredicate {
|
|||||||
}
|
}
|
||||||
const tags: string[] = [];
|
const tags: string[] = [];
|
||||||
for (const cast of movie.credits.cast) {
|
for (const cast of movie.credits.cast) {
|
||||||
tags.push(cast.name);
|
if (!this.excludeVoice || !cast.character || !cast.character.toLowerCase().includes('(voice)')) {
|
||||||
|
tags.push(cast.name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user