Skip to main content

Crate psyche_subtitle_toolkit

Crate psyche_subtitle_toolkit 

Source
Expand description

§psyche-subtitle-toolkit

Extract, translate, and mux ASS subtitles in MKV files. Built for Psyche but usable as a standalone CLI or library.

No cloud required. No telemetry. Every translation provider is opt-in.

§Supported providers

ProviderStructEndpoint
OllamaOllamaTranslator/api/generate
OpenAIOpenAiTranslator/v1/chat/completions
OpenRouterOpenRouterTranslator/api/v1/chat/completions
AnthropicAnthropicTranslator/v1/messages
DeepLDeepLTranslator/v2/translate
Google TranslateGoogleTranslator/language/translate/v2
GeminiGeminiTranslatorv1beta/models/{model}:generateContent

§Quick start (library)

Translate an MKV file in-place:

use std::sync::Arc;
use psyche_subtitle_toolkit::{translate_mkv, TranslateMkvOptions, OllamaTranslator, Translator};

let translator: Arc<dyn Translator> = Arc::new(OllamaTranslator::new("llama3.1")?);
translate_mkv(
    TranslateMkvOptions {
        input: "/media/anime/episode.mkv".into(),
        target_language: "pt-BR".into(),
        track_id: None,
        keep_temp: false,
        dry_run: false,
        resume: false,
        max_concurrent: 1,
    },
    translator,
).await?;

Translate ASS content directly (no MKV I/O):

use std::sync::Arc;
use psyche_subtitle_toolkit::{translate_ass, AssSubtitle, OllamaTranslator, Translator};

let ass = AssSubtitle::parse(&std::fs::read_to_string("source.ass")?)?;
let translator: Arc<dyn Translator> = Arc::new(OllamaTranslator::new("llama3.1")?);
let translated = translate_ass(ass, "pt-BR", 1, translator).await?;
std::fs::write("translated.ass", translated.render())?;

Implement a custom provider:

use async_trait::async_trait;
use psyche_subtitle_toolkit::{Translator, TranslationRequest, Result};

struct MyTranslator;

#[async_trait]
impl Translator for MyTranslator {
    async fn translate(&self, request: TranslationRequest<'_>) -> Result<String> {
        // Your translation logic here.
        // request.source_text is numbered: "<1> hello\n<2> world"
        // Return translated text in the same format.
        Ok(request.source_text.to_string())
    }
}

§Pipeline overview

  1. Inspectmkvmerge -J identifies tracks, selects the ASS subtitle
  2. Extractmkvextract tracks pulls the ASS file to a temp directory
  3. Parse — ASS parser reads dialogue lines, preserving headers and styles
  4. Strip tags — Override tags ({\pos(...)}, {\an7}) removed and stored
  5. Chunk — Cues split into 200-line batches
  6. Translate — Each chunk sent to the provider (concurrent if max_concurrent > 1)
  7. Retry — Failed chunks retried up to 3 times with exponential backoff
  8. Apply — Translated text mapped back to cues by ID
  9. Reinject tags — Original override tags prepended back
  10. Muxmkvmerge replaces the original subtitle track in-place

Re-exports§

pub use error::Result;
pub use error::SubtitleToolkitError;
pub use media::mkv::MkvInfo;
pub use media::mkv::MkvTrack;
pub use media::mkv::MkvTrackProperties;
pub use media::mkv::SubtitleFormat;
pub use media::mkv::inspect_mkv;
pub use media::mkv::select_ass_track;
pub use media::mkv::select_subtitle_track;
pub use pipeline::TranslateMkvOptions;
pub use pipeline::dry_run_summary;
pub use pipeline::translate_ass;
pub use pipeline::translate_mkv;
pub use pipeline::translate_srt;
pub use pipeline::translate_vtt;
pub use subtitles::ass::AssSubtitle;
pub use subtitles::srt::SrtSubtitle;
pub use subtitles::vtt::VttSubtitle;
pub use subtitles::model::SubtitleCue;
pub use subtitles::model::SubtitleDocument;
pub use subtitles::structured::apply_translation;
pub use subtitles::structured::chunk_document;
pub use subtitles::structured::chunk_document_by_lines;
pub use subtitles::structured::parse_numbered_text;
pub use subtitles::structured::reinject_tags;
pub use subtitles::structured::strip_tags;
pub use subtitles::structured::to_numbered_text;
pub use translation::anthropic::AnthropicTranslator;
pub use translation::deepl::DeepLTranslator;
pub use translation::gemini::GeminiTranslator;
pub use translation::google::GoogleTranslator;
pub use translation::ollama::OllamaTranslator;
pub use translation::openai::OpenAiTranslator;
pub use translation::openrouter::OpenRouterTranslator;
pub use translation::TranslationRequest;
pub use translation::Translator;

Modules§

error
Error types for the subtitle toolkit.
media
MKV container inspection and manipulation (mkvmerge/mkvextract wrappers).
pipeline
Translation pipeline: MKV full-pipeline and subtitle-only translation.
subtitles
Subtitle parsing, chunking, and tag manipulation.
translation
Pluggable translation providers and the Translator trait.