-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathVerifications.py
317 lines (264 loc) · 9.96 KB
/
Verifications.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
"""
:mod:`pymkv.Verifications` module provides functions for validating files, paths and MKVToolNix executables.
This module contains utilities for:
- Validating file paths and existence
- Verifying MKVToolNix installation and availability
- Checking Matroska file format compatibility
- Getting detailed media file information
Examples
--------
Basic path verification::
>>> from pymkv.Verifications import checking_file_path
>>> file_path = checking_file_path("path/to/file.mkv")
>>> print(f"Valid file path: {file_path}")
Checking MKVToolNix availability::
>>> from pymkv.Verifications import verify_mkvmerge
>>> if verify_mkvmerge("mkvmerge"):
... print("MKVToolNix is ready to use")
Full file verification::
>>> from pymkv.Verifications import verify_matroska, verify_supported
>>> file_path = "path/to/file.mkv"
>>> if verify_matroska(file_path, "mkvmerge"):
... if verify_supported(file_path):
... print("File is a valid and supported Matroska file")
See Also
--------
:class:`pymkv.MKVFile`
The main class for working with MKV files
:class:`pymkv.MKVTrack`
Class for handling individual MKV tracks
"""
from __future__ import annotations
import json
import os
import subprocess as sp
from collections.abc import Iterable, Sequence
from pathlib import Path
from re import match
from typing import Any
from pymkv.utils import prepare_mkvtoolnix_path
def checking_file_path(file_path: str | os.PathLike[Any] | None) -> str:
"""Check if a file path exists and is valid.
Parameters
----------
file_path : str | os.PathLike[Any] | None
The path to the file that needs to be checked.
Returns
-------
str
The resolved and expanded file path if it exists.
Raises
------
TypeError
If the provided file path is not of type str or PathLike.
FileNotFoundError
If the file path does not exist.
"""
if not isinstance(file_path, (str, os.PathLike)):
msg = f'"{file_path}" is not of type str'
raise TypeError(msg)
file_path = Path(file_path).expanduser()
if not file_path.is_file():
msg = f'"{file_path}" does not exist'
raise FileNotFoundError(msg)
return str(file_path)
def get_file_info(
file_path: str | os.PathLike[Any],
mkvmerge_path: str | os.PathLike | Iterable[str],
check_path: bool = True,
) -> dict[str, Any]:
"""Get information about a media file using mkvmerge.
Parameters
----------
file_path : str | os.PathLike[Any]
The path to the media file to analyze.
mkvmerge_path : str | os.PathLike | Iterable[str]
The path to the mkvmerge executable or a list of command parts.
check_path : bool, optional
Whether to check and validate the file path. Defaults to True.
Returns
-------
dict[str, Any]
A dictionary containing the parsed JSON output from mkvmerge,
which includes detailed information about the media file.
Raises
------
subprocess.CalledProcessError
If mkvmerge fails to execute or returns a non-zero exit status.
json.JSONDecodeError
If the output from mkvmerge cannot be parsed as JSON.
FileNotFoundError
If check_path is True and the file does not exist.
TypeError
If check_path is True and file_path is not a string or PathLike object.
"""
if check_path:
file_path = checking_file_path(file_path)
cmds = [*prepare_mkvtoolnix_path(mkvmerge_path), "-J", file_path]
return json.loads(sp.check_output(cmds).decode()) # noqa: S603
def verify_mkvmerge(
mkvmerge_path: str | os.PathLike | Iterable[str] = "mkvmerge",
) -> bool:
"""Verify if mkvmerge is available at the specified path.
Parameters
----------
mkvmerge_path : str | os.PathLike | Iterable[str], optional
The path to the mkvmerge executable. Defaults to "mkvmerge".
Returns
-------
bool
True if mkvmerge is available at the specified path, False otherwise.
"""
try:
mkvmerge_command = list(prepare_mkvtoolnix_path(mkvmerge_path))
mkvmerge_command.append("-V")
output = sp.check_output(mkvmerge_command).decode() # noqa: S603
except (sp.CalledProcessError, FileNotFoundError):
return False
return bool(match("mkvmerge.*", output))
def verify_matroska(
file_path: str | os.PathLike[Any],
mkvmerge_path: str | os.PathLike | Iterable[str] = "mkvmerge",
) -> bool:
"""Verify if a file is a valid Matroska file.
Parameters
----------
file_path : str | os.PathLike[Any]
The path to the Matroska file to be verified.
mkvmerge_path : str | os.PathLike | Iterable[str], optional
The path to the mkvmerge executable. Defaults to "mkvmerge".
Returns
-------
bool
True if the file is a valid Matroska file, False otherwise.
Raises
------
FileNotFoundError
If mkvmerge executable is not found at the specified path.
TypeError
If file_path is not a string or PathLike object.
FileNotFoundError
If the specified file_path does not exist.
ValueError
If the file_path could not be opened using mkvmerge.
Notes
-----
This function verifies the validity of a Matroska file by checking if it is of type "Matroska"
using the mkvmerge command-line tool.
"""
if not verify_mkvmerge(mkvmerge_path=mkvmerge_path):
msg = "mkvmerge is not at the specified path, add it there or change the mkvmerge_path property"
raise FileNotFoundError(msg)
try:
if isinstance(mkvmerge_path, Sequence) and not isinstance(mkvmerge_path, str):
mkvmerge_path = tuple(mkvmerge_path)
info_json: dict[str, Any] = get_file_info(file_path, mkvmerge_path)
except sp.CalledProcessError as e:
msg = f'"{file_path}" could not be opened'
raise ValueError(msg) from e
return info_json["container"]["type"] == "Matroska"
def verify_file_path_and_mkvmerge(
file_path: str | os.PathLike[Any],
mkvmerge_path: str | os.PathLike | Iterable[str] = "mkvmerge",
) -> str:
"""Verify both the file path and mkvmerge availability.
Parameters
----------
file_path : str | os.PathLike[Any]
The path to the file that needs to be verified.
mkvmerge_path : str | os.PathLike | Iterable[str], optional
The path to the mkvmerge executable. Defaults to "mkvmerge".
Returns
-------
str
The verified file path.
Raises
------
FileNotFoundError
If mkvmerge is not found at the specified path or if the file_path does not exist.
TypeError
If the file_path is not of type str or PathLike.
Notes
-----
This function combines the verification of both the file path and mkvmerge availability
in a single call, which is useful when both checks are needed.
"""
if not verify_mkvmerge(mkvmerge_path=mkvmerge_path):
msg = "mkvmerge is not at the specified path, add it there or change the mkvmerge_path property"
raise FileNotFoundError(msg)
return checking_file_path(file_path)
def verify_recognized(
file_path: str | os.PathLike[Any],
mkvmerge_path: str | os.PathLike | Iterable[str] = "mkvmerge",
) -> bool:
"""Verify if the file format is recognized by mkvmerge.
Parameters
----------
file_path : str | os.PathLike[Any]
The path to the file that will be verified.
mkvmerge_path : str | os.PathLike | Iterable[str], optional
The path to the mkvmerge executable. Defaults to "mkvmerge".
Returns
-------
bool
True if the container format of the file is recognized by mkvmerge, False otherwise.
Raises
------
ValueError
If the file cannot be opened or an error occurs during verification.
FileNotFoundError
If mkvmerge is not found at the specified path.
TypeError
If file_path is not of type str or PathLike.
Notes
-----
This function checks if mkvmerge can recognize the container format of the specified file,
which is a prerequisite for any further operations with the file.
"""
file_path = verify_file_path_and_mkvmerge(file_path, mkvmerge_path)
try:
if isinstance(mkvmerge_path, list):
mkvmerge_path = tuple(mkvmerge_path)
info_json = get_file_info(file_path, mkvmerge_path, check_path=False)
except sp.CalledProcessError as e:
msg = f'"{file_path}" could not be opened'
raise ValueError(msg) from e
return info_json["container"]["recognized"]
def verify_supported(
file_path: str | os.PathLike[Any],
mkvmerge_path: str | os.PathLike | Iterable[str] = "mkvmerge",
) -> bool:
"""Verify if the file format is supported by mkvmerge.
Parameters
----------
file_path : str | os.PathLike[Any]
The path to the file that will be verified.
mkvmerge_path : str | os.PathLike | Iterable[str], optional
The path to the mkvmerge executable. Defaults to "mkvmerge".
Returns
-------
bool
True if the container format of the file is supported by mkvmerge, False otherwise.
Raises
------
ValueError
If the file cannot be opened or an error occurs during verification.
FileNotFoundError
If mkvmerge is not found at the specified path.
TypeError
If file_path is not of type str or PathLike.
Notes
-----
This function checks if mkvmerge can fully support the container format of the specified file.
A file might be recognized but not fully supported for all operations.
"""
mkvmerge_path = prepare_mkvtoolnix_path(mkvmerge_path)
fp = verify_file_path_and_mkvmerge(file_path, mkvmerge_path)
try:
if isinstance(mkvmerge_path, list):
mkvmerge_path = tuple(mkvmerge_path)
info_json = get_file_info(fp, mkvmerge_path, check_path=False)
except sp.CalledProcessError as e:
msg = f'"{file_path}" could not be opened'
raise ValueError(msg) from e
return info_json["container"]["supported"]