mkv2cast

mkv2cast - Smart MKV to Chromecast-compatible converter with hardware acceleration.

This tool converts MKV video files to formats compatible with Chromecast devices and smart TVs, using VAAPI, QSV, or CPU encoding with intelligent codec detection.

Copyright (C) 2024-2026 voldardard License: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)

Example usage:

# As a command-line tool $ mkv2cast movie.mkv $ mkv2cast –hw vaapi –vaapi-qp 20

# As a Python module from mkv2cast import convert_file, Config

config = Config(hw=”vaapi”, crf=20) result = convert_file(“movie.mkv”, config)

class mkv2cast.Config(suffix: str = '.cast', container: str = 'mkv', recursive: bool = True, ignore_patterns: List[str] = <factory>, ignore_paths: List[str] = <factory>, include_patterns: List[str] = <factory>, include_paths: List[str] = <factory>, debug: bool = False, dryrun: bool = False, skip_when_ok: bool = True, force_h264: bool = False, allow_hevc: bool = False, force_aac: bool = False, keep_surround: bool = False, add_silence_if_no_audio: bool = True, abr: str = '192k', crf: int = 20, preset: str = 'slow', profile: str | None = None, vaapi_device: str = '/dev/dri/renderD128', vaapi_qp: int = 23, qsv_quality: int = 23, nvenc_cq: int = 23, amf_quality: int = 23, hw: str = 'auto', audio_lang: str | None = None, audio_track: int | None = None, subtitle_lang: str | None = None, subtitle_track: int | None = None, prefer_forced_subs: bool = True, no_subtitles: bool = False, preserve_metadata: bool = True, preserve_chapters: bool = True, preserve_attachments: bool = True, integrity_check: bool = True, stable_wait: int = 3, deep_check: bool = False, disk_min_free_mb: int = 1024, disk_min_free_tmp_mb: int = 512, max_output_mb: int = 0, max_output_ratio: float = 0.0, progress: bool = True, bar_width: int = 26, ui_refresh_ms: int = 120, stats_period: float = 0.2, pipeline: bool = True, encode_workers: int = 0, integrity_workers: int = 0, notify: bool = True, notify_on_success: bool = True, notify_on_failure: bool = True, lang: str | None = None, json_progress: bool = False, retry_attempts: int = 1, retry_delay_sec: float = 2.0, retry_fallback_cpu: bool = True)[source]

Bases: object

All configuration options for mkv2cast.

suffix: str = '.cast'
container: str = 'mkv'
recursive: bool = True
ignore_patterns: List[str]
ignore_paths: List[str]
include_patterns: List[str]
include_paths: List[str]
debug: bool = False
dryrun: bool = False
skip_when_ok: bool = True
force_h264: bool = False
allow_hevc: bool = False
force_aac: bool = False
keep_surround: bool = False
add_silence_if_no_audio: bool = True
abr: str = '192k'
crf: int = 20
preset: str = 'slow'
profile: str | None = None
vaapi_device: str = '/dev/dri/renderD128'
vaapi_qp: int = 23
qsv_quality: int = 23
nvenc_cq: int = 23
amf_quality: int = 23
hw: str = 'auto'
audio_lang: str | None = None
audio_track: int | None = None
subtitle_lang: str | None = None
subtitle_track: int | None = None
prefer_forced_subs: bool = True
no_subtitles: bool = False
preserve_metadata: bool = True
preserve_chapters: bool = True
preserve_attachments: bool = True
integrity_check: bool = True
stable_wait: int = 3
deep_check: bool = False
disk_min_free_mb: int = 1024
disk_min_free_tmp_mb: int = 512
max_output_mb: int = 0
max_output_ratio: float = 0.0
progress: bool = True
bar_width: int = 26
ui_refresh_ms: int = 120
stats_period: float = 0.2
pipeline: bool = True
encode_workers: int = 0
integrity_workers: int = 0
notify: bool = True
notify_on_success: bool = True
notify_on_failure: bool = True
lang: str | None = None
json_progress: bool = False
retry_attempts: int = 1
retry_delay_sec: float = 2.0
retry_fallback_cpu: bool = True
apply_script_mode() None[source]

Automatically disable UI features when running in script mode.

Call this method when using mkv2cast as a library to ensure no unwanted output is generated.

Disables: - progress: No progress bars - notify: No desktop notifications - pipeline: No Rich UI (use simple sequential mode)

apply_profile(name: str, only_if_default: bool = False) None[source]

Apply a preset profile to common encoding settings.

Parameters:
  • name – Profile name (“fast”, “balanced”, “quality”).

  • only_if_default – If True, only apply fields still at default values.

classmethod for_library(**kwargs) Config[source]

Create a Config instance optimized for library usage.

Automatically disables UI features (progress bars, notifications, Rich UI) that are not suitable for programmatic use.

Parameters:

**kwargs – Configuration options to override defaults.

Returns:

Config instance with script mode settings applied.

Example

>>> config = Config.for_library(hw="vaapi", crf=20)
>>> success, output, msg = convert_file(path, cfg=config)
mkv2cast.get_app_dirs() Dict[str, Path][source]

Return all application directories, creating them if needed.

mkv2cast.load_config_file(config_dir: Path) dict[source]

Load config with priority: 1. User config: ~/.config/mkv2cast/config.toml (highest priority) 2. System config: /etc/mkv2cast/config.toml (lowest priority, optional)

User config values override system config values.

mkv2cast.is_script_mode() bool[source]

Detect if running as a library (not CLI).

Returns True if: - stdout is not a TTY (piped or redirected) - NO_COLOR environment variable is set - MKV2CAST_SCRIPT_MODE environment variable is set - Being imported as a library (not running as __main__)

Returns:

True if running in script mode, False otherwise.

class mkv2cast.Decision(need_v: bool, need_a: bool, aidx: int, add_silence: bool, reason_v: str, vcodec: str, vpix: str, vbit: int, vhdr: bool, vprof: str, vlevel: int, acodec: str, ach: int, alang: str, format_name: str, sidx: int = -1, slang: str = '', sforced: bool = False)[source]

Bases: object

Decision about what transcoding is needed for a file.

need_v: bool
need_a: bool
aidx: int
add_silence: bool
reason_v: str
vcodec: str
vpix: str
vbit: int
vhdr: bool
vprof: str
vlevel: int
acodec: str
ach: int
alang: str
format_name: str
sidx: int = -1
slang: str = ''
sforced: bool = False
mkv2cast.decide_for(path: Path, cfg: Config | None = None) Decision[source]

Analyze a file and decide what transcoding is needed.

Parameters:
  • path – Path to the MKV file.

  • cfg – Config instance (uses global CFG if not provided).

Returns:

Decision dataclass with transcoding requirements.

mkv2cast.pick_backend(cfg: Config | None = None) str[source]

Select the best available encoding backend.

Parameters:

cfg – Config instance (uses global CFG if not provided).

Returns:

“nvenc”, “qsv”, “vaapi”, or “cpu”.

Return type:

Backend name

mkv2cast.build_transcode_cmd(inp: Path, decision: Decision, backend: str, tmp_out: Path, log_path: Path | None = None, cfg: Config | None = None) Tuple[List[str], str][source]

Build ffmpeg transcoding command.

Parameters:
  • inp – Input file path.

  • decision – Decision dataclass with transcoding requirements.

  • backend – Encoding backend to use.

  • tmp_out – Temporary output path.

  • log_path – Optional path to write command log.

  • cfg – Config instance.

Returns:

Tuple of (command_args, stage_name).

mkv2cast.convert_file(input_path: Path, cfg: Config | None = None, backend: str | None = None, output_dir: Path | None = None, log_path: Path | None = None, progress_callback: Callable[[Path, Dict[str, Any]], None] | None = None) Tuple[bool, Path | None, str][source]

Convert a single MKV file.

Parameters:
  • input_path – Path to input MKV file.

  • cfg – Config instance (uses global CFG if not provided).

  • backend – Backend to use (auto-detected if not provided).

  • output_dir – Output directory (same as input if not provided).

  • log_path – Path for conversion log.

  • progress_callback – Optional callback function called with progress updates. The callback receives (filepath, progress_dict) where progress_dict contains: - stage: “checking” | “encoding” | “done” | “skipped” | “failed” - progress_percent: float (0-100) - fps: float - eta_seconds: float - bitrate: str - speed: str - current_time_ms: int - duration_ms: int - error: Optional[str]

Returns:

Tuple of (success, output_path, message).

Example

>>> def on_progress(filepath, progress):
...     print(f"{filepath.name}: {progress['stage']} - {progress['progress_percent']:.1f}%")
>>> success, output, msg = convert_file(Path("movie.mkv"), progress_callback=on_progress)
mkv2cast.convert_batch(input_paths: List[Path], cfg: Config | None = None, progress_callback: Callable[[Path, Dict[str, Any]], None] | None = None, output_dir: Path | None = None, backend: str | None = None) Dict[Path, Tuple[bool, Path | None, str]][source]

Convert multiple files in parallel using multi-threading.

This function processes multiple files concurrently, respecting the configured number of workers. Each file’s progress is reported via the optional callback.

Parameters:
  • input_paths – List of input file paths to convert.

  • cfg – Config instance (uses global CFG if not provided). The number of parallel workers is determined by cfg.encode_workers.

  • progress_callback – Optional callback function called with progress updates. The callback receives (filepath, progress_dict) for each file. The callback should be thread-safe if processing multiple files.

  • output_dir – Output directory for all files (same as input if not provided).

  • backend – Backend to use (auto-detected if not provided).

