mkv-episode-matcher 0.9.2__tar.gz → 0.9.4__tar.gz

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.

Potentially problematic release.


This version of mkv-episode-matcher might be problematic. Click here for more details.

Files changed (45) hide show
  1. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/.coverage +0 -0
  2. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/CHANGELOG.md +12 -0
  3. mkv_episode_matcher-0.9.4/LICENSE +21 -0
  4. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/PKG-INFO +56 -11
  5. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/README.md +31 -9
  6. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/docs/configuration.md +0 -19
  7. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/docs/quickstart.md +24 -5
  8. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/mkv_episode_matcher/__main__.py +90 -48
  9. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/mkv_episode_matcher/episode_identification.py +59 -34
  10. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/mkv_episode_matcher/episode_matcher.py +50 -28
  11. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/mkv_episode_matcher/utils.py +54 -37
  12. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/mkv_episode_matcher.egg-info/PKG-INFO +56 -11
  13. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/mkv_episode_matcher.egg-info/SOURCES.txt +1 -0
  14. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/mkv_episode_matcher.egg-info/requires.txt +1 -0
  15. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/pyproject.toml +2 -2
  16. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/setup.cfg +1 -1
  17. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/tests/test_main.py +4 -25
  18. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/tests/test_path_handling.py +58 -36
  19. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/tests/test_trailing_slash.py +31 -11
  20. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/uv.lock +1174 -1174
  21. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/.gitattributes +0 -0
  22. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/.github/funding.yml +0 -0
  23. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/.github/workflows/documentation.yml +0 -0
  24. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/.github/workflows/python-publish.yml +0 -0
  25. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/.github/workflows/tests.yml +0 -0
  26. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/.gitignore +0 -0
  27. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/.gitmodules +0 -0
  28. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/.python-version +0 -0
  29. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/.vscode/settings.json +0 -0
  30. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/docs/api/index.md +0 -0
  31. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/docs/changelog.md +0 -0
  32. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/docs/cli.md +0 -0
  33. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/docs/installation.md +0 -0
  34. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/docs/tips.md +0 -0
  35. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/mkdocs.yml +0 -0
  36. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/mkv_episode_matcher/.gitattributes +0 -0
  37. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/mkv_episode_matcher/__init__.py +0 -0
  38. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/mkv_episode_matcher/config.py +0 -0
  39. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/mkv_episode_matcher/subtitle_utils.py +0 -0
  40. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/mkv_episode_matcher/tmdb_client.py +0 -0
  41. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/mkv_episode_matcher.egg-info/dependency_links.txt +0 -0
  42. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/mkv_episode_matcher.egg-info/entry_points.txt +0 -0
  43. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/mkv_episode_matcher.egg-info/top_level.txt +0 -0
  44. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/setup.py +0 -0
  45. {mkv_episode_matcher-0.9.2 → mkv_episode_matcher-0.9.4}/tests/__init__.py +0 -0
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.9.3] - 2025-07-07
9
+
10
+ ### Added
11
+ - Onboarding flag (`--onboard`) and interactive onboarding sequence for first-time setup and configuration updates
12
+ - Onboarding prompts for TMDb API key, OpenSubtitles API key, Consumer Name, Username, Password, and Show Directory
13
+ - Existing config values are shown as defaults during onboarding and can be accepted or overwritten
14
+ - Documentation updated to reflect onboarding requirements and workflow in README and docs
15
+
16
+ ### Changed
17
+ - Improved configuration experience for new and returning users
18
+ - Quick Start and Configuration documentation now reference onboarding and required credentials
19
+
8
20
  ## [0.9.0] - 2025-06-01
9
21
 
10
22
  ### Changed
@@ -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,11 +1,31 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mkv-episode-matcher
3
- Version: 0.9.2
3
+ Version: 0.9.4
4
4
  Summary: The MKV Episode Matcher is a tool for identifying TV series episodes from MKV files and renaming the files accordingly.
5
5
  Home-page: https://github.com/Jsakkos/mkv-episode-matcher
6
6
  Author: Jonathan Sakkos
7
7
  Author-email: Jsakkos <jonathansakkos@gmail.com>
8
- License: MIT
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.
9
29
  Project-URL: Documentation, https://github.com/Jsakkos/mkv-episode-matcher#readme
10
30
  Project-URL: Issues, https://github.com/Jsakkos/mkv-episode-matcher/issues
11
31
  Project-URL: Source, https://github.com/Jsakkos/mkv-episode-matcher
@@ -16,6 +36,8 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
16
36
  Classifier: Programming Language :: Python :: Implementation :: PyPy
17
37
  Requires-Python: <3.13,>=3.9
18
38
  Description-Content-Type: text/markdown
39
+ License-File: LICENSE
40
+ Requires-Dist: chardet>=5.2.0
19
41
  Requires-Dist: configparser>=7.1.0
20
42
  Requires-Dist: ffmpeg>=1.4
21
43
  Requires-Dist: loguru>=0.7.2
@@ -28,6 +50,7 @@ Requires-Dist: tmdb-client>=0.0.1
28
50
  Requires-Dist: torch>=2.5.1
29
51
  Requires-Dist: torchaudio>=2.5.1
30
52
  Requires-Dist: torchvision>=0.20.1
53
+ Dynamic: license-file
31
54
 
32
55
  # MKV Episode Matcher
33
56
 
@@ -45,15 +68,11 @@ Automatically match and rename your MKV TV episodes using The Movie Database (TM
45
68
 
46
69
  ## Features
47
70
 
48
- - 🎯 **Automatic Episode Matching**: Uses TMDb to accurately identify episodes
49
- - 🎨 **Rich User Interface**: Color-coded output and progress indicators
50
- - 📝 **Subtitle Extraction**: Extracts subtitles from MKV files
51
- - 🔊 **Speech Recognition**: Uses Whisper for accurate episode identification
52
- - 🚀 **Multi-threaded**: Fast processing of multiple files
71
+ - 🎯 **Automatic Episode Matching**: Uses TMDb and OpenSubtitles to accurately identify episodes
72
+ - 🔊 **Speech Recognition**: Uses OpenAI Whisper for accurate episode identification
53
73
  - ⬇️ **Subtitle Downloads**: Integration with OpenSubtitles
54
74
  - ✨ **Bulk Processing**: Handle entire seasons at once
55
75
  - 🧪 **Dry Run Mode**: Test changes before applying
56
- - 🎮 **Interactive Mode**: User-friendly season selection and configuration
57
76
 
58
77
  ## Prerequisites
59
78
 
@@ -66,15 +85,41 @@ Automatically match and rename your MKV TV episodes using The Movie Database (TM
66
85
 
67
86
  1. Install the package:
68
87
  ```bash
69
- pip install mkv-episode-matcher
88
+ pip install -U mkv-episode-matcher
70
89
  ```
71
- 2. Download .srt subtitles files to ~/.mkv-episode-matcher/cache/data/Show Name/
90
+ 2. Run onboarding to set up your configuration (first-time users or to update credentials):
91
+ ```bash
92
+ mkv-match --onboard
93
+ ```
94
+ - You will be prompted for:
95
+ - TMDb API key (for episode matching)
96
+ - OpenSubtitles API key, Consumer Name, Username, and Password (for subtitle downloads)
97
+ - Show Directory (main directory of your show)
98
+ - If a config value already exists, you can accept the default or enter a new value.
72
99
 
73
- 3. Run on your show directory:
100
+ 3.
101
+ a. If you setup the TMDb and Opensubtitles credentials above, automatically fetch subtitles with the `--get-subs` flag.
102
+ b. Alternatively, manually download .srt subtitles files to ~/.mkv-episode-matcher/cache/data/Show Name/
103
+
104
+ 4. Run on your show directory:
74
105
  ```bash
75
106
  mkv-match --show-dir "path/to/your/show"
76
107
  ```
77
108
 
109
+ ## Onboarding & Configuration
110
+
111
+ The onboarding process will prompt you for all required configuration values if you run with `--onboard` or if no config file exists. You can re-run onboarding at any time to update your credentials or show directory.
112
+
113
+ **Required information:**
114
+ - TMDb API key (for episode matching)
115
+ - OpenSubtitles API key (for subtitle downloads)
116
+ - OpenSubtitles Consumer Name (for subtitle downloads)
117
+ - OpenSubtitles Username (for subtitle downloads)
118
+ - OpenSubtitles Password (for subtitle downloads)
119
+ - Show Directory (main directory of your show)
120
+
121
+ If a value already exists, it will be shown as the default and you can accept it or enter a new value.
122
+
78
123
  ## Directory Structure
79
124
 
80
125
  MKV Episode Matcher expects your TV shows to be organized as follows:
@@ -14,15 +14,11 @@ Automatically match and rename your MKV TV episodes using The Movie Database (TM
14
14
 
15
15
  ## Features
16
16
 
17
- - 🎯 **Automatic Episode Matching**: Uses TMDb to accurately identify episodes
18
- - 🎨 **Rich User Interface**: Color-coded output and progress indicators
19
- - 📝 **Subtitle Extraction**: Extracts subtitles from MKV files
20
- - 🔊 **Speech Recognition**: Uses Whisper for accurate episode identification
21
- - 🚀 **Multi-threaded**: Fast processing of multiple files
17
+ - 🎯 **Automatic Episode Matching**: Uses TMDb and OpenSubtitles to accurately identify episodes
18
+ - 🔊 **Speech Recognition**: Uses OpenAI Whisper for accurate episode identification
22
19
  - ⬇️ **Subtitle Downloads**: Integration with OpenSubtitles
23
20
  - ✨ **Bulk Processing**: Handle entire seasons at once
24
21
  - 🧪 **Dry Run Mode**: Test changes before applying
25
- - 🎮 **Interactive Mode**: User-friendly season selection and configuration
26
22
 
27
23
  ## Prerequisites
28
24
 
@@ -35,15 +31,41 @@ Automatically match and rename your MKV TV episodes using The Movie Database (TM
35
31
 
36
32
  1. Install the package:
37
33
  ```bash
38
- pip install mkv-episode-matcher
34
+ pip install -U mkv-episode-matcher
39
35
  ```
40
- 2. Download .srt subtitles files to ~/.mkv-episode-matcher/cache/data/Show Name/
36
+ 2. Run onboarding to set up your configuration (first-time users or to update credentials):
37
+ ```bash
38
+ mkv-match --onboard
39
+ ```
40
+ - You will be prompted for:
41
+ - TMDb API key (for episode matching)
42
+ - OpenSubtitles API key, Consumer Name, Username, and Password (for subtitle downloads)
43
+ - Show Directory (main directory of your show)
44
+ - If a config value already exists, you can accept the default or enter a new value.
41
45
 
42
- 3. Run on your show directory:
46
+ 3.
47
+ a. If you setup the TMDb and Opensubtitles credentials above, automatically fetch subtitles with the `--get-subs` flag.
48
+ b. Alternatively, manually download .srt subtitles files to ~/.mkv-episode-matcher/cache/data/Show Name/
49
+
50
+ 4. Run on your show directory:
43
51
  ```bash
44
52
  mkv-match --show-dir "path/to/your/show"
45
53
  ```
46
54
 
55
+ ## Onboarding & Configuration
56
+
57
+ The onboarding process will prompt you for all required configuration values if you run with `--onboard` or if no config file exists. You can re-run onboarding at any time to update your credentials or show directory.
58
+
59
+ **Required information:**
60
+ - TMDb API key (for episode matching)
61
+ - OpenSubtitles API key (for subtitle downloads)
62
+ - OpenSubtitles Consumer Name (for subtitle downloads)
63
+ - OpenSubtitles Username (for subtitle downloads)
64
+ - OpenSubtitles Password (for subtitle downloads)
65
+ - Show Directory (main directory of your show)
66
+
67
+ If a value already exists, it will be shown as the default and you can accept it or enter a new value.
68
+
47
69
  ## Directory Structure
48
70
 
49
71
  MKV Episode Matcher expects your TV shows to be organized as follows:
@@ -36,25 +36,6 @@ mkv-match \
36
36
  --get-subs true
37
37
  ```
38
38
 
39
- ## Environment Variables
40
-
41
- You can also use environment variables:
42
-
43
- ```bash
44
- export TMDB_API_KEY="your_key"
45
- export SHOW_DIR="/path/to/shows"
46
- export OPEN_SUBTITLES_API_KEY="your_key"
47
- ```
48
-
49
- ## Configuration Priority
50
-
51
- Settings are loaded in the following order (later overrides earlier):
52
-
53
- 1. Default values
54
- 2. Configuration file
55
- 3. Environment variables
56
- 4. Command line arguments
57
-
58
39
  ## Detailed Options
59
40
 
60
41
  ### TMDb Configuration
@@ -4,22 +4,36 @@ Get started with MKV Episode Matcher quickly and efficiently.
4
4
 
5
5
  ## Basic Usage
6
6
 
7
- ### 1. Interactive Mode
7
+ ### 1. Onboarding (First-Time Setup)
8
+
9
+ Before running any matching, set up your configuration:
10
+ ```bash
11
+ mkv-match --onboard
12
+ ```
13
+ You will be prompted for:
14
+ - TMDb API key (for episode matching)
15
+ - OpenSubtitles API key, Consumer Name, Username, and Password (for subtitle downloads)
16
+ - Show Directory (main directory of your show)
17
+ If a value already exists, you can accept the default or enter a new value.
18
+
19
+ You can re-run onboarding at any time to update your credentials or show directory.
20
+
21
+ ### 2. Interactive Mode
8
22
 
9
23
  Simply run:
10
24
  ```bash
11
25
  mkv-match
12
26
  ```
13
- The program will guide you through the setup interactively.
27
+ The program will guide you through the setup interactively if configuration is missing.
14
28
 
15
- ### 2. Command Line Options
29
+ ### 3. Command Line Options
16
30
 
17
31
  Process a specific season:
18
32
  ```bash
19
33
  mkv-match --show-dir "/path/to/show" --season 1
20
34
  ```
21
35
 
22
- Process all seasons with subtitles:
36
+ Process all seasons with subtitles (requires onboarding):
23
37
  ```bash
24
38
  mkv-match --show-dir "/path/to/show" --get-subs
25
39
  ```
@@ -53,7 +67,12 @@ Show Name/
53
67
 
54
68
  ## Configuration
55
69
 
56
- Configuration is stored at `~/.mkv-episode-matcher/config.ini`:
70
+ Configuration is stored at `~/.mkv-episode-matcher/config.ini` and can be set up or updated at any time with:
71
+ ```bash
72
+ mkv-match --onboard
73
+ ```
74
+
75
+ Example config:
57
76
  ```ini
58
77
  [Config]
59
78
  tmdb_api_key = your_tmdb_api_key
@@ -7,7 +7,6 @@ from typing import Optional
7
7
  from loguru import logger
8
8
  from rich.console import Console
9
9
  from rich.panel import Panel
10
- from rich.progress import Progress, SpinnerColumn, TextColumn
11
10
  from rich.prompt import Confirm, Prompt
12
11
 
13
12
  from mkv_episode_matcher import __version__
@@ -62,15 +61,17 @@ def print_welcome_message():
62
61
  console.print()
63
62
 
64
63
 
65
- def confirm_api_key(config_value: Optional[str], key_name: str, description: str) -> str:
64
+ def confirm_api_key(
65
+ config_value: Optional[str], key_name: str, description: str
66
+ ) -> str:
66
67
  """
67
68
  Confirm if the user wants to use an existing API key or enter a new one.
68
-
69
+
69
70
  Args:
70
71
  config_value: The current value from the config
71
72
  key_name: The name of the key
72
73
  description: Description of the key for user information
73
-
74
+
74
75
  Returns:
75
76
  The API key to use
76
77
  """
@@ -79,7 +80,7 @@ def confirm_api_key(config_value: Optional[str], key_name: str, description: str
79
80
  console.print(f"Current value: [green]{mask_api_key(config_value)}[/green]")
80
81
  if Confirm.ask("Use existing key?", default=True):
81
82
  return config_value
82
-
83
+
83
84
  return Prompt.ask(f"Enter your {key_name}")
84
85
 
85
86
 
@@ -95,10 +96,10 @@ def mask_api_key(key: str) -> str:
95
96
  def select_season(seasons):
96
97
  """
97
98
  Allow user to select a season from a list.
98
-
99
+
99
100
  Args:
100
101
  seasons: List of available seasons
101
-
102
+
102
103
  Returns:
103
104
  Selected season number or None for all seasons
104
105
  """
@@ -106,21 +107,51 @@ def select_season(seasons):
106
107
  for i, season in enumerate(seasons, 1):
107
108
  season_num = Path(season).name.replace("Season ", "")
108
109
  console.print(f" {i}. Season {season_num}")
109
-
110
- console.print(f" 0. All Seasons")
111
-
110
+
111
+ console.print(" 0. All Seasons")
112
+
112
113
  choice = Prompt.ask(
113
114
  "Select a season number (0 for all)",
114
115
  choices=[str(i) for i in range(len(seasons) + 1)],
115
- default="0"
116
+ default="0",
116
117
  )
117
-
118
+
118
119
  if int(choice) == 0:
119
120
  return None
120
-
121
+
121
122
  selected_season = seasons[int(choice) - 1]
122
123
  return int(Path(selected_season).name.replace("Season ", ""))
123
124
 
125
+ def onboarding(config_path):
126
+ """Prompt user for all required config values, showing existing as defaults."""
127
+ config = get_config(config_path) if config_path.exists() else {}
128
+
129
+ def ask_with_default(prompt_text, key, description, secret=False):
130
+ current = config.get(key)
131
+ if current:
132
+ console.print(f"[cyan]{key}:[/cyan] {description}")
133
+ console.print(f"Current value: [green]{mask_api_key(current) if secret else current}[/green]")
134
+ if Confirm.ask("Use existing value?", default=True):
135
+ return current
136
+ return Prompt.ask(f"Enter your {key}", default=current or "")
137
+
138
+ tmdb_api_key = ask_with_default("TMDb API key", "tmdb_api_key", "Used to lookup show and episode information. To get your API key, create an account at https://www.themoviedb.org/ and follow the instructions at https://developer.themoviedb.org/docs/getting-started", secret=True)
139
+ open_subtitles_username = ask_with_default("OpenSubtitles Username", "open_subtitles_username", "Account username for OpenSubtitles. To create an account, visit https://www.opensubtitles.com/ then click 'Register'")
140
+ open_subtitles_password = ask_with_default("OpenSubtitles Password", "open_subtitles_password", "Account password for OpenSubtitles", secret=True)
141
+ open_subtitles_user_agent = ask_with_default("OpenSubtitles Consumer Name", "open_subtitles_user_agent", "Required for subtitle downloads. Go to https://www.opensubtitles.com/en/consumers, click 'New Consumer', give it a name, then click 'Save'")
142
+ open_subtitles_api_key = ask_with_default("OpenSubtitles API key", "open_subtitles_api_key", "Required for subtitle downloads. Enter the API key linked with the OpenSubtitles Consumer that you created in the previous step.", secret=True)
143
+ show_dir = ask_with_default("Show Directory", "show_dir", "Main directory of the show")
144
+
145
+ set_config(
146
+ tmdb_api_key,
147
+ open_subtitles_api_key,
148
+ open_subtitles_user_agent,
149
+ open_subtitles_username,
150
+ open_subtitles_password,
151
+ show_dir,
152
+ config_path,
153
+ )
154
+ console.print("[bold green]Onboarding complete! Configuration saved.[/bold green]")
124
155
 
125
156
  @logger.catch
126
157
  def main():
@@ -165,7 +196,8 @@ def main():
165
196
  help="Check if GPU is available for faster processing",
166
197
  )
167
198
  parser.add_argument(
168
- "--verbose", "-v",
199
+ "--verbose",
200
+ "-v",
169
201
  action="store_true",
170
202
  help="Enable verbose output",
171
203
  )
@@ -175,22 +207,30 @@ def main():
175
207
  default=0.7,
176
208
  help="Set confidence threshold for episode matching (0.0-1.0)",
177
209
  )
178
-
210
+ parser.add_argument(
211
+ "--onboard",
212
+ action="store_true",
213
+ help="Run onboarding to set up configuration",
214
+ )
179
215
  args = parser.parse_args()
180
216
  if args.verbose:
181
217
  console.print("[bold cyan]Command-line Arguments[/bold cyan]")
182
218
  console.print(args)
183
219
  if args.check_gpu:
184
220
  from mkv_episode_matcher.utils import check_gpu_support
221
+
185
222
  with console.status("[bold green]Checking GPU support..."):
186
223
  check_gpu_support()
187
224
  return
188
225
 
189
-
190
226
  logger.debug(f"Command-line arguments: {args}")
191
-
192
- # Load configuration once
193
- config = get_config(CONFIG_FILE)
227
+ # Onboarding: run if --onboard or config file missing
228
+ if args.onboard or not CONFIG_FILE.exists():
229
+ onboarding(CONFIG_FILE)
230
+ # Reload config after onboarding
231
+ config = get_config(CONFIG_FILE)
232
+ else:
233
+ config = get_config(CONFIG_FILE)
194
234
 
195
235
  # Get TMDb API key
196
236
  tmdb_api_key = args.tmdb_api_key or config.get("tmdb_api_key")
@@ -202,49 +242,49 @@ def main():
202
242
 
203
243
  if args.get_subs:
204
244
  console.print("[bold cyan]Subtitle Download Configuration[/bold cyan]")
205
-
245
+
206
246
  tmdb_api_key = confirm_api_key(
207
- tmdb_api_key,
208
- "TMDb API key",
209
- "Used to lookup show and episode information"
247
+ tmdb_api_key, "TMDb API key", "Used to lookup show and episode information"
210
248
  )
211
-
249
+
212
250
  open_subtitles_api_key = confirm_api_key(
213
251
  open_subtitles_api_key,
214
252
  "OpenSubtitles API key",
215
- "Required for subtitle downloads"
253
+ "Required for subtitle downloads",
216
254
  )
217
-
255
+
218
256
  open_subtitles_user_agent = confirm_api_key(
219
257
  open_subtitles_user_agent,
220
258
  "OpenSubtitles User Agent",
221
- "Required for subtitle downloads"
259
+ "Required for subtitle downloads",
222
260
  )
223
-
261
+
224
262
  open_subtitles_username = confirm_api_key(
225
263
  open_subtitles_username,
226
264
  "OpenSubtitles Username",
227
- "Account username for OpenSubtitles"
265
+ "Account username for OpenSubtitles",
228
266
  )
229
-
267
+
230
268
  open_subtitles_password = confirm_api_key(
231
269
  open_subtitles_password,
232
270
  "OpenSubtitles Password",
233
- "Account password for OpenSubtitles"
271
+ "Account password for OpenSubtitles",
234
272
  )
235
273
 
236
274
  # Use config for show directory
237
275
  show_dir = args.show_dir or config.get("show_dir")
238
276
  if not show_dir:
239
277
  show_dir = Prompt.ask("Enter the main directory of the show")
240
-
278
+
241
279
  logger.info(f"Show Directory: {show_dir}")
242
280
  if not Path(show_dir).exists():
243
- console.print(f"[bold red]Error:[/bold red] Show directory '{show_dir}' does not exist.")
281
+ console.print(
282
+ f"[bold red]Error:[/bold red] Show directory '{show_dir}' does not exist."
283
+ )
244
284
  return
245
-
285
+
246
286
  if not show_dir:
247
- show_dir = os.getcwd()
287
+ show_dir = Path.cwd()
248
288
  console.print(f"Using current directory: [cyan]{show_dir}[/cyan]")
249
289
 
250
290
  logger.debug(f"Show Directory: {show_dir}")
@@ -274,25 +314,27 @@ def main():
274
314
  border_style="yellow",
275
315
  )
276
316
  )
277
-
317
+
278
318
  seasons = get_valid_seasons(show_dir)
279
319
  if not seasons:
280
- console.print("[bold red]Error:[/bold red] No seasons with .mkv files found in the show directory.")
320
+ console.print(
321
+ "[bold red]Error:[/bold red] No seasons with .mkv files found in the show directory."
322
+ )
281
323
  return
282
-
324
+
283
325
  # If season wasn't specified and there are multiple seasons, let user choose
284
326
  selected_season = args.season
285
327
  if selected_season is None and len(seasons) > 1:
286
328
  selected_season = select_season(seasons)
287
-
329
+
288
330
  # Show what's going to happen
289
331
  show_name = Path(show_dir).name
290
332
  season_text = f"Season {selected_season}" if selected_season else "all seasons"
291
-
333
+
292
334
  console.print(
293
335
  f"[bold green]Processing[/bold green] [cyan]{show_name}[/cyan], {season_text}"
294
336
  )
295
-
337
+
296
338
  # # Setup progress spinner
297
339
  # with Progress(
298
340
  # TextColumn("[bold green]Processing...[/bold green]"),
@@ -300,15 +342,15 @@ def main():
300
342
  # ) as progress:
301
343
  # task = progress.add_task("", total=None)
302
344
  process_show(
303
- selected_season,
304
- dry_run=args.dry_run,
305
- get_subs=args.get_subs,
345
+ selected_season,
346
+ dry_run=args.dry_run,
347
+ get_subs=args.get_subs,
306
348
  verbose=args.verbose,
307
- confidence=args.confidence
349
+ confidence=args.confidence,
308
350
  )
309
-
351
+
310
352
  console.print("[bold green]✓[/bold green] Processing completed successfully!")
311
-
353
+
312
354
  # Show where logs are stored
313
355
  console.print(f"\n[dim]Logs available at: {log_dir}[/dim]")
314
356
 
@@ -323,4 +365,4 @@ if __name__ == "__main__":
323
365
  except Exception as e:
324
366
  console.print(f"\n[bold red]Error:[/bold red] {str(e)}")
325
367
  logger.exception("Unhandled exception")
326
- sys.exit(1)
368
+ sys.exit(1)