Flixpatrol-Top-10-on-Trakt

Flixpatrol-Top-10-on-Trakt

Docker app from grtgbln's Repository

Overview

This tool get TODAY top 10 from flixpatrol and push the result on trakt list (useful for syncing with Kometa)

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.

Build (main) Build (develop)

Docker Windows Linux macOS Discord Stars License

Downloads Release Commits in Develop Issues Pull Requests

Getting StartedConfigurationSupported PlatformsSchedulingDaemon ModeTroubleshootingDevelopment


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

  1. Download the latest release for your platform
  2. Make the binary executable and run it:
    chmod +x flixpatrol-top10-linux-x64
    ./flixpatrol-top10-linux-x64
    
  3. Edit ./config/default.json and run again

Windows

  1. Download the latest release for Windows
  2. Run the binary from the command line (double-clicking will close the window automatically)
  3. Edit ./config/default.json and 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.

  1. Create an account or login
  2. Create a new application with:
    • Redirect uri: urn:ietf:wg:oauth:2.0:oob
    • Other fields are optional
  3. Set the Client ID / Client Secret in ./config/default.json
  4. 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

  1. Open Task Scheduler
  2. Create a new task
  3. Set the trigger (e.g., daily at 6 AM)
  4. 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 error event), but it does not stop the daemon — the scheduler keeps waiting for the next trigger.
  • On SIGTERM (e.g. docker stop) or SIGINT (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

MIT 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.

Open the Apps tab on your Unraid server Search Community Apps for Flixpatrol-Top-10-on-Trakt Review the template variables and paths Click Install

Requirements


        Expects a config file in the Config Path. See documentation: https://github.com/Navino16/flixpatrol-top10-on-trakt#configuration-file
    

Details

Repository
ghcr.io/navino16/flixpatrol-top10-on-trakt:latest
Last Updated2026-07-17
First Seen2025-05-11

Runtime arguments

Network
bridge
Privileged
false

Template configuration

Config PathPath

Path to app data

Target
/app/config
Default
/mnt/user/appdata/flixpatrol_to_trakt/config
Value
/mnt/user/appdata/flixpatrol_to_trakt/config
Log LevelVariable

Log level for the application

Target
LOG_LEVEL
Default
info|err|warn|debug