AI-powered TV channel programmer for Tunarr written in Go.
Program Director generates themed channel programming in Tunarr by:
- Syncing media metadata from Radarr and Sonarr to local database
- Using similarity scoring and LLM (Ollama) to intelligently select content matching themes
- Applying generated playlists to Tunarr channels with cooldown tracking
- AI-Powered Selection: Uses Ollama LLM for intelligent media curation
- Theme-Based Playlists: Configure themes with genres, keywords, and scheduling
- Database-Backed: SQLite or PostgreSQL for media caching and cooldown tracking
- Radarr/Sonarr Integration: Syncs and caches media metadata locally
- Trakt.tv Integration: Explore trending content and media metadata
- Tunarr Channels: Updates channel programming with curated content
- Cooldown Management: Prevents media from being replayed too frequently
- HTTP API Server: RESTful API with health checks and Prometheus metrics
- Cron Scheduler: Automated playlist generation on configurable schedules
- Kubernetes Ready: Comprehensive Helm charts for production deployment
- CLI & Server Modes: Run one-off generations or as a scheduled service
go install github.com/geekxflood/program-director@latestdocker pull ghcr.io/geekxflood/program-director:latestgit clone https://github.com/geekxflood/program-director.git
cd program-director
go build -o program-director .| Variable | Description | Required |
|---|---|---|
RADARR_API_KEY |
Radarr API key | Yes |
SONARR_API_KEY |
Sonarr API key | Yes |
RADARR_URL |
Radarr API URL | No |
SONARR_URL |
Sonarr API URL | No |
TUNARR_URL |
Tunarr API URL | No |
TRAKT_CLIENT_ID |
Trakt.tv client ID (optional) | No |
TRAKT_CLIENT_SECRET |
Trakt.tv client secret (optional) | No |
OLLAMA_URL |
Ollama API URL | No |
OLLAMA_MODEL |
Ollama model name (default: dolphin-llama3:8b) | No |
DB_DRIVER |
Database driver (postgres/sqlite) | No |
POSTGRES_HOST |
PostgreSQL host | No |
POSTGRES_PORT |
PostgreSQL port | No |
POSTGRES_DATABASE |
PostgreSQL database name | No |
POSTGRES_USER |
PostgreSQL user | No |
POSTGRES_PASSWORD |
PostgreSQL password | No |
Copy configs/config.example.yaml to config.yaml and customize:
database:
driver: "sqlite" # or "postgres"
sqlite:
path: "./data/program-director.db"
radarr:
url: "http://localhost:7878"
# api_key from RADARR_API_KEY env var
sonarr:
url: "http://localhost:8989"
# api_key from SONARR_API_KEY env var
tunarr:
url: "http://localhost:8000"
ollama:
url: "http://localhost:11434"
model: "dolphin-llama3:8b"
temperature: 0.7
num_ctx: 8192
cooldown:
movie_days: 30
series_days: 14
anime_days: 14
themes:
- name: "sci-fi-night"
description: "Science fiction themed evening"
channel_id: "your-tunarr-channel-id"
schedule: "0 20 * * *" # 8 PM daily (cron format)
media_types:
- "movie"
- "series"
genres:
- "Science Fiction"
keywords:
- "space"
- "future"
min_rating: 6.0
max_items: 10
duration: 300 # minutes# Sync media metadata from Radarr/Sonarr
program-director sync
program-director sync --movies # Sync only movies
program-director sync --series --cleanup # Sync TV shows and cleanup removed media
# Scan media library (display stats)
program-director scan
program-director scan --detailed # Show detailed statistics with top genres
# Generate playlist for a specific theme
program-director generate --theme sci-fi-night
program-director generate --theme sci-fi-night --dry-run # Preview without applying
# Generate playlists for all themes
program-director generate --all-themes
# Run as HTTP server
program-director serve
program-director serve --port 9000 # Custom port
program-director serve --enable-scheduler # With automated scheduling
program-director serve --schedule "0 */6 * * *" # Custom schedule (every 6 hours)
# Trakt.tv commands
program-director trakt trending --movies # Show trending movies
program-director trakt popular --shows # Show popular TV shows
program-director trakt search --query "Inception" # Search for media
# Show version
program-director version
# Enable debug logging
program-director --debug sync
program-director --json serve # JSON formatted logsdocker run --rm \
-e RADARR_API_KEY=your-key \
-e SONARR_API_KEY=your-key \
-e OLLAMA_URL=http://ollama:11434 \
-e TUNARR_URL=http://tunarr:8000 \
-e RADARR_URL=http://radarr:7878 \
-e SONARR_URL=http://sonarr:8989 \
-v /path/to/config.yaml:/app/config/config.yaml \
-v /path/to/data:/app/data \
ghcr.io/geekxflood/program-director:latest \
generate --all-themesversion: '3.8'
services:
program-director:
image: ghcr.io/geekxflood/program-director:latest
environment:
- RADARR_API_KEY=${RADARR_API_KEY}
- SONARR_API_KEY=${SONARR_API_KEY}
volumes:
- ./config.yaml:/app/config/config.yaml
- ./data:/app/data
command: serveWhen running in server mode, Program Director provides a RESTful API:
# Start the HTTP server
program-director serve --port 8080
# Available endpoints:
# GET /health - Health check
# GET /ready - Readiness check (database connectivity)
# GET /metrics - Prometheus metrics
# GET /api/v1/media - List media items
# POST /api/v1/media/sync - Trigger media sync
# GET /api/v1/themes - List configured themes
# POST /api/v1/generate - Generate all playlists
# POST /api/v1/generate/:id - Generate specific theme
# GET /api/v1/history - View play history
# GET /api/v1/cooldowns - View active cooldowns
# POST /api/v1/webhooks - Webhook endpointDeploy Program Director to Kubernetes using Helm:
# Install with default values
helm install program-director ./charts/program-director
# Install with custom values
helm install program-director ./charts/program-director \
--set config.radarr.apiKey=your-key \
--set config.sonarr.apiKey=your-key \
--values custom-values.yaml
# Using production values
helm install program-director ./charts/program-director \
--values charts/program-director/values-production.yamlFor ArgoCD GitOps deployment, apply the ApplicationSet:
kubectl apply -f argocd/applicationset.yamlSee charts/program-director/README.md for complete Helm documentation.
┌─────────────┐ ┌────────────────────────────┐ ┌─────────────┐
│ Radarr │────▶│ Program Director (Go) │────▶│ Tunarr │
│ (Movies) │ │ │ │ (Channels) │
└─────────────┘ │ ┌──────────────────────┐ │ └─────────────┘
│ │ Media Sync Service │ │
┌─────────────┐ │ └──────────────────────┘ │
│ Sonarr │────▶│ ▼ │
│ (TV/Anime) │ │ ┌──────────────────────┐ │
└─────────────┘ │ │ Database (SQLite/PG) │ │
│ └──────────────────────┘ │
┌─────────────┐ │ ▼ │
│ Ollama │◀────│ ┌──────────────────────┐ │
│ (LLM AI) │ │ │ Playlist Generator │ │
└─────────────┘ │ │ + Similarity Scorer │ │
│ └──────────────────────┘ │
│ ▼ │
│ ┌──────────────────────┐ │
│ │ Cooldown Manager │ │
│ └──────────────────────┘ │
└────────────────────────────┘- Media Sync: Periodically fetches media metadata from Radarr/Sonarr
- Database: Caches media and tracks playback history/cooldowns
- Similarity Scorer: Ranks media by genre, keyword, and rating matching
- LLM Integration: Uses Ollama for intelligent content selection
- Playlist Generator: Builds themed lineups respecting cooldowns
- Cooldown Manager: Prevents repetitive content across channels
# Clone repository
git clone https://github.com/geekxflood/program-director.git
cd program-director
# Install dependencies
go mod download
# Build
go build -o program-director .
# Run locally
./program-director --help# Run all tests
go test ./...
# With coverage
go test -cover ./...
# Verbose output
go test -v ./...# Format code
go fmt ./...
# Lint
golangci-lint run
# Vet
go vet ./...MIT License - see LICENSE for details.
- Initial Sync: Run
program-director syncto populate the database with your media - Configure Themes: Edit
config.yamlwith your Tunarr channel IDs and theme definitions - Generate Playlists: Run
program-director generate --all-themesto create programming - Schedule Updates: Use
program-director serveto run as a service with automatic scheduling - Monitor: Check logs and database for playlist history and cooldown tracking