WIP V3: playlist populates from database

This commit is contained in:
Keith Edmunds 2023-10-19 13:46:10 +01:00
parent 51a827093a
commit bec336d2a3
3 changed files with 2807 additions and 1 deletions

View File

@ -67,7 +67,7 @@ import icons_rc # noqa F401
import music import music
from models import Base, Carts, Playdates, PlaylistRows, Playlists, Settings, Tracks from models import Base, Carts, Playdates, PlaylistRows, Playlists, Settings, Tracks
from config import Config from config import Config
from playlists import PlaylistTab from playlists_v3 import PlaylistTab
from ui.dlg_cart_ui import Ui_DialogCartEdit # type: ignore from ui.dlg_cart_ui import Ui_DialogCartEdit # type: ignore
from ui.dlg_search_database_ui import Ui_Dialog # type: ignore from ui.dlg_search_database_ui import Ui_Dialog # type: ignore
from ui.dlg_SelectPlaylist_ui import Ui_dlgSelectPlaylist # type: ignore from ui.dlg_SelectPlaylist_ui import Ui_dlgSelectPlaylist # type: ignore

217
app/playlistmodel.py Normal file
View File

@ -0,0 +1,217 @@
from datetime import datetime
from enum import auto, Enum
from typing import Optional
from PyQt6.QtCore import (
QAbstractTableModel,
QModelIndex,
Qt,
QVariant,
)
from PyQt6.QtGui import (
QColor,
QFont,
)
from config import Config
from dbconfig import Session
from helpers import (
file_is_unreadable,
)
from models import (
PlaylistRows,
)
class Col(Enum):
START_GAP = 0
TITLE = auto()
ARTIST = auto()
DURATION = auto()
START_TIME = auto()
END_TIME = auto()
LASTPLAYED = auto()
BITRATE = auto()
NOTE = auto()
class PlaylistRowData:
def __init__(self, plr: PlaylistRows) -> None:
"""
Populate PlaylistRowData from database PlaylistRows record
"""
self.start_gap: Optional[int] = None
self.title: str = ""
self.artist: str = ""
self.duration: int = 0
self.lastplayed: datetime = Config.EPOCH
self.bitrate = 0
self.path = ""
self.plrid: int = plr.id
self.plr_rownum: int = plr.plr_rownum
self.note: str = plr.note
if plr.track:
self.start_gap = plr.track.start_gap
self.title = plr.track.title
self.artist = plr.track.artist
self.duration = plr.track.duration
if plr.track.playdates:
self.lastplayed = max([a.lastplayed for a in plr.track.playdates])
else:
self.lastplayed = Config.EPOCH
self.bitrate = plr.track.bitrate or 0
self.path = plr.track.path
def __repr__(self) -> str:
return (
f"<PlaylistRowData: plrid={self.plrid}, plr_rownum={self.plr_rownum}, "
f"note='{self.note}', title='{self.title}', artist='{self.artist}'>"
)
class PlaylistModel(QAbstractTableModel):
def __init__(self, playlist_id: int, *args, **kwargs):
self.playlist_id = playlist_id
super().__init__(*args, **kwargs)
self.playlist_rows: dict[int, PlaylistRowData] = {}
# self.current_row = None
# self.next_row = None
self.previous_row = None
self.current_row = 2
self.next_row = 3
self.refresh_data()
def __repr__(self) -> str:
return (
f"<PlaylistModel: playlist_id={self.playlist_id}>"
)
def columnCount(self, parent: QModelIndex) -> int:
"""Standard function for view"""
return 9
def data(self, index: QModelIndex, role: Qt.ItemDataRole.DisplayRole):
"""Return data to view"""
if not index.isValid() or not (
0 <= index.row() < len(self.playlist_rows)):
return QVariant()
row = index.row()
column = index.column()
# prd for playlist row data as it's used a lot
prd = self.playlist_rows[row]
# Dispatch to role-specific functions
if role == Qt.ItemDataRole.DisplayRole:
return self.display_role(row, column, prd)
elif role == Qt.ItemDataRole.DecorationRole:
pass
elif role == Qt.ItemDataRole.EditRole:
pass
elif role == Qt.ItemDataRole.ToolTipRole:
pass
elif role == Qt.ItemDataRole.StatusTipRole:
pass
elif role == Qt.ItemDataRole.WhatsThisRole:
pass
elif role == Qt.ItemDataRole.SizeHintRole:
pass
elif role == Qt.ItemDataRole.FontRole:
pass
elif role == Qt.ItemDataRole.TextAlignmentRole:
pass
elif role == Qt.ItemDataRole.BackgroundRole:
pass
elif role == Qt.ItemDataRole.ForegroundRole:
pass
elif role == Qt.ItemDataRole.CheckStateRole:
pass
elif role == Qt.ItemDataRole.InitialSortOrderRole:
pass
# Fall through to no-op
return QVariant()
def display_role(self, row: int, column: int, prd: PlaylistRowData) -> QVariant:
"""
Return text for display
"""
if column == Col.START_GAP.value:
return QVariant(prd.start_gap)
if column == Col.TITLE.value:
return QVariant(prd.title)
if column == Col.ARTIST.value:
return QVariant(prd.artist)
if column == Col.DURATION.value:
return QVariant(prd.duration)
if column == Col.START_TIME.value:
return QVariant("FIXME")
if column == Col.END_TIME.value:
return QVariant("FIXME")
if column == Col.LASTPLAYED.value:
return QVariant(prd.lastplayed)
if column == Col.BITRATE.value:
return QVariant(prd.bitrate)
if column == Col.NOTE.value:
return QVariant(prd.note)
return QVariant()
if role == Qt.ItemDataRole.BackgroundRole:
if rowdata.path and file_is_unreadable(rowdata.path):
return QVariant(QColor(Config.COLOUR_UNREADABLE))
elif row == self.current_row:
return QVariant(QColor(Config.COLOUR_CURRENT_PLAYLIST))
elif row == self.next_row:
return QVariant(QColor(Config.COLOUR_NEXT_PLAYLIST))
elif column == BITRATE:
if rowdata.bitrate:
if rowdata.bitrate < Config.BITRATE_LOW_THRESHOLD:
cell_colour = Config.COLOUR_BITRATE_LOW
elif rowdata.bitrate < Config.BITRATE_OK_THRESHOLD:
cell_colour = Config.COLOUR_BITRATE_MEDIUM
else:
cell_colour = Config.COLOUR_BITRATE_OK
return QVariant(QColor(cell_colour))
# Return a QColor, QIcon or QPixmap. QColor puts a coloured
# block to left of text
return QVariant()
# Text colour, not currently used
return QVariant()
if not rowdata.played:
font = QFont()
font.setBold(True)
return QVariant(font)
return QVariant()
def refresh_data(self):
"""Populate dicts for data calls"""
# Populate self.playlist_rows with playlist data
with Session() as session:
for p in PlaylistRows.deep_rows(session, self.playlist_id):
self.playlist_rows[p.plr_rownum] = PlaylistRowData(p)
def rowCount(self, index: QModelIndex) -> int:
"""Standard function for view"""
return len(self.playlist_rows)

2589
app/playlists_v3.py Normal file

File diff suppressed because it is too large Load Diff