Returns:

Dict mapping input_path -> (success, output_path, message).

Example

>>> from mkv2cast import convert_batch, Config
>>> from pathlib import Path
>>>
>>> config = Config.for_library(hw="vaapi", encode_workers=2)
>>>
>>> def on_progress(filepath, progress):
...     print(f"{filepath.name}: {progress['progress_percent']:.1f}%")
>>>
>>> files = [Path("movie1.mkv"), Path("movie2.mkv")]
>>> results = convert_batch(files, cfg=config, progress_callback=on_progress)
>>>
>>> for filepath, (success, output, msg) in results.items():
...     print(f"{filepath.name}: {'OK' if success else 'FAIL'} - {msg}")
class mkv2cast.HistoryDB(state_dir: Path)[source]

Bases: object

History storage with SQLite primary and JSONL text fallback.

record_start(input_path: Path, backend: str, input_size: int = 0) int[source]

Record conversion start, return entry ID.

record_finish(entry_id: int, output_path: Path | None, status: str, encode_time: float = 0, integrity_time: float = 0, output_size: int = 0, duration_ms: int = 0, error_msg: str | None = None) None[source]

Update entry with completion info.

record_skip(input_path: Path, reason: str, backend: str) None[source]

Record a skipped file.

get_recent(limit: int = 20) List[dict][source]

Get recent conversions.

get_stats() dict[source]

Get conversion statistics.

clean_old(days: int) int[source]

Remove entries older than N days. Returns count removed.

mkv2cast.integrity_check(path: Path, enabled: bool = True, stable_wait: int = 3, deep_check: bool = False, log_path: Path | None = None, progress_callback: Callable[[str, int, str], None] | None = None) Tuple[bool, float][source]

Perform complete integrity check on a file.

Parameters:
  • path – Path to the file to check.

  • enabled – If False, skip all checks and return True.

  • stable_wait – Seconds to wait for file size stability.

  • deep_check – If True, perform full decode verification.

  • log_path – Optional path to write logs.

  • progress_callback – Optional callback(stage, pct, message) for UI updates.

Returns:

Tuple of (success, elapsed_seconds).

mkv2cast.setup_i18n(lang: str | None = None) Callable[[str], str][source]

Configure internationalization and return the translation function.

Parameters:

lang – Language code (e.g., ‘fr’, ‘en’). If None, auto-detect from system.

Returns:

Translation function that takes a string and returns translated string.

mkv2cast.send_notification(title: str, message: str, urgency: Literal['low', 'normal', 'critical'] = 'normal', icon: str = 'video-x-generic', timeout: int = 10) bool[source]

Send a desktop notification.

Tries notify-send first (Linux standard), then falls back to plyer if available.

Parameters:
  • title – Notification title.

  • message – Notification body text.

  • urgency – Urgency level - “low”, “normal”, or “critical”.

  • icon – Icon name (XDG icon spec) or path.

  • timeout – Notification timeout in seconds.

Returns:

True if notification was sent successfully, False otherwise.

class mkv2cast.JSONProgressOutput(stream=<_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>)[source]

Bases: object

Manages JSON progress output to stdout.

start(total_files: int, backend: str, encode_workers: int, integrity_workers: int) None[source]

Signal start of processing.

set_file_duration(filepath: str, duration_ms: int) None[source]

Set the duration for a file (from probe).

file_queued(filepath: Path, duration_ms: int = 0) None[source]

Signal a file has been queued.

file_checking(filepath: Path) None[source]

Signal a file integrity check has started.

file_check_done(filepath: Path) None[source]

Signal a file integrity check has finished.

file_encoding_start(filepath: Path, duration_ms: int = 0) None[source]

Signal encoding has started for a file.

file_progress(filepath: Path, frame: int = 0, fps: float = 0.0, time_ms: int = 0, bitrate: str = '', speed: str = '', size_bytes: int = 0) None[source]

Update encoding progress for a file.

file_done(filepath: Path, output_path: Path | None = None, skipped: bool = False, error: str | None = None) None[source]

Signal a file has finished processing.

complete() None[source]

Signal all processing is complete.

mkv2cast.parse_ffmpeg_progress_for_json(line: str) Dict[str, Any][source]

Parse FFmpeg progress line for JSON output.

Returns a dict with parsed values.

Modules

cli

Command-line interface for mkv2cast.

config

Configuration management for mkv2cast.

converter

Core conversion logic for mkv2cast.

history

History database for mkv2cast conversions.

i18n

Internationalization (i18n) support for mkv2cast.

integrity

File integrity checking for mkv2cast.

json_progress

JSON progress output for mkv2cast.

notifications

Desktop notification support for mkv2cast.

pipeline

Pipeline orchestrator for parallel processing in mkv2cast.

ui

User interface components for mkv2cast.

watcher

Watch mode for mkv2cast.