From 3171b1570be4fe5a520bda45049a50a34037fbbb Mon Sep 17 00:00:00 2001 From: Robert Honz Date: Wed, 13 Nov 2024 09:49:33 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Do=20not=20process=20tracks=20with?= =?UTF-8?q?=20missing=20segments.=20Refactored=20some=20method=20to=20`pat?= =?UTF-8?q?hlib.Path`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tidal_dl_ng/download.py | 90 +++++++++++++++++++------------------- tidal_dl_ng/helper/path.py | 12 ++--- 2 files changed, 52 insertions(+), 50 deletions(-) diff --git a/tidal_dl_ng/download.py b/tidal_dl_ng/download.py index a9348f3..98a7c75 100644 --- a/tidal_dl_ng/download.py +++ b/tidal_dl_ng/download.py @@ -92,7 +92,7 @@ class Download: self, media: Track | Video, path_file: pathlib.Path, - ) -> pathlib.Path: + ) -> (bool, pathlib.Path): media_name: str = name_builder_item(media) urls: [str] path_base: pathlib.Path = path_file.parent @@ -165,21 +165,20 @@ class Download: # mark the whole thing as corrupt. result_segments = False - # Bring list into right order, so segments can be easily merged. - dl_segment_results.sort(key=lambda x: x.id_segment) - # TODO: Implement error handling on corrupt segments (also in the following method. - reult_merge: bool = self._segments_merge(path_file, dl_segment_results) - tmp_path_file_decrypted: pathlib.Path = pathlib.Path("") + tmp_path_file_decrypted: pathlib.Path = path_file - if reult_merge: - if isinstance(media, Track) and stream_manifest.is_encrypted: + # Only if no error happened while downloading. + if result_segments: + # Bring list into right order, so segments can be easily merged. + dl_segment_results.sort(key=lambda x: x.id_segment) + reult_merge: bool = self._segments_merge(path_file, dl_segment_results) + + if reult_merge and isinstance(media, Track) and stream_manifest.is_encrypted: key, nonce = decrypt_security_token(stream_manifest.encryption_key) - tmp_path_file_decrypted = path_file + "_decrypted" + tmp_path_file_decrypted = path_file.with_suffix("_decrypted") decrypt_file(path_file, tmp_path_file_decrypted, key, nonce) - else: - tmp_path_file_decrypted = path_file - return tmp_path_file_decrypted + return result_segments, tmp_path_file_decrypted def _segments_merge(self, path_file, dl_segment_results) -> bool: result: bool @@ -229,7 +228,7 @@ class Download: except HTTPError as e: error = e self.progress.advance(p_task) - self.fn_logger.exception(e.charachter_written) + self.fn_logger.exception(e) # To send the progress to the GUI, we need to emit the percentage. if not progress_to_stdout: @@ -281,12 +280,14 @@ class Download: # Create file name and path file_extension_dummy: str = AudioExtensions.FLAC file_name_relative = format_path_media(file_template, media) - path_media_dst = os.path.abspath( - os.path.normpath(os.path.join(os.path.expanduser(self.path_base), file_name_relative)) + path_media_dst: pathlib.Path = ( + (pathlib.Path(self.path_base).expanduser() / file_name_relative).resolve().absolute() ) # Sanitize final path_file to fit into OS boundaries. - path_media_dst = path_file_sanitize(path_media_dst + file_extension_dummy, adapt=True) + path_media_dst = pathlib.Path( + path_file_sanitize(str(path_media_dst.with_suffix(file_extension_dummy)), adapt=True) + ) # Compute if and how downloads need to be skipped. if self.skip_existing: @@ -336,38 +337,39 @@ class Download: tmp_path_file.touch() # Download media. - tmp_path_file = self._download(media=media, path_file=tmp_path_file) + result_download, tmp_path_file = self._download(media=media, path_file=tmp_path_file) - # Convert video from TS to MP4 - if isinstance(media, Video) and self.settings.data.video_convert_mp4: - # Convert `*.ts` file to `*.mp4` using ffmpeg - tmp_path_file = self._video_convert(tmp_path_file) + if result_download: + # Convert video from TS to MP4 + if isinstance(media, Video) and self.settings.data.video_convert_mp4: + # Convert `*.ts` file to `*.mp4` using ffmpeg + tmp_path_file = self._video_convert(tmp_path_file) - # Extract FLAC from MP4 container using ffmpeg - if isinstance(media, Track) and self.settings.data.extract_flac and do_flac_extract: - tmp_path_file = self._extract_flac(tmp_path_file) + # Extract FLAC from MP4 container using ffmpeg + if isinstance(media, Track) and self.settings.data.extract_flac and do_flac_extract: + tmp_path_file = self._extract_flac(tmp_path_file) - tmp_path_lyrics: pathlib.Path | None = None - tmp_path_cover: pathlib.Path | None = None + tmp_path_lyrics: pathlib.Path | None = None + tmp_path_cover: pathlib.Path | None = None - # Write metadata to file. - if not isinstance(media, Video): - result_metadata, tmp_path_lyrics, tmp_path_cover = self.metadata_write( - media, tmp_path_file, is_parent_album - ) + # Write metadata to file. + if not isinstance(media, Video): + result_metadata, tmp_path_lyrics, tmp_path_cover = self.metadata_write( + media, tmp_path_file, is_parent_album + ) + + # Move lyrics file + if self.settings.data.lyrics_file and not isinstance(media, Video): + self._move_lyrics(tmp_path_lyrics, path_media_dst) + + # Move cover file + if self.settings.data.cover_album_file: + self._move_cover(tmp_path_cover, path_media_dst) # Move final file to the configured destination directory. - os.makedirs(os.path.dirname(path_media_dst), exist_ok=True) + os.makedirs(path_media_dst.parent, exist_ok=True) shutil.move(tmp_path_file, path_media_dst) - # Move lyrics file - if self.settings.data.lyrics_file and not isinstance(media, Video): - self._move_lyrics(tmp_path_lyrics, path_media_dst) - - # Move cover file - if self.settings.data.cover_album_file: - self._move_cover(tmp_path_cover, path_media_dst) - if quality_audio: # Set quality back to the global user value self.adjust_quality_audio(quality_audio_old) @@ -418,16 +420,16 @@ class Download: return result - def _move_lyrics(self, path_lyrics: pathlib.Path, file_media_dst: str) -> bool: + def _move_lyrics(self, path_lyrics: pathlib.Path, file_media_dst: pathlib.Path) -> bool: # Build tmp lyrics filename - path_file_lyrics: str = os.path.splitext(file_media_dst)[0] + EXTENSION_LYRICS + path_file_lyrics: pathlib.Path = file_media_dst.with_suffix(EXTENSION_LYRICS) result: bool = self._move_file(path_lyrics, path_file_lyrics) return result - def _move_cover(self, path_cover: pathlib.Path, file_media_dst: str) -> bool: + def _move_cover(self, path_cover: pathlib.Path, file_media_dst: pathlib.Path) -> bool: # Build tmp lyrics filename - path_file_cover: pathlib.Path = pathlib.Path(file_media_dst).parent.absolute() / COVER_NAME + path_file_cover: pathlib.Path = file_media_dst.parent / COVER_NAME result: bool = self._move_file(path_cover, path_file_cover) return result diff --git a/tidal_dl_ng/helper/path.py b/tidal_dl_ng/helper/path.py index e6f5b14..627f7c1 100644 --- a/tidal_dl_ng/helper/path.py +++ b/tidal_dl_ng/helper/path.py @@ -1,9 +1,9 @@ import math import os +import pathlib import posixpath import re import sys -from pathlib import Path, PosixPath from urllib.parse import unquote, urlsplit from pathvalidate import sanitize_filename, sanitize_filepath @@ -197,7 +197,7 @@ def get_format_template( def path_file_sanitize(path_file: str, adapt: bool = False, uniquify: bool = False) -> (bool, str): # Split into path and filename pathname, filename = os.path.split(path_file) - file_extension: str = Path(path_file).suffix + file_extension: str = pathlib.Path(path_file).suffix # Sanitize path try: @@ -207,7 +207,7 @@ def path_file_sanitize(path_file: str, adapt: bool = False, uniquify: bool = Fal except ValidationError: # If adaption of path is allowed in case of an error set path to HOME. if adapt: - pathname_sanitized: str = Path.home() + pathname_sanitized: str = str(pathlib.Path.home()) else: raise @@ -274,10 +274,10 @@ def file_unique_suffix(path_file: str, seperator: str = "_") -> str: return unique_suffix -def check_file_exists(path_file: str, extension_ignore: bool = False) -> bool: +def check_file_exists(path_file: pathlib.Path, extension_ignore: bool = False) -> bool: if extension_ignore: - path_file_stem: str = Path(path_file).stem - path_parent: PosixPath = Path(path_file).parent + path_file_stem: str = pathlib.Path(path_file).stem + path_parent: pathlib.Path = pathlib.Path(path_file).parent path_files: [str] = [] for extension in AudioExtensions: