[![Forks][forks-shield]][forks-url] [![Stargazers][stars-shield]][stars-url] [![Issues][issues-shield]][issues-url]
💫 automated lightweight service that updates media servers like Plex and Jellyfin
based on notifications from media organizers like Sonarr and Radarr
<a href="https://github.com/dan-online/autopulse/issues">Report Bug</a>
·
<a href="https://github.com/dan-online/autopulse/issues">Request Feature</a>
.
<a href="https://autopulse.dancodes.online/">Documentation</a>
.
<a href="https://autopulseui.pages.dev/">autopulseUI</a>
autopulse is a web server that receives notifications from media organizers like Sonarr/Radarr/Lidarr/etc (triggers) and updates the items in media servers like Plex/Jellyfin/Emby/etc (targets). It is designed to be efficient, only updating the items that have changed, reducing the load on media servers.
We use the following terminology:
- Trigger: A trigger is a specification for an endpoint that will be called when a file is ready to be processed
- Manual (default: /triggers/manual)
- Fileflows (sub-flow)
- Sonarr
- Radarr
- Lidarr
- Readarr
- Notify
- Linux: inotify
- MacOS: FSEvents
- Windows: ReadDirectoryChangesW
- Fallback: polling
- Target: A target is a specification for a library that will be updated when a file is ready to be processed
- Plex
- Jellyfin
- Emby
- Command
- Sonarr
- Radarr
- Tdarr
- FileFlows
- Audiobookshelf
- Another autopulse instance
The easiest way to get started with autopulse is to use the provided docker image on ghcr.io or Docker Hub
latest - full image with support for postgres/sqlitelatest-postgres - smaller image that only supports Postgreslatest-sqlite - smaller image that only supports SQLitestable - latest versioned releaseAll images are multi-arch and support
linux/amd64,linux/arm64, however -amd64 and -arm64 suffixes can be used to specify the architecture
An Unraid Community Apps template lives in unraid/autopulse.xml.
Once autopulse is listed in Community Apps, open the Apps tab in Unraid, search for autopulse, and click Install. Until then, install it as a private Community App:
bash
mkdir -p /boot/config/plugins/community.applications/private/autopulse
wget -O /boot/config/plugins/community.applications/private/autopulse/autopulse.xml \
https://raw.githubusercontent.com/dan-online/autopulse/main/unraid/autopulse.xml
change-me before clicking Apply.Docker Compose files for both SQLite and Postgres are provided in the example
# create a network
$ docker network create autopulse
# postgres database
$ docker run -d --net autopulse --name postgres -e POSTGRES_PASSWORD=autopulse -e POSTGRES_DB=autopulse postgres
$ docker run -d --net autopulse -e AUTOPULSE__APP__DATABASE_URL=postgres://postgres:autopulse@postgresql/autopulse --name autopulse ghcr.io/dan-online/autopulse
# sqlite database
$ docker run -d --net autopulse -e AUTOPULSE__APP__DATABASE_URL=sqlite://database.db --name autopulse ghcr.io/dan-online/autopulse
# or in-memory
$ docker run -d --net autopulse -e AUTOPULSE__APP__DATABASE_URL=sqlite://:memory: --name autopulse ghcr.io/dan-online/autopulse
All the documentation can be found on the website
Here's some quick links:
autopulse requires a configuration file to run. By default, it searches the current working directory for config.toml, config.yaml, config.yml, or config.json in that order. You can pass --config /path/to/config.toml to load an explicit file, and override values by setting environment variables in the format of: AUTOPULSE__{SECTION}__{KEY}.
For example: AUTOPULSE__APP__DATABASE_URL
An example has been provided in the example directory
Note: You can provide the config as
config.toml,config.yaml,config.yml, orconfig.jsonNote: You can also provide the path to a variable by appending
__FILEFor example:AUTOPULSE__AUTH__PASSWORD__FILE=/run/secrets/autopulse_password
autopulse uses basic authorization for the API. You can set the username and password in the config file or by setting the AUTOPULSE__AUTH__USERNAME and AUTOPULSE__AUTH__PASSWORD environment variables.
auth:
username: terry
password: yoghurt
Note: By default the username and password are
adminandpasswordrespectively, however it is HIGHLY recommended to change these values if you are exposing the API to the internet.
triggers:
my_sonarr:
type: "sonarr"
rewrite:
from: "/downloads"
to: "/tvshows"
filter:
exclude:
- "^/tvshows/extras/"
my_radarr:
type: "radarr"
rewrite:
from: "/downloads"
to: "/movies"
my_manual:
type: "manual"
rewrite:
from: "/downloads"
to: "/"
my_notify:
type: "notify"
paths:
- "/watch"
rewrite:
from: "/watch"
to: "/media"
webhooks:
my_discord:
type: "discord"
url: "https://discord.com/api/webhooks/1234567890/abcdefg"
my_discord_with_mentions:
type: "discord"
url: "https://discord.com/api/webhooks/1234567890/abcdefg"
mentions:
- targets:
- here
- role: "1234567890"
- user: "9876543210"
on: [failed, hash_mismatch]
- targets: [everyone]
my_hookshot:
type: "hookshot"
url: "https://matrix.example.com/_matrix/hookshot/webhook/abcdefg"
my_json:
type: "json"
url: "https://example.com/webhooks/autopulse"
targets:
my_plex:
type: "plex"
url: "http://plex:32400"
token: "<your_token>"
my_different_plex:
type: "plex"
url: "http://plex:32401"
token: "<your_token>"
rewrite:
from: "/media"
to: "/plex"
my_jellyfin:
type: "jellyfin"
url: "http://jellyfin:8096"
token: "<your_token>"
my_audiobookshelf:
type: "audiobookshelf"
url: "http://audiobookshelf:13378"
token: "<your_token>"
filter:
include:
- "^/audiobooks/"
exclude:
- "/samples/"
my_command:
type: "command"
raw: "echo $FILE_PATH >> list.txt"
By default a manual endpoint is provided which can be used to manually trigger a scan. This can be useful for testing or for when you want to trigger a scan without waiting for a file to be ready.
$ curl -u 'admin:password' 'http://localhost:2875/triggers/manual?path=/path/to/file&hash=1234567890'
# or
$ curl -H 'Authorization: Basic <base_64_encoded_login>' 'http://localhost:2875/triggers/manual?path=/path/to/file&hash=1234567890'
autopulse provides a configuration template API that allows external applications to dynamically generate configurations without embedding static TOML files. This is useful for applications like Bazarr that need to configure autopulse programmatically.
Returns configuration templates with optional parameters:
# Get basic templates
$ curl -u "admin:password" "http://localhost:2875/api/config-template"
# Get templates with specific types
$ curl -u "admin:password" "http://localhost:2875/api/config-template?database=postgres&triggers=sonarr,radarr&targets=plex,jellyfin&output=json"
Query Parameters:
- database: Database type (sqlite, postgres)
- triggers: Comma-separated trigger types (manual, sonarr, radarr, etc)
- targets: Comma-separated target types (plex, jellyfin, emby, etc)
- output: Output format (json, toml)
The web UI ships in the main autopulse image and is served at /ui/* on the same port (default 2875). It lets you browse scan events, retry failures, view config, and submit manual scans.
Default credentials are admin / password (the same as the API auth). Change them via the standard auth.username / auth.password config keys; sessions issued under old credentials are invalidated automatically.
To serve the UI behind a reverse proxy with a path prefix, set app.base_path and have the proxy pass the prefix through (no strip-prefix). UI routes mount under base_path server-side. See app settings for the full list of relevant options.
metadataRefreshMode currently set to FullRefreshContributions are what make the open-source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
This project follows the Conventional Commits specification
git checkout -b feat/AmazingFeature)git commit -m 'feat: add some AmazingFeature')git push origin feat/AmazingFeature)If you're a nix user then you can use the provided flake.nix to get started
# clone the repo
$ git clone https://github.com/dan-online/autopulse.git
$ cd autopulse
# basic easy config
$ cat <<EOF > config.toml
[app]
database_url = "sqlite://data/test.sqlite"
log_level = "trace"
EOF
# easy start using vendored/bundled dependencies
$ cargo run --features vendored
# or if you have the dependencies installed (libql-dev, libsqlite3-dev)
$ cargo run
# or if you only have one of the dependencies installed
$ cargo run --no-default-features --features sqlite # for sqlite
$ cargo run --no-default-features --features postgres # for postgres
Create a webhook/connection in the source app that points at the matching autopulse trigger:
http://<autopulse-host>:2875/triggers/<trigger-name>
For example, a config entry named triggers.radarr uses /triggers/radarr; triggers.my_radarr uses /triggers/my_radarr. Use POST and the same basic auth credentials configured under auth.username and auth.password.
Enable events that include file paths, such as import/download, upgrade, rename, and delete.
rewrite.from and rewrite.to?Use rewrite only when the path sent by the trigger is not the path autopulse or a target should use.
from is the path pattern in the webhook payload from Sonarr, Radarr, Lidarr, Readarr, etc.to is the path autopulse should process next.For Arr triggers, this usually means the final media path from the Arr app, not the temporar
$ claude mcp add autopulse \
-- python -m otcore.mcp_server <graph>