Merge pull request #68 from exislow/45-support-for-artist-download

45 support for artist download
This commit is contained in:
exislow
2024-03-22 18:19:49 +01:00
committed by GitHub
3 changed files with 74 additions and 31 deletions
+2 -3
View File
@@ -105,10 +105,9 @@ class DialogPreferences(QtWidgets.QDialog):
def _init_signals(self): def _init_signals(self):
self.ui.cb_video_convert_mp4.stateChanged.connect(self.on_cb_video_convert_mp4) self.ui.cb_video_convert_mp4.stateChanged.connect(self.on_cb_video_convert_mp4)
def on_cb_video_convert_mp4(self, int): def on_cb_video_convert_mp4(self, change_status: int):
if self.ui.cb_video_convert_mp4.isChecked():
# Check if ffmpeg is in PATH otherwise show error message. # Check if ffmpeg is in PATH otherwise show error message.
if not is_installed_ffmpeg(): if self.ui.cb_video_convert_mp4.isChecked() and not is_installed_ffmpeg():
self.ui.cb_video_convert_mp4.setChecked(False) self.ui.cb_video_convert_mp4.setChecked(False)
self.ui.cb_video_convert_mp4.setCheckState(QtCore.Qt.CheckState.Unchecked) self.ui.cb_video_convert_mp4.setCheckState(QtCore.Qt.CheckState.Unchecked)
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
+46 -8
View File
@@ -30,6 +30,7 @@ except ImportError as e:
import coloredlogs.converter import coloredlogs.converter
from rich.progress import Progress from rich.progress import Progress
from tidalapi import Album, Mix, Playlist, Quality, Track, UserPlaylist, Video from tidalapi import Album, Mix, Playlist, Quality, Track, UserPlaylist, Video
from tidalapi.artist import Artist
from tidalapi.session import SearchTypes from tidalapi.session import SearchTypes
from tidal_dl_ng.config import Settings, Tidal from tidal_dl_ng.config import Settings, Tidal
@@ -178,10 +179,10 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def _populate_search_types(self, ui_target: QtWidgets.QComboBox, options: SearchTypes): def _populate_search_types(self, ui_target: QtWidgets.QComboBox, options: SearchTypes):
for item in options: for item in options:
if item and item.__name__ != "Artist": if item:
ui_target.addItem(item.__name__, item) ui_target.addItem(item.__name__, item)
self.cb_search_type.setCurrentIndex(1) self.cb_search_type.setCurrentIndex(2)
def _init_tree_results(self, tree: QtWidgets.QTableWidget): def _init_tree_results(self, tree: QtWidgets.QTableWidget):
tree.setColumnHidden(5, True) tree.setColumnHidden(5, True)
@@ -321,10 +322,14 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
self.s_tr_results_add_top_level_item.emit(child) self.s_tr_results_add_top_level_item.emit(child)
def populate_tree_result_child(self, item: [Track | Video | Mix | Album | Playlist], index_count_digits: int): def populate_tree_result_child(self, item: [Track | Video | Mix | Album | Playlist], index_count_digits: int):
duration: str = ""
# TODO: Duration needs to be calculated later to properly fill with zeros. # TODO: Duration needs to be calculated later to properly fill with zeros.
if item.duration_sec > -1:
# Format seconds to mm:ss. # Format seconds to mm:ss.
m, s = divmod(item.duration_sec, 60) m, s = divmod(item.duration_sec, 60)
duration: str = f"{m:02d}:{s:02d}" duration: str = f"{m:02d}:{s:02d}"
# Since sorting happens only by string, we need to pad the index and add 1 (to avoid start at 0) # Since sorting happens only by string, we need to pad the index and add 1 (to avoid start at 0)
index: str = str(item.position + 1).zfill(index_count_digits) index: str = str(item.position + 1).zfill(index_count_digits)
@@ -337,7 +342,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
child.setText(4, duration) child.setText(4, duration)
child.setData(5, QtCore.Qt.ItemDataRole.UserRole, item.obj) child.setData(5, QtCore.Qt.ItemDataRole.UserRole, item.obj)
if isinstance(item.obj, Mix | Playlist | Album): if isinstance(item.obj, Mix | Playlist | Album | Artist):
# Add a disabled dummy child, so expansion arrow will appear. This Child will be replaced on expansion. # Add a disabled dummy child, so expansion arrow will appear. This Child will be replaced on expansion.
child_dummy: QtWidgets.QTreeWidgetItem = QtWidgets.QTreeWidgetItem() child_dummy: QtWidgets.QTreeWidgetItem = QtWidgets.QTreeWidgetItem()
@@ -442,6 +447,17 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
obj=item, obj=item,
) )
result.append(result_item)
elif isinstance(item, Artist):
result_item: ResultItem = ResultItem(
position=idx,
artist=item.name,
title="",
album="",
duration_sec=-1,
obj=item,
)
result.append(result_item) result.append(result_item)
return result return result
@@ -521,7 +537,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def list_items_show_result( def list_items_show_result(
self, self,
media_list: Album | Playlist | Mix | None = None, media_list: Album | Playlist | Mix | Artist | None = None,
point: QtCore.QPoint | None = None, point: QtCore.QPoint | None = None,
parent: QtWidgets.QTreeWidgetItem = None, parent: QtWidgets.QTreeWidgetItem = None,
) -> None: ) -> None:
@@ -530,7 +546,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
media_list = item.data(3, QtCore.Qt.ItemDataRole.UserRole) media_list = item.data(3, QtCore.Qt.ItemDataRole.UserRole)
# Get all results # Get all results
media_items: [Track | Video] = items_results_all(media_list) media_items: [Track | Video | Album] = items_results_all(media_list)
result: [ResultItem] = self.search_result_to_model(media_items) result: [ResultItem] = self.search_result_to_model(media_items)
self.populate_tree_results(result, parent=parent) self.populate_tree_results(result, parent=parent)
@@ -551,10 +567,30 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
if len(items) == 0: if len(items) == 0:
logger_gui.error("Please select a row first.") logger_gui.error("Please select a row first.")
else: else:
# If it is an artist resolve it with all available albums of him
if len(items) == 1:
tmp_media: QtWidgets.QTreeWidgetItem = items[0].data(5, QtCore.Qt.ItemDataRole.UserRole)
if isinstance(tmp_media, Artist):
tmp_children: [QtWidgets.QTreeWidgetItem] = []
is_dummy_child = not bool(items[0].child(0).data(5, QtCore.Qt.ItemDataRole.UserRole))
# Use the expand function to retrieve all albums.
if is_dummy_child:
self.on_tr_results_expanded(items[0])
count_children: int = items[0].childCount()
# Get all children.
for idx in range(count_children):
tmp_children.append(items[0].child(idx))
items: [Album] = tmp_children
items_pos_last = len(items) - 1 items_pos_last = len(items) - 1
for item in items: for item in items:
media: Track | Album | Playlist | Video = item.data(5, QtCore.Qt.ItemDataRole.UserRole) media: Track | Album | Playlist | Video | Artist = item.data(5, QtCore.Qt.ItemDataRole.UserRole)
# Skip only if Track item, skip option set and the item is not the last in the list. # Skip only if Track item, skip option set and the item is not the last in the list.
download_delay: bool = bool( download_delay: bool = bool(
isinstance(media, Track | Video) isinstance(media, Track | Video)
@@ -567,7 +603,9 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
self.pb_download.setText("Download") self.pb_download.setText("Download")
self.pb_download.setEnabled(True) self.pb_download.setEnabled(True)
def download(self, media: Track | Album | Playlist | Video | Mix, dl: Download, delay_track: bool = False) -> None: def download(
self, media: Track | Album | Playlist | Video | Mix | Artist, dl: Download, delay_track: bool = False
) -> None:
self.s_pb_reset.emit() self.s_pb_reset.emit()
self.s_statusbar_message.emit(StatusbarMessage(message="Download started...")) self.s_statusbar_message.emit(StatusbarMessage(message="Download started..."))
@@ -597,7 +635,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
if load_children: if load_children:
list_item.removeChild(list_item.child(0)) list_item.removeChild(list_item.child(0))
media_list: [Mix | Album | Playlist] = list_item.data(5, QtCore.Qt.ItemDataRole.UserRole) media_list: [Mix | Album | Playlist | Artist] = list_item.data(5, QtCore.Qt.ItemDataRole.UserRole)
self.list_items_show_result(media_list=media_list, parent=list_item) self.list_items_show_result(media_list=media_list, parent=list_item)
+13 -7
View File
@@ -1,3 +1,5 @@
from collections.abc import Callable
from tidalapi import Album, Mix, Playlist, Session, Track, UserPlaylist, Video from tidalapi import Album, Mix, Playlist, Session, Track, UserPlaylist, Video
from tidalapi.artist import Artist, Role from tidalapi.artist import Artist, Role
from tidalapi.session import SearchTypes from tidalapi.session import SearchTypes
@@ -87,21 +89,25 @@ def search_results_all(session: Session, needle: str, types_media: SearchTypes =
return result return result
def items_results_all(media_list: [Mix | Playlist | Album], videos_include: bool = True) -> [Track | Video]: def items_results_all(media_list: [Mix | Playlist | Album], videos_include: bool = True) -> [Track | Video | Album]:
limit: int = 100 limit: int = 100
offset: int = 0 offset: int = 0
done: bool = False done: bool = False
result: [Track | Video] = [] result: [Track | Video | Album] = []
if isinstance(media_list, Mix): if isinstance(media_list, Mix):
result = media_list.items() result = media_list.items()
else: else:
if isinstance(media_list, Playlist | Album):
if videos_include:
func_get_items_media: Callable = media_list.items
else:
func_get_items_media: Callable = media_list.tracks
else:
func_get_items_media: Callable = media_list.get_albums
while not done: while not done:
tmp_result: [Track | Video] = ( tmp_result: [Track | Video] = func_get_items_media(limit=limit, offset=offset)
media_list.items(limit=limit, offset=offset)
if videos_include
else media_list.tracks(limit=limit, offset=offset)
)
if bool(tmp_result): if bool(tmp_result):
result += tmp_result result += tmp_result