Using the HTTP API of tinyMediaManager
tinyMediaManager (commonly referred to as tmm) is a GUI application for organizing and managing local libraries of movies and TV shows. While it’s primarily desktop-oriented, it also includes a powerful but minimal HTTP API, making it suitable for automated and headless environments.
This blog post walks you through enabling the API, how it works internally, and how to integrate it with automation tools like Radarr, Sonarr, SABnzbd, or even shell scripts.
⚙️ What Is the tmm HTTP API?
The tmm HTTP API allows you to trigger core media actions:
- 🔄 Update data sources (scan folders)
- 🧲 Scrape metadata
- 🔧 Download trailers/subtitles
- 📝 Rename media files
- …
It’s designed for lightweight remote control, not full database querying. Think of it as a command queue for background jobs.
🛠️ How to Enable the API
To use the API, you must enable it in the tmm GUI.
✅ Steps:
- Open Settings →
General
→System
→HTTP API
. - Check ✅ Enable HTTP API.
- An API key (a random GUID) is pre-generated - you may use this or create your own.
- Choose the listening port (default is
7878
).
🔐 Keep your API key secure - anyone with access can control your media library.
🔐 Authentication and Request Format
All API requests must be authenticated using a custom header:
1
api-key: your-api-key
Do not pass the API key as a query parameter - it will be ignored.
📦 JSON Payload Format
All commands are issued as POST
requests with JSON.
Here’s the basic structure:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[
{
"action": <action name>,
"scope": {
"name": <scope name>,
"args": [
<value>
]
},
"args": {
<key>: <value>
}
},
...
]
You will find more details about possible actions and arguments in the Official API Documentation.
🧭 Understanding the scope = new
Behavior
This is one of the most misunderstood parts of the tmm API.
1
2
3
"scope": {
"name": "new"
}
This does not mean “process anything newly added since last time.”
Instead, here’s how it works:
If you include
"scope": "new"
in the same API call asupdate
, only media items detected during that update will be processed by subsequent commands (e.g.,scrape
,rename
).
🧠 Important notes:
- The
"new"
scope has no memory. It only applies to the results of theupdate
command in the same request. - If you run
scrape
alone with"scope": "new"
- it will do nothing, because there’s no list of new items.
✅ Correct Usage:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[
{
"action": "update",
"scope": {
"name": "all"
}
},
{
"action": "scrape",
"scope": {
"name": "new"
}
},
{
"action": "rename",
"scope": {
"name": "new"
}
}
]
This will:
- Scan your sources for new files.
- Scrape metadata only for new entries found in that scan.
- Rename those new entries.
🔄 API Execution Flow
Here’s how a request is processed inside tmm:
sequenceDiagram
participant ExternalTool as 🧰 External Tool (e.g. Radarr)
participant HttpServer as 🌐 tmm HTTP Server
participant CommandParser as ⚙️ Command Parser
participant JobQueue as 📬 Async Job Queue
participant Core as 📦 Core Executor
ExternalTool->>HttpServer: POST /api/v1/command\n+ JSON Payload\n+ api-key
HttpServer->>CommandParser: ✅ Validate & Parse
CommandParser->>JobQueue: 📨 Enqueue Commands
JobQueue-->>CommandParser: 🆗 Job(s) Queued
CommandParser-->>HttpServer: 🆗 Job(s) Queued
HttpServer-->>ExternalTool: 📬 HTTP 200 OK
JobQueue->>Core: 🔄 Execute Jobs (Async)
Core-->>JobQueue: ✅ Done
📝 Summary:
- The client receives
200 OK
once the commands are queued - not when they finish. - Jobs are processed asynchronously, in the internal order defined by the source code.
- The
"scope"
affects command behavior only within the context of this request.
🧩 Execution Order of Commands
Even though you send multiple commands like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[
{
"action": "rename",
"scope": {
"name": "new"
}
},
{
"action": "scrape",
"scope": {
"name": "new"
}
},
{
"action": "update",
"scope": {
"name": "all"
}
}
]
They are always processed in the predefined internal order, for example:
update
scrape
rename
This behavior is hardcoded in the tmm source files:
🧭 The order in your JSON request does not matter.
🧪 Real-World Automation Examples
🎬 Example: Scrape and Rename Newly Added Movies
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
curl -X POST http://localhost:7878/api/movie \
-H "Content-Type: application/json" \
-H "api-key: your-api-key" \
-d '[
{
"action": "update",
"scope": {
"name": "all"
}
},
{
"action": "scrape",
"scope": {
"name": "new"
}
},
{
"action": "rename",
"scope": {
"name": "new"
}
}
]'
📺 Example: TV Show Automation After Import of New Episodes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
curl -X POST http://localhost:7878/api/tvshow \
-H "Content-Type: application/json" \
-H "api-key: your-api-key" \
-d '[
{
"action": "update",
"scope": {
"name": "path",
"args": "/media/tv_shows/Show 1"
}
},
{
"action": "scrape",
"scope": {
"name" : "new"
}
}
]'
🖥️ Clean Bash Script Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
API_KEY="your-api-key"
API_URL="http://localhost:7878/api/movie"
curl -X POST "$API_URL" \
-H "Content-Type: application/json" \
-H "api-key: $API_KEY" \
-d '{
"action": "update",
"scope": {
"name": "all"
}
}'
📚 Resources
🧠 Final Thoughts
tinyMediaManager isn’t just for GUI users. With its JSON-based HTTP API, you can fully automate your media processing workflow:
- Trigger updates and metadata scraping after downloads
- Automatically rename files
- Integrate with Radarr, Sonarr, or custom scripts
Just remember:
- 📬 Use
POST
withContent-Type: application/json
- 🔐 Authenticate via
api-key
- 🔄 Commands are queued and run asynchronously
- 📑 Internal order of commands is fixed
- ⚠️
scope = new
only works withupdate
in the same request
With these tools, tmm becomes a solid part of any modern media automation setup.