refactor(gui): ✨ Enhance type annotations and improve method signatures
* Updated type hints for various methods in and classes. * Changed list types from to for better clarity and consistency. * Improved function signatures to include return types for better type safety.
This commit is contained in:
+32
-32
@@ -57,7 +57,7 @@ from tidal_dl_ng.model.gui_data import ProgressBars
|
|||||||
class RequestsClient:
|
class RequestsClient:
|
||||||
def download(
|
def download(
|
||||||
self, uri: str, timeout: int = REQUESTS_TIMEOUT_SEC, headers: dict | None = None, verify_ssl: bool = True
|
self, uri: str, timeout: int = REQUESTS_TIMEOUT_SEC, headers: dict | None = None, verify_ssl: bool = True
|
||||||
):
|
) -> tuple[str, str]:
|
||||||
if not headers:
|
if not headers:
|
||||||
headers = {}
|
headers = {}
|
||||||
|
|
||||||
@@ -84,12 +84,12 @@ class Download:
|
|||||||
path_base: str,
|
path_base: str,
|
||||||
fn_logger: Callable,
|
fn_logger: Callable,
|
||||||
skip_existing: bool = False,
|
skip_existing: bool = False,
|
||||||
progress_gui: ProgressBars = None,
|
progress_gui: ProgressBars | None = None,
|
||||||
progress: Progress = None,
|
progress: Progress | None = None,
|
||||||
progress_overall: Progress = None,
|
progress_overall: Progress | None = None,
|
||||||
event_abort: Event = None,
|
event_abort: Event | None = None,
|
||||||
event_run: Event = None,
|
event_run: Event | None = None,
|
||||||
):
|
) -> None:
|
||||||
self.settings = Settings()
|
self.settings = Settings()
|
||||||
self.session = session
|
self.session = session
|
||||||
self.skip_existing = skip_existing
|
self.skip_existing = skip_existing
|
||||||
@@ -118,12 +118,12 @@ class Download:
|
|||||||
media: Track | Video,
|
media: Track | Video,
|
||||||
path_file: pathlib.Path,
|
path_file: pathlib.Path,
|
||||||
stream_manifest: StreamManifest | None = None,
|
stream_manifest: StreamManifest | None = None,
|
||||||
) -> (bool, pathlib.Path):
|
) -> tuple[bool, pathlib.Path]:
|
||||||
media_name: str = name_builder_item(media)
|
media_name: str = name_builder_item(media)
|
||||||
urls: [str]
|
urls: list[str]
|
||||||
path_base: pathlib.Path = path_file.parent
|
path_base: pathlib.Path = path_file.parent
|
||||||
result_segments: bool = True
|
result_segments: bool = True
|
||||||
dl_segment_results: [DownloadSegmentResult] = []
|
dl_segment_results: list[DownloadSegmentResult] = []
|
||||||
result_merge: bool = False
|
result_merge: bool = False
|
||||||
|
|
||||||
# Get urls for media.
|
# Get urls for media.
|
||||||
@@ -179,7 +179,7 @@ class Download:
|
|||||||
max_workers=self.settings.data.downloads_simultaneous_per_track_max
|
max_workers=self.settings.data.downloads_simultaneous_per_track_max
|
||||||
) as executor:
|
) as executor:
|
||||||
# Dispatch all download tasks to worker threads
|
# Dispatch all download tasks to worker threads
|
||||||
l_futures: [futures.Future] = [
|
l_futures: list[futures.Future] = [
|
||||||
executor.submit(self._download_segment, url, path_base, block_size, p_task, progress_to_stdout)
|
executor.submit(self._download_segment, url, path_base, block_size, p_task, progress_to_stdout)
|
||||||
for url in urls
|
for url in urls
|
||||||
]
|
]
|
||||||
@@ -225,7 +225,7 @@ class Download:
|
|||||||
|
|
||||||
return result_merge, tmp_path_file_decrypted
|
return result_merge, tmp_path_file_decrypted
|
||||||
|
|
||||||
def _segments_merge(self, path_file, dl_segment_results) -> bool:
|
def _segments_merge(self, path_file: pathlib.Path, dl_segment_results: list[DownloadSegmentResult]) -> bool:
|
||||||
result: bool = True
|
result: bool = True
|
||||||
|
|
||||||
# Copy the content of all segments into one file.
|
# Copy the content of all segments into one file.
|
||||||
@@ -298,7 +298,7 @@ class Download:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def extension_guess(
|
def extension_guess(
|
||||||
self, quality_audio: Quality, metadata_tags: [str], is_video: bool
|
self, quality_audio: Quality, metadata_tags: list[str], is_video: bool
|
||||||
) -> AudioExtensions | VideoExtensions:
|
) -> AudioExtensions | VideoExtensions:
|
||||||
result: AudioExtensions | VideoExtensions
|
result: AudioExtensions | VideoExtensions
|
||||||
|
|
||||||
@@ -321,9 +321,9 @@ class Download:
|
|||||||
def item(
|
def item(
|
||||||
self,
|
self,
|
||||||
file_template: str,
|
file_template: str,
|
||||||
media: Track | Video = None,
|
media: Track | Video | None = None,
|
||||||
media_id: str = None,
|
media_id: str | None = None,
|
||||||
media_type: MediaType = None,
|
media_type: MediaType | None = None,
|
||||||
video_download: bool = True,
|
video_download: bool = True,
|
||||||
download_delay: bool = False,
|
download_delay: bool = False,
|
||||||
quality_audio: Quality | None = None,
|
quality_audio: Quality | None = None,
|
||||||
@@ -331,7 +331,7 @@ class Download:
|
|||||||
is_parent_album: bool = False,
|
is_parent_album: bool = False,
|
||||||
list_position: int = 0,
|
list_position: int = 0,
|
||||||
list_total: int = 0,
|
list_total: int = 0,
|
||||||
) -> (bool, pathlib.Path):
|
) -> tuple[bool, pathlib.Path | str]:
|
||||||
try:
|
try:
|
||||||
if media_id and media_type:
|
if media_id and media_type:
|
||||||
# If no media instance is provided, we need to create the media instance.
|
# If no media instance is provided, we need to create the media instance.
|
||||||
@@ -557,14 +557,14 @@ class Download:
|
|||||||
|
|
||||||
return path_media_dst
|
return path_media_dst
|
||||||
|
|
||||||
def adjust_quality_audio(self, quality) -> Quality:
|
def adjust_quality_audio(self, quality: Quality) -> Quality:
|
||||||
# Save original quality settings
|
# Save original quality settings
|
||||||
quality_old: Quality = self.session.audio_quality
|
quality_old: Quality = self.session.audio_quality
|
||||||
self.session.audio_quality = quality
|
self.session.audio_quality = quality
|
||||||
|
|
||||||
return quality_old
|
return quality_old
|
||||||
|
|
||||||
def adjust_quality_video(self, quality) -> QualityVideo:
|
def adjust_quality_video(self, quality: QualityVideo) -> QualityVideo:
|
||||||
quality_old: QualityVideo = self.settings.data.quality_video
|
quality_old: QualityVideo = self.settings.data.quality_video
|
||||||
|
|
||||||
self.settings.data.quality_video = quality
|
self.settings.data.quality_video = quality
|
||||||
@@ -618,7 +618,7 @@ class Download:
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def cover_data(url: str = None, path_file: str = None) -> str | bytes:
|
def cover_data(url: str | None = None, path_file: str | None = None) -> str | bytes:
|
||||||
result: str | bytes = ""
|
result: str | bytes = ""
|
||||||
|
|
||||||
if url:
|
if url:
|
||||||
@@ -642,7 +642,7 @@ class Download:
|
|||||||
|
|
||||||
def metadata_write(
|
def metadata_write(
|
||||||
self, track: Track, path_media: pathlib.Path, is_parent_album: bool, media_stream: Stream
|
self, track: Track, path_media: pathlib.Path, is_parent_album: bool, media_stream: Stream
|
||||||
) -> (bool, pathlib.Path | None, pathlib.Path | None):
|
) -> tuple[bool, pathlib.Path | None, pathlib.Path | None]:
|
||||||
result: bool = False
|
result: bool = False
|
||||||
path_lyrics: pathlib.Path | None = None
|
path_lyrics: pathlib.Path | None = None
|
||||||
path_cover: pathlib.Path | None = None
|
path_cover: pathlib.Path | None = None
|
||||||
@@ -713,14 +713,14 @@ class Download:
|
|||||||
def items(
|
def items(
|
||||||
self,
|
self,
|
||||||
file_template: str,
|
file_template: str,
|
||||||
media: Album | Playlist | UserPlaylist | Mix = None,
|
media: Album | Playlist | UserPlaylist | Mix | None = None,
|
||||||
media_id: str = None,
|
media_id: str | None = None,
|
||||||
media_type: MediaType = None,
|
media_type: MediaType | None = None,
|
||||||
video_download: bool = False,
|
video_download: bool = False,
|
||||||
download_delay: bool = True,
|
download_delay: bool = True,
|
||||||
quality_audio: Quality | None = None,
|
quality_audio: Quality | None = None,
|
||||||
quality_video: QualityVideo | None = None,
|
quality_video: QualityVideo | None = None,
|
||||||
):
|
) -> None:
|
||||||
try:
|
try:
|
||||||
if media_id and media_type:
|
if media_id and media_type:
|
||||||
# If no media instance is provided, we need to create the media instance.
|
# If no media instance is provided, we need to create the media instance.
|
||||||
@@ -765,14 +765,14 @@ class Download:
|
|||||||
is_album: bool = isinstance(media, Album)
|
is_album: bool = isinstance(media, Album)
|
||||||
# TODO: Refactor strings to constants (also in cfg.py)
|
# TODO: Refactor strings to constants (also in cfg.py)
|
||||||
sort_by_track_num: bool = bool("album_track_num" in file_name_relative or "list_pos" in file_name_relative)
|
sort_by_track_num: bool = bool("album_track_num" in file_name_relative or "list_pos" in file_name_relative)
|
||||||
result_dirs: [pathlib.Path] = []
|
result_dirs: list[pathlib.Path] = []
|
||||||
list_total: int = len(items)
|
list_total: int = len(items)
|
||||||
|
|
||||||
# Iterate through list items
|
# Iterate through list items
|
||||||
while not progress.finished:
|
while not progress.finished:
|
||||||
with futures.ThreadPoolExecutor(max_workers=self.settings.data.downloads_concurrent_max) as executor:
|
with futures.ThreadPoolExecutor(max_workers=self.settings.data.downloads_concurrent_max) as executor:
|
||||||
# Dispatch all download tasks to worker threads
|
# Dispatch all download tasks to worker threads
|
||||||
l_futures: [futures.Future] = [
|
l_futures: list[futures.Future] = [
|
||||||
executor.submit(
|
executor.submit(
|
||||||
self.item,
|
self.item,
|
||||||
media=item_media,
|
media=item_media,
|
||||||
@@ -817,9 +817,9 @@ class Download:
|
|||||||
self.fn_logger.info(f"Finished list '{list_media_name}'.")
|
self.fn_logger.info(f"Finished list '{list_media_name}'.")
|
||||||
|
|
||||||
def playlist_populate(
|
def playlist_populate(
|
||||||
self, dirs_scoped: [pathlib.Path], name_list: str, is_album: bool, sort_alphabetically
|
self, dirs_scoped: set[pathlib.Path], name_list: str, is_album: bool, sort_alphabetically: bool
|
||||||
) -> [pathlib.Path]:
|
) -> list[pathlib.Path]:
|
||||||
result: [pathlib.Path] = []
|
result: list[pathlib.Path] = []
|
||||||
|
|
||||||
# For each dir, which contains tracks
|
# For each dir, which contains tracks
|
||||||
for dir_scoped in dirs_scoped:
|
for dir_scoped in dirs_scoped:
|
||||||
@@ -830,7 +830,7 @@ class Download:
|
|||||||
self.fn_logger.debug(f"Playlist: Creating {path_playlist}")
|
self.fn_logger.debug(f"Playlist: Creating {path_playlist}")
|
||||||
|
|
||||||
# Get all tracks in the directory
|
# Get all tracks in the directory
|
||||||
path_tracks: [pathlib.Path] = []
|
path_tracks: list[pathlib.Path] = []
|
||||||
|
|
||||||
for extension_audio in AudioExtensions:
|
for extension_audio in AudioExtensions:
|
||||||
path_tracks = path_tracks + list(dir_scoped.glob(f"*{extension_audio!s}"))
|
path_tracks = path_tracks + list(dir_scoped.glob(f"*{extension_audio!s}"))
|
||||||
@@ -889,7 +889,7 @@ class Download:
|
|||||||
|
|
||||||
return path_media_out
|
return path_media_out
|
||||||
|
|
||||||
def _extract_video_stream(self, m3u8_variant: m3u8.M3U8, quality: int) -> (m3u8.M3U8 | bool, str):
|
def _extract_video_stream(self, m3u8_variant: m3u8.M3U8, quality: int) -> tuple[m3u8.M3U8 | bool, str]:
|
||||||
m3u8_playlist: m3u8.M3U8 | bool = False
|
m3u8_playlist: m3u8.M3U8 | bool = False
|
||||||
resolution_best: int = 0
|
resolution_best: int = 0
|
||||||
mime_type: str = ""
|
mime_type: str = ""
|
||||||
|
|||||||
+17
-17
@@ -326,7 +326,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
def handle_filter_activated(self) -> None:
|
def handle_filter_activated(self) -> None:
|
||||||
"""Handle activation of filter headers in the results tree."""
|
"""Handle activation of filter headers in the results tree."""
|
||||||
header = self.tr_results.header()
|
header = self.tr_results.header()
|
||||||
filters: list[str] = []
|
filters: list[tuple[int, str]] = []
|
||||||
for i in range(header.count()):
|
for i in range(header.count()):
|
||||||
text: str = header.filter_text(i)
|
text: str = header.filter_text(i)
|
||||||
|
|
||||||
@@ -369,7 +369,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
Args:
|
Args:
|
||||||
model (QStandardItemModel): The model to initialize.
|
model (QStandardItemModel): The model to initialize.
|
||||||
"""
|
"""
|
||||||
labels_column: [str] = ["#", "obj", "Artist", "Title", "Album", "Duration", "Quality", "Date"]
|
labels_column: list[str] = ["#", "obj", "Artist", "Title", "Album", "Duration", "Quality", "Date"]
|
||||||
|
|
||||||
model.setColumnCount(len(labels_column))
|
model.setColumnCount(len(labels_column))
|
||||||
model.setRowCount(0)
|
model.setRowCount(0)
|
||||||
@@ -404,7 +404,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
"""Populate the user lists tree with playlists, mixes, and favorites.
|
"""Populate the user lists tree with playlists, mixes, and favorites.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
user_lists (list): List of user playlists, mixes, and favorites.
|
user_lists (list[Playlist | UserPlaylist | Mix]): List of user playlists, mixes, and favorites.
|
||||||
"""
|
"""
|
||||||
twi_playlists: QtWidgets.QTreeWidgetItem = self.tr_lists_user.findItems(
|
twi_playlists: QtWidgets.QTreeWidgetItem = self.tr_lists_user.findItems(
|
||||||
TidalLists.Playlists, QtCore.Qt.MatchExactly, 0
|
TidalLists.Playlists, QtCore.Qt.MatchExactly, 0
|
||||||
@@ -612,7 +612,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
"""Download all media items in a selected list.
|
"""Download all media items in a selected list.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
point (QPoint, optional): The point in the tree. Defaults to None.
|
point (QPoint | None, optional): The point in the tree. Defaults to None.
|
||||||
"""
|
"""
|
||||||
items: list[QtWidgets.QTreeWidgetItem] = []
|
items: list[QtWidgets.QTreeWidgetItem] = []
|
||||||
|
|
||||||
@@ -733,12 +733,12 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
self.apply_settings(self.settings)
|
self.apply_settings(self.settings)
|
||||||
self._init_dl()
|
self._init_dl()
|
||||||
|
|
||||||
def search(self, query: str, types_media: Any) -> list[ResultItem]:
|
def search(self, query: str, types_media: list[Any]) -> list[ResultItem]:
|
||||||
"""Perform a search and return a list of ResultItems.
|
"""Perform a search and return a list of ResultItems.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
query (str): The search query.
|
query (str): The search query.
|
||||||
types_media (SearchTypes): The types of media to search for.
|
types_media (list[Any]): The types of media to search for.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list[ResultItem]: The search results.
|
list[ResultItem]: The search results.
|
||||||
@@ -759,7 +759,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
result_search = {"direct": [media]}
|
result_search = {"direct": [media]}
|
||||||
else:
|
else:
|
||||||
result_search: dict[str, [SearchTypes]] = search_results_all(
|
result_search: dict[str, list[SearchTypes]] = search_results_all(
|
||||||
session=self.tidal.session, needle=query, types_media=types_media
|
session=self.tidal.session, needle=query, types_media=types_media
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -780,7 +780,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
Returns:
|
Returns:
|
||||||
list[ResultItem]: List of ResultItem models.
|
list[ResultItem]: List of ResultItem models.
|
||||||
"""
|
"""
|
||||||
result = []
|
result: list[ResultItem] = []
|
||||||
|
|
||||||
for idx, item in enumerate(items):
|
for idx, item in enumerate(items):
|
||||||
result_item = self._to_result_item(idx, item)
|
result_item = self._to_result_item(idx, item)
|
||||||
@@ -1288,16 +1288,16 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
self,
|
self,
|
||||||
media_list: Album | Playlist | Mix | Artist | None = None,
|
media_list: Album | Playlist | Mix | Artist | None = None,
|
||||||
point: QtCore.QPoint | None = None,
|
point: QtCore.QPoint | None = None,
|
||||||
parent: QtGui.QStandardItem = None,
|
parent: QtGui.QStandardItem | None = None,
|
||||||
favorite_function: Callable = None,
|
favorite_function: Callable | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Populate the results tree with the items of a media list.
|
"""Populate the results tree with the items of a media list.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
media_list (Album | Playlist | Mix | Artist | None, optional): The media list to show. Defaults to None.
|
media_list (Album | Playlist | Mix | Artist | None, optional): The media list to show. Defaults to None.
|
||||||
point (QPoint | None, optional): The point in the tree. Defaults to None.
|
point (QPoint | None, optional): The point in the tree. Defaults to None.
|
||||||
parent (QStandardItem, optional): Parent item for nested results. Defaults to None.
|
parent (QStandardItem | None, optional): Parent item for nested results. Defaults to None.
|
||||||
favorite_function (Callable, optional): Function to fetch favorite items. Defaults to None.
|
favorite_function (Callable | None, optional): Function to fetch favorite items. Defaults to None.
|
||||||
"""
|
"""
|
||||||
if point:
|
if point:
|
||||||
item = self.tr_lists_user.itemAt(point)
|
item = self.tr_lists_user.itemAt(point)
|
||||||
@@ -1308,9 +1308,9 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
if isinstance(media_list, str):
|
if isinstance(media_list, str):
|
||||||
favorite_function = favorite_function_factory(self.tidal, media_list)
|
favorite_function = favorite_function_factory(self.tidal, media_list)
|
||||||
|
|
||||||
media_items: [Track | Video | Album] = favorite_function()
|
media_items: list[Track | Video | Album] = favorite_function()
|
||||||
else:
|
else:
|
||||||
media_items: [Track | Video | Album] = items_results_all(media_list)
|
media_items: list[Track | Video | Album] = items_results_all(media_list)
|
||||||
|
|
||||||
result: list[ResultItem] = self.search_result_to_model(media_items)
|
result: list[ResultItem] = self.search_result_to_model(media_items)
|
||||||
|
|
||||||
@@ -1346,7 +1346,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
Args:
|
Args:
|
||||||
regex (str): Regular expression to match items.
|
regex (str): Regular expression to match items.
|
||||||
"""
|
"""
|
||||||
items: [QtWidgets.QTreeWidgetItem | None] = self.tr_queue_download.findItems(
|
items: list[QtWidgets.QTreeWidgetItem | None] = self.tr_queue_download.findItems(
|
||||||
regex, QtCore.Qt.MatchFlag.MatchRegularExpression, column=0
|
regex, QtCore.Qt.MatchFlag.MatchRegularExpression, column=0
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1355,7 +1355,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
def on_queue_download_remove(self) -> None:
|
def on_queue_download_remove(self) -> None:
|
||||||
"""Remove selected items from the download queue."""
|
"""Remove selected items from the download queue."""
|
||||||
items: [QtWidgets.QTreeWidgetItem | None] = self.tr_queue_download.selectedItems()
|
items: list[QtWidgets.QTreeWidgetItem | None] = self.tr_queue_download.selectedItems()
|
||||||
|
|
||||||
if len(items) == 0:
|
if len(items) == 0:
|
||||||
logger_gui.error("Please select an item from the queue first.")
|
logger_gui.error("Please select an item from the queue first.")
|
||||||
@@ -1439,7 +1439,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
handling_app: HandlingApp = HandlingApp()
|
handling_app: HandlingApp = HandlingApp()
|
||||||
|
|
||||||
while not handling_app.event_abort.is_set():
|
while not handling_app.event_abort.is_set():
|
||||||
items: [QtWidgets.QTreeWidgetItem | None] = self.tr_queue_download.findItems(
|
items: list[QtWidgets.QTreeWidgetItem | None] = self.tr_queue_download.findItems(
|
||||||
QueueDownloadStatus.Waiting, QtCore.Qt.MatchFlag.MatchExactly, column=0
|
QueueDownloadStatus.Waiting, QtCore.Qt.MatchFlag.MatchExactly, column=0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user