Skip to content

Commit

Permalink
Merge pull request #68 from exislow/45-support-for-artist-download
Browse files Browse the repository at this point in the history
45 support for artist download
  • Loading branch information
exislow authored Mar 22, 2024
2 parents 6c3ed10 + d47517d commit efba6df
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 31 deletions.
25 changes: 12 additions & 13 deletions tidal_dl_ng/dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,19 +105,18 @@ def __init__(self, settings: Settings, settings_save: QtCore.Signal, parent=None
def _init_signals(self):
self.ui.cb_video_convert_mp4.stateChanged.connect(self.on_cb_video_convert_mp4)

def on_cb_video_convert_mp4(self, int):
if self.ui.cb_video_convert_mp4.isChecked():
# Check if ffmpeg is in PATH otherwise show error message.
if not is_installed_ffmpeg():
self.ui.cb_video_convert_mp4.setChecked(False)
self.ui.cb_video_convert_mp4.setCheckState(QtCore.Qt.CheckState.Unchecked)
QtWidgets.QMessageBox.critical(
self,
"FFmpeg not found!",
"Either FFmpeg is not installed on your computer or not set within "
"your PATH variable. You cannot activate this option until FFmpeg "
"is correctly installed and set to your environmental PATH variable.",
)
def on_cb_video_convert_mp4(self, change_status: int):
# Check if ffmpeg is in PATH otherwise show error message.
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.setCheckState(QtCore.Qt.CheckState.Unchecked)
QtWidgets.QMessageBox.critical(
self,
"FFmpeg not found!",
"Either FFmpeg is not installed on your computer or not set within "
"your PATH variable. You cannot activate this option until FFmpeg "
"is correctly installed and set to your environmental PATH variable.",
)

def _init_line_edit(self):
self.parameters_line_edit = [
Expand Down
60 changes: 49 additions & 11 deletions tidal_dl_ng/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import coloredlogs.converter
from rich.progress import Progress
from tidalapi import Album, Mix, Playlist, Quality, Track, UserPlaylist, Video
from tidalapi.artist import Artist
from tidalapi.session import SearchTypes

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

def _populate_search_types(self, ui_target: QtWidgets.QComboBox, options: SearchTypes):
for item in options:
if item and item.__name__ != "Artist":
if 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):
tree.setColumnHidden(5, True)
Expand Down Expand Up @@ -321,10 +322,14 @@ def populate_tree_results(self, results: [ResultItem], parent: QtWidgets.QTreeWi
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):
duration: str = ""

# TODO: Duration needs to be calculated later to properly fill with zeros.
# Format seconds to mm:ss.
m, s = divmod(item.duration_sec, 60)
duration: str = f"{m:02d}:{s:02d}"
if item.duration_sec > -1:
# Format seconds to mm:ss.
m, s = divmod(item.duration_sec, 60)
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)
index: str = str(item.position + 1).zfill(index_count_digits)

Expand All @@ -337,7 +342,7 @@ def populate_tree_result_child(self, item: [Track | Video | Mix | Album | Playli
child.setText(4, duration)
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.
child_dummy: QtWidgets.QTreeWidgetItem = QtWidgets.QTreeWidgetItem()

Expand Down Expand Up @@ -442,6 +447,17 @@ def search_result_to_model(self, items: [*SearchTypes]) -> [ResultItem]:
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)

return result
Expand Down Expand Up @@ -521,7 +537,7 @@ def on_list_items_show(self, item: QtWidgets.QTreeWidgetItem):

def list_items_show_result(
self,
media_list: Album | Playlist | Mix | None = None,
media_list: Album | Playlist | Mix | Artist | None = None,
point: QtCore.QPoint | None = None,
parent: QtWidgets.QTreeWidgetItem = None,
) -> None:
Expand All @@ -530,7 +546,7 @@ def list_items_show_result(
media_list = item.data(3, QtCore.Qt.ItemDataRole.UserRole)

# 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)

self.populate_tree_results(result, parent=parent)
Expand All @@ -551,10 +567,30 @@ def on_download_results(self):
if len(items) == 0:
logger_gui.error("Please select a row first.")
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

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.
download_delay: bool = bool(
isinstance(media, Track | Video)
Expand All @@ -567,7 +603,9 @@ def on_download_results(self):
self.pb_download.setText("Download")
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_statusbar_message.emit(StatusbarMessage(message="Download started..."))

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

if load_children:
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)

Expand Down
20 changes: 13 additions & 7 deletions tidal_dl_ng/helper/tidal.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from collections.abc import Callable

from tidalapi import Album, Mix, Playlist, Session, Track, UserPlaylist, Video
from tidalapi.artist import Artist, Role
from tidalapi.session import SearchTypes
Expand Down Expand Up @@ -87,21 +89,25 @@ def search_results_all(session: Session, needle: str, types_media: SearchTypes =
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
offset: int = 0
done: bool = False
result: [Track | Video] = []
result: [Track | Video | Album] = []

if isinstance(media_list, Mix):
result = media_list.items()
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:
tmp_result: [Track | Video] = (
media_list.items(limit=limit, offset=offset)
if videos_include
else media_list.tracks(limit=limit, offset=offset)
)
tmp_result: [Track | Video] = func_get_items_media(limit=limit, offset=offset)

if bool(tmp_result):
result += tmp_result
Expand Down

0 comments on commit efba6df

Please sign in to comment.