Skip to content
cromo9Public

About

Stalk over Radarr and Sonarr to download from a m3u playlist.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

202 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Stalkerr Logo

Stalkerr

Turn m3u playlists into source for Radarr and Sonarr

Parse M3U playlists and download missing media items from Radarr and Sonarr via direct links.

Features

  • πŸ“Ί Parse M3U playlist files for movies and TV shows
  • πŸ“₯ M3U Download - Download and archive M3U playlists from remote URLs with automatic rotation
  • 🎬 TMDB Integration - Enrich media metadata with title, year, genres, posters, and more
  • πŸ—„οΈ Store media information in PostgreSQL database
  • πŸ” Filter playlist items based on configurable patterns
  • 🌍 Multi-language support for TMDB metadata (English, French, Spanish, etc.)
  • 🎯 Identify missing items from Radarr and Sonarr
  • ⬇️ Download missing items via direct links
  • πŸš€ REST API for querying and managing media items
  • πŸ“Š Processing logs and statistics
  • πŸ–₯️ Web Dashboard (IHM) - Modern light-themed dashboard built with React 19 and Radix UI to explore playlists, monitor download progress, view processing logs, and execute folder-level media moves. Fully responsive on mobile.
  • πŸ”— Radarr/Sonarr path reconciliation - Automatic reconciliation of download destinations against Radarr/Sonarr root folders and monitored items
  • 🏷️ Automatic quality/language tagging of downloaded filenames
  • ⚠️ Dedicated downloads error tab with cancel, resync-path, and rename actions
  • πŸ—‚οΈ Grouped playlist view with per-group filters and expandable latest-run details

Architecture

Stalkerr bridges an IPTV/M3U playlist to Radarr/Sonarr: it figures out what those tools are still missing and downloads it straight from the M3U source over HTTP (no torrents involved, despite the repo's home). The diagrams below give the shape of the system before you dive into setup.

Stalkerr Overview

For more information about architecture implementation, you can read the page ARCHITECTURE.md.

Quick Start

Option 1: Docker (Recommended)

The fastest way to get started:

# Clone and start
git clone https://github.com/glefebvre/stalkerr.git
cd stalkerr
cp .env.example .env
docker-compose up -d

# Verify
curl http://localhost:8080/health

For detailed Docker deployment instructions, see:

Scheduled Execution: enable the cron profile (docker-compose --profile stalkerr --profile cron up -d) for an opt-in Ofelia sidecar that runs m3u-download/process/download on the same default cadence as the Helm chart's CronJob resources below. See Docker Quick Start for the full recipe, including a lower-privilege host-crontab alternative.

Option 2: Kubernetes (Helm)

A Helm chart is available under charts/stalkerr for deploying Stalkerr to a Kubernetes cluster, including a CronJob for scheduled processing. See charts/stalkerr/README.md for values and installation instructions.

Option 3: Build from Source

Prerequisites

  • Go 1.25 or higher
  • PostgreSQL 12 or higher
  • M3U playlist file

Installation

# Clone the repository
git clone https://github.com/glefebvre/stalkerr.git
cd stalkerr

# Install dependencies
go mod download

# Build the application
make build

Configuration

  1. Copy the example configuration:
cp config.yml.example config.yml
  1. Edit config.yml with your settings:
database:
  host: localhost
  port: 5432
  user: stalkerr
  password: your_password
  dbname: stalkerr

m3u:
  update_interval: 3600
  sources:
    - name: default
      file_path: /path/to/playlist.m3u

tmdb:
  enabled: true
  api_key: your_tmdb_api_key  # Get from https://www.themoviedb.org/settings/api
  language: en-US  # Language for metadata (en-US, fr-FR, es-ES, etc.)

api:
  port: 8080

Or use environment variables (m3u.sources is config-file only - see docs/M3U-DOWNLOAD.md):

export STALKEER_DATABASE_USER=stalkeer
export STALKEER_DATABASE_PASSWORD=your_password
export STALKEER_DATABASE_DBNAME=stalkeer

Running

# Process an M3U playlist file and store to database
./bin/stalkeer process /path/to/playlist.m3u

# Process with TMDB enrichment in French
./bin/stalkeer process /path/to/playlist.m3u --tmdb-language fr-FR

# Process without TMDB enrichment (faster)
./bin/stalkeer process /path/to/playlist.m3u --skip-tmdb

# Process with limit
./bin/stalkeer process /path/to/playlist.m3u --limit 100

# Force re-processing of existing entries
./bin/stalkeer process /path/to/playlist.m3u --force

# Dry-run analysis without database changes
./bin/stalkeer dryrun /path/to/playlist.m3u --limit 100

# Start the REST API server
./bin/stalkeer server --port 8080

# Run database migrations
./bin/stalkeer migrate

# Resume incomplete or failed downloads
./bin/stalkeer resume-downloads

# Resume downloads with options
./bin/stalkeer resume-downloads --limit 10 --parallel 5 --verbose

# Preview what would be resumed (dry-run)
./bin/stalkeer resume-downloads --dry-run

# Download missing movies/episodes from Radarr and Sonarr
./bin/stalkeer download --limit 20

# Preview matches without downloading
./bin/stalkeer download --dry-run

# Check version
./bin/stalkeer version

# Get help
./bin/stalkeer --help
./bin/stalkeer process --help

CLI Commands

m3u-download

Download M3U playlist from a remote URL and save it to the configured file path:

stalkeer m3u-download [flags]

Flags:
      --url string     M3U playlist URL (overrides config)
      --no-archive     skip creating archive copy

The m3u-download command:

  • Downloads M3U playlist from the configured URL or --url flag
  • Validates M3U format before saving
  • Saves to each configured source's effective file path atomically
  • Creates a timestamped archive copy (unless --no-archive)
  • Automatically rotates old archives based on retention settings

Example usage:

# Download using configured URL
stalkeer m3u-download

# Download from specific URL
stalkeer m3u-download --url https://example.com/playlist.m3u

# Download without creating archive
stalkeer m3u-download --no-archive

m3u-list-archives

List all archived M3U playlist files with timestamps and sizes:

stalkeer m3u-list-archives

Example output:

Archived M3U files (./m3u_playlist):

Filename                                 Size         Modified
--------------------------------------------------------------------------------
playlist_20260203_230154.054749.m3u      40.96 MB     2026-02-03 23:01:54
playlist_20260203_225902.373353.m3u      40.96 MB     2026-02-03 22:59:02
playlist_20260202_120000.000000.m3u      40.95 MB     2026-02-02 12:00:00

Total: 3 archived files

m3u-cleanup-archives

Manually trigger rotation of M3U archive files:

stalkeer m3u-cleanup-archives [flags]

Flags:
      --retention int   number of archives to keep (default: use config value)

Example usage:

# Clean up using configured retention count
stalkeer m3u-cleanup-archives

# Keep only the 3 most recent archives
stalkeer m3u-cleanup-archives --retention 3

process

Process an M3U playlist file, classify content, enrich with TMDB metadata, and store entries in the database:

stalkeer process [m3u file] [flags]

Flags:
      --force              re-process existing entries
      --limit int          maximum number of items to process (0 = no limit)
      --batch-size int     batch size for database inserts (default 100)
      --progress int       show progress every N entries (default 1000)
      --skip-tmdb          skip TMDB metadata enrichment
      --tmdb-language      TMDB API language (e.g., 'en-US', 'fr-FR')

Example output:

=== Processing Complete ===
Total lines in file:  1000
Successfully processed: 985
Duplicates skipped:   5
Filtered out:         8
Errors:               2

Content breakdown:
  Movies:        742
  TV Shows:      231
  Channels:      0
  Uncategorized: 12

TMDB Enrichment:
  Matched:       891
  Not found:     76
  Errors:        6
  Match rate:    92.1%

Processing time: 1.2s

resume-downloads

Resume incomplete or failed downloads that were interrupted:

stalkeer resume-downloads [flags]

Flags:
      --dry-run             preview downloads without executing
      --limit int           maximum number of downloads to process (0 = no limit)
      --parallel int        number of concurrent downloads (default 3)
      --max-retries int     maximum retry attempts (default 5)
      --clean-stale-locks   clean up stale download locks before resuming (default true)
  -v, --verbose             verbose output
      --service string      filter by service type: all, radarr, sonarr (default "all")

The resume-downloads command identifies and resumes downloads that:

  • Were interrupted by application shutdown or crashes
  • Failed due to temporary network issues
  • Are in pending, downloading, paused, or failed states
  • Haven't exceeded the maximum retry limit

Example usage:

# Resume all incomplete downloads
stalkeer resume-downloads

# Preview what would be resumed
stalkeer resume-downloads --dry-run --verbose

# Resume up to 10 downloads with 5 concurrent workers
stalkeer resume-downloads --limit 10 --parallel 5

# Resume only failed Radarr downloads
stalkeer resume-downloads --service radarr

download

Unified command that downloads missing movies (Radarr) and TV episodes (Sonarr) by matching against the M3U playlist. This command replaces the removed radarr and sonarr commands. Resuming incomplete downloads and tier-2 upgrades are now handled automatically by the scheduler (see downloads.force_tier_probability in the config) instead of dedicated --resume/--force flags:

stalkeer download [flags]

Flags:
      --dry-run      preview planned streams without downloading
      --limit int    maximum number of work units (movies/series) to consider (0 = no limit)
      --parallel int number of concurrent worker streams
  -v, --verbose      verbose output

cleanup

Clean up orphaned temp download files:

stalkeer cleanup [flags]

Flags:
      --dry-run             preview cleanup without deleting files
      --retention-hours int delete temp files older than this many hours (default 24)

config

Validate and display the current configuration:

stalkeer config [flags]

Flags:
      --show-secrets   reveal password fields

db-prune

Prune expired M3U stream URLs and orphaned metadata:

stalkeer db-prune [flags]

Flags:
      --dry-run   simulate pruning and display metrics without deleting
      --hard      force delete downloaded and downloading stream records

enrich-tvdb

Backfill missing TVDB IDs on Movie and TVShow records:

stalkeer enrich-tvdb [flags]

Flags:
      --dry-run     preview records that would be updated without writing to database
      --limit int   maximum number of records to process (0 = no limit)
  -v, --verbose     verbose output

reset

Surgically reset a specific movie or TV show stream state by ID:

stalkeer reset movie --id 42
stalkeer reset tvshow --id 17

dryrun

Analyze M3U playlist file without making database changes:

stalkeer dryrun [m3u file] [flags]

Flags:
      --limit int   maximum number of items to analyze (default 100)

server

Start the REST API server:

stalkeer server [flags]

Flags:
  -p, --port int       port to run the server on (default 8080)
  -a, --address string address to bind the server to (default "0.0.0.0")

migrate

Run database migrations:

stalkeer migrate

Using Docker Compose

# Start PostgreSQL
docker-compose up -d postgres

# Run the application
./bin/stalkeer process

Development

Project Structure

stalkerr/
β”œβ”€β”€ cmd/                    # CLI commands (process, download, resume-downloads,
β”‚                           # cleanup, config, db-prune, enrich-tvdb, reset, server, ...)
β”œβ”€β”€ frontend/               # React 19 + Radix UI Frontend Web Dashboard
β”œβ”€β”€ internal/               # Private application code
β”‚   β”œβ”€β”€ api/               # REST API handlers
β”‚   β”œβ”€β”€ classifier/        # Content classification (movie/TV/channel)
β”‚   β”œβ”€β”€ config/            # Configuration management
β”‚   β”œβ”€β”€ database/          # Database connection and migrations
β”‚   β”œβ”€β”€ downloader/        # Download engine (resume, tiers, path reconciliation)
β”‚   β”œβ”€β”€ external/          # Radarr/Sonarr/TMDB/TVDB API clients
β”‚   β”œβ”€β”€ filter/            # Include/exclude pattern filtering
β”‚   β”œβ”€β”€ logger/            # Modular application/database logging
β”‚   β”œβ”€β”€ matcher/           # Playlist-to-Radarr/Sonarr matching
β”‚   β”œβ”€β”€ models/            # Data models
β”‚   β”œβ”€β”€ parser/            # M3U parser
β”‚   β”œβ”€β”€ processor/         # M3U processing pipeline
β”‚   β”œβ”€β”€ scheduler/         # Download scheduler (tier selection, cron)
β”‚   └── testutil/          # Test helpers and fixtures
β”œβ”€β”€ charts/stalkerr/        # Helm chart for Kubernetes deployment
β”œβ”€β”€ docs/                  # Documentation
β”œβ”€β”€ .github/               # GitHub workflows and templates
β”œβ”€β”€ config.yml.example     # Example configuration
β”œβ”€β”€ docker-compose.yml     # Docker services
β”œβ”€β”€ Makefile              # Build automation
└── README.md             # This file

Building

# Build the binary
make build

# Run tests
make test

# Generate coverage report
make coverage

# Format code
make fmt

# Run linters
make lint

# Clean build artifacts
make clean

Running Tests

# Run all tests
go test ./...

# Run tests with coverage
go test -cover ./...

# Run tests with race detection
go test -race ./...

See docs/TESTING.md for detailed testing documentation.

Development Setup

To quickly run and develop both the Go backend API and the React 19 Frontend Web Dashboard locally, use the following commands:

1. Prerequisites

Ensure you have the following installed on your machine:

  • Go 1.25 or higher
  • Node.js 22 or higher (with npm)
  • Docker and Docker Compose (for the database and profile dependencies)

2. Local Database & Dependencies

Start the PostgreSQL container and any other necessary development profile dependencies:

make docker-up

3. Frontend Installation

Install the React dashboard dependencies in the /frontend directory:

make front-install

4. Run Both Servers Concurrently

Start the local development server unifing both Go API on port 8080 and Vite Frontend on port 5173:

make dev

Note: Vite is preconfigured to automatically proxy all REST API requests on /api/v1/* directly to port 8080 to avoid CORS issues.

For advanced settings, see docs/DEVELOPMENT.md for detailed development setup instructions.

API Documentation

The REST API provides endpoints for managing processed M3U items, movies, TV shows, filters, and downloads.

Health Check

GET /health

Items (processed M3U entries)

GET  /api/v1/items                    # List all processed items
GET  /api/v1/items/grouped            # List items grouped by title
GET  /api/v1/items/:id                # Get item by ID
PUT  /api/v1/items/:id                # Update item
POST /api/v1/items/search             # Search items
POST /api/v1/items/:id/override       # Manually override an item's match
POST /api/v1/items/:id/force-download # Force (re-)download an item

Movies

GET  /api/v1/movies             # List all movies
GET  /api/v1/movies/:id         # Get movie by ID
POST /api/v1/movies/:id/move    # Move a movie's folder
POST /api/v1/movies/:id/reset   # Reset a movie's stream state

TV Shows

GET  /api/v1/tvshows            # List all TV shows
GET  /api/v1/tvshows/:id        # Get TV show by ID
POST /api/v1/tvshows/:id/move   # Move a TV show's folder
POST /api/v1/tvshows/:id/reset  # Reset a TV show's stream state

Radarr / Sonarr

GET /api/v1/radarr/movies                  # List Radarr-monitored movies
GET /api/v1/radarr/movies/:id/matches       # Get playlist matches for a Radarr movie
GET /api/v1/sonarr/series                   # List Sonarr-monitored series
GET /api/v1/sonarr/series/:id/episodes      # Get episodes for a Sonarr series
GET /api/v1/radarr-sonarr/stats             # Radarr/Sonarr reconciliation stats

Filters

GET    /api/v1/filters            # List filters
POST   /api/v1/filters            # Create a filter
PATCH  /api/v1/filters/:id        # Update a filter
DELETE /api/v1/filters/:id        # Delete a filter
DELETE /api/v1/filters/runtime    # Clear runtime-only filters

Downloads

GET  /api/v1/downloads                     # List downloads (enriched)
GET  /api/v1/downloads/simple              # List downloads (simple)
POST /api/v1/downloads/:id/rename          # Rename a download
POST /api/v1/downloads/:id/resync-path     # Resync a download's destination path
POST /api/v1/downloads/:id/cancel          # Cancel a download

Dry Run, Stats & Logs

POST /api/v1/dryrun            # Execute a dry-run analysis
GET  /api/v1/stats             # Get processing statistics
GET  /api/v1/processing-logs   # List processing logs
GET  /api/v1/config/paths      # Get configured download paths

TMDB Proxy

GET /api/v1/tmdb/search   # Proxy a TMDB search query

Configuration

Database Configuration

Field Type Default Description
database.host string localhost PostgreSQL host
database.port int 5432 PostgreSQL port
database.user string - Database user (required)
database.password string - Database password
database.dbname string - Database name (required)
database.sslmode string disable SSL mode

M3U Configuration

Field Type Default Description
m3u.sources list - List of M3U sources (required, non-empty); see docs/M3U-DOWNLOAD.md
m3u.update_interval int 3600 Update interval in seconds

Logging Configuration

Stalkerr supports modular logging with independent control for application and database logging:

Field Type Default Description
logging.format string json Log output format (json or text)
logging.app.level string info Application log level (debug, info, warn, error)
logging.database.level string info Database log level (debug, info, warn, error)
logging.level string info Legacy fallback log level (deprecated)

Formats:

  • json: Structured JSON logs (recommended for production)
  • text: Human-readable text logs (useful for development)

Example:

logging:
  format: json  # or text
  app:
    level: info
  database:
    level: warn  # Less verbose for DB queries

For more details, see docs/LOGGING.md.

API Configuration

Field Type Default Description
api.port int 8080 API server port

Filter Configuration

File-based filters applied to group_title and tvg_name fields (can be overridden by runtime filters via the /api/v1/filters endpoints):

Field Type Description
filter.group_title.include_patterns []string Regex patterns a group title must match
filter.group_title.exclude_patterns []string Regex patterns that exclude a group title
filter.tvg_name.include_patterns []string Regex patterns a channel/stream name must match
filter.tvg_name.exclude_patterns []string Regex patterns that exclude a channel/stream name

TMDB Configuration

Field Type Default Description
tmdb.enabled bool true Enable TMDB metadata enrichment
tmdb.api_key string - TMDB API key
tmdb.language string en-US Language for TMDB metadata
tmdb.requests_per_second float 4.0 Max TMDB API requests per second (0 disables rate limiting)

Radarr / Sonarr Configuration

Field Type Default Description
radarr.enabled bool false Enable Radarr integration
radarr.url string - Radarr base URL
radarr.api_key string - Radarr API key
radarr.sync_interval int 3600 Sync interval in seconds
radarr.quality_profile_id int 1 Radarr quality profile ID
sonarr.enabled bool false Enable Sonarr integration
sonarr.url string - Sonarr base URL
sonarr.api_key string - Sonarr API key
sonarr.sync_interval int 3600 Sync interval in seconds
sonarr.quality_profile_id int 1 Sonarr quality profile ID

Downloads Configuration

Field Type Default Description
downloads.movies_path string ./data/downloads/movies Fallback path when Radarr's movie.Path is empty
downloads.tvshows_path string ./data/downloads/tvshows Fallback path when Sonarr's series.Path is empty
downloads.temp_dir string OS temp dir Directory for in-progress downloads
downloads.max_parallel int 3 Number of concurrent downloads
downloads.timeout int 600 Download timeout in seconds
downloads.retry_attempts int 3 HTTP sub-retry attempts within a single download attempt
downloads.resume_enabled bool true Enable resumable downloads
downloads.progress_interval_mb int 10 Persist progress every N megabytes
downloads.progress_interval_seconds int 30 Persist progress every N seconds
downloads.lock_timeout_minutes int 5 Consider a download lock stale after this many minutes
downloads.max_retry_attempts int 5 Max full download attempts before an occurrence is permanently skipped
downloads.force_tier_probability float 0.1 Chance (0-1) that the download command scheduler draws an already-downloaded/upgrade candidate instead of new content

Environment Variables

Most configuration options can be overridden with environment variables using the STALKEER_ prefix:

  • STALKEER_DATABASE_HOST
  • STALKEER_DATABASE_PORT
  • STALKEER_DATABASE_USER
  • STALKEER_DATABASE_PASSWORD
  • STALKEER_DATABASE_DBNAME
  • STALKEER_LOGGING_LEVEL
  • STALKEER_API_PORT

m3u.sources is the exception: it's a structured list and is config-file only, with no environment variable equivalent (see docs/M3U-DOWNLOAD.md).

Or use a PostgreSQL connection string:

export DATABASE_URL="postgres://user:password@localhost:5432/stalkerr"

Contributing

Contributions are welcome! Please read our contributing guidelines (coming soon) before submitting pull requests.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Commit / PR title format

This repository only allows squash merges, so a pull request's title becomes its commit message on main. That title must follow the Conventional Commits format (see .github/skills/git-commit/SKILL.md for the full type list and examples) - CI (commitlint.yml) enforces this on every pull request, and the format drives automatic semantic-version bumps and changelog generation via release-please.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

  • GORM - ORM library for Go
  • Gin - HTTP web framework
  • Cobra - CLI framework
  • Viper - Configuration management

Support

About

Stalk over Radarr and Sonarr to download from a m3u playlist.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages