Mediasage
Unofficial AI-powered Plex playlist generator with library awareness. Every track it suggests, you actually own.
Install / Use
/learn @ecwilsonaz/MediasageQuality Score
Category
Development & EngineeringSupported Platforms
README
MediaSage for Plex
AI-powered playlists and album recommendations for Plex—using only music you actually own.
MediaSage is a self-hosted web app that creates playlists and recommends albums by combining LLM intelligence with your Plex library. Every suggestion is guaranteed playable because it only considers music you have.
Sample Generated Playlist:

Sample Generated Album Recommendation:

Home Screen:

Playlist Flow:

Album Flow:

Quick Start
docker run -d \
--name mediasage \
-p 5765:5765 \
-v mediasage-data:/app/data \
--restart unless-stopped \
ghcr.io/ecwilsonaz/mediasage:latest
Open http://localhost:5765 — a setup wizard walks you through connecting Plex, choosing an AI provider, and syncing your library.
You can also pass credentials as environment variables to skip the wizard. See Configuration for details.
Requirements: Docker, a Plex server with music, a Plex token, and an API key from Google, Anthropic, or OpenAI (or a local model via Ollama).
Contents
Why MediaSage?
Plex users with personal music libraries have few good options for AI playlists.
Plexamp's built-in Sonic Sage used ChatGPT to generate playlists, but it was designed around Tidal streaming. The AI recommended tracks from an unlimited catalog, and Tidal made them playable. The "limit to library" setting just hid results you didn't own—so if you asked for 25 tracks and only 4 existed in your library, you got a 4-track playlist.
When Tidal integration ended in October 2024, Sonic Sage lost its foundation. Generic tools like ChatGPT have the same problem: they recommend from an infinite catalog with no awareness of what you actually own.
MediaSage inverts the approach:
| Filter-Last (Sonic Sage, ChatGPT) | Filter-First (MediaSage) | |-----------------------------------|-------------------------| | AI recommends from infinite catalog | AI only sees your library | | Hide missing tracks after | No missing tracks possible | | Near-empty playlists | Full playlists, every time |
The result: every track in every playlist exists in your Plex library and plays immediately.
Features
Playlist Generation
Create playlists two ways:
Describe what you want — Natural language prompts like:
- "Melancholy 90s alternative for a rainy day"
- "Upbeat instrumental jazz for a dinner party"
- "Late night electronic, nothing too aggressive"
Start from a song — Pick a track you love, then explore musical dimensions: mood, era, instrumentation, genre, production style. Select which qualities you want more of.
Album Recommendations
Describe a mood or moment, answer two quick questions about your preferences, and get a single perfect album to listen to—with an editorial pitch explaining why it fits.
- Library mode — recommends albums you own, ready for instant playback
- Discovery mode — suggests albums you don't own yet, based on your taste profile
- Familiarity control — choose between comfort picks, hidden gems, or rediscoveries
- Show Me Another — regenerate without starting over
- Primary recommendation with a full write-up, plus two secondary picks
Smart Filtering
Before the AI sees anything, you control the pool:
- Genres — Select from your library's actual genre tags
- Decades — Filter by era
- Minimum rating — Only tracks rated 3+, 4+, etc.
- Exclude live versions — Skip concert recordings automatically
Real-time track counts show exactly how your filters narrow results.
Local Library Cache
MediaSage syncs your Plex library to a local SQLite database. After a one-time sync (~2 min for 18,000 tracks), all library operations—filtering, counting, sending to AI—happen locally in milliseconds instead of waiting on Plex.
- Setup wizard walks you through first-run configuration and sync
- Footer status shows track count and last sync time
- Auto-refresh keeps cache current (syncs if >24h stale)
- Manual refresh available anytime
Multi-Provider Support
Bring your own API key—or run locally:
| Provider | Max Tracks | Typical Cost | Best For | |----------|------------|--------------|----------| | Google Gemini | ~18,000 | $0.03 – $0.25 | Large libraries, lowest cost | | Anthropic Claude | ~3,500 | $0.15 – $0.25 | Nuanced recommendations | | OpenAI GPT | ~2,300 | $0.05 – $0.10 | Solid all-around | | Ollama ⚗️ | Varies | Free | Privacy, local inference | | Custom ⚗️ | Configurable | Free | Self-hosted, OpenAI-compatible APIs |
⚗️ Local LLM support is experimental. Report issues.
Free option: Google Gemini offers a free API tier that's more than enough for personal use — no credit card required. See the Gemini free credit guide for setup instructions and details.
Estimated cost displays before you generate. MediaSage auto-detects your provider based on which key you configure.
Play and Save
- Play Now — send tracks directly to any Plex device for instant playback
- Create a new playlist, replace an existing one, or append tracks to one
- Device picker shows all active Plex clients with status indicators
- Duplicate detection when appending to existing playlists
- Preview tracks with album art before saving
- Remove tracks you don't want
- Rename the playlist
- See actual token usage and cost
Installation
Docker Compose (Recommended)
mkdir mediasage && cd mediasage
curl -O https://raw.githubusercontent.com/ecwilsonaz/mediasage/main/docker-compose.yml
curl -O https://raw.githubusercontent.com/ecwilsonaz/mediasage/main/.env.example
mv .env.example .env
Edit .env:
PLEX_URL=http://your-plex-server:32400
PLEX_TOKEN=your-plex-token
# Choose ONE provider:
GEMINI_API_KEY=your-gemini-key
# ANTHROPIC_API_KEY=sk-ant-your-key
# OPENAI_API_KEY=sk-your-key
Start:
docker compose up -d
NAS Platforms
<details> <summary><strong>Synology (Container Manager)</strong></summary>GUI:
- Container Manager → Registry → Search
ghcr.io/ecwilsonaz/mediasage - Download
latesttag - Container → Create
- Port: 5765 → 5765
- Add environment variables:
PLEX_URL,PLEX_TOKEN,GEMINI_API_KEY
Docker Compose:
mkdir -p /volume1/docker/mediasage && cd /volume1/docker/mediasage
curl -O https://raw.githubusercontent.com/ecwilsonaz/mediasage/main/docker-compose.yml
curl -O https://raw.githubusercontent.com/ecwilsonaz/mediasage/main/.env.example
mv .env.example .env && nano .env
Then in Container Manager → Project → Create, point to /volume1/docker/mediasage.
No Docker? Some Synology models (especially ARM-based units) don't support Docker/Container Manager. See Bare Metal below for running MediaSage directly with Python.
</details> <details> <summary><strong>Unraid</strong></summary>- Docker → Add Container
- Repository:
ghcr.io/ecwilsonaz/mediasage:latest - Port: 5765 → 5765
- Add variables:
PLEX_URL,PLEX_TOKEN,GEMINI_API_KEY
- Apps → Discover Apps → Custom App
- Image:
ghcr.io/ecwilsonaz/mediasage, Tag:latest - Port: 5765
- Add environment variables
Stacks → Add Stack:
services:
mediasage:
image: ghcr.io/ecwilsonaz/mediasage:latest
ports:
- "5765:5765"
environment:
- PLEX_URL=http://your-server:32400
- PLEX_TOKEN=your-token
- GEMINI_API_KEY=your-key
volumes:
- ./data:/app/data
restart: unless-stopped
</details>
Bare Metal (No Docker)
Docker isn't required. MediaSage is Python + FastAPI with no native dependencies, so it runs on any machine with Python 3.11+ — including ARM-based Synology NAS models, Raspberry Pis, or any Linux/macOS/Windows box.
git clone https://github.com/ecwilsonaz/mediasage.git
cd mediasage
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
Set your environment variables:
export PLEX_URL=http://your-plex-server:32400
export PLEX_TOKEN=your-plex-token
export GEMINI_API_KEY=your-gemini-key
Start the server:
uvicorn backend.main:app --host 0.0.0.0 --port 5765
Access at http://your-machine-ip:5765.
<details> <summary><strong>Running as a background service (systemd)</strong></summary>To keep MediaSage running after you close your terminal, create a systemd service:
# /etc/systemd/system/mediasage.service
[Unit]
Description=MediaSage
After=network.target
[Service]
Type=simple
User=your-user
WorkingDirectory=/pat
