diff --git a/src/tscut/cutting.py b/src/tscut/cutting.py index f97875b..f9a52eb 100644 --- a/src/tscut/cutting.py +++ b/src/tscut/cutting.py @@ -18,7 +18,7 @@ import hexdump from tqdm import tqdm from typeguard import typechecked -from tscut.exceptions import InvalidMediaError +from tscut.exceptions import InvalidMediaError, TemporaryFileError from tscut.h264.avc import get_avc_config_from_h264 from tscut.matroska.codec import dump_codec_private_data from tscut.models import CutResult, PreparedMedia, ProcessingOptions @@ -82,8 +82,7 @@ def concatenate_h264_ts_parts(h264_ts_parts: Sequence[TextIO], output: TextIO) - logger.debug('Parsing file: %s. Offset=%d', part, offset) isheader = part.readline() if (not isheader) or (isheader != header): - logger.error('Impossible to find a valid header: "%s"', isheader) - exit(-1) + raise InvalidMediaError(f"Impossible to find a valid header: {isheader}") while True: line = part.readline() if not line: @@ -128,14 +127,14 @@ def cut_recording(media: PreparedMedia, options: ProcessingOptions, head_frames = get_nearest_iframe(options.tools_paths['ffprobe'], media.movie, ts1, before=False) if head_frames is None: - raise InvalidMediaError("Impossible to retrieve first I-frame") + raise InvalidMediaError(f"Impossible to retrieve first I-frame") # Get the nearest I-frame whose timestamp ... # TODO: wrong here ... tail_frames = get_nearest_iframe(options.tools_paths['ffprobe'], media.movie, ts2, before=True) if tail_frames is None: - raise InvalidMediaError("Impossible to retrieve last I-frame") + raise InvalidMediaError(f"Impossible to retrieve last I-frame") nb_head_frames, head_iframe = head_frames nb_tail_frames, tail_iframe = tail_frames @@ -147,10 +146,10 @@ def cut_recording(media: PreparedMedia, options: ProcessingOptions, head_iframe_ts = get_ts_frame(head_iframe) if head_iframe_ts is None: - raise InvalidMediaError("Impossible to retrieve timestamp of first i-frame.") + raise InvalidMediaError(f"Impossible to retrieve timestamp of first i-frame.") tail_iframe_ts = get_ts_frame(tail_iframe) if tail_iframe_ts is None: - raise InvalidMediaError("Impossible to retrieve timestamp of final i-frame.") + raise InvalidMediaError(f"Impossible to retrieve timestamp of final i-frame.") checks.append(pos+head_iframe_ts-ts1) @@ -211,26 +210,22 @@ def cut_recording(media: PreparedMedia, options: ProcessingOptions, try: internal_mkv = open(internal_mkv_name, 'wb+') except OSError: - logger.error('Impossible to create file: %s', internal_mkv_name) - exit(-1) + raise TemporaryFileError(f"Impossible to create file: {internal_mkv_name}") try: internal_novideo_mkv = open(internal_novideo_mkv_name, 'wb+') except OSError: - logger.error('Impossible to create file: %s', internal_novideo_mkv_name) - exit(-1) + raise TemporaryFileError(f"Impossible to create file: {internal_novideo_mkv_name}") try: internal_h264 = open(internal_h264_name, 'wb+') except OSError: - logger.error('Impossible to create file: %s', internal_h264_name) - exit(-1) + raise TemporaryFileError(f"Impossible to create file: {internal_h264_name}") try: internal_h264_ts = open(internal_h264_ts_name, 'w+', encoding='utf8') except OSError: - logger.error('Impossible to create file: %s', internal_h264_ts_name) - exit(-1) + raise TemporaryFileError(f"Impossible to create file: {internal_h264_ts_name}") # logger.info('Merge header, middle and trailer subpart into: %s' % internal_mkv_name) # Extract internal part of MKV @@ -302,8 +297,7 @@ def cut_recording(media: PreparedMedia, options: ProcessingOptions, try: full_h264 = open(f'{media.basename}-full.h264', 'wb+') except OSError: - logger.error('Impossible to create file full H264 stream.') - exit(-1) + raise TemporaryFileError(f"Impossible to create file full H264 stream.") logger.info('Merging all H264 tracks') concatenate_h264_parts(h264parts=h264parts, output=full_h264) @@ -312,8 +306,7 @@ def cut_recording(media: PreparedMedia, options: ProcessingOptions, try: full_h264_ts = open(f'{media.basename}-ts.txt', 'w+', encoding='utf8') except OSError: - logger.error('Impossible to create file containing all video timestamps.') - exit(-1) + raise TemporaryFileError(f"Impossible to create file containing all video timestamps.") logger.info('Merging H264 timestamps') concatenate_h264_ts_parts(h264_ts_parts=h264_ts, output=full_h264_ts) @@ -336,8 +329,7 @@ def cut_recording(media: PreparedMedia, options: ProcessingOptions, try: final_novideo = open(final_novideo_name, 'rb') except OSError: - logger.error('Impossible to open file: %s.', final_novideo_name) - exit(-1) + raise TemporaryFileError(f"Impossible to open file: {final_novideo_name}") temporaries.append(final_novideo) diff --git a/src/tscut/exceptions.py b/src/tscut/exceptions.py index bad3b3e..11e56e3 100644 --- a/src/tscut/exceptions.py +++ b/src/tscut/exceptions.py @@ -14,9 +14,11 @@ class MissingToolError(TSCutError): class ExternalToolError(TSCutError): """Raised when an external tool fails.""" - class InvalidMediaError(TSCutError): """Raised when input media cannot be processed.""" +class TemporaryFileError(TSCutError): + """Raised when the manipulation of temporary file goes wrong""" + class UnimplementedFeatureError(TSCutError): """Raised when a rare feature is encountered and not yet implemented""" diff --git a/src/tscut/pipeline.py b/src/tscut/pipeline.py index 64ab874..afbd9ad 100644 --- a/src/tscut/pipeline.py +++ b/src/tscut/pipeline.py @@ -13,6 +13,7 @@ from typing import IO, Any, BinaryIO import hexdump from tscut.cutting import cut_recording +from tscut.exceptions import InvalidMediaError from tscut.h264.avc import parse_codec_private from tscut.matroska.codec import dump_codec_private_data from tscut.models import PreparedMedia, ProcessingOptions, SupportedFormat @@ -32,6 +33,16 @@ from tscut.tools.mkvtoolnix import ( logger = logging.getLogger(__name__) + +def detect_supported_format(format_name: str) -> SupportedFormat: + for media_format in SupportedFormat: + if format_name == str(media_format): + return media_format + + raise InvalidMediaError( + f"Unsupported media format: {format_name}" + ) + def process_recording(options: ProcessingOptions) -> None: nb_parts = len(options.parts) temporaries : list[IO[Any]] = [] @@ -50,7 +61,12 @@ def process_recording(options: ProcessingOptions) -> None: format_of_file = get_format(options.tools_paths['ffprobe'], input_file) if format_of_file is None: - exit(-1) + raise InvalidMediaError(f"Impossible to retrieve format of file: {input_file}") + if 'format_name' not in format_of_file: + raise InvalidMediaError(f"Impossible to retrieve format of file: {input_file}") + if 'duration' not in format_of_file: + raise InvalidMediaError(f"Impossible to retrieve duration of file: {input_file}") + format_name = format_of_file['format_name'] duration = timedelta(seconds=float(format_of_file['duration'])) logger.info("Durée de l'enregistrement: %s", duration) @@ -58,23 +74,13 @@ def process_recording(options: ProcessingOptions) -> None: if options.framerate is None: framerate = get_frame_rate(options.tools_paths['ffprobe'], input_file) if framerate is None: - logger.error('Impossible to estimate frame rate !') - exit(-1) + raise InvalidMediaError('Impossible to estimate frame rate !') else: framerate = options.framerate logger.info('Frame rate: %.1f fps', framerate) - found = False - for f in SupportedFormat: - if 'format_name' in format_of_file: - if format_of_file['format_name'] == str(f): - found = True - final_format_of_file = f - break - - if not found: - logger.error('Unsupported format of file') + final_format_of_file = detect_supported_format(format_name) mkv: BinaryIO