Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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