test
This commit is contained in:
201
tidal_dl_ng/helper/gui.py
Normal file
201
tidal_dl_ng/helper/gui.py
Normal file
@ -0,0 +1,201 @@
|
||||
import re
|
||||
|
||||
from PySide6 import QtCore, QtGui, QtWidgets
|
||||
from tidalapi import Album, Mix, Playlist, Track, UserPlaylist, Video
|
||||
from tidalapi.artist import Artist
|
||||
from tidalapi.media import Quality
|
||||
|
||||
|
||||
def get_table_data(
|
||||
item: QtWidgets.QTreeWidgetItem, column: int
|
||||
) -> Track | Video | Album | Artist | Mix | Playlist | UserPlaylist:
|
||||
result: Track | Video | Album | Artist = item.data(column, QtCore.Qt.ItemDataRole.UserRole)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def get_table_text(item: QtWidgets.QTreeWidgetItem, column: int) -> str:
|
||||
result: str = item.text(column)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def get_results_media_item(
|
||||
index: QtCore.QModelIndex, proxy: QtCore.QSortFilterProxyModel, model: QtGui.QStandardItemModel
|
||||
) -> Track | Video | Album | Artist | Playlist | Mix:
|
||||
# Switch column to "obj" column and map proxy data to our model.
|
||||
item: QtGui.QStandardItem = model.itemFromIndex(proxy.mapToSource(index.siblingAtColumn(1)))
|
||||
result: Track | Video | Album | Artist = item.data(QtCore.Qt.ItemDataRole.UserRole)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def get_user_list_media_item(item: QtWidgets.QTreeWidgetItem) -> Mix | Playlist | UserPlaylist:
|
||||
result: Mix | Playlist | UserPlaylist = get_table_data(item, 1)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def get_queue_download_media(
|
||||
item: QtWidgets.QTreeWidgetItem,
|
||||
) -> Mix | Playlist | UserPlaylist | Track | Video | Album | Artist:
|
||||
result: Mix | Playlist | UserPlaylist | Track | Video | Album | Artist = get_table_data(item, 1)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def get_queue_download_quality(
|
||||
item: QtWidgets.QTreeWidgetItem,
|
||||
) -> Quality:
|
||||
result: Quality = get_table_text(item, 4)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def set_table_data(
|
||||
item: QtWidgets.QTreeWidgetItem, data: Track | Video | Album | Artist | Mix | Playlist | UserPlaylist, column: int
|
||||
):
|
||||
item.setData(column, QtCore.Qt.ItemDataRole.UserRole, data)
|
||||
|
||||
|
||||
def set_results_media(item: QtWidgets.QTreeWidgetItem, media: Track | Video | Album | Artist):
|
||||
set_table_data(item, media, 1)
|
||||
|
||||
|
||||
def set_user_list_media(
|
||||
item: QtWidgets.QTreeWidgetItem, media: Track | Video | Album | Artist | Mix | Playlist | UserPlaylist
|
||||
):
|
||||
set_table_data(item, media, 1)
|
||||
|
||||
|
||||
def set_queue_download_media(
|
||||
item: QtWidgets.QTreeWidgetItem, media: Mix | Playlist | UserPlaylist | Track | Video | Album | Artist
|
||||
):
|
||||
set_table_data(item, media, 1)
|
||||
|
||||
|
||||
class FilterHeader(QtWidgets.QHeaderView):
|
||||
filter_activated = QtCore.Signal()
|
||||
|
||||
def __init__(self, parent):
|
||||
super().__init__(QtCore.Qt.Horizontal, parent)
|
||||
self._editors = []
|
||||
self._padding = 4
|
||||
self.setCascadingSectionResizes(True)
|
||||
self.setSectionResizeMode(QtWidgets.QHeaderView.Interactive)
|
||||
self.setStretchLastSection(True)
|
||||
self.setDefaultAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
self.setSortIndicatorShown(False)
|
||||
self.setSectionsMovable(True)
|
||||
self.sectionResized.connect(self.adjust_positions)
|
||||
parent.horizontalScrollBar().valueChanged.connect(self.adjust_positions)
|
||||
|
||||
def set_filter_boxes(self, count):
|
||||
while self._editors:
|
||||
editor = self._editors.pop()
|
||||
editor.deleteLater()
|
||||
|
||||
for _ in range(count):
|
||||
editor = QtWidgets.QLineEdit(self.parent())
|
||||
editor.setPlaceholderText("Filter")
|
||||
editor.setClearButtonEnabled(True)
|
||||
editor.returnPressed.connect(self.filter_activated.emit)
|
||||
self._editors.append(editor)
|
||||
|
||||
self.adjust_positions()
|
||||
|
||||
def sizeHint(self):
|
||||
size = super().sizeHint()
|
||||
|
||||
if self._editors:
|
||||
height = self._editors[0].sizeHint().height()
|
||||
|
||||
size.setHeight(size.height() + height + self._padding)
|
||||
|
||||
return size
|
||||
|
||||
def updateGeometries(self):
|
||||
if self._editors:
|
||||
height = self._editors[0].sizeHint().height()
|
||||
|
||||
self.setViewportMargins(0, 0, 0, height + self._padding)
|
||||
else:
|
||||
self.setViewportMargins(0, 0, 0, 0)
|
||||
|
||||
super().updateGeometries()
|
||||
self.adjust_positions()
|
||||
|
||||
def adjust_positions(self):
|
||||
for index, editor in enumerate(self._editors):
|
||||
height = editor.sizeHint().height()
|
||||
|
||||
editor.move(self.sectionPosition(index) - self.offset() + 2, height + (self._padding // 2))
|
||||
editor.resize(self.sectionSize(index), height)
|
||||
|
||||
def filter_text(self, index) -> str:
|
||||
if 0 <= index < len(self._editors):
|
||||
return self._editors[index].text()
|
||||
|
||||
return ""
|
||||
|
||||
def set_filter_text(self, index, text):
|
||||
if 0 <= index < len(self._editors):
|
||||
self._editors[index].setText(text)
|
||||
|
||||
def clear_filters(self):
|
||||
for editor in self._editors:
|
||||
editor.clear()
|
||||
|
||||
|
||||
class HumanProxyModel(QtCore.QSortFilterProxyModel):
|
||||
def _human_key(self, key):
|
||||
parts = re.split(r"(\d*\.\d+|\d+)", key)
|
||||
|
||||
return tuple((e.swapcase() if i % 2 == 0 else float(e)) for i, e in enumerate(parts))
|
||||
|
||||
def lessThan(self, source_left, source_right):
|
||||
data_left = source_left.data()
|
||||
data_right = source_right.data()
|
||||
|
||||
if isinstance(data_left, str) and isinstance(data_right, str):
|
||||
return self._human_key(data_left) < self._human_key(data_right)
|
||||
|
||||
return super().lessThan(source_left, source_right)
|
||||
|
||||
@property
|
||||
def filters(self):
|
||||
if not hasattr(self, "_filters"):
|
||||
self._filters = []
|
||||
|
||||
return self._filters
|
||||
|
||||
@filters.setter
|
||||
def filters(self, filters):
|
||||
self._filters = filters
|
||||
|
||||
self.invalidateFilter()
|
||||
|
||||
def filterAcceptsRow(self, source_row: int, source_parent: QtCore.QModelIndex) -> bool:
|
||||
model = self.sourceModel()
|
||||
source_index = model.index(source_row, 0, source_parent)
|
||||
result: [bool] = []
|
||||
|
||||
# Show top level children
|
||||
for child_row in range(model.rowCount(source_index)):
|
||||
if self.filterAcceptsRow(child_row, source_index):
|
||||
return True
|
||||
|
||||
# Filter for actual needle
|
||||
for i, text in self.filters:
|
||||
if 0 <= i < self.columnCount():
|
||||
ix = self.sourceModel().index(source_row, i, source_parent)
|
||||
data = ix.data()
|
||||
|
||||
# Append results to list to enable an AND operator for filtering.
|
||||
result.append(bool(re.search(rf"{text}", data, re.MULTILINE | re.IGNORECASE)) if data else False)
|
||||
|
||||
# If no filter set, just set the result to True.
|
||||
if not result:
|
||||
result.append(True)
|
||||
|
||||
return all(result)
|
Reference in New Issue
Block a user