SQLA2.0 playlist column headers display

This commit is contained in:
Keith Edmunds 2022-07-03 20:59:10 +01:00
parent bef4507ef6
commit ab47bb0ab4
6 changed files with 145 additions and 173 deletions

2
.envrc
View File

@ -5,5 +5,5 @@ if on_git_branch master; then
export MM_DB="mysql+mysqldb://musicmuster:musicmuster@localhost/musicmuster_prod"
else MYSQL_DATABASE="musicmuster_dev"
export MM_ENV="DEVELOPMENT"
export MM_DB="mysql+mysqldb://musicmuster:musicmuster@localhost/musicmuster_dev"
export MM_DB="mysql+mysqldb://musicmusterv3:musicmusterv3@localhost/musicmuster_dev_v3"
fi

View File

@ -28,6 +28,7 @@ class Config(object):
COLUMN_NAME_LAST_PLAYED = "Last played"
COLUMN_NAME_LEADING_SILENCE = "Gap"
COLUMN_NAME_LENGTH = "Length"
COLUMN_NAME_NOTES = "Notes"
COLUMN_NAME_START_TIME = "Start"
COLUMN_NAME_TITLE = "Title"
DBFS_FADE = -12

View File

@ -1,3 +1,4 @@
import inspect
import logging
import os
from config import Config

View File

@ -3,25 +3,26 @@
# import os.path
# import re
#
# from dbconfig import Session
from dbconfig import Session
#
# from datetime import datetime
# from typing import List, Optional
from datetime import datetime
from typing import List, Optional
#
# from pydub import AudioSegment
# from sqlalchemy.ext.associationproxy import association_proxy
# from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta
# from sqlalchemy import (
# Boolean,
# Column,
# DateTime,
# Float,
# ForeignKey,
# func,
# Integer,
# String,
# UniqueConstraint,
# )
from sqlalchemy import (
Boolean,
Column,
DateTime,
# Float,
# ForeignKey,
# func,
Integer,
String,
# UniqueConstraint,
select,
)
# from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import (
# backref,
@ -253,19 +254,19 @@ Base = declarative_base()
# session.query(Playdates).filter(
# Playdates.track_id == track_id).delete()
# session.flush()
#
#
# class Playlists(Base):
# """
# Manage playlists
# """
#
# __tablename__ = "playlists"
#
# id: int = Column(Integer, primary_key=True, autoincrement=True)
# name: str = Column(String(32), nullable=False, unique=True)
# last_used: datetime = Column(DateTime, default=None, nullable=True)
# loaded: bool = Column(Boolean, default=True, nullable=False)
class Playlists(Base):
"""
Manage playlists
"""
__tablename__ = "playlists"
id: int = Column(Integer, primary_key=True, autoincrement=True)
name: str = Column(String(32), nullable=False, unique=True)
last_used: datetime = Column(DateTime, default=None, nullable=True)
loaded: bool = Column(Boolean, default=True, nullable=False)
# notes = relationship(
# "Notes", order_by="Notes.row",
# back_populates="playlist", lazy="select"
@ -278,9 +279,9 @@ Base = declarative_base()
# self.name = name
# session.add(self)
# session.flush()
#
# def __repr__(self) -> str:
# return f"<Playlists(id={self.id}, name={self.name}>"
def __repr__(self) -> str:
return f"<Playlists(id={self.id}, name={self.name}>"
#
# def add_track(
# self, session: Session, track_id: int,
@ -323,25 +324,29 @@ Base = declarative_base()
# .filter(cls.loaded.is_(False))
# .order_by(cls.last_used.desc())
# ).all()
#
# @classmethod
# def get_open(cls, session: Session) -> List["Playlists"]:
# """
# Return a list of playlists marked "loaded", ordered by loaded date.
# """
#
# return (
# session.query(cls)
# .filter(cls.loaded.is_(True))
# .order_by(cls.last_used.desc())
# ).all()
#
# def mark_open(self, session: Session) -> None:
# """Mark playlist as loaded and used now"""
#
# self.loaded = True
# self.last_used = datetime.now()
# session.flush()
@classmethod
def get_open(cls, session: Session) -> List[Optional["Playlists"]]:
"""
Return a list of playlists marked "loaded", ordered by loaded date.
"""
return (
session.execute(
select(cls)
.where(cls.loaded.is_(True))
.order_by(cls.last_used.desc())
)
.scalars()
.all()
)
def mark_open(self, session: Session) -> None:
"""Mark playlist as loaded and used now"""
self.loaded = True
self.last_used = datetime.now()
# session.flush()
#
# @staticmethod
# def next_free_row(session: Session, playlist_id: int) -> int:

