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" export MM_DB="mysql+mysqldb://musicmuster:musicmuster@localhost/musicmuster_prod"
else MYSQL_DATABASE="musicmuster_dev" else MYSQL_DATABASE="musicmuster_dev"
export MM_ENV="DEVELOPMENT" 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 fi

View File

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

View File

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

View File

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

View File

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

View File

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