https://github.com/adrianmusante/subtitle-tools
CLI toolkit for cleaning, fixing, and translating subtitles.
https://github.com/adrianmusante/subtitle-tools
cli media srt subtitle
Last synced: 4 months ago
JSON representation
CLI toolkit for cleaning, fixing, and translating subtitles.
- Host: GitHub
- URL: https://github.com/adrianmusante/subtitle-tools
- Owner: adrianmusante
- License: apache-2.0
- Created: 2026-02-14T01:25:09.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2026-02-21T20:46:31.000Z (5 months ago)
- Last Synced: 2026-02-22T01:15:41.916Z (5 months ago)
- Topics: cli, media, srt, subtitle
- Language: Go
- Homepage:
- Size: 134 KB
- Stars: 3
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# subtitle-tools
CLI toolkit for cleaning, fixing, and translating subtitles.
## Install
```bash
go install github.com/adrianmusante/subtitle-tools/cmd/subtitle-tools@latest
```
Alternatively, download a pre-built binary from [GitHub Releases](https://github.com/adrianmusante/subtitle-tools/releases) and place it on your `PATH`.
## CLI Reference
Command-line tools for working with subtitle file.
### Top-level
General flags for `subtitle-tools`
Flags:
| Flag | Environment variable | Description | Type | Default |
|-----------------|--------------------------|-----------------------------------|------|---------|
| `-h, --help` | | Show help for `subtitle-tools` | bool | `false` |
| `-v, --verbose` | `SUBTITLE_TOOLS_VERBOSE` | Enable verbose (debug) logging | bool | `false` |
| `--version` | | Show version for `subtitle-tools` | bool | `false` |
Usage:
```text
subtitle-tools [flags]
subtitle-tools [command]
```
### fix
Fixes common issues in `.srt` files.
Fixes:
- overlaps: subtitles sharing the same time span.
- out-of-order: subtitles not sorted by time.
- cue index: invalid sequence of cue indices.
- line wrap: rewraps lines that may exceed typical screen width.
- style stripping: removes styling such as HTML tags (when enabled).
- empty cues: removes subtitles with no text.
- deduplication: removes duplicated subtitles.
#### Usage:
```text
subtitle-tools fix [flags]
```
Flags:
| Flag | Environment variable | Description | Type | Default |
|---------------------|--------------------------|--------------------------------------------------------------------|--------|---------|
| `--dry-run` | `SUBTITLE_TOOLS_DRY_RUN` | Write output to a temporary file and do not overwrite the original | bool | `false` |
| `--max-line-len` | | Max line length when wrapping | int | `70` |
| `--min-words-merge` | | Minimum words to consider a line short for merging | int | `3` |
| `-o, --output` | | Output file path (defaults to overwriting input) | string | |
| `--skip-backup` | | Do not create a .bak backup when overwriting the input file | bool | `false` |
| `--strip-style` | | Remove HTML/XML style tags from subtitle text | bool | `false` |
| `-w, --workdir` | `SUBTITLE_TOOLS_WORKDIR` | Working directory base; unique subdirectory per run | string | |
Behavior:
- If `-o/--output` is omitted, `fix` overwrites the input file.
- When overwriting the input file, a `*.bak` backup is created by default. Use `--skip-backup` to disable it.
- If `--dry-run` is set, the original file is never modified; output is written to a temporary file.
- If `-w/--workdir` is provided, a unique subdirectory is created inside it per run.
If omitted, a system temp directory is used and deleted at the end.
- If `--strip-style` is set, all styling (e.g. HTML tags) is removed from subtitle lines.
### translate
Translate subtitles to another language using an OpenAI-compatible API
> [!TIP]
> Run `fix` before `translate` to clean the subtitle file. This can improve translation quality and reduce errors from non-standard formatting.
> After translating, you can run `fix` again to apply line wrap to the translated text.
#### Usage:
```text
subtitle-tools translate [flags]
```
Flags:
| Flag | Environment variable | Description | Type | Default |
|------------------------------|-----------------------------------------------------|--------------------------------------------------------------------------|----------|----------|
| `--api-key` | `SUBTITLE_TOOLS_TRANSLATE_API_KEY` | API key; comma-separated list distributes requests across keys | string | |
| `--dry-run` | `SUBTITLE_TOOLS_DRY_RUN` | Write output to a temporary file and do not create the final output file | bool | `false` |
| `--max-batch-chars` | `SUBTITLE_TOOLS_TRANSLATE_MAX_BATCH_CHARS` | Soft limit for the batch payload size | int | `7000` |
| `--max-workers` | `SUBTITLE_TOOLS_TRANSLATE_MAX_WORKERS` | Number of concurrent translation workers (batches in-flight) | int | `2` |
| `--model` | `SUBTITLE_TOOLS_TRANSLATE_MODEL` | Model to use (e.g. gpt-5, gemini-flash-latest) | string | required |
| `-o, --output` | | Output file path; must not already exist | string | required |
| `--request-timeout` | `SUBTITLE_TOOLS_TRANSLATE_REQUEST_TIMEOUT` | HTTP request timeout duration (e.g. 30s, 1m; 0 disables timeout) | duration | `2m30s` |
| `--retry-max-attempts` | `SUBTITLE_TOOLS_TRANSLATE_RETRY_MAX_ATTEMPTS` | Max attempts per request for retryable errors | int | `5` |
| `--retry-parse-max-attempts` | `SUBTITLE_TOOLS_TRANSLATE_RETRY_PARSE_MAX_ATTEMPTS` | Max attempts per batch when model output is invalid/unparseable | int | `2` |
| `--rps` | `SUBTITLE_TOOLS_TRANSLATE_RPS` | Max requests per second (0 disables rate limiting) | float | `4` |
| `--source-language` | | Source language. If omitted, it’s auto-detected. (e.g. es, es-MX, fr) | string | |
| `--target-language` | | Target language (e.g. es, es-MX, fr) | string | required |
| `--url` | `SUBTITLE_TOOLS_TRANSLATE_URL` | Base URL for the API endpoint (inferred from --model if omitted) | string | |
| `-w, --workdir` | `SUBTITLE_TOOLS_WORKDIR` | Working directory base; unique subdirectory per run | string | |
### update
Download and replace the CLI with the latest version.
#### Usage:
```text
subtitle-tools update [flags]
```
Flags:
| Flag | Environment variable | Description | Type | Default |
|-----------------|---------------------------------|--------------------------------------------------------------------------|--------|---------|
| `--api-key` | `SUBTITLE_TOOLS_GITHUB_API_KEY` | GitHub API key (optional; helps avoid rate limits) | string | |
| `--dry-run` | `SUBTITLE_TOOLS_DRY_RUN` | Download the update but do not replace the current executable | bool | `false` |
| `-w, --workdir` | `SUBTITLE_TOOLS_WORKDIR` | Working directory base; unique subdirectory per run | string | |
## Configuration (environment variables)
You can provide some flag values via environment variables.
Precedence:
1. CLI flag value (if explicitly provided)
2. Environment variable
3. Flag default
> **Bool values accept:** `true/false`, `1/0`, `yes/no`, `on/off`.