Skip to content

panakour/subsnag

Repository files navigation

subsnag — subtitles downloader

Find and download subtitles from OpenSubtitles for your local video files.

verify lint report license

subsnag is a small command-line tool that finds and downloads subtitles from OpenSubtitles for your local video files. It matches files by their OpenSubtitles movie hash when possible (the most reliable match), and falls back to a title/year/episode search otherwise.

It is careful about the things that matter:

  • Transient API failures (429, 5xx, network blips) retry with backoff and respect Retry-After.
  • Subtitles are written atomically — a failed or cancelled download never clobbers an existing file.
  • One bad file does not abort the whole batch, and the run stops cleanly when the daily quota is exhausted.

OpenSubtitles REST API

subsnag talks to the official OpenSubtitles REST API v1 at https://api.opensubtitles.com/api/v1. This is the modern REST API (not the legacy XML-RPC service). Every request carries your consumer Api-Key and a User-Agent; authenticated requests additionally send a Bearer token obtained via subsnag login. Downloading a subtitle is a two-step flow: request a short-lived download link (POST /download), then fetch the file from that link.

Install

go install github.com/panakour/subsnag@latest

This installs a subsnag binary into $GOBIN (or $GOPATH/bin). Alternatively, download a prebuilt binary from GitHub Releases.

Release builds target:

  • macOS (arm64)
  • Linux (amd64)
  • Windows (amd64)

Build from source

Requires Go 1.26 or newer.

# build a local binary named ./subsnag
go build -o subsnag .

# or install into $GOBIN / $GOPATH/bin
go install .

A Makefile is provided with convenience targets:

make build   # go build -o subsnag .
make install # go install .
make test    # go test ./...
make race    # go test -race ./...
make vet     # go vet ./...
make lint    # golangci-lint run
make check   # race + vet + lint + build (mirrors CI)
make fmt     # gofmt -w .
make tidy    # go mod tidy
make clean   # rm -f subsnag

Getting a free API key

  1. Create a free account at https://www.opensubtitles.com.

  2. Register a consumer application under your account's API / Consumers section to obtain an API key.

  3. Save it for subsnag:

    subsnag config set-key YOUR_API_KEY

    Alternatively, set the SUBSNAG_API_KEY environment variable or pass --api-key on any command.

Quickstart

# 1. store your consumer API key
subsnag config set-key YOUR_API_KEY

# 2. log in with your OpenSubtitles account (token is saved for you)
subsnag login --username your_user

# 3. download subtitles for a file or a whole directory
subsnag download "The.Matrix.1999.1080p.BluRay.x264.mkv"
subsnag download -r ~/Movies

The subtitle is written next to the video, e.g. The.Matrix.1999.1080p.BluRay.x264.en.srt.

Command reference

Global flags (available on every command):

Flag Description
--config <path> Use an alternate config file location.
--api-key <key> Override the API key for this invocation.
--user-agent <ua> Override the User-Agent header.
-v, --verbose Verbose output.

subsnag login

Authenticate and store a session token.

subsnag login --username your_user                # prompts for password securely
subsnag login --username your_user --password pw  # non-interactive (less secure)
SUBSNAG_PASSWORD=pw subsnag login --username your_user

The username falls back to the saved config and then an interactive prompt. The password may come from --password, the SUBSNAG_PASSWORD env var, or a hidden terminal prompt. On success the token, username and account base URL are saved, and your plan level / VIP status / allowed downloads are printed.

subsnag logout

Clear the stored session token.

subsnag logout

subsnag version

Print version, commit, build date, platform, and Go runtime.

subsnag version
subsnag --version   # one-line form

subsnag config

Inspect and modify configuration.

subsnag config show            # print config (the token is masked)
subsnag config path            # print the config file path
subsnag config set-key KEY     # store the API key
subsnag config set-agent UA    # store the User-Agent
subsnag config set-langs en,es # store default languages (comma separated)

subsnag search

Search OpenSubtitles and print a numbered table.

# free-text search
subsnag search the matrix

# filter by language, year and type
subsnag search -l en,es --year 1999 --type movie the matrix

# search by a local file's movie hash
subsnag search --hash "The.Matrix.1999.mkv"

# episode search
subsnag search -l en --season 1 --episode 2 breaking bad

# download the 2nd listed result into the current directory (or --output)
subsnag search -l en the matrix --download 2 --output ~/Subtitles

Columns: # | LANG | DOWNLOADS | HASH | RELEASE. The HASH column shows a check mark (✓) when a result matched by movie hash.

Useful flags: -l/--lang, --imdb, --tmdb, --season, --episode, --year, --type, --hash, --hearing-impaired, --page, -d/--download N, -o/--output.

subsnag download

Download subtitles for files or directories.

# single file, default language(s)
subsnag download movie.mkv

# multiple languages
subsnag download -l en,es movie.mkv

# recurse into a directory, overwrite existing subtitles
subsnag download -r -f ~/Movies

# preview matches without downloading
subsnag download --dry-run -r ~/Movies

# pick a subtitle format and hearing-impaired preference
subsnag download --format srt --hearing-impaired exclude movie.mkv

After the run a summary is printed:

3 downloaded, 1 skipped, 0 not found, 0 errors

The command exits non-zero only when all downloads failed; per-file errors otherwise leave the exit code at 0. If authentication is required you will be prompted to run subsnag login.

Useful flags: -l/--lang, -r/--recursive, -f/--force (overwrite), --format (default srt), --dry-run, --hearing-impaired.

Language codes

Use lowercase ISO-639-1 codes, optionally with a region suffix:

  • en — English
  • es — Spanish
  • pt-br — Brazilian Portuguese
  • fr, de, it, nl, ...

Pass several at once as a comma-separated list (-l en,es,pt-br) and set your defaults with subsnag config set-langs en,es.

Download quota caveat

OpenSubtitles enforces a daily download limit, and the free tier allows only a limited number of downloads per day. Once the quota is exhausted, download requests are rejected until it resets. subsnag login prints your allowed_downloads, and the search download flow reports how many downloads remain. Searching does not consume the download quota; only fetching a subtitle file does.

Configuration file location

Config is stored as JSON at:

  • $SUBSNAG_CONFIG if that environment variable is set, otherwise
  • $XDG_CONFIG_HOME/subsnag/config.json if XDG_CONFIG_HOME is set, otherwise
  • ~/.config/subsnag/config.json on every platform (Linux and macOS alike).

Run subsnag config path to print the exact location. The file contains your session token and is written with 0600 permissions.

Environment variables (SUBSNAG_API_KEY, SUBSNAG_USER_AGENT) override the saved config for a single invocation but are never written back to the file.

For Developers

Requirements: Go 1.26+, golangci-lint, and goreleaser only for testing release packaging locally.

go run . --help
go test -race ./...
go vet ./...
golangci-lint run
go build ./...

make check runs the verification suite (race tests, vet, lint, build).

Repo-specific engineering notes for contributors and coding agents live in AGENTS.md.

License

MIT

About

Subtitles downloader

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors