mkv-episode-matcher 0.8.1__py3-none-any.whl → 0.9.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.

Potentially problematic release.


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

@@ -1,7 +1,7 @@
1
1
  # __main__.py (enhanced version)
2
2
  import argparse
3
- import os
4
3
  import sys
4
+ from pathlib import Path
5
5
  from typing import Optional
6
6
 
7
7
  from loguru import logger
@@ -20,33 +20,33 @@ console = Console()
20
20
  logger.info("Starting the application")
21
21
 
22
22
  # Check if the configuration directory exists, if not create it
23
- CONFIG_DIR = os.path.join(os.path.expanduser("~"), ".mkv-episode-matcher")
24
- if not os.path.exists(CONFIG_DIR):
25
- os.makedirs(CONFIG_DIR)
23
+ CONFIG_DIR = Path.home() / ".mkv-episode-matcher"
24
+ if not CONFIG_DIR.exists():
25
+ CONFIG_DIR.mkdir(parents=True, exist_ok=True)
26
26
 
27
27
  # Define the paths for the configuration file and cache directory
28
- CONFIG_FILE = os.path.join(CONFIG_DIR, "config.ini")
29
- CACHE_DIR = os.path.join(CONFIG_DIR, "cache")
28
+ CONFIG_FILE = CONFIG_DIR / "config.ini"
29
+ CACHE_DIR = CONFIG_DIR / "cache"
30
30
 
31
31
  # Check if the cache directory exists, if not create it
32
- if not os.path.exists(CACHE_DIR):
33
- os.makedirs(CACHE_DIR)
32
+ if not CACHE_DIR.exists():
33
+ CACHE_DIR.mkdir(parents=True, exist_ok=True)
34
34
 
35
35
  # Check if logs directory exists, if not create it
36
- log_dir = os.path.join(CONFIG_DIR, "logs")
37
- if not os.path.exists(log_dir):
38
- os.mkdir(log_dir)
36
+ log_dir = CONFIG_DIR / "logs"
37
+ if not log_dir.exists():
38
+ log_dir.mkdir(exist_ok=True)
39
39
  logger.remove()
40
40
  # Add a new handler for stdout logs
41
41
  logger.add(
42
- os.path.join(log_dir, "stdout.log"),
42
+ str(log_dir / "stdout.log"),
43
43
  format="{time} {level} {message}",
44
44
  level="INFO",
45
45
  rotation="10 MB",
46
46
  )
47
47
 
48
48
  # Add a new handler for error logs
49
- logger.add(os.path.join(log_dir, "stderr.log"), level="ERROR", rotation="10 MB")
49
+ logger.add(str(log_dir / "stderr.log"), level="ERROR", rotation="10 MB")
50
50
 
51
51
 
52
52
  def print_welcome_message():
@@ -104,7 +104,7 @@ def select_season(seasons):
104
104
  """
105
105
  console.print("[bold cyan]Available Seasons:[/bold cyan]")
106
106
  for i, season in enumerate(seasons, 1):
107
- season_num = os.path.basename(season).replace("Season ", "")
107
+ season_num = Path(season).name.replace("Season ", "")
108
108
  console.print(f" {i}. Season {season_num}")
109
109
 
110
110
  console.print(f" 0. All Seasons")
@@ -119,7 +119,7 @@ def select_season(seasons):
119
119
  return None
120
120
 
121
121
  selected_season = seasons[int(choice) - 1]
122
- return int(os.path.basename(selected_season).replace("Season ", ""))
122
+ return int(Path(selected_season).name.replace("Season ", ""))
123
123
 
124
124
 
125
125
  @logger.catch
@@ -239,7 +239,7 @@ def main():
239
239
  show_dir = Prompt.ask("Enter the main directory of the show")
240
240
 
241
241
  logger.info(f"Show Directory: {show_dir}")
242
- if not os.path.exists(show_dir):
242
+ if not Path(show_dir).exists():
243
243
  console.print(f"[bold red]Error:[/bold red] Show directory '{show_dir}' does not exist.")
244
244
  return
245
245
 
@@ -286,7 +286,7 @@ def main():
286
286
  selected_season = select_season(seasons)
287
287
 
288
288
  # Show what's going to happen
289
- show_name = os.path.basename(show_dir)
289
+ show_name = Path(show_dir).name
290
290
  season_text = f"Season {selected_season}" if selected_season else "all seasons"
291
291
 
292
292
  console.print(
@@ -1,7 +1,7 @@
1
1
  # config.py
2
2
  import configparser
3
3
  import multiprocessing
4
- import os
4
+ from pathlib import Path
5
5
 
6
6
  from loguru import logger
7
7
 
@@ -73,7 +73,7 @@ def get_config(file):
73
73
  """
74
74
  logger.info(f"Loading config from {file}")
75
75
  config = configparser.ConfigParser()
76
- if os.path.exists(file):
76
+ if Path(file).exists():
77
77
  config.read(file)
78
78
  return config["Config"] if "Config" in config else None
79
79
  return {}
@@ -1,7 +1,5 @@
1
1
  # mkv_episode_matcher/episode_matcher.py
2
2
 
3
- import glob
4
- import os
5
3
  import re
6
4
  import shutil
7
5
  from pathlib import Path
@@ -19,6 +17,7 @@ from mkv_episode_matcher.utils import (
19
17
  clean_text,
20
18
  get_subtitles,
21
19
  get_valid_seasons,
20
+ normalize_path,
22
21
  rename_episode_file,
23
22
  )
24
23
 
@@ -39,7 +38,7 @@ def process_show(season=None, dry_run=False, get_subs=False, verbose=False, conf
39
38
  """
40
39
  config = get_config(CONFIG_FILE)
41
40
  show_dir = config.get("show_dir")
42
- show_name = clean_text(os.path.basename(show_dir))
41
+ show_name = clean_text(normalize_path(show_dir).name)
43
42
  matcher = EpisodeMatcher(CACHE_DIR, show_name, min_confidence=confidence)
44
43
 
45
44
  # Early check for reference files
@@ -58,7 +57,7 @@ def process_show(season=None, dry_run=False, get_subs=False, verbose=False, conf
58
57
  return
59
58
 
60
59
  if season is not None:
61
- season_path = os.path.join(show_dir, f"Season {season}")
60
+ season_path = str(Path(show_dir) / f"Season {season}")
62
61
  if season_path not in season_paths:
63
62
  console.print(f"[bold red]Error:[/bold red] Season {season} has no .mkv files to process")
64
63
  return
@@ -69,12 +68,12 @@ def process_show(season=None, dry_run=False, get_subs=False, verbose=False, conf
69
68
 
70
69
  for season_path in season_paths:
71
70
  mkv_files = [
72
- f for f in glob.glob(os.path.join(season_path, "*.mkv"))
71
+ f for f in Path(season_path).glob("*.mkv")
73
72
  if not check_filename(f)
74
73
  ]
75
74
 
76
75
  if not mkv_files:
77
- season_num = os.path.basename(season_path).replace("Season ", "")
76
+ season_num = Path(season_path).name.replace("Season ", "")
78
77
  console.print(f"[dim]No new files to process in Season {season_num}[/dim]")
79
78
  continue
80
79
 
@@ -104,7 +103,7 @@ def process_show(season=None, dry_run=False, get_subs=False, verbose=False, conf
104
103
  task = progress.add_task(f"[cyan]Matching Season {season_num}[/cyan]", total=len(mkv_files))
105
104
 
106
105
  for mkv_file in mkv_files:
107
- file_basename = os.path.basename(mkv_file)
106
+ file_basename = Path(mkv_file).name
108
107
  progress.update(task, description=f"[cyan]Processing[/cyan] {file_basename}")
109
108
 
110
109
  if verbose:
@@ -1,5 +1,5 @@
1
- import os
2
1
  import re
2
+ from pathlib import Path
3
3
  from typing import Optional
4
4
 
5
5
 
@@ -55,8 +55,8 @@ def find_existing_subtitle(
55
55
  patterns = generate_subtitle_patterns(series_name, season, episode)
56
56
 
57
57
  for pattern in patterns:
58
- filepath = os.path.join(series_cache_dir, pattern)
59
- if os.path.exists(filepath):
58
+ filepath = Path(series_cache_dir) / pattern
59
+ if filepath.exists():
60
60
  return filepath
61
61
 
62
62
  return None
@@ -1,7 +1,8 @@
1
1
  # utils.py
2
- import os
3
2
  import re
4
3
  import shutil
4
+ import os
5
+ from pathlib import Path
5
6
 
6
7
  import requests
7
8
  import torch
@@ -16,6 +17,35 @@ from mkv_episode_matcher.subtitle_utils import find_existing_subtitle, sanitize_
16
17
  from mkv_episode_matcher.tmdb_client import fetch_season_details
17
18
 
18
19
  console = Console()
20
+
21
+
22
+ def normalize_path(path_str):
23
+ """
24
+ Normalize a path string to handle cross-platform path issues.
25
+ Properly handles trailing slashes and backslashes in both Windows and Unix paths.
26
+
27
+ Args:
28
+ path_str (str): The path string to normalize
29
+
30
+ Returns:
31
+ pathlib.Path: A normalized Path object
32
+ """
33
+ # Convert to string if it's a Path object
34
+ if isinstance(path_str, Path):
35
+ path_str = str(path_str)
36
+
37
+ # Remove trailing slashes or backslashes
38
+ path_str = path_str.rstrip('/').rstrip('\\')
39
+
40
+ # Handle Windows paths on non-Windows platforms
41
+ if os.name != 'nt' and '\\' in path_str and ':' in path_str[:2]:
42
+ # This looks like a Windows path on a non-Windows system
43
+ # Extract the last component which should be the directory/file name
44
+ components = path_str.split('\\')
45
+ return Path(components[-1])
46
+
47
+ return Path(path_str)
48
+
19
49
  def get_valid_seasons(show_dir):
20
50
  """
21
51
  Get all season directories that contain MKV files.
@@ -27,26 +57,28 @@ def get_valid_seasons(show_dir):
27
57
  list: List of paths to valid season directories
28
58
  """
29
59
  # Get all season directories
60
+ show_path = normalize_path(show_dir)
30
61
  season_paths = [
31
- os.path.join(show_dir, d)
32
- for d in os.listdir(show_dir)
33
- if os.path.isdir(os.path.join(show_dir, d))
62
+ str(show_path / d.name)
63
+ for d in show_path.iterdir()
64
+ if d.is_dir()
34
65
  ]
35
66
 
36
67
  # Filter seasons to only include those with .mkv files
37
68
  valid_season_paths = []
38
69
  for season_path in season_paths:
39
- mkv_files = [f for f in os.listdir(season_path) if f.endswith(".mkv")]
70
+ season_path_obj = Path(season_path)
71
+ mkv_files = [f for f in season_path_obj.iterdir() if f.name.endswith(".mkv")]
40
72
  if mkv_files:
41
73
  valid_season_paths.append(season_path)
42
74
 
43
75
  if not valid_season_paths:
44
76
  logger.warning(
45
- f"No seasons with .mkv files found in show '{os.path.basename(show_dir)}'"
77
+ f"No seasons with .mkv files found in show '{normalize_path(show_dir).name}'"
46
78
  )
47
79
  else:
48
80
  logger.info(
49
- f"Found {len(valid_season_paths)} seasons with .mkv files in '{os.path.basename(show_dir)}'"
81
+ f"Found {len(valid_season_paths)} seasons with .mkv files in '{normalize_path(show_dir).name}'"
50
82
  )
51
83
 
52
84
  return valid_season_paths
@@ -57,11 +89,14 @@ def check_filename(filename):
57
89
  Check if the filename is in the correct format (S01E02).
58
90
 
59
91
  Args:
60
- filename (str): The filename to check.
92
+ filename (str or Path): The filename to check.
61
93
 
62
94
  Returns:
63
95
  bool: True if the filename matches the expected pattern.
64
96
  """
97
+ # Convert Path object to string if needed
98
+ if isinstance(filename, Path):
99
+ filename = str(filename)
65
100
  # Check if the filename matches the expected format
66
101
  match = re.search(r".*S\d+E\d+", filename)
67
102
  return bool(match)
@@ -79,16 +114,14 @@ def scramble_filename(original_file_path, file_number):
79
114
  None
80
115
  """
81
116
  logger.info(f"Scrambling {original_file_path}")
82
- series_title = os.path.basename(
83
- os.path.dirname(os.path.dirname(original_file_path))
84
- )
85
- original_file_name = os.path.basename(original_file_path)
86
- extension = os.path.splitext(original_file_path)[-1]
117
+ series_title = normalize_path(original_file_path).parent.parent.name
118
+ original_file_name = Path(original_file_path).name
119
+ extension = Path(original_file_path).suffix
87
120
  new_file_name = f"{series_title} - {file_number:03d}{extension}"
88
- new_file_path = os.path.join(os.path.dirname(original_file_path), new_file_name)
89
- if not os.path.exists(new_file_path):
121
+ new_file_path = Path(original_file_path).parent / new_file_name
122
+ if not new_file_path.exists():
90
123
  logger.info(f"Renaming {original_file_name} -> {new_file_name}")
91
- os.rename(original_file_path, new_file_path)
124
+ Path(original_file_path).rename(new_file_path)
92
125
 
93
126
 
94
127
  def rename_episode_file(original_file_path, new_filename):
@@ -96,32 +129,32 @@ def rename_episode_file(original_file_path, new_filename):
96
129
  Rename an episode file with a standardized naming convention.
97
130
 
98
131
  Args:
99
- original_file_path (str): The original file path of the episode.
100
- new_filename (str): The new filename including season/episode info.
132
+ original_file_path (str or Path): The original file path of the episode.
133
+ new_filename (str or Path): The new filename including season/episode info.
101
134
 
102
135
  Returns:
103
- str: Path to the renamed file, or None if rename failed.
136
+ Path: Path to the renamed file, or None if rename failed.
104
137
  """
105
- original_dir = os.path.dirname(original_file_path)
106
- new_file_path = os.path.join(original_dir, new_filename)
138
+ original_dir = Path(original_file_path).parent
139
+ new_file_path = original_dir / new_filename
107
140
 
108
141
  # Check if new filepath already exists
109
- if os.path.exists(new_file_path):
142
+ if new_file_path.exists():
110
143
  logger.warning(f"File already exists: {new_filename}")
111
144
 
112
145
  # Add numeric suffix if file exists
113
- base, ext = os.path.splitext(new_filename)
146
+ base, ext = Path(new_filename).stem, Path(new_filename).suffix
114
147
  suffix = 2
115
148
  while True:
116
149
  new_filename = f"{base}_{suffix}{ext}"
117
- new_file_path = os.path.join(original_dir, new_filename)
118
- if not os.path.exists(new_file_path):
150
+ new_file_path = original_dir / new_filename
151
+ if not new_file_path.exists():
119
152
  break
120
153
  suffix += 1
121
154
 
122
155
  try:
123
- os.rename(original_file_path, new_file_path)
124
- logger.info(f"Renamed {os.path.basename(original_file_path)} -> {new_filename}")
156
+ Path(original_file_path).rename(new_file_path)
157
+ logger.info(f"Renamed {Path(original_file_path).name} -> {new_filename}")
125
158
  return new_file_path
126
159
  except OSError as e:
127
160
  logger.error(f"Failed to rename file: {e}")
@@ -143,7 +176,7 @@ def get_subtitles(show_id, seasons: set[int], config=None):
143
176
  if config is None:
144
177
  config = get_config(CONFIG_FILE)
145
178
  show_dir = config.get("show_dir")
146
- series_name = sanitize_filename(os.path.basename(show_dir))
179
+ series_name = sanitize_filename(normalize_path(show_dir).name)
147
180
  tmdb_api_key = config.get("tmdb_api_key")
148
181
  open_subtitles_api_key = config.get("open_subtitles_api_key")
149
182
  open_subtitles_user_agent = config.get("open_subtitles_user_agent")
@@ -175,7 +208,7 @@ def get_subtitles(show_id, seasons: set[int], config=None):
175
208
  for episode in range(1, episodes + 1):
176
209
  logger.info(f"Processing Season {season}, Episode {episode}...")
177
210
 
178
- series_cache_dir = os.path.join(CACHE_DIR, "data", series_name)
211
+ series_cache_dir = Path(CACHE_DIR) / "data" / series_name
179
212
  os.makedirs(series_cache_dir, exist_ok=True)
180
213
 
181
214
  # Check for existing subtitle in any supported format
@@ -185,15 +218,12 @@ def get_subtitles(show_id, seasons: set[int], config=None):
185
218
 
186
219
  if existing_subtitle:
187
220
  logger.info(
188
- f"Subtitle already exists: {os.path.basename(existing_subtitle)}"
221
+ f"Subtitle already exists: {Path(existing_subtitle).name}"
189
222
  )
190
223
  continue
191
224
 
192
225
  # Default to standard format for new downloads
193
- srt_filepath = os.path.join(
194
- series_cache_dir,
195
- f"{series_name} - S{season:02d}E{episode:02d}.srt",
196
- )
226
+ srt_filepath = str(series_cache_dir / f"{series_name} - S{season:02d}E{episode:02d}.srt")
197
227
 
198
228
  # get the episode info from TMDB
199
229
  url = f"https://api.themoviedb.org/3/tv/{show_id}/season/{season}/episode/{episode}?api_key={tmdb_api_key}"
@@ -241,17 +271,15 @@ def process_reference_srt_files(series_name):
241
271
  dict: A dictionary containing the reference files where the keys are the MKV filenames
242
272
  and the values are the corresponding SRT texts.
243
273
  """
244
- import os
245
-
246
274
  from mkv_episode_matcher.__main__ import CACHE_DIR
247
275
 
248
276
  reference_files = {}
249
- reference_dir = os.path.join(CACHE_DIR, "data", series_name)
277
+ reference_dir = Path(CACHE_DIR) / "data" / series_name
250
278
 
251
279
  for dirpath, _, filenames in os.walk(reference_dir):
252
280
  for filename in filenames:
253
281
  if filename.lower().endswith(".srt"):
254
- srt_file = os.path.join(dirpath, filename)
282
+ srt_file = Path(dirpath) / filename
255
283
  logger.info(f"Processing {srt_file}")
256
284
  srt_text = extract_srt_text(srt_file)
257
285
  season, episode = extract_season_episode(filename)
@@ -333,7 +361,7 @@ def process_srt_files(show_dir):
333
361
  for dirpath, _, filenames in os.walk(show_dir):
334
362
  for filename in filenames:
335
363
  if filename.lower().endswith(".srt"):
336
- srt_file = os.path.join(dirpath, filename)
364
+ srt_file = Path(dirpath) / filename
337
365
  logger.info(f"Processing {srt_file}")
338
366
  srt_text = extract_srt_text(srt_file)
339
367
  srt_files[srt_file] = srt_text
@@ -353,22 +381,20 @@ def compare_and_rename_files(srt_files, reference_files, dry_run=False):
353
381
  f"Comparing {len(srt_files)} srt files with {len(reference_files)} reference files"
354
382
  )
355
383
  for srt_text in srt_files.keys():
356
- parent_dir = os.path.dirname(os.path.dirname(srt_text))
384
+ parent_dir = Path(srt_text).parent.parent
357
385
  for reference in reference_files.keys():
358
386
  _season, _episode = extract_season_episode(reference)
359
- mkv_file = os.path.join(
360
- parent_dir, os.path.basename(srt_text).replace(".srt", ".mkv")
361
- )
387
+ mkv_file = str(parent_dir / Path(srt_text).name.replace(".srt", ".mkv"))
362
388
  matching_lines = compare_text(
363
389
  reference_files[reference], srt_files[srt_text]
364
390
  )
365
391
  if matching_lines >= int(len(reference_files[reference]) * 0.1):
366
392
  logger.info(f"Matching lines: {matching_lines}")
367
393
  logger.info(f"Found matching file: {mkv_file} ->{reference}")
368
- new_filename = os.path.join(parent_dir, reference)
394
+ new_filename = parent_dir / reference
369
395
  if not dry_run:
370
- logger.info(f"Renaming {mkv_file} to {new_filename}")
371
- rename_episode_file(mkv_file, new_filename)
396
+ logger.info(f"Renaming {mkv_file} to {str(new_filename)}")
397
+ rename_episode_file(mkv_file, reference)
372
398
 
373
399
 
374
400
  def compare_text(text1, text2):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mkv-episode-matcher
3
- Version: 0.8.1
3
+ Version: 0.9.0
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
@@ -0,0 +1,14 @@
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=tIx_lahBMvwIGC_LHYHvCP7ILNIFGyyn0Go2gyaVA-0,10006
4
+ mkv_episode_matcher/config.py,sha256=KuKxvKuOrmpCZ80mjykT6oZeD3uArsq6XPioMBrAxuU,2279
5
+ mkv_episode_matcher/episode_identification.py,sha256=xH5HIa6oC4nXhlqzdqQn1XYQFNUrnbUVlW-R9RsBHq4,16745
6
+ mkv_episode_matcher/episode_matcher.py,sha256=OHtBZd3HnLpANe7HgSvcAQIZjilWgKHVOqfju557NyA,6300
7
+ mkv_episode_matcher/subtitle_utils.py,sha256=z4eYTMAoI8BVzdCNeqHu-9mkhwG8RzxE5BbNjWUJwCg,2552
8
+ mkv_episode_matcher/tmdb_client.py,sha256=LbMCgjmp7sCbrQo_CDlpcnryKPz5S7inE24YY9Pyjk4,4172
9
+ mkv_episode_matcher/utils.py,sha256=sQ6GpP9xDJ6_BRrTSYys2xtaF-ryJpaNcXDHgLsriOg,15394
10
+ mkv_episode_matcher-0.9.0.dist-info/METADATA,sha256=mKIrCTXDbpE5dzwbOQ7yLbt3sat1zXA-vRL3WFkQlok,5384
11
+ mkv_episode_matcher-0.9.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
12
+ mkv_episode_matcher-0.9.0.dist-info/entry_points.txt,sha256=IglJ43SuCZq2eQ3shMFILCkmQASJHnDCI3ogohW2Hn4,64
13
+ mkv_episode_matcher-0.9.0.dist-info/top_level.txt,sha256=XRLbd93HUaedeWLtkyTvQjFcE5QcBRYa3V-CfHrq-OI,20
14
+ mkv_episode_matcher-0.9.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.8.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,14 +0,0 @@
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=O3GQk5R9BFuA-QNlqfBgDSS7G_W8IGSxiV8CFUbcaLc,10059
4
- mkv_episode_matcher/config.py,sha256=EcJJjkekQ7oWtarUkufCYON_QWbQvq55-zMqCTOqSa4,2265
5
- mkv_episode_matcher/episode_identification.py,sha256=xH5HIa6oC4nXhlqzdqQn1XYQFNUrnbUVlW-R9RsBHq4,16745
6
- mkv_episode_matcher/episode_matcher.py,sha256=SxAbnXuTJITD1o0WohE9heE3Fm9zW_w0Nq3GzqtcIpQ,6329
7
- mkv_episode_matcher/subtitle_utils.py,sha256=Hz9b4CKPV07YKTY4dcN3WbvdbvH-S3J4zcb9CiyvPlE,2551
8
- mkv_episode_matcher/tmdb_client.py,sha256=LbMCgjmp7sCbrQo_CDlpcnryKPz5S7inE24YY9Pyjk4,4172
9
- mkv_episode_matcher/utils.py,sha256=modXMLmt2fpny8liXwqe4ylxnwwfg_98OLOacv5izps,14501
10
- mkv_episode_matcher-0.8.1.dist-info/METADATA,sha256=JpSdL1OU5UwQb6aPARqV9YzQWtoEdmoJZkmw_7FcUwM,5384
11
- mkv_episode_matcher-0.8.1.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
12
- mkv_episode_matcher-0.8.1.dist-info/entry_points.txt,sha256=IglJ43SuCZq2eQ3shMFILCkmQASJHnDCI3ogohW2Hn4,64
13
- mkv_episode_matcher-0.8.1.dist-info/top_level.txt,sha256=XRLbd93HUaedeWLtkyTvQjFcE5QcBRYa3V-CfHrq-OI,20
14
- mkv_episode_matcher-0.8.1.dist-info/RECORD,,