docs/reference/command-line.md
seconv is Subtitle Edit's headless command-line converter. It reuses the same core libraries as the desktop app (libse, libuilogic), so it supports the same formats, operations, and OCR engines — without any GUI dependency. Useful for scripts, CI pipelines, server-side workflows, and bulk conversion.
seconv lives in the main Subtitle Edit repository and ships in lockstep with the desktop app — no separately maintained fork, no version drift.
.mkv / .mks), MP4, MCC, transport stream teletext, Blu-Ray .sup.Pre-built binaries are distributed alongside Subtitle Edit. To build from source:
dotnet build src/seconv/SeConv.csproj -c Release
The executable is seconv (or seconv.exe on Windows).
seconv <pattern> <format> [options]
seconv <pattern> --format <name> [options] # alternative syntax
The format may be passed as the second positional argument or via --format <name>. Multiple input patterns can be passed as separate quoted arguments or comma-separated:
seconv "file1.srt" "file2.srt" subrip --overwrite
seconv "*.srt,*.ass" subrip --input-folder:./in
Options accept either --option:value, --option=value, or --option value. The colon form is shown throughout this page.
seconv *.srt sami # SRT → SAMI
seconv movie.srt subrip --encoding:windows-1252 # encoding override
seconv movie.srt subrip --encoding:source # keep input's encoding on output
seconv *.sub subrip --fps:25 --output-folder:./out # frame-based → time-based
seconv movie.mkv subrip --track-number:3 # extract MKV text track #3
seconv movie.sup subrip --ocr-engine:tesseract --ocr-language:eng # OCR a Blu-Ray .sup
seconv movie.sup subrip --ocr-engine:nocr --ocr-db:Latin.nocr # OCR via nOCR
seconv movie.sup subrip --ocr-engine:binaryocr --ocr-db:Latin.db # OCR via BinaryOCR
seconv movie.sup subrip --ocr-engine:ollama --ollama-model:llama3.2-vision
seconv movie.sup subrip --ocr-engine:llamacpp # OCR via llama.cpp (auto-starts llama-server)
seconv subs.srt bluraysup --resolution:1920x1080 # render text → Blu-Ray sup
seconv subs.srt bdnxml --resolution:1920x1080 # render text → BDN-XML
seconv subs.srt bluraysup --background-color:"#B4000000" # ... with a black background box
seconv subs.srt customtext --custom-format:my-template.xml # custom template
seconv *.srt subrip --multiple-replace:rules.csv # search-and-replace pass (GUI export: .csv/.template/.xml)
seconv subs.srt subrip --offset:-2000 --renumber:1 --overwrite # offset 2s back, renumber from 1
seconv formats # list all supported formats
seconv list-encodings # list text encodings
seconv list-pac-codepages # list PAC code pages
seconv list-ocr-engines # list OCR engines + installation status
seconv list-fce-rules # list FixCommonErrors rule IDs
seconv dump-settings # print a full --settings JSON with libse defaults
seconv info <file> # print format/encoding/duration/language for a file
seconv lint <pattern> # validate subtitle(s); exit 1 if issues found
seconv --help # show help
seconv --version # print version and exit
seconv info movie.srt # human-readable table
seconv info movie.srt --json # machine-parseable
seconv lint *.srt # check overlaps, line lengths, tags, ...
seconv lint *.srt --json # CI-friendly: exit 1 on any issue
| Option | Description |
|---|---|
--input-folder:<path> | Input folder; relative patterns resolve against it |
--output-folder:<path> | Output folder (default: input file's directory) |
--output-filename:<name> | Output file name (single input only) |
--overwrite | Overwrite existing files (default: rotate to name_2.ext, _3.ext, ...) |
--encoding:<name> | Encoding name or codepage. Special values: utf-8, utf-8-no-bom (also utf-8-nobom, utf8-nobom), a code page number, or source to keep the input file's detected encoding. Defaults: auto-detect on input, UTF-8 BOM on output |
| Option | Description |
|---|---|
--offset:hh:mm:ss:ms | Shift all timecodes (also accepts plain ms, signed: -1500, +1500) |
--fps:<rate> | Source frame rate (used for frame-based input formats) |
--target-fps:<rate> | Target frame rate (with --fps, calls Subtitle.ChangeFrameRate) |
--adjust-duration:<ms> | Add/subtract milliseconds to each paragraph's duration |
--change-speed:<percent> | Scale all times by 100/percent (e.g. 125 = 1.25× faster). Must be > 0 |
--renumber:<n> | Renumber paragraphs starting at n |
| Option | Applies to | Description |
|---|---|---|
--resolution:<WxH> | ASSA, image-based | Sets PlayResX/PlayResY for ASSA; sets canvas for image outputs (default 1920x1080) |
--assa-style-file:<file> | ASSA | Apply [V4+ Styles] block from another ASSA file |
--pac-codepage:<page> | PAC | Code page name (Latin, Greek, Hebrew, …) or numeric (0–12). See seconv list-pac-codepages |
--ebu-header-file:<file> | EBU STL | Reuse the GSI header block from an existing .stl file |
--plaintext-merge | Plain text (txt) | Merge all subtitles into one space-separated block (no blank lines). Takes precedence over the two options below |
--plaintext-unbreak | Plain text (txt) | Unbreak each subtitle, joining its lines into one |
--plaintext-no-blank-line | Plain text (txt) | Do not put a blank line between subtitles (default keeps it) |
When rendering a text subtitle to an image-based target (Blu-Ray sup, VobSub, BDN-XML, DOST, FCP / Final Cut Pro + image, D-Cinema, images-with-time-code, WebVTT thumbnails), these options control how the text is drawn. <i>, <b>, and <font color=...> tags in the subtitle text are honored. The same values can be set in a --settings JSON file's exportImages section (see Settings JSON); CLI flags win over the JSON.
| Option | Description |
|---|---|
--font-name:<name> | Font family (default: Arial) |
--font-size:<pt> | Font size in points (default: 50) |
--font-color:<color> | Text colour (default: white) |
--font-bold | Render text bold |
--outline-color:<color> | Outline colour (default: black) |
--outline-width:<px> | Outline width (default: 2.5; 0 disables) |
--shadow-color:<color> | Shadow colour (default: black) |
--shadow-width:<px> | Shadow width (default: 0 = off) |
--background-color:<color> | Background box colour, e.g. black or #B4000000 (semi-transparent black). Implies --box-type:one-box unless --box-type is given |
--background-corner-radius:<px> | Corner radius of the background box (default: 0) |
--box-type:<type> | none (default) | one-box | box-per-line |
--box-padding:<px> | Box padding: one value for all sides, or left,right,top,bottom (default: 5,5,3,3) |
--line-spacing:<percent> | Extra gap between lines as percent of line height (default: 0) |
--alignment:<pos> | Screen position: bottom-center (default), top-left, middle-right, ... |
--content-alignment:<align> | Multi-line text justification: left | center (default) | right |
--bottom-top-margin:<px> | Vertical screen-edge margin (default: 5% of height) |
--left-right-margin:<px> | Horizontal screen-edge margin (default: 5% of width) |
Colours accept hex (#AARRGGBB, #RRGGBB, with or without #) or a colour name (white, black, yellow, ...).
# SRT → UHD Blu-Ray sup with a semi-transparent black background box (SE4-style)
seconv movie.srt bluraysup --resolution:3840x2160 --background-color:"#B4000000"
# Custom font, bold, box per line
seconv movie.srt bluraysup --font-name:Verdana --font-size:60 --font-bold --box-type:box-per-line
seconv automatically extracts subtitle tracks from container files:
| Extension | Sources |
|---|---|
.mkv, .mks | Matroska text tracks (S_TEXT/UTF8, SSA, ASS, HDMV/TEXTST) and image tracks (S_HDMV/PGS via OCR) |
.mp4, .m4v, .m4s, .3gp | MP4 text tracks and WebVTT VTTC |
.mcc | MacCaption 1.0 |
.ts, .m2ts, .mts | Transport stream — teletext (no OCR) and DVB-sub (via OCR) |
.sup | Blu-Ray sup (via OCR) |
When a container has multiple usable tracks, one output file is written per track with the track's language code as a suffix:
movie.mkv → movie.eng.srt
movie.deu.srt
movie.fra.srt
If two tracks share a language, the track number is added: movie.#3.eng.srt.
| Option | Description |
|---|---|
--track-number:<list> | Comma-separated track numbers to keep |
--forced-only | MKV: keep only forced tracks |
--teletext-only | TS: skip DVB-sub OCR (teletext only) |
--teletext-only-page:<n> | TS: extract only this teletext page |
--ocr-engine | Type | Setup |
|---|---|---|
tesseract (default) | Subprocess | Install Tesseract (apt install tesseract-ocr, brew install tesseract, or the Windows installer); ensure it is on PATH. Pass --ocr-language as ISO 639-2 (eng, deu, spa, …). |
nocr | In-process | Built-in nOCR matcher. Required: --ocr-db:<path-to-Latin.nocr>. |
binaryocr (alias: binary) | In-process | Built-in BinaryOCR matcher (different accuracy profile, similar speed). Required: --ocr-db:<path-to-Latin.db>. |
ollama | HTTP | Local Ollama server with a vision-capable model (e.g. llama3.2-vision, qwen2.5vl). Configure via --ollama-url (default http://localhost:11434/api/chat) and --ollama-model (default llama3.2-vision). Pass --ocr-language as a human name like English. |
llamacpp (aliases: llama.cpp, llama) | HTTP | llama.cpp with a curated OCR vision model (GLM-OCR, LightOnOCR, PaddleOCR-VL). With no --ocr-url, seconv finds llama-server (SE data folder next to seconv, installed SE data folder, then PATH) and an installed OCR model, starts the server on a free loopback port, and stops it at exit. seconv never downloads engines/models — install them via the SE UI's OCR window (engine "llama.cpp") or point --ocr-url at a running server. Pass --ocr-language as a human name like English. |
paddle (alias: paddleocr) | Subprocess | Install via pip install paddleocr; ensure the paddleocr binary is on PATH. Pass --ocr-language as a short code (en, de, …). |
| Option | Description |
|---|---|
--ocr-engine:<engine> | tesseract (default) | nocr | binaryocr | ollama | llamacpp | paddle |
--ocr-language:<lang> | Tesseract: ISO 639-2 (eng, deu); Paddle: short (en); Ollama/llama.cpp: human (English) |
--ocr-db:<path> | OCR database file: .nocr for nocr, .db for binaryocr (required for both) |
--dictionary-folder:<path> | Folder with Hunspell dictionaries + *_OCRFixReplaceList.xml; enables the "Fix common OCR errors" pass of --fix-common-errors (English is bundled, so this is only needed for other languages) |
--ollama-url:<url> | Default http://localhost:11434/api/chat |
--ollama-model:<model> | Default llama3.2-vision |
--ocr-model:<model> | llama.cpp OCR model: curated .gguf file name (e.g. GLM-OCR-Q8_0.gguf) or a full path to a .gguf with its mmproj sidecar next to it. Default: the first downloaded OCR model. |
--ocr-url:<url> | llama.cpp: endpoint of an already-running llama-server (a bare host:port is completed to /v1/chat/completions); skips the local auto-start. |
--time-codes-only | Image sources (.sup, VobSub .sub/.idx, MKV PGS/VobSub, MP4 VobSub, TS DVB-sub) → text format with time codes only and empty text. Skips OCR entirely — no OCR engine required. Ignored for text inputs and image output targets. |
--no-vobsub-isolate-colors | Disable VobSub OCR colour isolation, which is on by default. Isolation rebuilds each subpicture as a crisp black-on-white bitmap via histogram-based colour analysis — the most frequent opaque colour (the glyph fill) becomes black and the gray outline / anti-alias colours collapse into the white background, which helps on discs whose outlines otherwise melt adjacent characters together (Yuri → Yurl). Pass this flag to OCR the raw palette instead. Ignored for non-VobSub sources and with --time-codes-only. |
OCR database files are not bundled with
seconv. Thenocrandbinaryocrengines need a.nocror.dbfile passed via--ocr-db. Sources:
- If you have the desktop UI installed:
%AppData%\Subtitle Edit\OCR\(Windows) or~/.config/Subtitle Edit/OCR/(Linux/macOS).- From the repo:
Ocr/Latin.nocrandOcr/Latin.db.- Other languages: download from the SE UI (Tools → "OCR with nOCR" / BinaryOCR → download).
Run seconv list-ocr-engines for the per-engine installation-status table.
# Tesseract
seconv movie.sup subrip --ocr-engine:tesseract --ocr-language:eng
# nOCR (no external dependency)
seconv movie.sup subrip --ocr-engine:nocr --ocr-db:"C:\Users\me\AppData\Roaming\Subtitle Edit\Ocr\Latin.nocr"
# BinaryOCR
seconv movie.sup subrip --ocr-engine:binaryocr --ocr-db:"C:\Users\me\AppData\Roaming\Subtitle Edit\Ocr\Latin.db"
# llama.cpp — auto-starts a local llama-server with a downloaded OCR model
seconv movie.sup subrip --ocr-engine:llamacpp
seconv movie.sup subrip --ocr-engine:llamacpp --ocr-model:GLM-OCR-Q8_0.gguf
seconv movie.sup subrip --ocr-engine:llamacpp --ocr-url:http://127.0.0.1:8080
# MKV with image (PGS or VobSub) tracks — OCR runs automatically
seconv movie.mkv subrip --ocr-engine:tesseract --ocr-language:eng
# VobSub .sub + .idx pair — the .idx companion is auto-detected
seconv movie.sub subrip --ocr-engine:tesseract --ocr-language:eng
# Transport-stream teletext (no OCR needed)
seconv broadcast.ts subrip
# Time codes only — extract timing with no OCR (empty text); works for any image source
seconv movie.sup subrip --time-codes-only
seconv movie.sub subrip --time-codes-only
--translate-to:<language> machine-translates each file as part of the conversion (after OCR for image sources, before the cleanup operations). Languages are given as a code or English name (de, German, da, Danish, …); the source language is auto-detected per file unless --translate-from is set.
| Option | Description |
|---|---|
--translate-to:<lang> | Target language — enables translation |
--translate-from:<lang> | Source language (default: auto-detect per file) |
--translate-engine:<engine> | llamacpp (default) | ollama | lmstudio | libretranslate | nllb-serve | nllb-api |
--translate-url:<url> | Endpoint of an already-running translate server. For llamacpp this skips the local server auto-start; a bare host:port is completed to /v1/chat/completions. |
--translate-model:<model> | ollama/lmstudio: model name. llamacpp: a .gguf file name from the models folder or a full path (default: the first installed translate model). |
llama.cpp (default engine). With no --translate-url, seconv runs a local llama-server for you: it looks for the binary in Subtitle Edit's data folder (llama.cpp next to seconv, then %AppData%\Subtitle Edit\llama.cpp / ~/Library/Application Support/Subtitle Edit/llama.cpp / ~/.config/Subtitle Edit/llama.cpp) and falls back to llama-server on PATH. The server is started on a free localhost port with the model's correct chat-template flags and stopped again when seconv exits. Models resolve against the data folder's models subfolder.
seconv never downloads engines or models (same policy as Tesseract/PaddleOCR). Get llama.cpp + a translation model in one of these ways:
- Run auto-translate with llama.cpp once in the Subtitle Edit UI (Tools → Auto-translate → llama.cpp) — it downloads both into the data folder that seconv probes.
- Install llama.cpp yourself (
brew install llama.cpp,winget install ggml.llamacpp, or a GitHub release) and drop a.gguftranslation model (e.g. TranslateGemma) into the models folder, or pass it via--translate-model:<path.gguf>.- Point
--translate-urlat any llama-server you already have running.
# Translate to German via a local llama.cpp server (started and stopped automatically)
seconv movie.srt subrip --translate-to:de
# Specific source language and model
seconv movie.srt subrip --translate-from:en --translate-to:da --translate-model:translategemma-4b_Q4_K_M.gguf
# Already-running llama-server (local or remote)
seconv movie.srt subrip --translate-to:de --translate-url:http://192.168.1.10:8080
# Ollama
seconv movie.srt subrip --translate-to:da --translate-engine:ollama --translate-model:gemma2
# OCR a Blu-Ray sup and translate the result in one pass
seconv movie.sup subrip --ocr-engine:tesseract --ocr-language:eng --translate-to:de
| Option | Description |
|---|---|
--multiple-replace:<path> | Multiple-replace rules applied per paragraph after operations. Accepts the legacy SE MultipleSearchAndReplaceGroups XML and the file the SE5 GUI exports from Tools → Multiple replace → export — either .template (JSON) or .csv. Supports case-insensitive, CaseSensitive, and RegularExpression rules; only active rules are applied. The format is chosen by extension, then by content |
--custom-format:<path.xml> | SE CustomFormatItem XML (use with --format customtext) |
--settings:<path.json> | JSON file overlaying Configuration.Settings (general / tools / removeTextForHearingImpaired) plus image-output styling (exportImages). Optional profiles map for named overlays |
--profile:<name> | Selects a named overlay from the settings file's profiles map. Requires --settings |
The quickest way to share rules between the GUI and seconv: in Subtitle Edit open Tools → Multiple replace, then export the rules as .template (JSON) or .csv, and pass that file to --multiple-replace. Both are read directly — no conversion needed.
seconv *.srt subrip --multiple-replace:my-rules.csv # exported from the GUI
seconv *.srt subrip --multiple-replace:my-rules.template # JSON export
seconv *.srt subrip --multiple-replace:fixes.xml # legacy SE4 XML
CSV columns (a header row is recognised; Type is CaseInsensitive / CaseSensitive / RegularExpression):
Category,Find,ReplaceWith,Description,Active,Type
Demo,colour,color,,true,CaseInsensitive
Demo,"\bteh\b",the,,true,RegularExpression
The legacy XML shape is still accepted (its SearchType value Normal = the GUI's CaseInsensitive):
<?xml version="1.0" encoding="utf-8"?>
<MultipleSearchAndReplaceGroups>
<Group>
<Name>Demo</Name>
<IsActive>true</IsActive>
<Rules>
<Rule>
<Active>true</Active>
<FindWhat>colour</FindWhat>
<ReplaceWith>color</ReplaceWith>
<SearchType>Normal</SearchType>
</Rule>
<Rule>
<Active>true</Active>
<FindWhat>\bteh\b</FindWhat>
<ReplaceWith>the</ReplaceWith>
<SearchType>RegularExpression</SearchType>
</Rule>
</Rules>
</Group>
</MultipleSearchAndReplaceGroups>
<?xml version="1.0" encoding="utf-8"?>
<CustomFormatItem>
<Name>JSON-ish</Name>
<Extension>.json</Extension>
<FormatHeader>{
"lines": [</FormatHeader>
<FormatParagraph> {"start": "{start}", "end": "{end}", "text": "{text}"},</FormatParagraph>
<FormatFooter> ]
}</FormatFooter>
<FormatTimeCode>hh:mm:ss.zzz</FormatTimeCode>
</CustomFormatItem>
seconv subs.srt customtext --custom-format:lines.xml
Available template tokens: {title}, {number}, {start}, {end}, {duration}, {gap}, {text}, {text-line-1}, {text-line-2}, {actor}, {cps-comma}, {cps-period}, {text-length}, {bookmark}, {media-file-name}, {media-file-name-full}, {#lines}, {#total-words}, {#total-characters}, {tab}. Time-code tokens accept hh/h, mm/m, ss/s, and zzz/zz/z for milliseconds (or zzzzzzz... for total milliseconds without breakdown).
This is seconv's own schema — not the Subtitle Edit GUI's
Settings.json. The desktop app's settings file uses different key names (e.g. the GUI'sIsRemoveTextUppercaseLineOnisremoveIfAllUppercasehere) and a different structure; feeding it to--settingswon't do what you expect (unrecognized keys are ignored with a warning). To get a correct starter file, runseconv dump-settings— it prints this whole schema populated with the current libse defaults:bashseconv dump-settings > my-settings.json # edit, then: --settings:my-settings.json
The keys and defaults below are exactly what dump-settings emits:
{
"general": {
"subtitleLineMaximumLength": 43,
"subtitleMinimumDisplayMilliseconds": 1000,
"subtitleMaximumDisplayMilliseconds": 8000,
"currentFrameRate": 23.976,
"defaultFrameRate": 23.976,
"minimumMillisecondsBetweenLines": 24,
"maxNumberOfLines": 2,
"mergeLinesShorterThan": 33,
"subtitleMaximumCharactersPerSeconds": 25.0,
"subtitleOptimalCharactersPerSeconds": 15.0,
"subtitleMaximumWordsPerMinute": 400.0,
"dialogStyle": "DashBothLinesWithSpace",
"continuationStyle": "None"
},
"removeTextForHearingImpaired": {
"removeTextBeforeColon": true,
"removeInterjections": false
},
"exportImages": {
"fontName": "Arial",
"fontSize": 50,
"fontColor": "#FFFFFF",
"isBold": false,
"outlineColor": "black",
"outlineWidth": 2.5,
"shadowColor": "black",
"shadowWidth": 0,
"backgroundColor": "#B4000000",
"backgroundCornerRadius": 0,
"boxType": "one-box",
"boxPaddingLeft": 5,
"boxPaddingRight": 5,
"boxPaddingTop": 3,
"boxPaddingBottom": 3,
"lineSpacingPercent": 0,
"alignment": "bottom-center",
"contentAlignment": "center",
"bottomTopMargin": 54,
"leftRightMargin": 96
},
"profiles": {
"broadcast": {
"general": { "subtitleMaximumDisplayMilliseconds": 6000 },
"removeTextForHearingImpaired": { "removeInterjections": true }
},
"uhd": {
"exportImages": { "fontSize": 100 }
}
}
}
The exportImages section styles text → image rendering (see Image output styling for the semantics); the equivalent CLI flags override it. The general section mirrors Configuration.Settings.General; any key left out keeps the libse default. The profile-shaping values (minimumMillisecondsBetweenLines, maxNumberOfLines, mergeLinesShorterThan, subtitleMaximumCharactersPerSeconds, subtitleOptimalCharactersPerSeconds, subtitleMaximumWordsPerMinute, dialogStyle, continuationStyle) feed Fix common errors and the split/merge operations, so set them to reproduce an SE4 profile. dialogStyle and continuationStyle take the enum names (case-insensitive): dialogStyle ∈ DashBothLinesWithSpace, DashBothLinesWithoutSpace, DashSecondLineWithSpace, DashSecondLineWithoutSpace; continuationStyle ∈ None, NoneTrailingDots, NoneTrailingEllipsis, OnlyTrailingDots, LeadingTrailingDots, LeadingTrailingEllipsis, LeadingTrailingDash, … (see the Fix common errors continuation styles).
Keys that seconv does not recognize are ignored, so a settings file written for a newer version still applies everything this one understands — but they are listed in a warning, so a typo (or a key your seconv is too old to know) does not silently give you default output.
seconv *.srt subrip --settings:my.json --profile:broadcast --remove-text-for-hi
| Option | Description |
|---|---|
--quiet / -q | Suppress per-file progress and the parameters table; only print the final summary |
--verbose / -v | Print extra diagnostic information, including full exception details (stack traces) on errors |
--json | Emit per-file results as JSON to stdout (suppresses Spectre output) |
Operations run after the structural transforms (offset, fps, renumber, adjust-duration, change-speed) in a fixed, sensible order regardless of where they appear on the command line:
| Option | Description |
|---|---|
--apply-duration-limits | Apply duration limits |
--apply-min-gap[:<ms>] | Enforce a minimum gap between paragraphs. Without a value, uses minimumMillisecondsBetweenLines from --settings (libse default: 24 ms) |
--balance-lines | Balance line lengths |
--beautify-time-codes | Beautify time codes |
--bridge-gaps:<ms> | Bridge gaps shorter than N ms (extends previous end time) |
--convert-colors-to-dialog | Convert colors to dialog |
--delete-first:<n> | Delete first N entries |
--delete-last:<n> | Delete last N entries |
--delete-contains:<word> | Delete entries containing the given word |
--fix-common-errors | Fix common subtitle errors (all 39 rules) |
--fix-common-errors-rules:<list> | Run a subset of FCE rules (CSV; supports all,-RuleId) |
--fce-language:<code> | Force the language for FCE language-gated rules (code or English name, e.g. es / Spanish); default: auto-detect from content |
--fix-rtl-via-unicode-chars | Fix RTL via Unicode characters |
--merge-same-texts | Merge entries with same text |
--merge-same-time-codes | Merge entries with same time codes |
--merge-short-lines | Merge short lines |
--redo-casing | Redo text casing |
--remove-formatting | Remove formatting tags |
--remove-line-breaks | Remove line breaks |
--remove-text-for-hi | Remove text for hearing impaired |
--remove-unicode-control-chars | Remove Unicode control characters |
--reverse-rtl-start-end | Reverse RTL start/end |
--split-long-lines | Split long lines |
# Common cleanup pass
seconv *.srt subrip --remove-text-for-hi --merge-same-texts --split-long-lines --overwrite
--apply-min-gap vs --fix-common-errors-rules:FixOverlappingDisplayTimesBoth touch boundary timings but solve different problems:
--apply-min-gap[:<ms>] walks every pair of adjacent paragraphs and, when the gap is shorter than <ms>, shortens the previous cue's end time to open it up. It does not move the next cue's start. Pairs are also skipped when shortening would drop the previous cue below General.SubtitleMinimumDisplayMilliseconds — so this is best-effort, not a hard guarantee. Use it for delivery specs (e.g. broadcast standards that ask for 2 frames between cues) while accepting that minimum-display-duration collisions are left alone.FixOverlappingDisplayTimes is one rule inside Fix Common Errors and only resolves cases where a paragraph's end > the next paragraph's start (a true overlap). It does not enforce a non-zero minimum gap once overlaps are gone.In most batch pipelines --apply-min-gap is the better choice; reach for the FCE rule when you specifically want to keep the tight gaps the source already has and only repair true overlaps.
--fix-common-errors (no value) runs all 39 rules. Pass --fix-common-errors-rules:<list> to pick a subset — supplying that option implies --fix-common-errors.
seconv movie.srt subrip --fix-common-errors # all rules
seconv movie.srt subrip --fix-common-errors-rules:FixCommas,FixMissingSpaces
seconv movie.srt subrip --fix-common-errors-rules:all,-FixDanishLetterI # all except one
seconv movie.srt subrip --fix-common-errors --fce-language:es # force the Spanish gate
seconv list-fce-rules # show rule IDs (marks language gates)
Language-specific rules. A few rules only make sense for one language and mirror the GUI's Fix Common Errors window, which only offers them when the detected language matches: FixAloneLowercaseIToUppercaseI (English), FixDanishLetterI (Danish), FixSpanishInvertedQuestionAndExclamationMarks (Spanish), and FixTurkishAnsiToUnicode (Turkish). seconv list-fce-rules marks each gated rule with its language in a Language gate column. These run only when the language matches — so e.g. the Spanish inverted-¿ fix never lands on English content (issue #11037). This holds however the rule was selected: naming it in --fix-common-errors-rules picks it into the run but does not bypass the gate, which makes mixed-language batches safe (a Spanish rule in your rule set self-skips on the English and French files).
The language is auto-detected from the content. To force it:
--fce-language:<code> forces the language used for all gated rules (and the OCR-fix pass). Use it when a genuinely Spanish/Danish/Turkish file mis-detects (e.g. it's too short), or to run a named language rule on content that would auto-detect as something else. Accepts a two-letter code, three-letter code, or English name (es, spa, Spanish); an unrecognized value warns and falls back to auto-detection.Rule selection is CLI-only. The set of rules is chosen with --fix-common-errors-rules, not through the --settings JSON. The settings file shapes how the rules behave (line length, min gap, dialog/continuation style, CPS — see Settings JSON); it does not select which rules run.
FixCommonOcrErrors runs only when a dictionary folder is available — bundled for English, or supplied via --dictionary-folder for other languages (see OCR options). Without one, that rule is skipped and every other rule still runs.
The CLI rule IDs match the check-box rules in the desktop app's Fix Common Errors window. If you prototyped a fix set in the GUI, use this table (or seconv list-fce-rules, which prints the same three columns) to find the matching --fix-common-errors-rules IDs. Language gate marks rules that only run for one detected language (override with --fce-language, or by naming the rule).
| Rule ID | GUI equivalent | Language gate |
|---|---|---|
AddMissingQuotes | Add missing quotes (") | — |
Fix3PlusLines | Fix subtitles with more than two lines | — |
FixAloneLowercaseIToUppercaseI | Fix alone lowercase 'i' to 'I' (English) | en only |
FixCommas | Fix commas | — |
FixContinuationStyle | Fix continuation style | — |
FixDanishLetterI | Fix Danish letter 'i' | da only |
FixDialogsOnOneLine | Split dialogs on one line | — |
FixDoubleApostrophes | Fix double apostrophe characters ('') to a single quote (") | — |
FixDoubleDash | Fix '--' -> '...' | — |
FixDoubleGreaterThan | Remove '>>' | — |
FixEllipsesStart | Remove leading '...' | — |
FixEmptyLines | Remove empty lines/unused line breaks | — |
FixHyphensInDialog | Fix dash in dialogs via style | — |
FixHyphensRemoveDashSingleLine | Remove dialog dashes in single lines | — |
FixInvalidItalicTags | Fix invalid italic tags | — |
FixLongDisplayTimes | Fix long display times | — |
FixLongLines | Break long lines | — |
FixMissingOpenBracket | Fix missing [ or ( in line | — |
FixMissingPeriodsAtEndOfLine | Add period after lines where next line starts with uppercase letter | — |
FixMissingSpaces | Fix missing spaces | — |
FixMusicNotation | Replace music symbols with preferred symbol | — |
FixOverlappingDisplayTimes | Fix overlapping display times | — |
FixShortDisplayTimes | Fix short display times | — |
FixShortGaps | Fix short gaps | — |
FixShortLines | Remove line breaks in short texts with only one sentence | — |
FixShortLinesAll | Remove line breaks in short texts (all except dialogs) | — |
FixShortLinesPixelWidth | Unbreak subtitles that can fit on one line (pixel width) | — |
FixSpanishInvertedQuestionAndExclamationMarks | Fix Spanish inverted question and exclamation marks | es only |
FixStartWithUppercaseLetterAfterColon | Start with uppercase letter after colon/semicolon | — |
FixStartWithUppercaseLetterAfterParagraph | Start with uppercase letter after paragraph | — |
FixStartWithUppercaseLetterAfterPeriodInsideParagraph | Start with uppercase letter after period inside paragraph | — |
FixTurkishAnsiToUnicode | Fix Turkish ANSI (Icelandic) letters to Unicode | tr only |
FixUnnecessaryLeadingDots | Remove unnecessary leading dots | — |
FixUnneededPeriods | Remove unneeded periods | — |
FixUnneededSpaces | Remove unneeded spaces | — |
FixUppercaseIInsideWords | Fix uppercase 'i' inside lowercase words (OCR error) | — |
NormalizeStrings | Normalize strings | — |
RemoveDialogFirstLineInNonDialogs | Remove start dash in first line for non-dialogs | — |
RemoveSpaceBetweenNumbers | Remove space between numbers | — |
FixCommonOcrErrors | Fix common OCR errors (using OCR replace list) | — |
| Aliases | Format |
|---|---|
srt, subrip | SubRip |
ass, assa | Advanced Sub Station Alpha |
ssa | Sub Station Alpha |
vtt, webvtt | WebVTT |
smi, sami | SAMI |
sbv | YouTube SBV |
pac | PAC (Screen Electronics) — binary |
unipac, pacunicode | PAC Unicode |
ebu, ebustl, stl | EBU STL — binary |
cavena, cavena890 | Cavena 890 — binary |
cheetahcaption | CheetahCaption — binary |
capmakerplus | CapMakerPlus — binary |
ayato | Ayato — binary |
bluraysup, sup | Blu-Ray sup — image |
vobsub | VobSub — image |
bdnxml, bdn-xml | BDN-XML — image (folder of PNGs + index.xml) |
dost, dostimage | DOST/image |
fcpimage, fcp | FCP/image |
dcinemainterop | D-Cinema interop/png |
dcinemasmpte2014 | D-Cinema SMPTE 2014/png |
imageswithtimecode | Images with time codes in file name |
plaintext, text, txt | Plain text (HTML stripped) |
customtext, customtextformat | Custom-templated text (requires --custom-format) |
Run seconv formats for the full catalog (380+ entries, including input-only formats like Matroska, MP4, and MCC).
| Code | Meaning |
|---|---|
0 | Conversion succeeded for all matched files |
1 | Any error: validation failure, parse error, OCR engine missing, invalid --settings file, or one or more files failed to convert |
/parameter:value syntax is auto-translated to --parameter:value.--inputfolder, --ocrengine, --FixCommonErrors, …) are kept as hidden aliases for the new POSIX-style names (--input-folder, --ocr-engine, --fix-common-errors, …), so existing scripts keep working.seconv "*.srt" assa --input-folder:./input --output-folder:./output --overwrite
seconv movie.mkv subrip --overwrite # one SRT per language
seconv movie.mkv subrip --track-number:3 --overwrite # only track 3
seconv movie.mkv subrip --forced-only --overwrite # forced only
seconv subs.sup subrip \
--ocr-engine:tesseract \
--ocr-language:eng \
--remove-text-for-hi \
--split-long-lines \
--overwrite
seconv subs.srt bluraysup --resolution:1920x1080 --overwrite
seconv subs.srt bdnxml --overwrite
/convert parity)# SE4: SubtitleEdit.exe /convert movie.srt blu-raysup /Resolution:3840x2160 (+ styling from Settings.xml)
seconv movie.srt bluraysup \
--resolution:3840x2160 \
--font-name:Arial --font-size:100 \
--background-color:"#B4000000" \
--overwrite
seconv new.srt ebustl --ebu-header-file:original.stl --overwrite
seconv subs.srt subrip --fps:24 --target-fps:25 --offset:500 --overwrite
seconv movie.srt plaintext --overwrite
seconv movie.srt customtext --custom-format:lines-template.xml --output-filename:movie.json --overwrite
seconv depends only on Subtitle Edit's core libraries — no Avalonia / GUI runtime:
src/
├── libse/ Core subtitle library (NuGet-shippable, netstandard2.1;net10.0)
├── libuilogic/ Shared headless logic (BatchConverter pipeline, OCR matchers, image renderer)
├── seconv/ This CLI
└── ui/ Avalonia desktop UI (not referenced by seconv)
This means seconv can run on systems without a display (CI, headless servers, Docker) without bundling Avalonia or any X server.