View File

@ -27,8 +27,7 @@ from PyQt5.QtWidgets import (
# QMessageBox,
)
#
import dbconfig
# from dbconfig import Session
from dbconfig import engine, Session
# import helpers
# import music
#
@ -36,11 +35,11 @@ import dbconfig
from models import (
Base,
# Playdates,
# Playlists,
Playlists,
# Settings,
# Tracks
)
# from playlists import PlaylistTab
from playlists import PlaylistTab
# from sqlalchemy.orm.exc import DetachedInstanceError
# from ui.dlg_search_database_ui import Ui_Dialog
# from ui.dlg_SelectPlaylist_ui import Ui_dlgSelectPlaylist
@ -95,7 +94,7 @@ class Window(QMainWindow, Ui_MainWindow):
# self.visible_playlist_tab: Callable[[], PlaylistTab] = \
# self.tabPlaylist.currentWidget
#
#self.load_last_playlists()
self._load_last_playlists()
# self.enable_play_next_controls()
# self.check_audacity()
# self.timer.start(Config.TIMER_MS)
@ -270,18 +269,18 @@ class Window(QMainWindow, Ui_MainWindow):
# except AttributeError:
# # Just return if there's no visible playlist tab
# return
#
# def create_playlist_tab(self, session: Session,
# playlist: Playlists) -> None:
# """
# Take the passed playlist database object, create a playlist tab and
# add tab to display.
# """
#
# playlist_tab: PlaylistTab = PlaylistTab(
# musicmuster=self, session=session, playlist_id=playlist.id)
# idx: int = self.tabPlaylist.addTab(playlist_tab, playlist.name)
# self.tabPlaylist.setCurrentIndex(idx)
def create_playlist_tab(self, session: Session,
playlist: Playlists) -> None:
"""
Take the passed playlist database object, create a playlist tab and
add tab to display.
"""
playlist_tab: PlaylistTab = PlaylistTab(
musicmuster=self, session=session, playlist_id=playlist.id)
idx: int = self.tabPlaylist.addTab(playlist_tab, playlist.name)
self.tabPlaylist.setCurrentIndex(idx)
#
# def disable_play_next_controls(self) -> None:
# """
@ -494,14 +493,14 @@ class Window(QMainWindow, Ui_MainWindow):
# # If we don't specify "repaint=False", playlist will
# # also be saved to database
# self.visible_playlist_tab().insert_track(session, track)
#
# def load_last_playlists(self):
# """Load the playlists that were loaded at end of last session"""
#
# with Session() as session:
# for playlist in Playlists.get_open(session):
# self.create_playlist_tab(session, playlist)
# playlist.mark_open(session)
def _load_last_playlists(self):
"""Load the playlists that were open when the last session closed"""
with Session() as session:
for playlist in Playlists.get_open(session):
self.create_playlist_tab(session, playlist)
playlist.mark_open(session)
#
# def move_selected(self) -> None:
# """Move selected rows to another playlist"""
@ -1168,7 +1167,7 @@ if __name__ == "__main__":
# else:
# # Normal run
try:
Base.metadata.create_all(dbconfig.engine)
Base.metadata.create_all(engine)
app = QApplication(sys.argv)
win = Window()
win.show()

