Translate subtitles from a local media library and keep every translation in a durable job history.
- Translate local media: Choose subtitle files next to your media or text subtitles embedded in the media itself.
- Keep terminology consistent: Reuse named term maps across translations, or import them from JSON.
- Protect your files: Choose a numbered output when a translation already exists, or explicitly replace it after a successful translation.
- Track the work: See queued, active, completed, failed, and interrupted translations in one place.
- Resume safely: Keep the Work volume across restarts so job history and recoverable work are not lost.
- Docker with permission to build and run containers.
- A media directory that the container can read and write when it publishes translated subtitles.
- A supported translation provider and its credentials supplied through environment variables.
Run these commands from the project directory:
mkdir -p media
read -r -s -p "DeepSeek API key: " DEEPSEEK_API_KEY
printf '\n'
docker build -t cueweaver .
docker run --rm \
--publish 127.0.0.1:8000:8000 \
--env PROVIDER=DeepSeek \
--env DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
--env DEEPSEEK_API_BASE=https://api.deepseek.com \
--env DEEPSEEK_MODEL=deepseek-chat \
--env CUEWEAVER_MEDIA_ROOT=/media \
--env CUEWEAVER_WORK_ROOT=/work \
--volume "$PWD/media:/media" \
--volume cueweaver-work:/work \
cueweaverOpen http://localhost:8000 in your browser.
The media directory is the library shown in CueWeaver. Replace it with an existing directory if your media is stored elsewhere. Keep the cueweaver-work volume: it contains job history and in-progress translation state.
| Variable | Value | Required for |
|---|---|---|
PROVIDER |
DeepSeek in the startup example |
Translation |
DEEPSEEK_API_KEY |
Your DeepSeek API key | DeepSeek translation |
DEEPSEEK_API_BASE |
https://api.deepseek.com |
Optional |
DEEPSEEK_MODEL |
deepseek-chat |
Optional |
CUEWEAVER_MEDIA_ROOT |
Absolute path inside the container for the media library | Startup |
CUEWEAVER_WORK_ROOT |
Absolute, writable path inside the container for job data | Startup |
The selected media directory must be writable so CueWeaver can save translated subtitles. The Work volume must be writable and persistent so CueWeaver can keep job history and resumable work.
Application data is stored in the SQLite database at cueweaver.sqlite3 in the
Work root. The database contains Job records, Term maps, directory bindings,
and application metadata. Schema upgrades run automatically through the
versioned migrations shipped with CueWeaver. Existing JSON Job and Term map
records are imported once when the application starts, then their snapshots
are retired. The Work root also contains .cueweaver.lease, which prevents
multiple CueWeaver processes from using the same Work root. Do not remove the
Work volume while Jobs are active.
After an unclean process stop, the next startup restores Queued Jobs in
queue order and marks Jobs that were in Extracting or Translating as
Interrupted. A subtitle is written to a same-directory temporary file before
it is atomically published, so readers never observe a partial output. A
completed Job is persisted before its Work directory is removed; cleanup
failure leaves the Job Completed and logs the leftover directory. The
operating system releases the lease after a process crash; do not delete
.cueweaver.lease manually. If SQLite cannot be opened, CueWeaver refuses startup;
preserve the entire Work volume before restoring or inspecting a backup.
CueWeaver supports these providers in the built-in image:
| Provider | PROVIDER value |
Credentials |
|---|---|---|
| DeepSeek | DeepSeek |
DEEPSEEK_API_KEY |
| OpenRouter | OpenRouter |
OPENROUTER_API_KEY |
| OpenAI-compatible remote server | Custom Server |
CUSTOM_SERVER_ADDRESS or the built-in localhost default; CUSTOM_API_KEY if required |
| OpenAI | OpenAI |
OPENAI_API_KEY |
| Azure OpenAI | Azure |
AZURE_API_KEY, AZURE_API_BASE, AZURE_API_VERSION, AZURE_DEPLOYMENT_NAME |
| Google Gemini | Gemini |
GEMINI_API_KEY |
| Anthropic Claude | Claude |
CLAUDE_API_KEY |
| Mistral | Mistral |
MISTRAL_API_KEY |
| Amazon Bedrock | Bedrock |
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, BEDROCK_MODEL |
Set PROVIDER and the matching provider variables before starting the container. Restart CueWeaver after changing them. Credentials cannot be entered in the Web interface.
If no provider is configured, CueWeaver still starts so you can browse media, manage term maps, and view job history. New translations remain unavailable until PROVIDER and the matching credentials are configured.
The provider status performs a local preflight only. It confirms that the provider is bundled and its required variables are non-empty; it does not call the provider API or verify credentials, account access, region availability, or model access.
The defaults below match the provider integration bundled with CueWeaver.
The startup command above is a complete DeepSeek configuration. These optional settings let you adjust it:
| Variable | Default | Type | Purpose and notes |
|---|---|---|---|
DEEPSEEK_API_KEY |
None | string | Required. Create a key in the DeepSeek account that will pay for the requests. |
DEEPSEEK_API_BASE |
https://api.deepseek.com |
string | Base URL for the DeepSeek API or a compatible DeepSeek deployment. |
DEEPSEEK_MODEL |
deepseek-chat |
string | Model ID sent to the API. |
DEEPSEEK_MAX_TOKENS |
8192 |
integer | Maximum output tokens per request. |
DEEPSEEK_TEMPERATURE |
1.3 |
float | Sampling temperature. Lower values generally produce more consistent translations. |
DEEPSEEK_RATE_LIMIT |
None | float | Maximum API requests per minute. Leave unset unless the provider limits request frequency. |
DEEPSEEK_PROXY |
None | string | Optional HTTP proxy URL. |
You do not need to set an endpoint for DeepSeek. CueWeaver explicitly disables thinking for the DeepSeek provider.
Set PROVIDER=OpenRouter and replace the DeepSeek credentials with these variables:
| Variable | Default | Type | Purpose and notes |
|---|---|---|---|
OPENROUTER_API_KEY |
None | string | Required. Create a key at OpenRouter. |
OPENROUTER_SERVER_ADDRESS |
https://openrouter.ai/api/ |
string | OpenRouter API base URL. |
OPENROUTER_MODEL |
google/gemini-3-flash-preview |
string | OpenRouter model ID. |
OPENROUTER_MODEL_FAMILY |
Google |
string | Optional model family filter. |
OPENROUTER_STREAM_RESPONSES |
True |
boolean | Stream partial responses. Use True to enable streaming. |
OPENROUTER_MAX_TOKENS |
0 |
integer | Maximum output tokens. 0 means the provider default. |
OPENROUTER_TEMPERATURE |
0.0 |
float | Sampling temperature. |
OPENROUTER_RATE_LIMIT |
None | float | Maximum API requests per minute. |
OPENROUTER_PROXY |
None | string | Optional HTTP proxy URL. |
Use an OpenRouter model identifier for OPENROUTER_MODEL, not a display name from the OpenRouter Web site.
Set PROVIDER=OpenAI and configure the OpenAI API:
| Variable | Default | Type | Purpose and notes |
|---|---|---|---|
OPENAI_API_KEY |
None | string | Required. |
OPENAI_API_BASE |
Provider default | string | Optional compatible API base URL. |
OPENAI_MODEL |
gpt-5-mini |
string | Model ID sent to the API. |
OPENAI_TEMPERATURE |
0.0 |
float | Sampling temperature for non-reasoning models. |
OPENAI_RATE_LIMIT |
None | float | Maximum API requests per minute. |
OPENAI_REASONING_EFFORT |
low |
string | Reasoning effort for supported reasoning models. |
OPENAI_STREAM_RESPONSES |
False |
boolean | Stream reasoning responses. |
OPENAI_PROXY |
None | string | Optional proxy URL. |
Set PROVIDER=Azure. Azure uses the OpenAI SDK but requires an Azure deployment:
| Variable | Default | Type | Purpose and notes |
|---|---|---|---|
AZURE_API_KEY |
None | string | Required. |
AZURE_API_BASE |
None | string | Required Azure resource endpoint. |
AZURE_API_VERSION |
None | string | Required API version. |
AZURE_DEPLOYMENT_NAME |
None | string | Required deployment name. |
AZURE_PROXY |
None | string | Optional proxy URL. |
Set PROVIDER=Gemini and configure Google AI:
| Variable | Default | Type | Purpose and notes |
|---|---|---|---|
GEMINI_API_KEY |
None | string | Required. |
GEMINI_MODEL |
gemini-3-flash-preview |
string | Model ID. |
GEMINI_STREAM_RESPONSES |
True |
boolean | Stream partial responses. |
GEMINI_ENABLE_THINKING |
False |
boolean | Enable model reasoning when supported. |
GEMINI_THINKING_BUDGET |
100 |
integer | Reasoning token budget. |
GEMINI_TEMPERATURE |
0.0 |
float | Sampling temperature. |
GEMINI_RATE_LIMIT |
60.0 |
float | Maximum API requests per minute. |
GEMINI_PROXY |
None | string | Optional proxy URL. |
Gemini model discovery and credential validation happen only when a translation request is made; the startup preflight does not call Google APIs.
Set PROVIDER=Claude and configure Anthropic:
| Variable | Default | Type | Purpose and notes |
|---|---|---|---|
CLAUDE_API_KEY |
None | string | Required. |
CLAUDE_MODEL |
Claude Haiku 4.5 |
string | Model ID or display name supported by the API. |
CLAUDE_STREAM_RESPONSES |
True |
boolean | Stream partial responses. |
CLAUDE_THINKING |
False |
boolean | Enable Claude thinking mode. |
CLAUDE_MAX_TOKENS |
4096 |
integer | Maximum output tokens. |
CLAUDE_MAX_THINKING_TOKENS |
1024 |
integer | Maximum thinking tokens when enabled. |
CLAUDE_TEMPERATURE |
0.0 |
float | Sampling temperature. |
CLAUDE_RATE_LIMIT |
10.0 |
float | Maximum API requests per minute. |
CLAUDE_PROXY |
None | string | Optional proxy URL. |
Set PROVIDER=Mistral and configure Mistral:
| Variable | Default | Type | Purpose and notes |
|---|---|---|---|
MISTRAL_API_KEY |
None | string | Required. |
MISTRAL_SERVER_URL |
Provider default | string | Optional compatible API base URL. |
MISTRAL_MODEL |
mistral-small-latest |
string | Model ID. Larger models generally translate better. |
MISTRAL_TEMPERATURE |
0.0 |
float | Sampling temperature. |
MISTRAL_RATE_LIMIT |
None | float | Maximum API requests per minute. |
MISTRAL_PROXY |
None | string | Optional proxy URL. |
CueWeaver pins the Mistral SDK below version 2 because PySubtrans 1.6.0 uses its version 1 client API.
Set PROVIDER=Bedrock. Bedrock requires static AWS credentials and an explicit model ID:
| Variable | Default | Type | Purpose and notes |
|---|---|---|---|
AWS_ACCESS_KEY_ID |
None | string | Required. |
AWS_SECRET_ACCESS_KEY |
None | string | Required. |
AWS_REGION |
None | string | Required by CueWeaver, for example us-east-1. |
BEDROCK_MODEL |
None | string | Required model ID with Bedrock access enabled. |
BEDROCK_MAX_TOKENS |
8192 |
integer | Maximum output tokens. |
BEDROCK_TEMPERATURE |
0.0 |
float | Sampling temperature. |
BEDROCK_RATE_LIMIT |
None | float | Maximum API requests per minute. |
BEDROCK_PROXY |
None | string | Optional proxy URL. |
The image currently supports access key and secret key authentication. It does not configure IAM roles or session tokens. Bedrock model access must be enabled in AWS, and some models may not follow subtitle translation instructions reliably.
Custom Server connects to a remote server that exposes an OpenAI-compatible API. Set PROVIDER=Custom Server and configure the following variables:
| Variable | Default | Type | Purpose and notes |
|---|---|---|---|
CUSTOM_SERVER_ADDRESS |
http://localhost:1234 |
string | Server base URL. Set this to the remote API address; the default points to the CueWeaver container itself and is usually not useful. |
CUSTOM_ENDPOINT |
/v1/chat/completions |
string | Path used by the remote service. |
CUSTOM_SUPPORTS_CONVERSATION |
True |
boolean | Send a chat-style request when true. Use a completion endpoint with False. |
CUSTOM_SUPPORTS_SYSTEM_MESSAGES |
True |
boolean | Send instructions as system messages when true. Set false when the endpoint does not support them. |
CUSTOM_PROMPT_TEMPLATE |
Built-in (leave unset) | string | Advanced: change only if the remote service requires a different prompt format. |
CUSTOM_TEMPERATURE |
0.0 |
float | Sampling temperature. |
CUSTOM_MAX_TOKENS |
0 |
integer | Maximum output tokens. 0 disables this limit. |
CUSTOM_MAX_COMPLETION_TOKENS |
0 |
integer | Alternative token limit used by some OpenAI-compatible servers. 0 disables it. |
CUSTOM_TIMEOUT |
300 |
integer | Request timeout in seconds. |
CUSTOM_API_KEY |
None | string | Optional API key for the remote server. |
CUSTOM_MODEL |
None | string | Optional model ID. Some servers select the model on the server side. |
CUSTOM_SUPPORTS_PARALLEL_THREADS |
False |
boolean | Allow parallel translation requests. Enable only when the remote server supports them. |
CUSTOM_REPETITION_PENALTY |
0.0 |
float | Repetition penalty for servers that support it. 0.0 disables it. |
CUSTOM_MIN_P |
0.0 |
float | Minimum-probability sampling threshold for servers that support it. 0.0 disables it. |
The remote server must be reachable from inside the container, not only from the host. Set the compatibility options to match the server's documented API.
CueWeaver also disables thinking when CUSTOM_MODEL starts with deepseek-, regardless of letter case.
Most users can leave the advanced settings at their defaults.
- If the CueWeaver Web interface says that the translation provider is unavailable, use the message shown in the status panel to identify the missing variable. Provider names are case-sensitive and must exactly match the table above.
- If translation cannot start, check the provider's API key, endpoint, model, region, and account permissions.
- For a
Custom Server404, checkCUSTOM_SERVER_ADDRESSandCUSTOM_ENDPOINT. - For a
Custom Servertimeout or connection error, verify that the remote server accepts connections from the container and that its firewall allows the request. - Set
CUSTOM_SUPPORTS_CONVERSATION=falsewhen the remote service uses a completion endpoint rather than a chat endpoint. SetCUSTOM_SUPPORTS_SYSTEM_MESSAGES=falsewhen it does not support system messages. - If a request is rejected for authentication, check the provider's API key and restart the container.
- Changing any provider environment variable requires a container restart. The Work volume can be kept across restarts; it contains job history and resumable translation state.
- Queued Jobs are restored in queue order after a restart. Jobs that were already extracting or translating are marked interrupted and can be retried from the Jobs page. Completed Jobs are persisted before best-effort Work-directory cleanup; cleanup failures leave them completed.
- Put media and subtitle files in the mounted media directory.
- Open Translate and browse to a media file.
- Select an available subtitle. CueWeaver supports
.srt,.ass, and.vttfiles, plus text subtitles embedded in media containers. - Choose the target language and, if needed, select a saved term map.
- Choose how to handle an existing output, then start the translation.
- Follow progress and results from Jobs.
Translated subtitles use the media name, your chosen suffix, and the source subtitle format. Failed translations never replace an existing output.
CueWeaver has no authentication and is intended for trusted local use. The startup command binds the Web interface to the loopback address. Do not publish it to another network unless you put it behind an authenticated reverse proxy.