All apps · 0 apps
Flixpatrol-Top-10-on-Trakt
Docker app from grtgbln's Repository
Overview
Readme
View on GitHub
Flixpatrol Top 10 on Trakt
Scrape today's top 10 from FlixPatrol and sync them to Trakt.tv lists.
Supports 72+ streaming platforms, 200+ countries, and is compatible with Kometa.
Getting Started • Configuration • Supported Platforms • Scheduling • Daemon Mode • Troubleshooting • Development
Warning Running at your own risk of being IP banned from FlixPatrol.
Due to FlixPatrol limitations, titles are matched on Trakt by name and release year. This may occasionally cause bad matching.
Features
- Sync Top 10 lists from 72 streaming platforms (Netflix, Disney+, HBO Max, Amazon Prime, etc.)
- Sync Top 10 Kids lists from Netflix (country-specific)
- Sync Popular lists from 2 sources (Wikipedia and Youtube)
- Sync Netflix Most Watched annual rankings
- Sync Netflix Most Hours rankings (total, first week, first month)
- Support for 200+ countries/regions
- Intelligent caching to reduce API calls (7-day TTL by default)
- Automatic Trakt list management (create, update, sync)
- Dry-run mode for safe testing
- Compatible with Kometa (formerly Plex Meta Manager)
Getting Started
Docker
docker run --rm -v "/path/to/config:/app/config" ghcr.io/navino16/flixpatrol-top10-on-trakt:latest
Edit ./config/default.json, then schedule periodic runs with cron.
Linux / macOS
- Download the latest release for your platform
- Make the binary executable and run it:
chmod +x flixpatrol-top10-linux-x64 ./flixpatrol-top10-linux-x64 - Edit
./config/default.jsonand run again
Windows
- Download the latest release for Windows
- Run the binary from the command line (double-clicking will close the window automatically)
- Edit
./config/default.jsonand run again
Configuration
Environment Variables
| Name | Description | Values | Default |
|---|---|---|---|
| LOG_LEVEL | How verbose the log will be | error, warn, info, debug, silly | info |
| DRY_RUN | Run without making changes to Trakt | true, false | false |
| LIST_NAME_PREFIX | String prepended to every list name (useful for dev/testing) | Any string, e.g. [TEST] |
(none) |
Dry-Run Mode
Run the tool without modifying Trakt lists. Useful for testing your configuration:
# Linux/macOS
DRY_RUN=true ./flixpatrol-top10-linux-x64
# Docker
docker run --rm -e DRY_RUN=true -v "/path/to/config:/app/config" ghcr.io/navino16/flixpatrol-top10-on-trakt:latest
In dry-run mode:
- FlixPatrol scraping runs normally
- Trakt search for ID conversion runs normally
- OAuth authentication runs normally
- List creation, item addition/removal, and updates are logged but not executed
List Name Prefix
Prepend a fixed string to every list name. Useful when running the tool against your real Trakt account during development or testing — the prefixed lists stay separate from your real lists and can be deleted in bulk afterwards.
# Linux/macOS — produces lists like "[TEST]netflix-world-top10-without-fallback"
LIST_NAME_PREFIX='[TEST]' ./flixpatrol-top10-linux-x64
# Docker
docker run --rm -e LIST_NAME_PREFIX='[TEST]' -v "/path/to/config:/app/config" ghcr.io/navino16/flixpatrol-top10-on-trakt:latest
The prefix is applied verbatim, after the normalization step (so brackets, spaces, and special characters in the prefix are preserved as-is). When active, a warning is emitted at startup so you don't forget it is set.
Notifications
Send a notification at the start of a run, at the end (with a summary), and on terminal errors. The block is optional — omit it entirely to disable notifications.
{
"Notifications": {
"run_start": [
{ "type": "webhook", "url": "https://discord.com/api/webhooks/..." }
],
"run_end": [
{ "type": "webhook", "url": "https://discord.com/api/webhooks/..." },
{ "type": "apprise", "url": "http://apprise:8000", "key": "flixpatrol" }
],
"error": [
{ "type": "gotify", "url": "https://gotify.example.com", "token": "AbCdEf123" },
{ "type": "ntfy", "url": "https://ntfy.sh", "topic": "flixpatrol-alerts" }
]
}
}
Each event takes a list of destinations. A destination has a type and the fields required by that type:
| Type | Fields | Notes |
|---|---|---|
webhook |
url |
Sends generic JSON. If url matches discord.com/api/webhooks/... a Discord-shaped payload is sent automatically. |
gotify |
url, token |
POSTs to {url}/message with the token sent via the X-Gotify-Key header (never in the query string, so it cannot leak into reverse-proxy access logs). |
ntfy |
url, topic |
POSTs JSON to {url} with the topic in the body. Use https://ntfy.sh for the public service. |
apprise |
url, key |
POSTs to {url}/notify/{key} against an Apprise API sidecar (see below). |
Notifications are best-effort: a failing destination is logged at warn level but never blocks the main sync. Each adapter has a 5-second HTTP timeout and the manager caps total wait at 6 seconds. Failure logs include the adapter name and the destination's host (e.g. WebhookAdapter[discord.com]: HTTP 401) — never the full URL or any path / query secrets, so webhook tokens (Discord bearer tokens in the path, Apprise routing keys, etc.) cannot leak into log files or container stdout.
Every url field is validated as a full URL with scheme at config-load time — typos like discord.com/... (missing https://) are rejected at startup with a clear error rather than silently failing at runtime.
DRY_RUN=true does not suppress notifications (useful for testing the setup). Title and body are both prefixed with [DRY-RUN] so they cannot be mistaken for a real run, and the run_end body says items "would be added" rather than "added".
Apprise sidecar (optional)
The apprise destination talks to an Apprise API instance you host yourself. Once it is running, you configure your downstream services (Discord, Telegram, Email, etc.) inside Apprise — flixpatrol-top10 only needs to know the Apprise URL and a config key.
# docker-compose.yml excerpt
services:
flixpatrol:
image: ghcr.io/navino16/flixpatrol-top10-on-trakt:latest
volumes:
- ./config:/app/config
depends_on:
- apprise
apprise:
image: caronc/apprise:latest
ports:
- "8000:8000"
volumes:
- ./apprise-config:/config
In the Apprise web UI (default http://localhost:8000), create a configuration key (for example flixpatrol) and add your downstream Apprise URLs (discord://..., tgram://..., mailto://..., etc.) under that key. Then reference it from config/default.json:
{ "type": "apprise", "url": "http://apprise:8000", "key": "flixpatrol" }
Configuration File
The configuration file is stored at ./config/default.json (auto-generated on first run).
If there is any configuration error, the tool will exit with information about the error.
FlixPatrolTop10 — Top 10 list configuration
| Name | Description | Mandatory | Values | Default |
|---|---|---|---|---|
| platform | Which platform to get from Flixpatrol | Yes | Any Flixpatrol platform (see this) | |
| location | Which location to get from Flixpatrol | Yes | Any Flixpatrol location (see this) | |
| fallback | Fallback to another location if no results? | Yes | False or any Flixpatrol location (see this) | false |
| privacy | The privacy of the generated Trakt list | Yes | private, link, friends, public | private |
| limit | How many movie/show to get | Yes | Number >= 1 | 10 |
| type | Movies, shows or both? | Yes | movies, shows, both | both |
| name | Optional custom list name | No | Any valid string | A generated name based on the top10 config |
| normalizeName | Normalize the list name to kebab-case? | No | true, false | true |
| kids | Get Kids Top 10 (Netflix only, requires specific country) | No | true, false | false |
FlixPatrolPopular — Popular list configuration
| Name | Description | Mandatory | Values | Default |
|---|---|---|---|---|
| platform | Which popular source to get from Flixpatrol | Yes | Any Flixpatrol popular platform (see this) | |
| privacy | The privacy of the generated Trakt list | Yes | private, link, friends, public | private |
| limit | How many movie/show to get | Yes | Number between 1 and 100 | 100 |
| type | Movies, shows or both? | Yes | movies, shows, both | both |
| name | Optional custom list name | No | Any valid string | A generated name based on the popular config |
| normalizeName | Normalize the list name to kebab-case? | No | true, false | true |
FlixPatrolMostWatched — Netflix Most Watched configuration
| Name | Description | Mandatory | Values | Default |
|---|---|---|---|---|
| enabled | Enable this most watched list? | Yes | true, false | true |
| privacy | The privacy of the generated Trakt list | Yes | private, link, friends, public | private |
| type | Movies, shows or both? | Yes | movies, shows, both | both |
| limit | How many movie/show to get | Yes | Number between 1 and 50 | 50 |
| year | Year of the most watched list | Yes | Number between 2023 and current year | current year |
| name | Optional custom list name | No | Any valid string | most-watched |
| normalizeName | Normalize the list name to kebab-case? | No | true, false | true |
| premiere | Filter by premiere year | No | Year between 1980 and current year | All |
| country | Filter by release country | No | Any Flixpatrol location (see this) | All |
| original | Netflix originals only? | No | true, false | false |
| orderByViews | Order by views instead of hours? | No | true, false | false |
FlixPatrolMostHours — Netflix Most Hours configuration
| Name | Description | Mandatory | Values | Default |
|---|---|---|---|---|
| enabled | Enable this most hours list? | Yes | true, false | true |
| privacy | The privacy of the generated Trakt list | Yes | private, link, friends, public | private |
| type | Movies, shows or both? | Yes | movies, shows, both | both |
| limit | How many movie/show to get | Yes | Number between 1 and 100 | 50 |
| period | Which ranking period | Yes | total, first-week, first-month | total |
| language | Filter by language (first-week and first-month only) | No | all, english, non-english | all |
| name | Optional custom list name | No | Any valid string | netflix-most-hours-{period} |
| normalizeName | Normalize the list name to kebab-case? | No | true, false | true |
Trakt & Cache — Authentication and caching
| Name | Description | Mandatory | Values | Default |
|---|---|---|---|---|
| Trakt.saveFile | Where to save the Trakt session file | Yes | Any valid path | ./config/.trakt |
| Trakt.clientId | Your clientId from Trakt (get one here) | Yes | A valid string | |
| Trakt.clientSecret | Your clientSecret from Trakt (get one here) | Yes | A valid string | |
| Cache.enabled | Enable caching? (recommended) | Yes | true, false | true |
| Cache.savePath | Where to save the cache files | Yes | Any valid path | ./config/.cache |
| Cache.ttl | Cache validity duration in seconds | Yes | Number > 0 | 604800 (7 days) |
Schedule — Daemon mode / built-in scheduling configuration
| Name | Description | Mandatory | Values | Default |
|---|---|---|---|---|
| enabled | Enable the built-in scheduler (daemon mode)? | No | true, false | false |
| crons | Cron expression(s) the app runs on, 5-field format (min hour day month weekday) |
Yes, when enabled: true |
Array of valid cron strings, e.g. ["0 6 * * *"] |
[] |
| runOnStart | Also run immediately at startup, in addition to the schedule? | No | true, false | false |
The whole Schedule block is optional — omit it entirely (or leave enabled: false) to keep the classic one-shot behaviour: the app runs once and exits, exactly like today. See Daemon Mode below for details.
Example configuration
{
"FlixPatrolTop10": [
{
"platform": "netflix",
"location": "world",
"fallback": false,
"privacy": "private",
"limit": 10,
"name": "Netflix Top 10 Movies",
"type": "movies"
},
{
"platform": "disney",
"location": "world",
"fallback": false,
"privacy": "private",
"limit": 10,
"name": "Disney Plus Top 10 Shows",
"type": "shows"
},
{
"platform": "amazon-prime",
"location": "world",
"fallback": false,
"privacy": "private",
"limit": 10,
"name": "Amazon Prime Top 10",
"type": "both"
},
{
"platform": "netflix",
"location": "united-states",
"fallback": false,
"privacy": "private",
"limit": 10,
"name": "Netflix Top 10 Kids",
"type": "both",
"kids": true
}
],
"FlixPatrolPopular": [
{
"platform": "wikipedia",
"privacy": "private",
"limit": 100,
"type": "both"
}
],
"FlixPatrolMostWatched": [
{
"enabled": true,
"privacy": "public",
"year": 2023,
"limit": 50,
"type": "both"
}
],
"FlixPatrolMostHours": [
{
"enabled": true,
"privacy": "public",
"limit": 50,
"type": "both",
"period": "total"
},
{
"enabled": true,
"privacy": "public",
"limit": 50,
"type": "both",
"period": "first-week"
},
{
"enabled": true,
"privacy": "public",
"limit": 50,
"type": "movies",
"period": "first-month",
"language": "english"
}
],
"Trakt": {
"saveFile": "./config/.trakt",
"clientId": "You need to replace this client ID",
"clientSecret": "You need to replace this client secret"
},
"Cache": {
"enabled": true,
"savePath": "./config/.cache",
"ttl": 604800
},
"Notifications": {
"run_start": [],
"run_end": [],
"error": []
},
"Schedule": {
"enabled": false,
"crons": ["0 6 * * *"],
"runOnStart": false
}
}
The Notifications block is fully optional — leave the arrays empty (or omit the block entirely) to disable notifications. See Notifications above for the supported destination types and a worked example.
The Schedule block is fully optional and disabled by default — omit it (or leave enabled: false) to keep the classic one-shot behaviour. See Daemon Mode below.
Trakt Setup
To run this application you need a Trakt account and a Client ID / Client Secret.
Warning Trakt free accounts are limited to 5 lists. If you configure more, the tool will fail. Remove some or upgrade to Trakt VIP.
- Create an account or login
- Create a new application with:
- Redirect uri:
urn:ietf:wg:oauth:2.0:oob - Other fields are optional
- Redirect uri:
- Set the Client ID / Client Secret in
./config/default.json - Run the app and follow the on-screen instructions
Supported Platforms
Top 10 Platforms (72)
9now, abema, amazon, amazon-channels, amazon-prime, amc-plus, antenna-tv, apple-tv, bbc, canal, catchplay, cda, chili, claro-video, coupang-play, crunchyroll, discovery-plus, disney, francetv, friday, globoplay, go3, google, hami-video, hayu, hbo-max, hrti, hulu, hulu-nippon, itunes, jiocinema, jiohotstar, joyn, lemino, m6plus, mgm-plus, myvideo, neon-tv, netflix, now, oneplay, osn, paramount-plus, peacock, player, pluto-tv, raiplay, rakuten-tv, rtl-plus, sbs, shahid, skyshowtime, stan, starz, streamz, telasa, tf1, tod, trueid, tubi, tv-2-norge, u-next, viaplay, videoland, vidio, viki, viu, vix, voyo, vudu, watchit, wavve, wow, zee5
Popular Sources (12)
wikipedia, youtube
Locations (199)
world, united-states, france, united-kingdom, germany, canada, australia, japan, and 191 more countries...
For the complete list, see the source code: Config.types.ts
Scheduling
Linux (cron)
# Run daily at 6 AM
0 6 * * * /path/to/flixpatrol-top10-linux-x64
# Run every 12 hours
0 */12 * * * /path/to/flixpatrol-top10-linux-x64
Docker with cron
# Run daily at 6 AM
0 6 * * * docker run --rm -v "/path/to/config:/app/config" ghcr.io/navino16/flixpatrol-top10-on-trakt:latest
Windows Task Scheduler
- Open Task Scheduler
- Create a new task
- Set the trigger (e.g., daily at 6 AM)
- Set the action to run the executable
Daemon Mode (built-in scheduling)
Instead of relying on an external scheduler (cron, Task Scheduler, docker run on a timer), the app can run as a long-lived
process with its own built-in scheduler. Add a Schedule block to config/default.json and set enabled: true:
{
"Schedule": {
"enabled": true,
"crons": ["0 6 * * *"],
"runOnStart": false
}
}
| Field | Description |
|---|---|
enabled |
Turns daemon mode on. When false or omitted, the app runs once and exits — the current behaviour is completely unchanged. |
crons |
One or more cron expressions, standard 5-field format (min hour day month weekday), e.g. "0 6 * * *" for daily at 6 AM. Must contain at least one entry when enabled is true. |
runOnStart |
When true, triggers an immediate run at startup, then continues to follow the configured schedule. |
Backward compatibility
The Schedule block is entirely optional. If it is absent, or enabled is false, the app behaves exactly as before:
it runs once and exits with the appropriate code. Your existing external cron job or docker run on a timer keeps
working without any change.
Timezone
The scheduler follows the system clock. There is no timezone field in the config — set the TZ environment variable
(e.g. TZ=Europe/Paris) on the host or container so cron expressions are evaluated in the timezone you expect.
Behaviour while running
- If a scheduled trigger fires while a run is still in progress, it is skipped (logged as a warning) rather than queued or run concurrently.
- A failed run is logged and sent through the Notifications system (the
errorevent), but it does not stop the daemon — the scheduler keeps waiting for the next trigger. - On
SIGTERM(e.g.docker stop) orSIGINT(Ctrl-C), the app performs a graceful shutdown: it stops accepting new triggers and waits for the current run to finish its Trakt write before exiting, so lists are never left half-updated.
Docker Compose example
Run the container as a long-lived daemon instead of a one-shot job:
# docker-compose.yml
services:
flixpatrol:
image: ghcr.io/navino16/flixpatrol-top10-on-trakt:latest
restart: unless-stopped
environment:
- TZ=Europe/Paris
volumes:
- ./config:/app/config
With Schedule.enabled: true in config/default.json, this container stays up, runs on the configured cron
schedule(s), and survives restarts (restart: unless-stopped). This replaces the external-cron pattern shown above
(docker run triggered by a host cron entry) — you no longer need a cron job on the host, since the schedule now
lives inside the app itself.
Troubleshooting
| Problem | Solution |
|---|---|
| "Rate limit exceeded" | Increase time between runs. The cache helps reduce API calls. |
| "List limit reached" | Trakt free accounts are limited to 5 lists. Upgrade to VIP or reduce configured lists. |
| "No items found" | Verify the platform/location combination exists on FlixPatrol. |
| "Bad matching" | This is a FlixPatrol/Trakt limitation. Titles are matched by name and year. |
| "Authentication failed" | Delete ./config/.trakt and re-authenticate. |
| "Permission denied" on config folder (Docker) | The Docker image runs as a non-root user (flixpatrol, UID 1000). Fix permissions with: sudo chown -R 1000:1000 /path/to/config |
Development
# Install dependencies
npm install
# Run in development mode (hot reload)
npm run start:dev
# Build
npm run build
# Run after build
npm run start
# Lint
npm run lint
# Lint and auto-fix
npm run lint-and-fix
# Create cross-platform binaries
npm run package
License
Install Flixpatrol-Top-10-on-Trakt on Unraid in a few clicks.
Find Flixpatrol-Top-10-on-Trakt in Community Apps on your Unraid server, review the template, and click Install. Unraid handles the Docker app or plugin setup from the published template.
Requirements
Expects a config file in the Config Path. See documentation: https://github.com/Navino16/flixpatrol-top10-on-trakt#configuration-file
Related apps
Explore more like this
Explore allDetails
ghcr.io/navino16/flixpatrol-top10-on-trakt:latestRuntime arguments
- Network
bridge- Privileged
- false
Template configuration
Path to app data
- Target
- /app/config
- Default
- /mnt/user/appdata/flixpatrol_to_trakt/config
- Value
- /mnt/user/appdata/flixpatrol_to_trakt/config
Log level for the application
- Target
- LOG_LEVEL
- Default
- info|err|warn|debug