View File

@ -1,3 +1,5 @@
from collections import namedtuple
# from enum import Enum, auto
# from typing import Dict, List, Optional, Set, Tuple, Union
#
@ -6,18 +8,18 @@
# from PyQt5.Qt import QFont
# from PyQt5.QtGui import QColor, QDropEvent
# from PyQt5 import QtWidgets
# from PyQt5.QtWidgets import (
# QAbstractItemView,
# QApplication,
# QInputDialog,
# QLineEdit,
# QMainWindow,
# QMenu,
# QStyledItemDelegate,
# QMessageBox,
# QTableWidget,
# QTableWidgetItem,
# )
from PyQt5.QtWidgets import (
# QAbstractItemView,
# QApplication,
# QInputDialog,
# QLineEdit,
QMainWindow,
# QMenu,
# QStyledItemDelegate,
# QMessageBox,
QTableWidget,
QTableWidgetItem,
)
#
# import helpers
# import os
@ -25,7 +27,7 @@
# import subprocess
# import threading
#
# from config import Config
from config import Config
# from datetime import datetime, timedelta
# from helpers import get_relative_date, open_in_audacity
# from log import log.debug, log.error
@ -38,8 +40,8 @@
# Tracks,
# NoteColours
# )
# from dbconfig import Session
#
from dbconfig import Session
#from collections import namedtuple
# start_time_re = re.compile(r"@\d\d:\d\d:\d\d")
#
#
@ -50,20 +52,19 @@
# NEXT = 3
# CURRENT = 4
# PLAYED = 5
#
#
# class Columns(Enum):
# AUTOPLAY = COL_USERDATA = auto()
# MSS = auto()
# NOTE = TITLE = auto()
# ARTIST = auto()
# DURATION = auto()
# START_TIME = auto()
# END_TIME = auto()
# LAST_PLAYED = auto()
# ROW_NOTES = auto()
# LAST = ROW_NOTES
#
# Columns
Column = namedtuple("Column", ['idx', 'heading'])
columns = {}
columns["userdata"] = Column(idx=0, heading=Config.COLUMN_NAME_AUTOPLAY),
columns["mss"] = Column(idx=1, heading=Config.COLUMN_NAME_LEADING_SILENCE),
columns["title"] = Column(idx=2, heading=Config.COLUMN_NAME_TITLE),
columns["artist"] = Column(idx=3, heading=Config.COLUMN_NAME_ARTIST),
columns["duration"] = Column(idx=4, heading=Config.COLUMN_NAME_LENGTH),
columns["start_time"] = Column(idx=5, heading=Config.COLUMN_NAME_START_TIME),
columns["end_time"] = Column(idx=6, heading=Config.COLUMN_NAME_END_TIME),
columns["last_played"] = Column(idx=7, heading=Config.COLUMN_NAME_LAST_PLAYED),
columns["row_notes"] = Column(idx=8, heading=Config.COLUMN_NAME_NOTES),
#
# class NoSelectDelegate(QStyledItemDelegate):
# """https://stackoverflow.com/questions/72790705/dont-select-text-in-qtablewidget-cell-when-editing/72792962#72792962"""
@ -79,84 +80,49 @@
# editor.deselect()
# editor.selectionChanged.connect(deselect)
# return editor
#
# class PlaylistTab(QTableWidget):
# cellEditingStarted = QtCore.pyqtSignal(int, int)
# cellEditingEnded = QtCore.pyqtSignal()
#
# # Column names
# COL_AUTOPLAY = COL_USERDATA = 0
# COL_MSS = 1
# COL_NOTE = COL_TITLE = 2
# COL_ARTIST = 3
# COL_DURATION = 4
# COL_START_TIME = 5
# COL_END_TIME = 6
# COL_LAST_PLAYED = 7
# COL_ROW_NOTES = 8
# COL_LAST = COL_ROW_NOTES
#
# NOTE_COL_SPAN = COL_LAST - COL_NOTE + 1
# NOTE_ROW_SPAN = 1
#
# # Qt.UserRoles
# ROW_METADATA = Qt.UserRole
# CONTENT_OBJECT = Qt.UserRole + 1
# ROW_DURATION = Qt.UserRole + 2
#
# def __init__(self, musicmuster: QMainWindow, session: Session,
# playlist_id: int, *args, **kwargs):
# super().__init__(*args, **kwargs)
#
# self.musicmuster: QMainWindow = musicmuster
# self.playlist_id: int = playlist_id
class PlaylistTab(QTableWidget):
# cellEditingStarted = QtCore.pyqtSignal(int, int)
# cellEditingEnded = QtCore.pyqtSignal()
# # Qt.UserRoles
# ROW_METADATA = Qt.UserRole
# CONTENT_OBJECT = Qt.UserRole + 1
# ROW_DURATION = Qt.UserRole + 2
def __init__(self, musicmuster: QMainWindow, session: Session,
playlist_id: int, *args, **kwargs):
super().__init__(*args, **kwargs)
self.musicmuster: QMainWindow = musicmuster
self.playlist_id: int = playlist_id
# self.menu: Optional[QMenu] = None
# self.current_track_start_time: Optional[datetime] = None
#
# # Don't select text on edit
# self.setItemDelegate(NoSelectDelegate(self))
#
# # Set up widget
# Set up widget
# self.setEditTriggers(QtWidgets.QAbstractItemView.AllEditTriggers)
# self.setAlternatingRowColors(True)
self.setAlternatingRowColors(True)
# self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
# self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
# self.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
# self.setRowCount(0)
# self.setColumnCount(9)
# # Add header row
# item: QTableWidgetItem = QtWidgets.QTableWidgetItem()
# self.setHorizontalHeaderItem(0, item)
# item = QtWidgets.QTableWidgetItem()
# self.setHorizontalHeaderItem(1, item)
# item = QtWidgets.QTableWidgetItem()
# self.setHorizontalHeaderItem(2, item)
# item = QtWidgets.QTableWidgetItem()
# self.setHorizontalHeaderItem(3, item)
# item = QtWidgets.QTableWidgetItem()
# self.setHorizontalHeaderItem(4, item)
# item = QtWidgets.QTableWidgetItem()
# self.setHorizontalHeaderItem(5, item)
# item = QtWidgets.QTableWidgetItem()
# self.setHorizontalHeaderItem(6, item)
# item = QtWidgets.QTableWidgetItem()
# self.setHorizontalHeaderItem(7, item)
# item = QtWidgets.QTableWidgetItem()
# self.setHorizontalHeaderItem(8, item)
# self.horizontalHeader().setMinimumSectionSize(0)
#
# self._set_column_widths(session)
# self.setHorizontalHeaderLabels([
# Config.COLUMN_NAME_AUTOPLAY,
# Config.COLUMN_NAME_LEADING_SILENCE,
# Config.COLUMN_NAME_TITLE,
# Config.COLUMN_NAME_ARTIST,
# Config.COLUMN_NAME_LENGTH,
# Config.COLUMN_NAME_START_TIME,
# Config.COLUMN_NAME_END_TIME,
# Config.COLUMN_NAME_LAST_PLAYED,
# "Row notes",
# ])
self.setRowCount(0)
self.setColumnCount(len(columns))
# Add header row
for idx in [a for a in range(len(columns))]:
item: QTableWidgetItem = QTableWidgetItem()
self.setHorizontalHeaderItem(idx, item)
self.horizontalHeader().setMinimumSectionSize(0)
# self._set_column_widths(session)
# Set column headings sorted by idx
self.setHorizontalHeaderLabels(
[a[0].heading for a in list(sorted(columns.values(),
key=lambda item: item[0][0]))]
)
#
# self.setDragEnabled(True)
# self.setAcceptDrops(True)