Skip to content

Commit efba6df

Browse files
authored
Merge pull request #68 from exislow/45-support-for-artist-download
45 support for artist download
2 parents 6c3ed10 + d47517d commit efba6df

File tree

3 files changed

+74
-31
lines changed

3 files changed

+74
-31
lines changed

tidal_dl_ng/dialog.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -105,19 +105,18 @@ def __init__(self, settings: Settings, settings_save: QtCore.Signal, parent=None
105105
def _init_signals(self):
106106
self.ui.cb_video_convert_mp4.stateChanged.connect(self.on_cb_video_convert_mp4)
107107

108-
def on_cb_video_convert_mp4(self, int):
109-
if self.ui.cb_video_convert_mp4.isChecked():
110-
# Check if ffmpeg is in PATH otherwise show error message.
111-
if not is_installed_ffmpeg():
112-
self.ui.cb_video_convert_mp4.setChecked(False)
113-
self.ui.cb_video_convert_mp4.setCheckState(QtCore.Qt.CheckState.Unchecked)
114-
QtWidgets.QMessageBox.critical(
115-
self,
116-
"FFmpeg not found!",
117-
"Either FFmpeg is not installed on your computer or not set within "
118-
"your PATH variable. You cannot activate this option until FFmpeg "
119-
"is correctly installed and set to your environmental PATH variable.",
120-
)
108+
def on_cb_video_convert_mp4(self, change_status: int):
109+
# Check if ffmpeg is in PATH otherwise show error message.
110+
if self.ui.cb_video_convert_mp4.isChecked() and not is_installed_ffmpeg():
111+
self.ui.cb_video_convert_mp4.setChecked(False)
112+
self.ui.cb_video_convert_mp4.setCheckState(QtCore.Qt.CheckState.Unchecked)
113+
QtWidgets.QMessageBox.critical(
114+
self,
115+
"FFmpeg not found!",
116+
"Either FFmpeg is not installed on your computer or not set within "
117+
"your PATH variable. You cannot activate this option until FFmpeg "
118+
"is correctly installed and set to your environmental PATH variable.",
119+
)
121120

122121
def _init_line_edit(self):
123122
self.parameters_line_edit = [

tidal_dl_ng/gui.py

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import coloredlogs.converter
3131
from rich.progress import Progress
3232
from tidalapi import Album, Mix, Playlist, Quality, Track, UserPlaylist, Video
33+
from tidalapi.artist import Artist
3334
from tidalapi.session import SearchTypes
3435

3536
from tidal_dl_ng.config import Settings, Tidal
@@ -178,10 +179,10 @@ def _populate_quality(self, ui_target: QtWidgets.QComboBox, options: type[Qualit
178179

179180
def _populate_search_types(self, ui_target: QtWidgets.QComboBox, options: SearchTypes):
180181
for item in options:
181-
if item and item.__name__ != "Artist":
182+
if item:
182183
ui_target.addItem(item.__name__, item)
183184

184-
self.cb_search_type.setCurrentIndex(1)
185+
self.cb_search_type.setCurrentIndex(2)
185186

186187
def _init_tree_results(self, tree: QtWidgets.QTableWidget):
187188
tree.setColumnHidden(5, True)
@@ -321,10 +322,14 @@ def populate_tree_results(self, results: [ResultItem], parent: QtWidgets.QTreeWi
321322
self.s_tr_results_add_top_level_item.emit(child)
322323

323324
def populate_tree_result_child(self, item: [Track | Video | Mix | Album | Playlist], index_count_digits: int):
325+
duration: str = ""
326+
324327
# TODO: Duration needs to be calculated later to properly fill with zeros.
325-
# Format seconds to mm:ss.
326-
m, s = divmod(item.duration_sec, 60)
327-
duration: str = f"{m:02d}:{s:02d}"
328+
if item.duration_sec > -1:
329+
# Format seconds to mm:ss.
330+
m, s = divmod(item.duration_sec, 60)
331+
duration: str = f"{m:02d}:{s:02d}"
332+
328333
# Since sorting happens only by string, we need to pad the index and add 1 (to avoid start at 0)
329334
index: str = str(item.position + 1).zfill(index_count_digits)
330335

@@ -337,7 +342,7 @@ def populate_tree_result_child(self, item: [Track | Video | Mix | Album | Playli
337342
child.setText(4, duration)
338343
child.setData(5, QtCore.Qt.ItemDataRole.UserRole, item.obj)
339344

340-
if isinstance(item.obj, Mix | Playlist | Album):
345+
if isinstance(item.obj, Mix | Playlist | Album | Artist):
341346
# Add a disabled dummy child, so expansion arrow will appear. This Child will be replaced on expansion.
342347
child_dummy: QtWidgets.QTreeWidgetItem = QtWidgets.QTreeWidgetItem()
343348

@@ -442,6 +447,17 @@ def search_result_to_model(self, items: [*SearchTypes]) -> [ResultItem]:
442447
obj=item,
443448
)
444449

450+
result.append(result_item)
451+
elif isinstance(item, Artist):
452+
result_item: ResultItem = ResultItem(
453+
position=idx,
454+
artist=item.name,
455+
title="",
456+
album="",
457+
duration_sec=-1,
458+
obj=item,
459+
)
460+
445461
result.append(result_item)
446462

447463
return result
@@ -521,7 +537,7 @@ def on_list_items_show(self, item: QtWidgets.QTreeWidgetItem):
521537

522538
def list_items_show_result(
523539
self,
524-
media_list: Album | Playlist | Mix | None = None,
540+
media_list: Album | Playlist | Mix | Artist | None = None,
525541
point: QtCore.QPoint | None = None,
526542
parent: QtWidgets.QTreeWidgetItem = None,
527543
) -> None:
@@ -530,7 +546,7 @@ def list_items_show_result(
530546
media_list = item.data(3, QtCore.Qt.ItemDataRole.UserRole)
531547

532548
# Get all results
533-
media_items: [Track | Video] = items_results_all(media_list)
549+
media_items: [Track | Video | Album] = items_results_all(media_list)
534550
result: [ResultItem] = self.search_result_to_model(media_items)
535551

536552
self.populate_tree_results(result, parent=parent)
@@ -551,10 +567,30 @@ def on_download_results(self):
551567
if len(items) == 0:
552568
logger_gui.error("Please select a row first.")
553569
else:
570+
# If it is an artist resolve it with all available albums of him
571+
if len(items) == 1:
572+
tmp_media: QtWidgets.QTreeWidgetItem = items[0].data(5, QtCore.Qt.ItemDataRole.UserRole)
573+
574+
if isinstance(tmp_media, Artist):
575+
tmp_children: [QtWidgets.QTreeWidgetItem] = []
576+
is_dummy_child = not bool(items[0].child(0).data(5, QtCore.Qt.ItemDataRole.UserRole))
577+
578+
# Use the expand function to retrieve all albums.
579+
if is_dummy_child:
580+
self.on_tr_results_expanded(items[0])
581+
582+
count_children: int = items[0].childCount()
583+
584+
# Get all children.
585+
for idx in range(count_children):
586+
tmp_children.append(items[0].child(idx))
587+
588+
items: [Album] = tmp_children
589+
554590
items_pos_last = len(items) - 1
555591

556592
for item in items:
557-
media: Track | Album | Playlist | Video = item.data(5, QtCore.Qt.ItemDataRole.UserRole)
593+
media: Track | Album | Playlist | Video | Artist = item.data(5, QtCore.Qt.ItemDataRole.UserRole)
558594
# Skip only if Track item, skip option set and the item is not the last in the list.
559595
download_delay: bool = bool(
560596
isinstance(media, Track | Video)
@@ -567,7 +603,9 @@ def on_download_results(self):
567603
self.pb_download.setText("Download")
568604
self.pb_download.setEnabled(True)
569605

570-
def download(self, media: Track | Album | Playlist | Video | Mix, dl: Download, delay_track: bool = False) -> None:
606+
def download(
607+
self, media: Track | Album | Playlist | Video | Mix | Artist, dl: Download, delay_track: bool = False
608+
) -> None:
571609
self.s_pb_reset.emit()
572610
self.s_statusbar_message.emit(StatusbarMessage(message="Download started..."))
573611

@@ -597,7 +635,7 @@ def on_tr_results_expanded(self, list_item: QtWidgets.QTreeWidgetItem) -> None:
597635

598636
if load_children:
599637
list_item.removeChild(list_item.child(0))
600-
media_list: [Mix | Album | Playlist] = list_item.data(5, QtCore.Qt.ItemDataRole.UserRole)
638+
media_list: [Mix | Album | Playlist | Artist] = list_item.data(5, QtCore.Qt.ItemDataRole.UserRole)
601639

602640
self.list_items_show_result(media_list=media_list, parent=list_item)
603641

tidal_dl_ng/helper/tidal.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from collections.abc import Callable
2+
13
from tidalapi import Album, Mix, Playlist, Session, Track, UserPlaylist, Video
24
from tidalapi.artist import Artist, Role
35
from tidalapi.session import SearchTypes
@@ -87,21 +89,25 @@ def search_results_all(session: Session, needle: str, types_media: SearchTypes =
8789
return result
8890

8991

90-
def items_results_all(media_list: [Mix | Playlist | Album], videos_include: bool = True) -> [Track | Video]:
92+
def items_results_all(media_list: [Mix | Playlist | Album], videos_include: bool = True) -> [Track | Video | Album]:
9193
limit: int = 100
9294
offset: int = 0
9395
done: bool = False
94-
result: [Track | Video] = []
96+
result: [Track | Video | Album] = []
9597

9698
if isinstance(media_list, Mix):
9799
result = media_list.items()
98100
else:
101+
if isinstance(media_list, Playlist | Album):
102+
if videos_include:
103+
func_get_items_media: Callable = media_list.items
104+
else:
105+
func_get_items_media: Callable = media_list.tracks
106+
else:
107+
func_get_items_media: Callable = media_list.get_albums
108+
99109
while not done:
100-
tmp_result: [Track | Video] = (
101-
media_list.items(limit=limit, offset=offset)
102-
if videos_include
103-
else media_list.tracks(limit=limit, offset=offset)
104-
)
110+
tmp_result: [Track | Video] = func_get_items_media(limit=limit, offset=offset)
105111

106112
if bool(tmp_result):
107113
result += tmp_result

0 commit comments

Comments
 (0)