mkv-episode-matcher 0.3.3__py3-none-any.whl → 1.0.0__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.
Files changed (38) hide show
  1. mkv_episode_matcher/__init__.py +8 -0
  2. mkv_episode_matcher/__main__.py +2 -177
  3. mkv_episode_matcher/asr_models.py +506 -0
  4. mkv_episode_matcher/cli.py +558 -0
  5. mkv_episode_matcher/core/config_manager.py +100 -0
  6. mkv_episode_matcher/core/engine.py +577 -0
  7. mkv_episode_matcher/core/matcher.py +214 -0
  8. mkv_episode_matcher/core/models.py +91 -0
  9. mkv_episode_matcher/core/providers/asr.py +85 -0
  10. mkv_episode_matcher/core/providers/subtitles.py +341 -0
  11. mkv_episode_matcher/core/utils.py +148 -0
  12. mkv_episode_matcher/episode_identification.py +550 -118
  13. mkv_episode_matcher/subtitle_utils.py +82 -0
  14. mkv_episode_matcher/tmdb_client.py +56 -14
  15. mkv_episode_matcher/ui/flet_app.py +708 -0
  16. mkv_episode_matcher/utils.py +262 -139
  17. mkv_episode_matcher-1.0.0.dist-info/METADATA +242 -0
  18. mkv_episode_matcher-1.0.0.dist-info/RECORD +23 -0
  19. {mkv_episode_matcher-0.3.3.dist-info → mkv_episode_matcher-1.0.0.dist-info}/WHEEL +1 -1
  20. mkv_episode_matcher-1.0.0.dist-info/licenses/LICENSE +21 -0
  21. mkv_episode_matcher/config.py +0 -82
  22. mkv_episode_matcher/episode_matcher.py +0 -100
  23. mkv_episode_matcher/libraries/pgs2srt/.gitignore +0 -2
  24. mkv_episode_matcher/libraries/pgs2srt/Libraries/SubZero/SubZero.py +0 -321
  25. mkv_episode_matcher/libraries/pgs2srt/Libraries/SubZero/dictionaries/data.py +0 -16700
  26. mkv_episode_matcher/libraries/pgs2srt/Libraries/SubZero/post_processing.py +0 -260
  27. mkv_episode_matcher/libraries/pgs2srt/README.md +0 -26
  28. mkv_episode_matcher/libraries/pgs2srt/__init__.py +0 -0
  29. mkv_episode_matcher/libraries/pgs2srt/imagemaker.py +0 -89
  30. mkv_episode_matcher/libraries/pgs2srt/pgs2srt.py +0 -150
  31. mkv_episode_matcher/libraries/pgs2srt/pgsreader.py +0 -225
  32. mkv_episode_matcher/libraries/pgs2srt/requirements.txt +0 -4
  33. mkv_episode_matcher/mkv_to_srt.py +0 -302
  34. mkv_episode_matcher/speech_to_text.py +0 -90
  35. mkv_episode_matcher-0.3.3.dist-info/METADATA +0 -125
  36. mkv_episode_matcher-0.3.3.dist-info/RECORD +0 -25
  37. {mkv_episode_matcher-0.3.3.dist-info → mkv_episode_matcher-1.0.0.dist-info}/entry_points.txt +0 -0
  38. {mkv_episode_matcher-0.3.3.dist-info → mkv_episode_matcher-1.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,242 @@
1
+ Metadata-Version: 2.4
2
+ Name: mkv-episode-matcher
3
+ Version: 1.0.0
4
+ Summary: The MKV Episode Matcher is a tool for identifying TV series episodes from MKV files and renaming the files accordingly.
5
+ Home-page: https://github.com/Jsakkos/mkv-episode-matcher
6
+ Author: Jonathan Sakkos
7
+ Author-email: Jsakkos <jonathansakkos@gmail.com>
8
+ License: MIT License
9
+
10
+ Copyright (c) 2025 Jonathan Sakkos
11
+
12
+ Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ of this software and associated documentation files (the "Software"), to deal
14
+ in the Software without restriction, including without limitation the rights
15
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ copies of the Software, and to permit persons to whom the Software is
17
+ furnished to do so, subject to the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be included in all
20
+ copies or substantial portions of the Software.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
+ SOFTWARE.
29
+ Project-URL: Documentation, https://github.com/Jsakkos/mkv-episode-matcher#readme
30
+ Project-URL: Issues, https://github.com/Jsakkos/mkv-episode-matcher/issues
31
+ Project-URL: Source, https://github.com/Jsakkos/mkv-episode-matcher
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: Programming Language :: Python
34
+ Classifier: Programming Language :: Python :: 3.12
35
+ Classifier: Programming Language :: Python :: Implementation :: CPython
36
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
37
+ Requires-Python: <3.13,>=3.10
38
+ Description-Content-Type: text/markdown
39
+ License-File: LICENSE
40
+ Requires-Dist: chardet>=5.2.0
41
+ Requires-Dist: configparser>=7.1.0
42
+ Requires-Dist: ffmpeg>=1.4
43
+ Requires-Dist: librosa>=0.10.2
44
+ Requires-Dist: loguru>=0.7.2
45
+ Requires-Dist: nemo-toolkit[asr]>=2.0.0
46
+ Requires-Dist: opensubtitlescom>=0.1.5
47
+ Requires-Dist: rapidfuzz>=3.10.1
48
+ Requires-Dist: requests>=2.32.3
49
+ Requires-Dist: rich[jupyter]>=13.9.4
50
+ Requires-Dist: soundfile>=0.12.1
51
+ Requires-Dist: tmdb-client>=0.0.1
52
+ Requires-Dist: torch>=2.5.1
53
+ Requires-Dist: torchaudio>=2.5.1
54
+ Requires-Dist: torchvision>=0.20.1
55
+ Requires-Dist: typer>=0.9.0
56
+ Requires-Dist: flet[all]>=0.80.0
57
+ Requires-Dist: pydantic>=2.0.0
58
+ Requires-Dist: pydantic-settings>=2.0.0
59
+ Requires-Dist: ty>=0.0.7
60
+ Provides-Extra: cu128
61
+ Requires-Dist: torch>=2.9.1; sys_platform != "darwin" and extra == "cu128"
62
+ Requires-Dist: torchvision>=0.24.1; sys_platform != "darwin" and extra == "cu128"
63
+ Provides-Extra: nemo
64
+ Requires-Dist: nemo_toolkit[asr]>=2.0.0; extra == "nemo"
65
+ Dynamic: license-file
66
+
67
+ # MKV Episode Matcher
68
+
69
+ [![Development Status](https://img.shields.io/pypi/status/mkv-episode-matcher)](https://pypi.org/project/mkv-episode-matcher/)
70
+ [![PyPI version](https://img.shields.io/pypi/v/mkv-episode-matcher.svg)](https://pypi.org/project/mkv-episode-matcher/)
71
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
72
+ [![Documentation Status](https://img.shields.io/github/actions/workflow/status/Jsakkos/mkv-episode-matcher/documentation.yml?label=docs)](https://jsakkos.github.io/mkv-episode-matcher/)
73
+ [![Downloads](https://static.pepy.tech/badge/mkv-episode-matcher)](https://pepy.tech/project/mkv-episode-matcher)
74
+ [![GitHub last commit](https://img.shields.io/github/last-commit/Jsakkos/mkv-episode-matcher)](https://github.com/Jsakkos/mkv-episode-matcher/commits/main)
75
+ [![GitHub issues](https://img.shields.io/github/issues/Jsakkos/mkv-episode-matcher)](https://github.com/Jsakkos/mkv-episode-matcher/issues)
76
+ [![Tests](https://github.com/Jsakkos/mkv-episode-matcher/actions/workflows/tests.yml/badge.svg)](https://github.com/Jsakkos/mkv-episode-matcher/actions/workflows/tests.yml)
77
+ [![codecov](https://codecov.io/gh/Jsakkos/mkv-episode-matcher/branch/main/graph/badge.svg)](https://codecov.io/gh/Jsakkos/mkv-episode-matcher/)
78
+
79
+ Automatically match and rename your MKV TV episodes using advanced speech recognition and subtitle matching.
80
+
81
+ ## ✨ Key Features
82
+
83
+ - 🖥️ **Modern Desktop GUI**: Cross-platform Flet-based graphical interface with real-time progress tracking
84
+ - 🤖 **Advanced Speech Recognition**: NVIDIA Parakeet ASR for highly accurate episode identification
85
+ - 🎯 **Intelligent Matching**: Multi-segment analysis with confidence scoring and fallback strategies
86
+ - ⬇️ **Smart Subtitle Integration**: Automatic subtitle downloads from OpenSubtitles with local caching
87
+ - ✨ **Bulk Processing**: Handle entire libraries with automatic series/season detection
88
+ - 🧪 **Dry Run Mode**: Preview matches before making any changes
89
+ - 📊 **Rich Progress Tracking**: Real-time progress indicators and detailed match results
90
+ - ⚡ **Performance Optimized**: Caching, background model loading, and efficient processing
91
+ - 🌐 **Cross-Platform**: Available as desktop applications for Windows, macOS, and Linux
92
+
93
+ ## Prerequisites
94
+
95
+ - Python 3.10-3.12
96
+ - [FFmpeg](https://ffmpeg.org/download.html) installed and available in system PATH
97
+ - TMDb API key (optional, for episode matching)
98
+ - OpenSubtitles.com account (required for subtitle downloads)
99
+
100
+ ## 🚀 Quick Start
101
+
102
+ ### 1. Install MKV Episode Matcher
103
+
104
+ **Option A: Using uv (Recommended)**
105
+ ```bash
106
+ # Install with CUDA support for GPU acceleration
107
+ uv sync --extra cu128
108
+
109
+ # Or basic installation
110
+ uv sync
111
+ ```
112
+
113
+ **Option B: Using pip**
114
+ ```bash
115
+ pip install mkv-episode-matcher
116
+ ```
117
+
118
+ **Option C: Download Standalone Desktop Apps**
119
+ - [Windows Executable](https://github.com/Jsakkos/mkv-episode-matcher/releases/latest/download/MKVEpisodeMatcher-windows.zip)
120
+ - [macOS Application](https://github.com/Jsakkos/mkv-episode-matcher/releases/latest/download/MKVEpisodeMatcher-macos.zip)
121
+ - [Linux AppImage](https://github.com/Jsakkos/mkv-episode-matcher/releases/latest/download/mkv-episode-matcher-linux.AppImage)
122
+
123
+ ### 2. Launch the Application
124
+
125
+ **🖥️ GUI Mode (Recommended)**
126
+ Launches the modern desktop interface with real-time progress tracking:
127
+ ```bash
128
+ uv run mkv-match gui
129
+ ```
130
+
131
+ **💻 CLI Mode**
132
+ For automation and advanced users:
133
+ ```bash
134
+ uv run mkv-match match "/path/to/your/show"
135
+ ```
136
+
137
+ **⚙️ Configuration**
138
+ ```bash
139
+ uv run mkv-match config
140
+ ```
141
+
142
+ ### 3. Alternative Launch Methods
143
+ ```bash
144
+ # GUI
145
+ python -m mkv_episode_matcher gui
146
+
147
+ # CLI
148
+ python -m mkv_episode_matcher match "/path/to/show"
149
+ ```
150
+ ## 🖥️ Desktop GUI Features
151
+
152
+ The modern Flet-based desktop interface provides:
153
+
154
+ - **🎨 Theme-Adaptive Interface**: Automatically adapts to your system's light/dark theme
155
+ - **📂 Folder Browser**: Easy directory selection with visual folder picker
156
+ - **⏱️ Real-time Progress**: Live progress bars showing "Processing file X of Y"
157
+ - **🔄 Background Model Loading**: Non-blocking ASR model initialization with status indicators
158
+ - **🧪 Dry Run Preview**: Test matches without making changes, with preview functionality
159
+ - **⚙️ Comprehensive Settings**: Built-in configuration dialog for all options
160
+ - **📊 Detailed Results**: Color-coded success/failure results with confidence scores
161
+ - **🚀 Performance Indicators**: Model loading status and processing statistics
162
+
163
+ ## ⚙️ Configuration
164
+
165
+ ### GUI Configuration
166
+ The desktop app includes a built-in settings dialog accessible via the gear icon. Configure all options including:
167
+ - Cache directory and confidence thresholds
168
+ - ASR and subtitle provider settings
169
+ - OpenSubtitles API credentials
170
+ - TMDb integration (optional)
171
+
172
+ ### CLI Configuration
173
+ For command-line users:
174
+ ```bash
175
+ mkv-match config # Interactive configuration
176
+ mkv-match --onboard # First-time setup wizard
177
+ ```
178
+
179
+ **Required API Keys:**
180
+ - **OpenSubtitles API Key**: Required for subtitle downloads ([Get one here](https://www.opensubtitles.com/consumers))
181
+ - **TMDb API Key**: Optional, for enhanced episode metadata ([Get one here](https://www.themoviedb.org/settings/api))
182
+
183
+ **OpenSubtitles Setup:**
184
+ - Username and password (recommended for better rate limits)
185
+ - API key from the OpenSubtitles developer console
186
+
187
+ ## Directory Structure
188
+
189
+ MKV Episode Matcher expects your TV shows to be organized as follows:
190
+
191
+ ```
192
+ Show Name/
193
+ ├── Season 1/
194
+ │ ├── episode1.mkv
195
+ │ ├── episode2.mkv
196
+ ├── Season 2/
197
+ │ ├── episode1.mkv
198
+ │ └── episode2.mkv
199
+ ```
200
+
201
+ ## Reference Subtitle File Structure
202
+
203
+ Subtitle files that are not automatically downloaded using the `--get-subs` flag should be named as follows:
204
+
205
+ ```
206
+
207
+ ~/.mkv-episode-matcher/cache/data/Show Name/
208
+ ├── Show Name - S01E01.srt
209
+ ├── Show Name - S01E02.srt
210
+ └── ...
211
+ ```
212
+
213
+ On Windows, the cache directory is located at `C:\Users\{username}\.mkv-episode-matcher\cache\data\`
214
+
215
+ Reference subtitle files should follow this naming pattern:
216
+ `{show_name} - S{season:02d}E{episode:02d}.srt`
217
+
218
+ ## Contributing
219
+
220
+ 1. Fork the repository
221
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
222
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
223
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
224
+ 5. Open a Pull Request
225
+
226
+ ## License
227
+
228
+ Distributed under the MIT License. See `LICENSE` for more information.
229
+
230
+ ## Acknowledgments
231
+
232
+ - [TMDb](https://www.themoviedb.org/) for their excellent API
233
+ - [OpenSubtitles](https://www.opensubtitles.com/) for subtitle integration
234
+ - All contributors who have helped improve this project
235
+
236
+ ## Documentation
237
+
238
+ Full documentation is available at [https://jsakkos.github.io/mkv-episode-matcher/](https://jsakkos.github.io/mkv-episode-matcher/)
239
+
240
+ ## Changelog
241
+
242
+ See [CHANGELOG.md](CHANGELOG.md) for a detailed list of changes.
@@ -0,0 +1,23 @@
1
+ mkv_episode_matcher/.gitattributes,sha256=Gh2-F2vCM7SZ01pX23UT8pQcmauXWfF3gwyRSb6ZAFs,66
2
+ mkv_episode_matcher/__init__.py,sha256=u3yZcpuK0ICeUjxYKePvW-zS61E5ss5q2AvqnSHuz9E,240
3
+ mkv_episode_matcher/__main__.py,sha256=GB1fwuAaDzpYnr-XWG9pL9O5g_MRDeDVAEDsO8T5IXI,104
4
+ mkv_episode_matcher/asr_models.py,sha256=zydUzO2vPfUbBgbRStr3rECz7oi_0Lw1hRz84ASa3Ns,17067
5
+ mkv_episode_matcher/cli.py,sha256=x5ZOKHy-ut4XWkJe1i6KPgZYq2RfBJRQB-YPHS2Z_-E,17923
6
+ mkv_episode_matcher/episode_identification.py,sha256=dN_uwkLlP4_75bBHNjI7zFmQx8F20LMTdmUnfe8IEzM,21785
7
+ mkv_episode_matcher/subtitle_utils.py,sha256=3n5msR9H6PQj5gQDTHDhX-pN1GffK8zXzlVsGhY26BY,2521
8
+ mkv_episode_matcher/tmdb_client.py,sha256=7DraZs7-pdGJu9LgzJ2H3cct_Eiayhm_2oC9JDZVVZQ,5674
9
+ mkv_episode_matcher/utils.py,sha256=2EfMz9u2sfhAVJBpmImOn_LjI9ixHDNCRujLDcYN8PI,18699
10
+ mkv_episode_matcher/core/config_manager.py,sha256=q9_qwP6guVEgA01NrXCQ-TcmSlOi9arUOXzCoNYU_VQ,3567
11
+ mkv_episode_matcher/core/engine.py,sha256=4y659ElJ1B0yFUJujdX9cYXCf7ZCo80B4V0m61tZWAs,22046
12
+ mkv_episode_matcher/core/matcher.py,sha256=6_4_tex5UAf2df8afCSqIARCxypN2Q_IcdmABONMQns,8217
13
+ mkv_episode_matcher/core/models.py,sha256=gJ0QuIj_On1ilNQ-Nxt8J3muEC2R4owlTCnuJQc5JDs,2233
14
+ mkv_episode_matcher/core/utils.py,sha256=KU90CiF2H49ELV_6VwRQKOTa61ehfOf34siusoafuyk,4536
15
+ mkv_episode_matcher/core/providers/asr.py,sha256=7ATCBRuWYYaPAys69mSam1UK2E4fC532eHoF_KEzeXs,2405
16
+ mkv_episode_matcher/core/providers/subtitles.py,sha256=5IPTRkTvWYBsJkdQqKuKgUb7Tzmv3kl7NVH4Xj-lRKY,12339
17
+ mkv_episode_matcher/ui/flet_app.py,sha256=WgZXHf9UrbIsG8mP6b5D2aiBiE4tMozNapiSofpMvxw,28236
18
+ mkv_episode_matcher-1.0.0.dist-info/licenses/LICENSE,sha256=ScBvQ_sUEpaRMDYp01qmMDELT1nTknFP2w-VRAS54TY,1071
19
+ mkv_episode_matcher-1.0.0.dist-info/METADATA,sha256=ituP5GyTvTrT2xfKrRq6xtXRIMuIko70ZcX4UekSZkM,10005
20
+ mkv_episode_matcher-1.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
21
+ mkv_episode_matcher-1.0.0.dist-info/entry_points.txt,sha256=IglJ43SuCZq2eQ3shMFILCkmQASJHnDCI3ogohW2Hn4,64
22
+ mkv_episode_matcher-1.0.0.dist-info/top_level.txt,sha256=XRLbd93HUaedeWLtkyTvQjFcE5QcBRYa3V-CfHrq-OI,20
23
+ mkv_episode_matcher-1.0.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.6.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Jonathan Sakkos
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,82 +0,0 @@
1
- # config.py
2
- import configparser
3
- import multiprocessing
4
- import os
5
-
6
- from loguru import logger
7
-
8
- MAX_THREADS = 4
9
-
10
-
11
- def get_total_threads():
12
- return multiprocessing.cpu_count()
13
-
14
-
15
- total_threads = get_total_threads()
16
-
17
- if total_threads < MAX_THREADS:
18
- MAX_THREADS = total_threads
19
- logger.info(f"Total available threads: {total_threads} -> Setting max to {MAX_THREADS}")
20
-
21
-
22
- def set_config(
23
- tmdb_api_key,
24
- open_subtitles_api_key,
25
- open_subtitles_user_agent,
26
- open_subtitles_username,
27
- open_subtitles_password,
28
- show_dir,
29
- file,
30
- tesseract_path=None,
31
- ):
32
- """
33
- Sets the configuration values and writes them to a file.
34
-
35
- Args:
36
- tmdb_api_key (str): The API key for TMDB (The Movie Database).
37
- open_subtitles_api_key (str): The API key for OpenSubtitles.
38
- open_subtitles_user_agent (str): The user agent for OpenSubtitles.
39
- open_subtitles_username (str): The username for OpenSubtitles.
40
- open_subtitles_password (str): The password for OpenSubtitles.
41
- show_dir (str): The directory where the TV show episodes are located.
42
- file (str): The path to the configuration file.
43
- tesseract_path (str, optional): The path to the Tesseract OCR executable.
44
-
45
- Returns:
46
- None
47
- """
48
- config = configparser.ConfigParser()
49
- config["Config"] = {
50
- "tmdb_api_key": str(tmdb_api_key),
51
- "show_dir": show_dir,
52
- "max_threads": int(MAX_THREADS),
53
- "open_subtitles_api_key": str(open_subtitles_api_key),
54
- "open_subtitles_user_agent": str(open_subtitles_user_agent),
55
- "open_subtitles_username": str(open_subtitles_username),
56
- "open_subtitles_password": str(open_subtitles_password),
57
- "tesseract_path": str(tesseract_path),
58
- }
59
- logger.info(
60
- f"Setting config with API:{tmdb_api_key}, show_dir: {show_dir}, and max_threads: {MAX_THREADS}"
61
- )
62
- with open(file, "w") as configfile:
63
- config.write(configfile)
64
-
65
-
66
- def get_config(file):
67
- """
68
- Read and return the configuration from the specified file.
69
-
70
- Args:
71
- file (str): The path to the configuration file.
72
-
73
- Returns:
74
- dict: The configuration settings as a dictionary.
75
-
76
- """
77
- logger.info(f"Loading config from {file}")
78
- config = configparser.ConfigParser()
79
- if os.path.exists(file):
80
- config.read(file)
81
- return config["Config"] if "Config" in config else None
82
- return {}
@@ -1,100 +0,0 @@
1
- # mkv_episode_matcher/episode_matcher.py
2
-
3
- from pathlib import Path
4
- import shutil
5
- import glob
6
- import os
7
- from loguru import logger
8
- import re
9
- from mkv_episode_matcher.__main__ import CONFIG_FILE, CACHE_DIR
10
- from mkv_episode_matcher.config import get_config
11
- from mkv_episode_matcher.mkv_to_srt import convert_mkv_to_srt
12
- from mkv_episode_matcher.tmdb_client import fetch_show_id
13
- from mkv_episode_matcher.utils import (
14
- check_filename,
15
- clean_text,
16
- cleanup_ocr_files,
17
- get_subtitles,
18
- process_reference_srt_files,
19
- process_srt_files,
20
- compare_and_rename_files,get_valid_seasons,rename_episode_file
21
- )
22
- from mkv_episode_matcher.speech_to_text import process_speech_to_text
23
- from mkv_episode_matcher.episode_identification import EpisodeMatcher
24
-
25
- def process_show(season=None, dry_run=False, get_subs=False):
26
- """Process the show using streaming speech recognition with OCR fallback."""
27
- config = get_config(CONFIG_FILE)
28
- show_dir = config.get("show_dir")
29
- show_name = clean_text(os.path.basename(show_dir))
30
- matcher = EpisodeMatcher(CACHE_DIR, show_name)
31
-
32
- season_paths = get_valid_seasons(show_dir)
33
- if not season_paths:
34
- logger.warning(f"No seasons with .mkv files found")
35
- return
36
-
37
- if season is not None:
38
- season_path = os.path.join(show_dir, f"Season {season}")
39
- if season_path not in season_paths:
40
- logger.warning(f"Season {season} has no .mkv files to process")
41
- return
42
- season_paths = [season_path]
43
-
44
- for season_path in season_paths:
45
- mkv_files = [f for f in glob.glob(os.path.join(season_path, "*.mkv"))
46
- if not check_filename(f)]
47
-
48
- if not mkv_files:
49
- logger.info(f"No new files to process in {season_path}")
50
- continue
51
-
52
- season_num = int(re.search(r'Season (\d+)', season_path).group(1))
53
- temp_dir = Path(season_path) / "temp"
54
- ocr_dir = Path(season_path) / "ocr"
55
- temp_dir.mkdir(exist_ok=True)
56
- ocr_dir.mkdir(exist_ok=True)
57
-
58
- try:
59
- if get_subs:
60
- show_id = fetch_show_id(matcher.show_name)
61
- if show_id:
62
- get_subtitles(show_id, seasons={season_num})
63
-
64
- unmatched_files = []
65
- for mkv_file in mkv_files:
66
- logger.info(f"Attempting speech recognition match for {mkv_file}")
67
- match = matcher.identify_episode(mkv_file, temp_dir, season_num)
68
-
69
- if match:
70
- new_name = f"{matcher.show_name} - S{match['season']:02d}E{match['episode']:02d}.mkv"
71
- new_path = os.path.join(season_path, new_name)
72
-
73
- logger.info(f"Speech matched {os.path.basename(mkv_file)} to {new_name} "
74
- f"(confidence: {match['confidence']:.2f})")
75
-
76
- if not dry_run:
77
- logger.info(f"Renaming {mkv_file} to {new_name}")
78
- rename_episode_file(mkv_file, new_name)
79
- else:
80
- logger.info(f"Speech recognition match failed for {mkv_file}, trying OCR")
81
- unmatched_files.append(mkv_file)
82
-
83
- # OCR fallback for unmatched files
84
- if unmatched_files:
85
- logger.info(f"Attempting OCR matching for {len(unmatched_files)} unmatched files")
86
- convert_mkv_to_srt(season_path, unmatched_files)
87
-
88
- reference_text_dict = process_reference_srt_files(matcher.show_name)
89
- srt_text_dict = process_srt_files(str(ocr_dir))
90
-
91
- compare_and_rename_files(
92
- srt_text_dict,
93
- reference_text_dict,
94
- dry_run=dry_run,
95
- )
96
-
97
- finally:
98
- if not dry_run:
99
- shutil.rmtree(temp_dir)
100
- cleanup_ocr_files(show_dir)
@@ -1,2 +0,0 @@
1
- __pycache__/
2
- .DS_Store