mkv2cast 1.2.7.post4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1411 @@
1
+ Metadata-Version: 2.4
2
+ Name: mkv2cast
3
+ Version: 1.2.7.post4
4
+ Summary: Smart MKV to Chromecast-compatible converter with hardware acceleration
5
+ Project-URL: Homepage, https://github.com/voldardard/mkv2cast
6
+ Project-URL: Documentation, https://voldardard.github.io/mkv2cast
7
+ Project-URL: Repository, https://github.com/voldardard/mkv2cast
8
+ Project-URL: Issues, https://github.com/voldardard/mkv2cast/issues
9
+ Project-URL: Changelog, https://github.com/voldardard/mkv2cast/blob/main/CHANGELOG.md
10
+ Author: voldardard
11
+ License-Expression: GPL-3.0-or-later
12
+ License-File: LICENSE
13
+ Keywords: chromecast,converter,ffmpeg,mkv,qsv,transcoding,vaapi,video
14
+ Classifier: Development Status :: 5 - Production/Stable
15
+ Classifier: Environment :: Console
16
+ Classifier: Intended Audience :: End Users/Desktop
17
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
18
+ Classifier: Operating System :: POSIX :: Linux
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.8
21
+ Classifier: Programming Language :: Python :: 3.9
22
+ Classifier: Programming Language :: Python :: 3.10
23
+ Classifier: Programming Language :: Python :: 3.11
24
+ Classifier: Programming Language :: Python :: 3.12
25
+ Classifier: Topic :: Multimedia :: Video :: Conversion
26
+ Requires-Python: >=3.8
27
+ Provides-Extra: dev
28
+ Requires-Dist: mypy>=1.0; extra == 'dev'
29
+ Requires-Dist: myst-parser>=2.0.0; extra == 'dev'
30
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
31
+ Requires-Dist: pytest>=7.0; extra == 'dev'
32
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
33
+ Requires-Dist: sphinx-rtd-theme>=2.0; extra == 'dev'
34
+ Requires-Dist: sphinx>=7.0; extra == 'dev'
35
+ Provides-Extra: full
36
+ Requires-Dist: plyer>=2.1.0; extra == 'full'
37
+ Requires-Dist: rich>=13.0.0; extra == 'full'
38
+ Requires-Dist: tomli>=2.0.0; (python_version < '3.11') and extra == 'full'
39
+ Requires-Dist: watchdog>=3.0.0; extra == 'full'
40
+ Provides-Extra: notifications
41
+ Requires-Dist: plyer>=2.1.0; extra == 'notifications'
42
+ Provides-Extra: rich
43
+ Requires-Dist: rich>=13.0.0; extra == 'rich'
44
+ Provides-Extra: watch
45
+ Requires-Dist: watchdog>=3.0.0; extra == 'watch'
46
+ Description-Content-Type: text/markdown
47
+
48
+ # mkv2cast
49
+
50
+ <p align="center">
51
+ <img src="https://github.com/voldardard/mkv2cast/blob/main/docs/_static/mkv2cast-logo.svg" alt="mkv2cast logo" width="280">
52
+ </p>
53
+
54
+ <!-- Badges de statut -->
55
+ [![CI](https://github.com/voldardard/mkv2cast/actions/workflows/ci.yml/badge.svg)](https://github.com/voldardard/mkv2cast/actions/workflows/ci.yml)
56
+ [![Tests](https://img.shields.io/github/actions/workflow/status/voldardard/mkv2cast/ci.yml?label=tests)](https://github.com/voldardard/mkv2cast/actions/workflows/ci.yml)
57
+ [![Documentation](https://github.com/voldardard/mkv2cast/actions/workflows/docs.yml/badge.svg)](https://github.com/voldardard/mkv2cast/actions/workflows/docs.yml)
58
+
59
+ <!-- Badges de version -->
60
+ [![PyPI](https://img.shields.io/pypi/v/mkv2cast.svg)](https://pypi.org/project/mkv2cast/)
61
+ [![PyPI Downloads](https://img.shields.io/pypi/dm/mkv2cast)](https://pypi.org/project/mkv2cast/)
62
+ [![Python](https://img.shields.io/pypi/pyversions/mkv2cast.svg)](https://pypi.org/project/mkv2cast/)
63
+
64
+ <!-- Badges de projet -->
65
+ [![License: GPL-3.0](https://img.shields.io/badge/License-GPL%203.0-green.svg)](https://www.gnu.org/licenses/gpl-3.0)
66
+ [![Platform](https://img.shields.io/badge/platform-Linux-lightgrey.svg)](https://www.linux.org/)
67
+ [![Code style: ruff](https://img.shields.io/badge/code%20style-ruff-000000.svg)](https://github.com/astral-sh/ruff)
68
+
69
+ **Smart MKV to Chromecast-compatible converter with hardware acceleration**
70
+
71
+ Convert your MKV video files to formats compatible with Chromecast devices and Smart TVs, using intelligent codec detection and hardware-accelerated encoding.
72
+
73
+ <p align="center">
74
+ <img src="https://github.com/voldardard/mkv2cast/blob/main/docs/screenshot.png" alt="mkv2cast progress interface" width="700">
75
+ </p>
76
+
77
+ ---
78
+
79
+ ## Table of Contents
80
+
81
+ - [Features](#features)
82
+ - [Distribution](#distribution)
83
+ - [Purpose](#purpose)
84
+ - [Tested Devices](#tested-devices)
85
+ - [Prerequisites](#prerequisites)
86
+ - [Installation](#installation)
87
+ - [Configuration](#configuration)
88
+ - [Usage](#usage)
89
+ - [Using mkv2cast as a Python Package](#using-mkv2cast-as-a-python-package)
90
+ - [Options Reference](#options-reference)
91
+ - [Examples](#examples)
92
+ - [Maintenance](#maintenance)
93
+ - [Points de Vigilance](#points-de-vigilance)
94
+ - [Troubleshooting](#troubleshooting)
95
+ - [Contributing](#contributing)
96
+ - [Bug Reports](#bug-reports)
97
+ - [Roadmap](#roadmap)
98
+ - [Acknowledgments](#acknowledgments)
99
+ - [License](#license)
100
+
101
+ ---
102
+
103
+ ## Features
104
+
105
+ - **Intelligent Codec Detection**: Automatically analyzes video and audio streams to determine if transcoding is needed
106
+ - **Hardware Acceleration**: Supports Intel VAAPI and Quick Sync Video (QSV) for faster encoding
107
+ - **Parallel Processing**: Process multiple files simultaneously with configurable worker counts
108
+ - **Rich Progress Display**: Beautiful terminal UI with progress bars, ETA, and speed indicators
109
+ - **Integrity Checking**: Verifies source files before processing to avoid corrupted outputs
110
+ - **Conversion History**: Track all conversions with SQLite database and statistics
111
+ - **Flexible Filtering**: Include/exclude files using glob patterns or path filters
112
+ - **XDG Compliant**: Follows Linux standards for configuration, cache, and state directories
113
+ - **Automatic Audio Selection**: Prefers French audio tracks, falls back to first available
114
+ - **Configurable**: TOML/INI configuration file with sensible defaults
115
+ - **Desktop Notifications**: Get notified when conversions complete (via notify-send or plyer)
116
+ - **Multi-Language Support**: Available in English, French, Spanish, Italian, and German
117
+ - **PyPI Distribution**: Easy installation via `pip install mkv2cast`
118
+ - **GPU Acceleration**: NVIDIA NVENC, AMD AMF, Intel QSV, and VAAPI backends with auto-detection
119
+ - **Watch Mode**: Inotify/watchdog-based auto-conversion with optional systemd unit
120
+
121
+ ---
122
+
123
+ ## Distribution
124
+
125
+ | | |
126
+ |---|---|
127
+ | **Version** | 1.2.5 |
128
+ | **Author** | voldardard |
129
+ | **Date** | January 2026 |
130
+ | **License** | GPL-3.0 |
131
+ | **Repository** | https://github.com/voldardard/mkv2cast |
132
+ | **PyPI** | https://pypi.org/project/mkv2cast/ |
133
+ | **Documentation** | https://voldardard.github.io/mkv2cast |
134
+
135
+ ### Version Format
136
+
137
+ mkv2cast uses semantic versioning with support for patch releases:
138
+
139
+ - **Standard releases**: `X.Y.Z` (e.g., `1.2.0`)
140
+ - **Patch releases**: `X.Y.Z-N` (e.g., `1.2.0-1`, `1.2.0-2`) - Used for bug fixes and minor updates without changing the main version
141
+ - **Pre-releases**: `X.Y.Z-beta.N`, `X.Y.Z-alpha.N`, `X.Y.Z-rc.N` (e.g., `1.2.0-beta.1`)
142
+
143
+ Patch releases (format `X.Y.Z-N`) are treated as stable releases and will:
144
+ - Be published to PyPI (automatically converted to PEP 440 format: `X.Y.Z.postN`)
145
+ - Trigger AUR and Debian package builds
146
+ - Not be treated as beta/alpha/rc releases
147
+
148
+ **Note on PyPI compatibility**: PyPI follows PEP 440 which doesn't support the `-N` format. Patch releases are automatically converted to `X.Y.Z.postN` format when publishing to PyPI (e.g., `1.2.7-1` becomes `1.2.7.post1` on PyPI). The original format `1.2.7-1` is preserved in Git tags and other package formats.
149
+
150
+ For AUR packages, patch releases are converted to `pkgver=X.Y.Z` and `pkgrel=N` format.
151
+
152
+ ---
153
+
154
+ ## Purpose
155
+
156
+ **mkv2cast** was created to simplify the process of converting video files for playback on Chromecast devices and Smart TVs.
157
+
158
+ Many media files use codecs that aren't natively supported by Chromecast (like HEVC/H.265, AV1, or non-AAC audio). This tool:
159
+
160
+ 1. **Analyzes** your MKV files to detect incompatible codecs
161
+ 2. **Transcodes** only what's necessary (video, audio, or both)
162
+ 3. **Preserves** compatible streams by copying them without re-encoding
163
+ 4. **Outputs** Chromecast-compatible files ready for streaming
164
+
165
+ ### Integration with catt
166
+
167
+ This tool is designed to work seamlessly with [catt](https://github.com/skorokithakis/catt) (Cast All The Things), a command-line tool for casting videos to Chromecast devices:
168
+
169
+ ```bash
170
+ # Convert your files first
171
+ mkv2cast movie.mkv
172
+
173
+ # Then cast to your TV
174
+ catt cast movie.h264.aac.cast.mkv
175
+ ```
176
+
177
+ ---
178
+
179
+ ## Tested Devices
180
+
181
+ mkv2cast has been tested and confirmed working with:
182
+
183
+ | Device | Status | Notes |
184
+ |--------|--------|-------|
185
+ | **TCL 55C635** | ✅ Verified | Primary test device, 4K HDR |
186
+ | **TCL 65C735** | ✅ Verified | Similar to 55C635 |
187
+ | **Chromecast (Gen 3)** | ✅ Verified | 1080p |
188
+ | **Chromecast with Google TV** | ✅ Verified | 4K HDR |
189
+ | **Chromecast Ultra** | ✅ Verified | 4K HDR |
190
+
191
+ > **Note**: If you test with other devices, please submit a PR to update this list!
192
+
193
+ ---
194
+
195
+ ## Prerequisites
196
+
197
+ ### Required
198
+
199
+ | Dependency | Version | Installation |
200
+ |------------|---------|--------------|
201
+ | **Python** | 3.8+ | Pre-installed on most Linux systems |
202
+ | **ffmpeg** | 4.0+ | `sudo pacman -S ffmpeg` (Arch) / `sudo apt install ffmpeg` (Debian) |
203
+ | **ffprobe** | 4.0+ | Included with ffmpeg |
204
+
205
+ ### Optional (Recommended)
206
+
207
+ | Package | Purpose | Installation |
208
+ |---------|---------|--------------|
209
+ | **rich** | Beautiful progress UI | See below |
210
+ | **tomli** | TOML config support (Python < 3.11) | See below |
211
+
212
+ **Installing optional packages:**
213
+
214
+ ```bash
215
+ # Arch Linux (recommended - system packages)
216
+ sudo pacman -S python-rich
217
+ sudo pacman -S python-tomli # Only needed for Python < 3.11
218
+
219
+ # Debian/Ubuntu
220
+ pip install --user rich tomli
221
+
222
+ # Other distributions
223
+ pip install --user rich tomli
224
+ ```
225
+
226
+ ### Hardware Acceleration
227
+
228
+ For hardware-accelerated encoding:
229
+
230
+ - **Intel VAAPI**: Install `intel-media-driver` or `libva-intel-driver`
231
+ - **Intel QSV**: Install `intel-media-sdk` or `oneVPL`
232
+
233
+ Check your hardware support:
234
+
235
+ ```bash
236
+ # List available encoders
237
+ ffmpeg -encoders 2>/dev/null | grep -E 'vaapi|qsv'
238
+
239
+ # Test VAAPI
240
+ ls -la /dev/dri/renderD128
241
+
242
+ # Check with mkv2cast
243
+ mkv2cast --check-requirements
244
+ ```
245
+
246
+ ---
247
+
248
+ ## Installation
249
+
250
+ ### PyPI (Recommended) 🚀
251
+
252
+ ```bash
253
+ # Basic installation
254
+ pip install mkv2cast
255
+
256
+ # With all optional features (rich UI, notifications)
257
+ pip install "mkv2cast[full]"
258
+ ```
259
+
260
+ ### Arch Linux (AUR)
261
+
262
+ ```bash
263
+ yay -S mkv2cast
264
+ # or
265
+ paru -S mkv2cast
266
+ ```
267
+
268
+ The AUR package ships the man page, bash/zsh completions, and both user + system cleanup timers by default.
269
+
270
+ ### Debian/Ubuntu (APT Repository)
271
+
272
+ Add the official APT repository for automatic updates:
273
+
274
+ ```bash
275
+ # Add the repository
276
+ echo "deb [trusted=yes] https://voldardard.github.io/mkv2cast/apt stable main" | sudo tee /etc/apt/sources.list.d/mkv2cast.list
277
+
278
+ # Update and install
279
+ sudo apt update
280
+ sudo apt install mkv2cast
281
+ ```
282
+
283
+ Or download the `.deb` package directly from [GitHub Releases](https://github.com/voldardard/mkv2cast/releases):
284
+
285
+ ```bash
286
+ # Download and install specific version
287
+ wget https://github.com/voldardard/mkv2cast/releases/download/v1.2.5/mkv2cast_1.2.5-1_all.deb
288
+ sudo dpkg -i mkv2cast_1.2.5-1_all.deb
289
+ sudo apt-get install -f # Install dependencies
290
+ ```
291
+
292
+ Debian packages install the man page, bash/zsh completions, the user cleanup timer, and the optional system-wide cleanup timer. The watch mode service and timer are also available under the user systemd directory.
293
+
294
+ ### Script Install (One-Liner)
295
+
296
+ ```bash
297
+ curl -fsSL https://raw.githubusercontent.com/voldardard/mkv2cast/main/install.sh | bash
298
+ ```
299
+
300
+ The installer will:
301
+ - Download mkv2cast automatically
302
+ - Install to `~/.local/bin/`
303
+ - Set up man page and shell completions
304
+ - Configure your PATH automatically (if needed)
305
+
306
+ After installation, reload your shell or run:
307
+
308
+ ```bash
309
+ source ~/.bashrc # or ~/.zshrc for Zsh users
310
+ ```
311
+
312
+ ### Update
313
+
314
+ ```bash
315
+ # PyPI
316
+ pip install --upgrade mkv2cast
317
+
318
+ # Script
319
+ curl -fsSL https://raw.githubusercontent.com/voldardard/mkv2cast/main/install.sh | bash -s -- --update
320
+ ```
321
+
322
+ ### System-Wide Installation
323
+
324
+ For servers or multi-user systems, install to `/usr/local`:
325
+
326
+ ```bash
327
+ curl -fsSL https://raw.githubusercontent.com/voldardard/mkv2cast/main/install.sh | sudo bash -s -- --system
328
+ ```
329
+
330
+ **System-wide cleanup**: When cleanup commands are run as root, mkv2cast automatically cleans temp files and logs for all users:
331
+
332
+ ```bash
333
+ # Clean temp files for all users (as root)
334
+ sudo mkv2cast --clean-tmp
335
+
336
+ # Clean logs for all users (as root)
337
+ sudo mkv2cast --clean-logs 30
338
+ ```
339
+
340
+ A system-wide systemd timer is also available for automated cleanup.
341
+
342
+ ### Installation Options
343
+
344
+ | Option | Description |
345
+ |--------|-------------|
346
+ | `--user` | Install for current user only (default) |
347
+ | `--system` | Install system-wide (requires sudo) |
348
+ | `--update` | Update existing installation |
349
+ | `--uninstall` | Remove mkv2cast |
350
+ | `--with-systemd` | Install cleanup timer |
351
+ | `--no-modify-rc` | Don't modify shell config files |
352
+
353
+ ### Alternative: Manual Clone
354
+
355
+ If you prefer to clone the repository:
356
+
357
+ ```bash
358
+ git clone https://github.com/voldardard/mkv2cast.git
359
+ cd mkv2cast
360
+ ./install.sh
361
+ ```
362
+
363
+ ### Verify Installation
364
+
365
+ ```bash
366
+ mkv2cast --version
367
+ mkv2cast --check-requirements
368
+ man mkv2cast
369
+ ```
370
+
371
+ ### Uninstallation
372
+
373
+ ```bash
374
+ # Quick uninstall
375
+ mkv2cast-uninstall
376
+
377
+ # Or via curl
378
+ curl -fsSL https://raw.githubusercontent.com/voldardard/mkv2cast/main/install.sh | bash -s -- --uninstall
379
+ ```
380
+
381
+ ### Installation Paths
382
+
383
+ | Mode | Script | Man Page | Completions | Config |
384
+ |------|--------|----------|-------------|--------|
385
+ | **User** | `~/.local/bin` | `~/.local/share/man/man1` | `~/.local/share/bash-completion` | `~/.config/mkv2cast` |
386
+ | **System** | `/usr/local/bin` | `/usr/local/share/man/man1` | `/etc/bash_completion.d` | `/etc/mkv2cast` |
387
+
388
+ ---
389
+
390
+ ## Configuration
391
+
392
+ ### Configuration Files
393
+
394
+ mkv2cast uses a layered configuration system:
395
+
396
+ 1. **System config** (optional): `/etc/mkv2cast/config.toml`
397
+ - Applied to all users
398
+ - Created only with `--system` installation
399
+
400
+ 2. **User config**: `~/.config/mkv2cast/config.toml`
401
+ - Per-user settings
402
+ - Overrides system config
403
+ - Created automatically on first run
404
+
405
+ > **Priority**: User config values always override system config values.
406
+
407
+ ### Example config.toml
408
+
409
+ ```toml
410
+ [output]
411
+ suffix = ".cast"
412
+ container = "mkv"
413
+
414
+ [scan]
415
+ recursive = true
416
+ ignore_patterns = ["*sample*", "*.eng.*"]
417
+ ignore_paths = []
418
+ include_patterns = []
419
+ include_paths = []
420
+
421
+ [encoding]
422
+ backend = "auto" # auto, vaapi, qsv, cpu
423
+ crf = 20
424
+ preset = "slow"
425
+ abr = "192k"
426
+
427
+ [workers]
428
+ encode = 0 # 0 = auto-detect
429
+ integrity = 0 # 0 = auto-detect
430
+
431
+ [integrity]
432
+ enabled = true
433
+ stable_wait = 3
434
+ deep_check = false
435
+ ```
436
+
437
+ ### Directory Structure
438
+
439
+ mkv2cast follows the [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html):
440
+
441
+ **User directories:**
442
+
443
+ | Directory | Purpose | Default Path |
444
+ |-----------|---------|--------------|
445
+ | Config | User configuration | `~/.config/mkv2cast/` |
446
+ | State | History, logs | `~/.local/state/mkv2cast/` |
447
+ | Cache | Temporary files | `~/.cache/mkv2cast/` |
448
+
449
+ **System directories** (only for system-wide installation):
450
+
451
+ | Directory | Purpose | Default Path |
452
+ |-----------|---------|--------------|
453
+ | Config | System-wide defaults | `/etc/mkv2cast/` |
454
+
455
+ View all directories:
456
+
457
+ ```bash
458
+ mkv2cast --show-dirs
459
+ ```
460
+
461
+ ---
462
+
463
+ ## Usage
464
+
465
+ ### Basic Usage
466
+
467
+ ```bash
468
+ # Process all MKV files in current directory (recursive)
469
+ mkv2cast
470
+
471
+ # Process a single file
472
+ mkv2cast movie.mkv
473
+
474
+ # Process with debug output
475
+ mkv2cast --debug movie.mkv
476
+
477
+ # Dry run (show what would be done)
478
+ mkv2cast --dryrun
479
+ ```
480
+
481
+ ### Output File Naming
482
+
483
+ Output files are named based on transformations applied:
484
+
485
+ | Input | Output | Meaning |
486
+ |-------|--------|---------|
487
+ | `movie.mkv` | `movie.h264.cast.mkv` | Video transcoded to H.264 |
488
+ | `movie.mkv` | `movie.aac.cast.mkv` | Audio transcoded to AAC |
489
+ | `movie.mkv` | `movie.h264.aac.cast.mkv` | Both transcoded |
490
+ | `movie.mkv` | `movie.remux.cast.mkv` | Container changed only |
491
+
492
+ ### Common Workflows
493
+
494
+ #### Convert entire movie collection
495
+
496
+ ```bash
497
+ cd /path/to/movies
498
+ mkv2cast
499
+ ```
500
+
501
+ #### Convert only French movies from 2024
502
+
503
+ ```bash
504
+ mkv2cast -i '*French*' -i '*2024*'
505
+ ```
506
+
507
+ #### Fast encoding (lower quality)
508
+
509
+ ```bash
510
+ mkv2cast --hw cpu --preset fast --crf 23
511
+ ```
512
+
513
+ #### High quality with hardware acceleration
514
+
515
+ ```bash
516
+ mkv2cast --hw vaapi --vaapi-qp 20
517
+ ```
518
+
519
+ #### Process without recursive scan
520
+
521
+ ```bash
522
+ mkv2cast --no-recursive
523
+ ```
524
+
525
+ ---
526
+
527
+ ## Using mkv2cast as a Python Package
528
+
529
+ mkv2cast can be imported and used as a Python library in your scripts, allowing you to programmatically convert video files with full control over the conversion process.
530
+
531
+ ### Installation
532
+
533
+ First, ensure mkv2cast is installed:
534
+
535
+ ```bash
536
+ pip install mkv2cast
537
+ ```
538
+
539
+ ### Basic Usage
540
+
541
+ The simplest way to use mkv2cast programmatically is with the `convert_file` function:
542
+
543
+ ```python
544
+ from mkv2cast import convert_file
545
+ from pathlib import Path
546
+
547
+ # Convert a single file
548
+ success, output_path, message = convert_file(Path("movie.mkv"))
549
+
550
+ if success:
551
+ if output_path:
552
+ print(f"Converted to: {output_path}")
553
+ else:
554
+ print(f"Skipped: {message}")
555
+ else:
556
+ print(f"Failed: {message}")
557
+ ```
558
+
559
+ ### Configuration
560
+
561
+ Create a custom configuration to control encoding settings:
562
+
563
+ ```python
564
+ from mkv2cast import Config, convert_file
565
+ from pathlib import Path
566
+
567
+ # Create custom configuration
568
+ config = Config(
569
+ hw="vaapi", # Use VAAPI hardware acceleration
570
+ crf=20, # Quality setting (lower = better quality)
571
+ preset="slow", # Encoding preset
572
+ container="mp4", # Output container format
573
+ suffix=".cast", # Output file suffix
574
+ notify=False # Disable notifications in scripts
575
+ )
576
+
577
+ # Convert with custom config
578
+ success, output_path, message = convert_file(
579
+ Path("movie.mkv"),
580
+ cfg=config
581
+ )
582
+ ```
583
+
584
+ ### JSON Progress Output
585
+
586
+ For integration with web UIs or monitoring tools, use `--json-progress`:
587
+
588
+ ```bash
589
+ mkv2cast --json-progress movie.mkv
590
+ ```
591
+
592
+ This outputs JSON events to stdout:
593
+
594
+ ```json
595
+ {"version":"1.0","event":"start","overall":{"total_files":1,"backend":"vaapi"}}
596
+ {"version":"1.0","event":"file_start","file":"movie.mkv"}
597
+ {"version":"1.0","event":"progress","files":{"movie.mkv":{"progress_percent":45.2,"fps":120.5,"eta_seconds":30}}}
598
+ {"version":"1.0","event":"file_done","file":"movie.mkv","status":"done"}
599
+ {"version":"1.0","event":"complete"}
600
+ ```
601
+
602
+ ### Using JSON Progress in Python
603
+
604
+ ```python
605
+ import json
606
+ import subprocess
607
+ from typing import Generator, Dict, Any
608
+
609
+ def stream_progress(filepath: str) -> Generator[Dict[str, Any], None, None]:
610
+ """Stream JSON progress events from mkv2cast."""
611
+ proc = subprocess.Popen(
612
+ ["mkv2cast", "--json-progress", filepath],
613
+ stdout=subprocess.PIPE,
614
+ text=True
615
+ )
616
+ for line in proc.stdout:
617
+ yield json.loads(line)
618
+
619
+ # Example: Display progress
620
+ for event in stream_progress("movie.mkv"):
621
+ if event["event"] == "progress":
622
+ for filename, data in event.get("files", {}).items():
623
+ print(f"{filename}: {data['progress_percent']:.1f}%")
624
+ ```
625
+
626
+ ### Advanced: Progress Callbacks
627
+
628
+ Instead of parsing JSON output, use progress callbacks directly in your Python code:
629
+
630
+ ```python
631
+ from mkv2cast import convert_file, Config
632
+ from pathlib import Path
633
+
634
+ def on_progress(filepath: Path, progress: dict):
635
+ """Called during conversion with progress updates."""
636
+ stage = progress.get("stage", "unknown")
637
+ percent = progress.get("progress_percent", 0)
638
+ fps = progress.get("fps", 0)
639
+ eta = progress.get("eta_seconds", 0)
640
+
641
+ print(f"{filepath.name}: {stage} - {percent:.1f}% @ {fps:.1f}fps, ETA: {eta:.0f}s")
642
+
643
+ config = Config.for_library(hw="auto") # Auto-disables UI for library usage
644
+
645
+ success, output, msg = convert_file(
646
+ Path("movie.mkv"),
647
+ cfg=config,
648
+ progress_callback=on_progress
649
+ )
650
+ ```
651
+
652
+ **Progress callback receives:**
653
+
654
+ | Field | Type | Description |
655
+ |-------|------|-------------|
656
+ | `stage` | str | "checking", "encoding", "done", "skipped", "failed" |
657
+ | `progress_percent` | float | Progress percentage (0-100) |
658
+ | `fps` | float | Current encoding FPS |
659
+ | `eta_seconds` | float | Estimated time remaining |
660
+ | `bitrate` | str | Current bitrate (e.g., "2500kbits/s") |
661
+ | `speed` | str | Encoding speed (e.g., "2.5x") |
662
+ | `current_time_ms` | int | Current position in milliseconds |
663
+ | `duration_ms` | int | Total duration in milliseconds |
664
+ | `error` | str/None | Error message if stage is "failed" |
665
+
666
+ ### Batch Processing with Multi-threading
667
+
668
+ Process multiple files in parallel using `convert_batch()`:
669
+
670
+ ```python
671
+ from mkv2cast import convert_batch, Config
672
+ from pathlib import Path
673
+
674
+ config = Config.for_library(
675
+ hw="vaapi",
676
+ encode_workers=2, # 2 parallel encoders
677
+ )
678
+
679
+ def on_progress(filepath: Path, progress: dict):
680
+ """Thread-safe callback for progress updates."""
681
+ percent = progress.get("progress_percent", 0)
682
+ stage = progress.get("stage", "")
683
+ print(f"{filepath.name}: {stage} {percent:.1f}%")
684
+
685
+ files = [Path("movie1.mkv"), Path("movie2.mkv"), Path("movie3.mkv")]
686
+
687
+ results = convert_batch(
688
+ files,
689
+ cfg=config,
690
+ progress_callback=on_progress
691
+ )
692
+
693
+ # Check results
694
+ for filepath, (success, output, msg) in results.items():
695
+ if success:
696
+ print(f"OK {filepath.name}: {msg}")
697
+ else:
698
+ print(f"FAIL {filepath.name}: {msg}")
699
+ ```
700
+
701
+ ### Script Mode (No Colors/Output)
702
+
703
+ When used as a library, mkv2cast can automatically disable:
704
+
705
+ - Progress bars
706
+ - Colored output
707
+ - Desktop notifications
708
+ - Rich UI
709
+
710
+ **Automatic detection** happens when:
711
+
712
+ - `sys.stdout` is not a TTY (piped or redirected)
713
+ - `NO_COLOR` environment variable is set
714
+ - `MKV2CAST_SCRIPT_MODE=1` is set
715
+
716
+ **Recommended for library usage:**
717
+
718
+ ```python
719
+ # Use Config.for_library() which auto-disables UI features
720
+ config = Config.for_library(hw="vaapi", crf=20)
721
+
722
+ # Or manually disable
723
+ config = Config(
724
+ progress=False, # No progress bars
725
+ notify=False, # No notifications
726
+ pipeline=False, # No Rich UI
727
+ )
728
+ ```
729
+
730
+ ### Analyzing Files
731
+
732
+ Before converting, you can analyze a file to see what transcoding is needed:
733
+
734
+ ```python
735
+ from mkv2cast import decide_for, pick_backend
736
+ from pathlib import Path
737
+
738
+ # Analyze a file
739
+ decision = decide_for(Path("movie.mkv"))
740
+
741
+ print(f"Video codec: {decision.vcodec}")
742
+ print(f"Audio codec: {decision.acodec}")
743
+ print(f"Needs video transcode: {decision.need_v}")
744
+ print(f"Needs audio transcode: {decision.need_a}")
745
+ print(f"Reason: {decision.reason_v}")
746
+
747
+ # Check available backend
748
+ backend = pick_backend()
749
+ print(f"Best backend: {backend}")
750
+ ```
751
+
752
+ ### Batch Processing (Sequential)
753
+
754
+ Process multiple files sequentially with custom logic:
755
+
756
+ ```python
757
+ from pathlib import Path
758
+ from mkv2cast import convert_file, Config
759
+
760
+ config = Config.for_library(hw="auto", container="mkv")
761
+
762
+ input_dir = Path("/media/videos")
763
+ output_dir = Path("/media/converted")
764
+
765
+ for mkv_file in input_dir.glob("**/*.mkv"):
766
+ success, output, msg = convert_file(
767
+ mkv_file,
768
+ cfg=config,
769
+ output_dir=output_dir
770
+ )
771
+
772
+ if success and output:
773
+ print(f"OK {mkv_file.name} -> {output.name}")
774
+ elif not success:
775
+ print(f"FAIL {mkv_file.name}: {msg}")
776
+ else:
777
+ print(f"SKIP {mkv_file.name}: {msg}")
778
+ ```
779
+
780
+ For parallel batch processing, see [Batch Processing with Multi-threading](#batch-processing-with-multi-threading) above.
781
+
782
+ ### Advanced: Building Custom Commands
783
+
784
+ For more control, you can build FFmpeg commands manually:
785
+
786
+ ```python
787
+ from mkv2cast import decide_for, pick_backend, build_transcode_cmd, Config
788
+ from pathlib import Path
789
+ import subprocess
790
+
791
+ input_file = Path("movie.mkv")
792
+ output_file = Path("movie.h264.cast.mkv")
793
+ config = Config()
794
+
795
+ # Analyze file
796
+ decision = decide_for(input_file, config)
797
+
798
+ # Select backend
799
+ backend = pick_backend(config)
800
+
801
+ # Build command
802
+ cmd, stage = build_transcode_cmd(
803
+ input_file,
804
+ decision,
805
+ backend,
806
+ output_file,
807
+ log_path=None, # Optional: Path to log file
808
+ cfg=config
809
+ )
810
+
811
+ # Run manually
812
+ result = subprocess.run(cmd)
813
+ ```
814
+
815
+ ### Working with History
816
+
817
+ Access conversion history programmatically:
818
+
819
+ ```python
820
+ from mkv2cast import HistoryDB, get_app_dirs
821
+
822
+ # Get history database
823
+ dirs = get_app_dirs()
824
+ history = HistoryDB(dirs["state"])
825
+
826
+ # Get recent conversions
827
+ recent = history.get_recent(20)
828
+ for entry in recent:
829
+ print(f"{entry['status']}: {entry['input_path']}")
830
+
831
+ # Get statistics
832
+ stats = history.get_stats()
833
+ print(f"Total conversions: {sum(stats['by_status'].values())}")
834
+ ```
835
+
836
+ ### Loading Configuration Files
837
+
838
+ Load settings from configuration files:
839
+
840
+ ```python
841
+ from mkv2cast import load_config_file, get_app_dirs, Config
842
+
843
+ # Get config directory
844
+ dirs = get_app_dirs()
845
+
846
+ # Load config file (TOML or INI)
847
+ file_config = load_config_file(dirs["config"])
848
+
849
+ # Create config and manually apply settings from file
850
+ config = Config()
851
+ if "encoding" in file_config:
852
+ if "backend" in file_config["encoding"]:
853
+ config.hw = file_config["encoding"]["backend"]
854
+ if "crf" in file_config["encoding"]:
855
+ config.crf = file_config["encoding"]["crf"]
856
+ # ... apply other settings as needed
857
+ ```
858
+
859
+ ### Available Functions and Classes
860
+
861
+ Main exports from `mkv2cast`:
862
+
863
+ | Function/Class | Description |
864
+ |----------------|-------------|
865
+ | **`convert_file()`** | Convert a single file with optional progress callback |
866
+ | **`convert_batch()`** | Convert multiple files in parallel with multi-threading |
867
+ | **`decide_for()`** | Analyze what transcoding is needed for a file |
868
+ | **`pick_backend()`** | Auto-detect best encoding backend |
869
+ | **`build_transcode_cmd()`** | Build FFmpeg command manually |
870
+ | **`Config`** | Configuration dataclass with `for_library()` factory |
871
+ | **`Config.for_library()`** | Create config optimized for library usage |
872
+ | **`Decision`** | Analysis result dataclass |
873
+ | **`HistoryDB`** | Conversion history database |
874
+ | **`get_app_dirs()`** | Get XDG directories |
875
+ | **`load_config_file()`** | Load config from file |
876
+ | **`is_script_mode()`** | Check if running in script/library mode |
877
+ | **`send_notification()`** | Send desktop notification |
878
+ | **`setup_i18n()`** | Setup internationalization |
879
+
880
+ For detailed API documentation, see the [API Reference](https://voldardard.github.io/mkv2cast/api/index.html).
881
+
882
+ ---
883
+
884
+ ## Options Reference
885
+
886
+ ### General Options
887
+
888
+ | Option | Description |
889
+ |--------|-------------|
890
+ | `-h, --help` | Show help message |
891
+ | `-V, --version` | Show version information |
892
+ | `--check-requirements` | Check system requirements |
893
+
894
+ ### Output Settings
895
+
896
+ | Option | Default | Description |
897
+ |--------|---------|-------------|
898
+ | `--suffix SUFFIX` | `.cast` | Output file suffix |
899
+ | `--container FORMAT` | `mkv` | Output format: `mkv` or `mp4` |
900
+
901
+ ### Scan Settings
902
+
903
+ | Option | Default | Description |
904
+ |--------|---------|-------------|
905
+ | `-r, --recursive` | enabled | Scan directories recursively |
906
+ | `--no-recursive` | - | Disable recursive scanning |
907
+ | `-I, --ignore-pattern PATTERN` | - | Ignore files matching glob pattern |
908
+ | `--ignore-path PATH` | - | Ignore specific paths/folders |
909
+ | `-i, --include-pattern PATTERN` | - | Only process matching files |
910
+ | `--include-path PATH` | - | Only process files in path |
911
+
912
+ ### Codec Decisions
913
+
914
+ | Option | Default | Description |
915
+ |--------|---------|-------------|
916
+ | `--skip-when-ok` | enabled | Skip compatible files |
917
+ | `--no-skip-when-ok` | - | Process all files |
918
+ | `--force-h264` | disabled | Force H.264 transcoding |
919
+ | `--allow-hevc` | disabled | Allow HEVC passthrough |
920
+ | `--force-aac` | disabled | Force AAC transcoding |
921
+ | `--keep-surround` | disabled | Keep surround audio |
922
+ | `--no-silence` | - | Don't add silence track |
923
+
924
+ ### Encoding Quality
925
+
926
+ | Option | Default | Description |
927
+ |--------|---------|-------------|
928
+ | `--abr BITRATE` | `192k` | Audio bitrate |
929
+ | `--crf VALUE` | `20` | CRF for CPU encoding (18-28) |
930
+ | `--preset PRESET` | `slow` | x264 preset |
931
+
932
+ ### Profiles
933
+
934
+ | Option | Default | Description |
935
+ |--------|---------|-------------|
936
+ | `--profile {fast,balanced,quality}` | - | Apply encoding profile (sets CRF, preset, and hardware quality defaults) |
937
+
938
+ ### Hardware Acceleration
939
+
940
+ | Option | Default | Description |
941
+ |--------|---------|-------------|
942
+ | `--hw BACKEND` | `auto` | Backend: `auto`, `nvenc`, `amf`, `qsv`, `vaapi`, `cpu` |
943
+ | `--vaapi-device PATH` | `/dev/dri/renderD128` | VAAPI device |
944
+ | `--vaapi-qp VALUE` | `23` | VAAPI quality |
945
+ | `--qsv-quality VALUE` | `23` | QSV quality |
946
+ | `--nvenc-cq VALUE` | `23` | NVENC constant quality (0-51) |
947
+ | `--amf-quality VALUE` | `23` | AMD AMF quality (0-51) |
948
+
949
+ ### Preservation
950
+
951
+ | Option | Default | Description |
952
+ |--------|---------|-------------|
953
+ | `--no-metadata` | enabled | Disable metadata preservation |
954
+ | `--no-chapters` | enabled | Disable chapter preservation |
955
+ | `--no-attachments` | enabled | Disable MKV attachments preservation |
956
+
957
+ ### Integrity Checks
958
+
959
+ | Option | Default | Description |
960
+ |--------|---------|-------------|
961
+ | `--integrity-check` | enabled | Enable integrity check |
962
+ | `--no-integrity-check` | - | Disable integrity check |
963
+ | `--stable-wait SECONDS` | `3` | Wait for file stability |
964
+ | `--deep-check` | disabled | Deep decode verification |
965
+
966
+ ### Disk Guards & Quotas
967
+
968
+ | Option | Default | Description |
969
+ |--------|---------|-------------|
970
+ | `--min-free-mb MB` | `1024` | Minimum free space to keep in output filesystem |
971
+ | `--min-free-tmp-mb MB` | `512` | Minimum free space to keep in temp filesystem |
972
+ | `--max-output-mb MB` | `0` | Max output size per file (0 = disabled) |
973
+ | `--max-output-ratio RATIO` | `0.0` | Max output size ratio vs input (0 = disabled) |
974
+
975
+ ### Parallelism
976
+
977
+ | Option | Default | Description |
978
+ |--------|---------|-------------|
979
+ | `--pipeline` | enabled | Parallel processing |
980
+ | `--no-pipeline` | - | Sequential mode |
981
+ | `--encode-workers N` | `0` (auto) | Parallel encoding workers |
982
+ | `--integrity-workers N` | `0` (auto) | Parallel integrity workers |
983
+
984
+ ### Reliability
985
+
986
+ | Option | Default | Description |
987
+ |--------|---------|-------------|
988
+ | `--retry-attempts N` | `1` | Number of retries after failure (0 = disabled) |
989
+ | `--retry-delay SECONDS` | `2.0` | Delay between retries |
990
+ | `--no-retry-fallback-cpu` | enabled | Disable CPU fallback on last retry |
991
+
992
+ ### JSON Progress Output
993
+
994
+ | Option | Default | Description |
995
+ |--------|---------|-------------|
996
+ | `--json-progress` | disabled | Output structured JSON progress |
997
+
998
+ ### Utility Commands
999
+
1000
+ | Option | Description |
1001
+ |--------|-------------|
1002
+ | `--show-dirs` | Show XDG directory paths |
1003
+ | `--history [N]` | Show recent conversions (default: 20, max: 1000) |
1004
+ | `--history-stats` | Show conversion statistics |
1005
+ | `--clean-tmp` | Remove orphaned temp files (all users if root) |
1006
+ | `--clean-logs DAYS` | Remove old log files (all users if root) |
1007
+ | `--clean-history DAYS` | Remove old history entries |
1008
+
1009
+ ---
1010
+
1011
+ ## Examples
1012
+
1013
+ ### Filtering Examples
1014
+
1015
+ ```bash
1016
+ # Ignore sample files and English tracks
1017
+ mkv2cast -I '*sample*' -I '*.eng.*'
1018
+
1019
+ # Process only French content
1020
+ mkv2cast -i '*French*' -i '*VFF*' -i '*FRENCH*'
1021
+
1022
+ # Ignore specific folders
1023
+ mkv2cast --ignore-path Downloads/temp --ignore-path "To Sort"
1024
+
1025
+ # Process only specific folder
1026
+ mkv2cast --include-path Movies/2024
1027
+ ```
1028
+
1029
+ ### Encoding Examples
1030
+
1031
+ ```bash
1032
+ # Use CPU with fast preset (quick, lower quality)
1033
+ mkv2cast --hw cpu --preset fast --crf 23
1034
+
1035
+ # Use VAAPI with high quality
1036
+ mkv2cast --hw vaapi --vaapi-qp 18
1037
+
1038
+ # Keep surround sound
1039
+ mkv2cast --keep-surround --abr 256k
1040
+
1041
+ # Output to MP4 instead of MKV
1042
+ mkv2cast --container mp4
1043
+ ```
1044
+
1045
+ ### Parallel Processing Examples
1046
+
1047
+ ```bash
1048
+ # Use 3 parallel encoders
1049
+ mkv2cast --encode-workers 3
1050
+
1051
+ # Disable parallel processing
1052
+ mkv2cast --no-pipeline
1053
+
1054
+ # Custom worker configuration
1055
+ mkv2cast --encode-workers 2 --integrity-workers 4
1056
+ ```
1057
+
1058
+ ### Maintenance Examples
1059
+
1060
+ ```bash
1061
+ # View conversion history (default: 20 lines)
1062
+ mkv2cast --history
1063
+
1064
+ # View more history (50 or 100 lines)
1065
+ mkv2cast --history 50
1066
+ mkv2cast --history 100
1067
+
1068
+ # View statistics
1069
+ mkv2cast --history-stats
1070
+
1071
+ # Clean temporary files
1072
+ mkv2cast --clean-tmp
1073
+
1074
+ # Clean logs older than 30 days
1075
+ mkv2cast --clean-logs 30
1076
+
1077
+ # Clean history older than 90 days
1078
+ mkv2cast --clean-history 90
1079
+ ```
1080
+
1081
+ ---
1082
+
1083
+ ## Maintenance
1084
+
1085
+ ### Automatic Cleanup with systemd
1086
+
1087
+ Install the systemd timer for weekly automatic cleanup:
1088
+
1089
+ ```bash
1090
+ ./install.sh --with-systemd
1091
+ ```
1092
+
1093
+ Or manually:
1094
+
1095
+ ```bash
1096
+ # Copy service files
1097
+ cp systemd/mkv2cast-cleanup.* ~/.config/systemd/user/
1098
+
1099
+ # Enable timer
1100
+ systemctl --user enable --now mkv2cast-cleanup.timer
1101
+
1102
+ # Check status
1103
+ systemctl --user status mkv2cast-cleanup.timer
1104
+ ```
1105
+
1106
+ ### Automatic Cleanup with cron
1107
+
1108
+ Add to your crontab (`crontab -e`):
1109
+
1110
+ ```cron
1111
+ # Weekly cleanup on Sunday at 3 AM
1112
+ 0 3 * * 0 mkv2cast --clean-tmp && mkv2cast --clean-logs 30
1113
+ ```
1114
+
1115
+ ### Manual Cleanup
1116
+
1117
+ ```bash
1118
+ # Clean orphaned temp files
1119
+ mkv2cast --clean-tmp
1120
+
1121
+ # Clean logs older than 30 days
1122
+ mkv2cast --clean-logs 30
1123
+
1124
+ # Clean history older than 90 days
1125
+ mkv2cast --clean-history 90
1126
+ ```
1127
+
1128
+ ---
1129
+
1130
+ ## Points de Vigilance
1131
+
1132
+ ### Important Notes
1133
+
1134
+ 1. **Recursive Scanning is Default**
1135
+ - mkv2cast scans subdirectories by default
1136
+ - Use `--no-recursive` to process only the current directory
1137
+ - Be careful when running in large directory trees!
1138
+
1139
+ 2. **Original Files are Preserved**
1140
+ - mkv2cast creates new output files, it does NOT modify originals
1141
+ - Output files have a distinct suffix (`.cast.mkv` by default)
1142
+
1143
+ 3. **Temporary Files**
1144
+ - During encoding, temp files are created in `~/.cache/mkv2cast/tmp/`
1145
+ - They are automatically cleaned on successful completion
1146
+ - Use `--clean-tmp` to remove orphaned temp files after interruption
1147
+
1148
+ 4. **French Audio Preference**
1149
+ - By default, mkv2cast selects French audio tracks when available
1150
+ - Falls back to the first audio track if no French track found
1151
+
1152
+ 5. **HEVC/H.265 Transcoding**
1153
+ - By default, HEVC content is transcoded to H.264
1154
+ - Use `--allow-hevc` if your device supports HEVC
1155
+
1156
+ 6. **Disk Space**
1157
+ - Ensure sufficient disk space for output files
1158
+ - Temporary files can also consume significant space during encoding
1159
+
1160
+ ---
1161
+
1162
+ ## Troubleshooting
1163
+
1164
+ ### Common Issues
1165
+
1166
+ #### "ffmpeg not found"
1167
+
1168
+ ```bash
1169
+ # Arch Linux
1170
+ sudo pacman -S ffmpeg
1171
+
1172
+ # Debian/Ubuntu
1173
+ sudo apt install ffmpeg
1174
+
1175
+ # Fedora
1176
+ sudo dnf install ffmpeg
1177
+ ```
1178
+
1179
+ #### "VAAPI encoding failed"
1180
+
1181
+ ```bash
1182
+ # Check VAAPI device exists
1183
+ ls -la /dev/dri/
1184
+
1185
+ # Install Intel drivers (for Intel GPUs)
1186
+ sudo pacman -S intel-media-driver # Arch
1187
+ sudo apt install intel-media-va-driver # Debian
1188
+
1189
+ # Test with mkv2cast
1190
+ mkv2cast --check-requirements
1191
+ ```
1192
+
1193
+ #### "No progress display"
1194
+
1195
+ Install the `rich` Python package:
1196
+
1197
+ ```bash
1198
+ # Arch Linux
1199
+ sudo pacman -S python-rich
1200
+
1201
+ # Other distributions
1202
+ pip install --user rich
1203
+ ```
1204
+
1205
+ #### "Permission denied" errors
1206
+
1207
+ Ensure the script is executable and in your PATH:
1208
+
1209
+ ```bash
1210
+ chmod +x ~/.local/bin/mkv2cast
1211
+ echo $PATH | grep -q ".local/bin" || echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
1212
+ ```
1213
+
1214
+ #### "TOML config not loading"
1215
+
1216
+ For Python < 3.11, install tomli:
1217
+
1218
+ ```bash
1219
+ # Arch Linux
1220
+ sudo pacman -S python-tomli
1221
+
1222
+ # Other distributions
1223
+ pip install --user tomli
1224
+ ```
1225
+
1226
+ ### Getting Help
1227
+
1228
+ ```bash
1229
+ # Check requirements
1230
+ mkv2cast --check-requirements
1231
+
1232
+ # View debug output
1233
+ mkv2cast --debug movie.mkv
1234
+
1235
+ # Dry run to see commands
1236
+ mkv2cast --dryrun movie.mkv
1237
+
1238
+ # Check logs
1239
+ ls ~/.local/state/mkv2cast/logs/
1240
+ ```
1241
+
1242
+ ---
1243
+
1244
+ ## Contributing
1245
+
1246
+ Contributions are welcome! Here's how to get started:
1247
+
1248
+ ### Development Setup
1249
+
1250
+ ```bash
1251
+ # Clone the repository
1252
+ git clone https://github.com/voldardard/mkv2cast.git
1253
+ cd mkv2cast
1254
+
1255
+ # Install development dependencies
1256
+ # Arch Linux:
1257
+ sudo pacman -S python-rich python-tomli
1258
+ # Other distributions:
1259
+ pip install --user rich tomli
1260
+
1261
+ # Run tests
1262
+ python mkv2cast.py --check-requirements
1263
+ ```
1264
+
1265
+ ### Submitting Changes
1266
+
1267
+ 1. Fork the repository
1268
+ 2. Create a feature branch: `git checkout -b feature/my-feature`
1269
+ 3. Make your changes
1270
+ 4. Test thoroughly
1271
+ 5. Commit with descriptive message: `git commit -m "Add feature X"`
1272
+ 6. Push to your fork: `git push origin feature/my-feature`
1273
+ 7. Open a Pull Request
1274
+
1275
+ ### Code Style
1276
+
1277
+ - Follow PEP 8 for Python code
1278
+ - Add docstrings to new functions
1279
+ - Update documentation for new features
1280
+ - Test on both CPU and hardware-accelerated backends if possible
1281
+
1282
+ ---
1283
+
1284
+ ## Bug Reports
1285
+
1286
+ Found a bug? Please report it!
1287
+
1288
+ ### How to Report
1289
+
1290
+ 1. Go to [GitHub Issues](https://github.com/voldardard/mkv2cast/issues)
1291
+ 2. Click "New Issue"
1292
+ 3. Include:
1293
+ - Your operating system and version
1294
+ - Python version (`python3 --version`)
1295
+ - FFmpeg version (`ffmpeg -version`)
1296
+ - mkv2cast version (`mkv2cast --version`)
1297
+ - Output of `mkv2cast --check-requirements`
1298
+ - Steps to reproduce the bug
1299
+ - Error messages or log files (from `~/.local/state/mkv2cast/logs/`)
1300
+
1301
+ ### Example Bug Report
1302
+
1303
+ ```
1304
+ ### Environment
1305
+ - OS: Arch Linux 2026.01
1306
+ - Python: 3.12.1
1307
+ - FFmpeg: 7.0
1308
+ - mkv2cast: 1.0.0
1309
+
1310
+ ### Description
1311
+ Encoding fails with VAAPI on AMD GPU...
1312
+
1313
+ ### Steps to Reproduce
1314
+ 1. Run `mkv2cast --hw vaapi movie.mkv`
1315
+ 2. Error occurs at 15%
1316
+
1317
+ ### Error Output
1318
+ [paste error here]
1319
+ ```
1320
+
1321
+ ---
1322
+
1323
+ ## Web Interface
1324
+
1325
+ Looking for a web-based interface? Check out **[mkv2castUI](https://github.com/voldardard/mkv2castUI)** - a full-featured web application for mkv2cast with:
1326
+
1327
+ - 🌐 **Web Upload**: Drag and drop MKV files for conversion
1328
+ - 📊 **Real-time Progress**: WebSocket-based progress tracking
1329
+ - 🔐 **OAuth Authentication**: Sign in with Google or GitHub
1330
+ - 💳 **Subscription Tiers**: Free, Pro, and Enterprise plans
1331
+ - 🐳 **Docker Ready**: Easy deployment with Docker Compose
1332
+
1333
+ ```bash
1334
+ git clone https://github.com/voldardard/mkv2castUI.git
1335
+ cd mkv2castUI
1336
+ docker-compose up -d
1337
+ ```
1338
+
1339
+ ---
1340
+
1341
+ ## Roadmap
1342
+
1343
+ | Feature | Priority | Complexity | Status |
1344
+ |---------|----------|------------|--------|
1345
+ | Profiles (fast/balanced/quality) | Medium | Low | ✅ Done |
1346
+ | Disk guards & quotas | High | Low | ✅ Done |
1347
+ | Metadata/chapters/attachments preservation | Medium | Medium | ✅ Done |
1348
+ | Pipeline auto-retry + CPU fallback | Medium | Medium | ✅ Done |
1349
+ | HDR to SDR tone mapping | Low | High | Planned |
1350
+ | Webhooks notifications | Low | Low | Planned |
1351
+ | Audio loudness normalization (EBU R128) | Medium | Medium | Planned |
1352
+ | Subtitle extraction + forced-burn options | Medium | Medium | Planned |
1353
+ | Integration Plex/Jellyfin | Low | High | Planned |
1354
+ | Automatic device capability detection (Chromecast/TV) | Medium | Medium | Idea |
1355
+ | Metrics export (Prometheus/StatsD) from history and live runs | Low | Medium | Idea |
1356
+ | Remote/agent workers for headless servers | Low | High | Idea |
1357
+ | Package signing (APT GPG + checksums) | Medium | Low | Idea |
1358
+
1359
+ ### Recent Additions (v1.2.x)
1360
+
1361
+ - ✅ NVIDIA NVENC & AMD AMF hardware acceleration (auto-priority)
1362
+ - ✅ Audio & subtitle selection by language or track index
1363
+ - ✅ Watch mode (watchdog/inotify) with systemd unit and timer
1364
+ - ✅ JSON progress output + Python callbacks for integrations
1365
+ - ✅ Library-friendly config factory (`Config.for_library`) and batch API
1366
+ - ✅ Multi-language CLI (EN, FR, ES, IT, DE) and desktop notifications
1367
+
1368
+ Have a feature request? [Open an issue](https://github.com/voldardard/mkv2cast/issues)!
1369
+
1370
+ ---
1371
+
1372
+ ## Acknowledgments
1373
+
1374
+ *This section will be updated as the project grows.*
1375
+
1376
+ Thanks to:
1377
+ - The FFmpeg team for their incredible media processing tools
1378
+ - The `rich` library for beautiful terminal interfaces
1379
+ - All contributors and users who report bugs and suggest improvements
1380
+
1381
+ ---
1382
+
1383
+ ## License
1384
+
1385
+ This project is licensed under the **GNU General Public License v3.0**.
1386
+
1387
+ ```
1388
+ mkv2cast - Smart MKV to Chromecast-compatible converter
1389
+ Copyright (C) 2024-2026 voldardard
1390
+
1391
+ This program is free software: you can redistribute it and/or modify
1392
+ it under the terms of the GNU General Public License as published by
1393
+ the Free Software Foundation, either version 3 of the License, or
1394
+ (at your option) any later version.
1395
+
1396
+ This program is distributed in the hope that it will be useful,
1397
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1398
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1399
+ GNU General Public License for more details.
1400
+
1401
+ You should have received a copy of the GNU General Public License
1402
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
1403
+ ```
1404
+
1405
+ See the [LICENSE](LICENSE) file for the full license text.
1406
+
1407
+ ---
1408
+
1409
+ <p align="center">
1410
+ Made with ❤️ for the media enthusiast community
1411
+ </p>