Plex Media Server API — library management, media search, playback sessions, server status, and automation
48
52%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./plex-media-server/SKILL.mdManage your Plex Media Server: scan libraries, search media, monitor playback sessions, and automate maintenance.
All Plex API calls require an X-Plex-Token. Find yours:
X-Plex-Token=curl -s "https://plex.tv/api/v2/user" -H "X-Plex-Token: YOUR_TOKEN" | jq .export PLEX_URL="http://localhost:32400"
export PLEX_TOKEN="YOUR_PLEX_TOKEN"# Server identity
curl -s -H "X-Plex-Token: $PLEX_TOKEN" \
-H "Accept: application/json" \
"$PLEX_URL/identity" | jq .
# Server capabilities
curl -s -H "X-Plex-Token: $PLEX_TOKEN" \
-H "Accept: application/json" \
"$PLEX_URL/" | jq '.MediaContainer | {friendlyName, version, platform, updatedAt}'
# Server preferences
curl -s -H "X-Plex-Token: $PLEX_TOKEN" \
-H "Accept: application/json" \
"$PLEX_URL/:/prefs" | jq '.MediaContainer.Setting[] | {id, value}'curl -s -H "X-Plex-Token: $PLEX_TOKEN" \
-H "Accept: application/json" \
"$PLEX_URL/library/sections" | \
jq '.MediaContainer.Directory[] | {key, title, type, agent, scanner}'# Scan specific library (use key from list)
curl -s -X POST -H "X-Plex-Token: $PLEX_TOKEN" \
"$PLEX_URL/library/sections/SECTION_KEY/refresh"
# Scan all libraries
curl -s -X POST -H "X-Plex-Token: $PLEX_TOKEN" \
"$PLEX_URL/library/sections/all/refresh"
# Force full metadata refresh
curl -s -X POST -H "X-Plex-Token: $PLEX_TOKEN" \
"$PLEX_URL/library/sections/SECTION_KEY/refresh?force=1"# List all items in a library section
curl -s -H "X-Plex-Token: $PLEX_TOKEN" \
-H "Accept: application/json" \
"$PLEX_URL/library/sections/SECTION_KEY/all" | \
jq '.MediaContainer.Metadata[] | {title, year, rating, addedAt}'
# Recently added
curl -s -H "X-Plex-Token: $PLEX_TOKEN" \
-H "Accept: application/json" \
"$PLEX_URL/library/recentlyAdded" | \
jq '.MediaContainer.Metadata[] | {title, type, year, addedAt}'
# On deck (continue watching)
curl -s -H "X-Plex-Token: $PLEX_TOKEN" \
-H "Accept: application/json" \
"$PLEX_URL/library/onDeck" | \
jq '.MediaContainer.Metadata[] | {title, grandparentTitle, viewOffset, duration}'# Search across all libraries
curl -s -H "X-Plex-Token: $PLEX_TOKEN" \
-H "Accept: application/json" \
"$PLEX_URL/hubs/search?query=inception" | \
jq '.MediaContainer.Hub[] | {type, size, Metadata: [.Metadata[]? | {title, year, type}]}'
# Search specific library
curl -s -H "X-Plex-Token: $PLEX_TOKEN" \
-H "Accept: application/json" \
"$PLEX_URL/library/sections/SECTION_KEY/search?query=inception" | \
jq '.MediaContainer.Metadata[] | {title, year, summary}'curl -s -H "X-Plex-Token: $PLEX_TOKEN" \
-H "Accept: application/json" \
"$PLEX_URL/status/sessions" | \
jq '.MediaContainer.Metadata[]? | {
title,
user: .User.title,
player: .Player.title,
state: .Player.state,
progress: ((.viewOffset / .duration * 100) | round),
transcoding: (.TranscodeSession != null)
}'curl -s -H "X-Plex-Token: $PLEX_TOKEN" \
-H "Accept: application/json" \
"$PLEX_URL/status/sessions/history/all" | \
jq '.MediaContainer.Metadata[] | {title, viewedAt, accountID}'curl -s -H "X-Plex-Token: $PLEX_TOKEN" \
-H "Accept: application/json" \
"$PLEX_URL/library/metadata/RATING_KEY" | \
jq '.MediaContainer.Metadata[0] | {title, year, summary, rating, Media: [.Media[] | {videoResolution, bitrate, container}]}'# Seasons of a show
curl -s -H "X-Plex-Token: $PLEX_TOKEN" \
-H "Accept: application/json" \
"$PLEX_URL/library/metadata/SHOW_RATING_KEY/children" | \
jq '.MediaContainer.Metadata[] | {title, index, leafCount}'
# Episodes of a season
curl -s -H "X-Plex-Token: $PLEX_TOKEN" \
-H "Accept: application/json" \
"$PLEX_URL/library/metadata/SEASON_RATING_KEY/children" | \
jq '.MediaContainer.Metadata[] | {title, index, duration}'curl -s -X PUT -H "X-Plex-Token: $PLEX_TOKEN" \
"$PLEX_URL/library/optimize"curl -s -X PUT -H "X-Plex-Token: $PLEX_TOKEN" \
"$PLEX_URL/library/clean/bundles"curl -s -X PUT -H "X-Plex-Token: $PLEX_TOKEN" \
"$PLEX_URL/library/sections/SECTION_KEY/emptyTrash"# Analyze all items in a library
curl -s -X POST -H "X-Plex-Token: $PLEX_TOKEN" \
"$PLEX_URL/library/sections/SECTION_KEY/analyze"# Get list of available players
curl -s -H "X-Plex-Token: $PLEX_TOKEN" \
-H "Accept: application/json" \
"$PLEX_URL/clients" | \
jq '.MediaContainer.Server[] | {name, address, port, machineIdentifier}'services:
plex:
image: lscr.io/linuxserver/plex:latest
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Amsterdam
- VERSION=docker
- PLEX_CLAIM=claim-XXXXX # From https://plex.tv/claim
ports:
- "32400:32400"
volumes:
- ./plex-config:/config
- /path/to/movies:/movies
- /path/to/tv:/tv
restart: unless-stoppedPlex can send webhooks on playback events (requires Plex Pass):
Events: media.play, media.pause, media.resume, media.stop, media.scrobble, library.new, library.on.deck
Configure in Settings → Webhooks → Add Webhook URL.
# Receive webhook and forward to ntfy (simple Flask/Node server)
# Plex sends POST with JSON payload containing event type and metadata
# Parse and forward:
curl -H "Authorization: Bearer $NTFY_TOKEN" \
-H "Tags: movie_camera" \
-d "New on Plex: $TITLE ($YEAR)" \
"https://ntfy.example.com/plex"Trigger Plex library scan after Radarr/Sonarr imports:
This automatically scans the relevant library section after new media is imported.
| Problem | Fix |
|---|---|
| Library not showing new files | Trigger manual scan: POST /library/sections/KEY/refresh |
| Remote access not working | Check port 32400 forwarded, or use reverse proxy. Check Settings → Remote Access |
| Transcoding issues | Check hardware transcoding enabled. Verify /dev/dri mapped for Intel QSV |
| Slow library scan | Run optimize and clean/bundles. Check disk I/O |
| Metadata wrong | Force refresh: PUT /library/metadata/KEY/refresh?force=1 |
| "Not authorized" | Token expired or wrong. Re-fetch from Plex Web UI |
| Database locked | Stop Plex, check for com.plexapp.plugins.library.db-wal, restart |
808c382
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.