Merge branch 'newcarts' into dev

This commit is contained in:
Keith Edmunds 2022-10-21 22:55:06 +01:00
commit 001df4cfce
12 changed files with 578 additions and 38 deletions

3
.envrc
View File

@ -6,6 +6,9 @@ if on_git_branch master; then
elif on_git_branch carts; then
export MM_ENV="DEVELOPMENT"
export MM_DB="mysql+mysqldb://dev_musicmuster:dev_musicmuster@localhost/dev_musicmuster_carts"
elif on_git_branch newcarts; then
export MM_ENV="DEVELOPMENT"
export MM_DB="mysql+mysqldb://dev_musicmuster:dev_musicmuster@localhost/dev_musicmuster_carts"
else
export MM_ENV="DEVELOPMENT"
export MM_DB="mysql+mysqldb://dev_musicmuster:dev_musicmuster@localhost/dev_musicmuster"

View File

@ -42,6 +42,7 @@ prepend_sys_path = .
sqlalchemy.url = SET
# sqlalchemy.url = mysql+mysqldb://musicmuster:musicmuster@localhost/musicmuster_prod
# sqlalchemy.url = mysql+mysqldb://dev_musicmuster:dev_musicmuster@localhost/dev_musicmuster
# sqlalchemy.url = mysql+mysqldb://dev_musicmuster:dev_musicmuster@localhost/dev_musicmuster_carts
[post_write_hooks]
# post_write_hooks defines scripts or Python functions that are run

View File

@ -9,9 +9,15 @@ class Config(object):
BITRATE_LOW_THRESHOLD = 192
BITRATE_OK_THRESHOLD = 300
CHECK_AUDACITY_AT_STARTUP = True
CART_DIRECTORY = "/home/kae/radio/CartTracks"
CARTS_COUNT = 10
COLOUR_BITRATE_LOW = "#ffcdd2"
COLOUR_BITRATE_MEDIUM = "#ffeb6f"
COLOUR_BITRATE_OK = "#dcedc8"
COLOUR_CART_ERROR = "#dc3545"
COLOUR_CART_PLAYING = "#248f24"
COLOUR_CART_READY = "#ffc107"
COLOUR_CART_UNCONFIGURED = "#f2f2f2"
COLOUR_CURRENT_HEADER = "#d4edda"
COLOUR_CURRENT_PLAYLIST = "#7eca8f"
COLOUR_CURRENT_TAB = "#248f24"

View File

@ -51,6 +51,54 @@ Base = declarative_base()
# Database classes
class Carts(Base):
__tablename__ = 'carts'
id: int = Column(Integer, primary_key=True, autoincrement=True)
cart_number = Column(Integer, nullable=False, unique=True)
name = Column(String(256), index=True)
duration = Column(Integer, index=True)
path = Column(String(2048), index=False)
enabled = Column(Boolean, default=False, nullable=False)
def __repr__(self) -> str:
return (
f"<Carts(id={self.id}, cart={self.cart_number}, "
f"name={self.name}, path={self.path}>"
)
def __init__(self, session: Session, cart_number: int, name: str = None,
duration: int = None, path: str = None,
enabled: bool = True) -> None:
"""Create new cart"""
self.cart_number = cart_number
self.name = name
self.duration = duration
self.path = path
self.enabled = enabled
session.add(self)
session.commit()
@classmethod
def get_or_create(cls, session: Session, cart_number: int) -> "Carts":
"""
Return cart with passed cart number, or create a record if
none exists.
"""
try:
return (
session.execute(
select(Carts)
.where(Carts.cart_number == cart_number)
).scalar_one()
)
except NoResultFound:
return Carts(session, cart_number)
class NoteColours(Base):
__tablename__ = 'notecolours'

View File

@ -9,8 +9,8 @@ import threading
from datetime import datetime, timedelta
from typing import List, Optional
from PyQt5.QtCore import QDate, QEvent, Qt, QTime, QTimer
from PyQt5.QtGui import QColor, QPalette
from PyQt5.QtCore import QDate, QEvent, Qt, QSize, QTime, QTimer
from PyQt5.QtGui import QColor, QPalette, QFont
from PyQt5.QtWidgets import (
QApplication,
QDialog,
@ -21,6 +21,7 @@ from PyQt5.QtWidgets import (
QListWidgetItem,
QMainWindow,
QMessageBox,
QPushButton,
)
from dbconfig import engine, Session
@ -29,22 +30,61 @@ import music
from models import (
Base,
Carts,
Playdates,
PlaylistRows,
Playlists,
Settings,
Tracks
)
from config import Config
from playlists import PlaylistTab
from sqlalchemy.orm.exc import DetachedInstanceError
from ui.dlg_cart_ui import Ui_DialogCartEdit # 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.downloadcsv_ui import Ui_DateSelect # type: ignore
from config import Config
from ui.main_window_ui import Ui_MainWindow # type: ignore
from utilities import check_db, update_bitrates
class CartButton(QPushButton):
"""Button for playing carts"""
def __init__(self, parent: QMainWindow, cart: Carts):
"""Create a cart pushbutton and set it disabled"""
super().__init__(parent)
self.parent = parent
self.cart_id = cart.id
self.path = cart.path
self.player = None
self.is_playing = False
self.setEnabled(True)
self.setMinimumSize(QSize(147, 61))
font = QFont()
font.setPointSize(14)
self.setFont(font)
self.setObjectName("cart_" + str(cart.cart_number))
def __repr__(self) -> str:
return (
f"<CartButton(cart_id={self.cart_id} "
f"path={self.path}, is_playing={self.is_playing}>"
)
def event(self, event: QEvent) -> bool:
"""Allow right click even when button is disabled"""
if event.type() == QEvent.MouseButtonRelease:
if event.button() == Qt.RightButton:
self.parent.cart_edit(self, event)
return True
return super().event(event)
class TrackData:
def __init__(self, track):
self.id = track.id
@ -95,31 +135,110 @@ class Window(QMainWindow, Ui_MainWindow):
self.tabPlaylist.currentWidget
self.load_last_playlists()
self.carts_init()
self.enable_play_next_controls()
self.timer.start(Config.TIMER_MS)
self.connect_signals_slots()
def about(self) -> None:
"""Get git tag and database name"""
def cart_configure(self, cart: Carts, btn: CartButton) -> None:
"""Configure button with cart data"""
try:
git_tag = str(
subprocess.check_output(
['git', 'describe'], stderr=subprocess.STDOUT
)
).strip('\'b\\n')
except subprocess.CalledProcessError as exc_info:
git_tag = str(exc_info.output)
btn.setEnabled(False)
if cart.path:
if helpers.file_is_readable(cart.path):
colour = Config.COLOUR_CART_READY
btn.path = cart.path
btn.player = self.music.VLC.media_player_new(cart.path)
btn.player.audio_set_volume(Config.VOLUME_VLC_DEFAULT)
if cart.enabled:
btn.setEnabled(True)
else:
colour = Config.COLOUR_CART_ERROR
else:
colour = Config.COLOUR_CART_UNCONFIGURED
btn.setStyleSheet("background-color: " + colour + ";\n")
btn.setText(cart.name)
def cart_click(self) -> None:
"""Handle cart click"""
btn = self.sender()
if helpers.file_is_readable(btn.path):
btn.player.play()
btn.is_playing = True
colour = Config.COLOUR_CART_PLAYING
else:
colour = Config.COLOUR_CART_ERROR
btn.setStyleSheet("background-color: " + colour + ";\n")
def cart_edit(self, btn: CartButton, event: QEvent):
"""Handle context menu for cart button"""
with Session() as session:
dbname = session.bind.engine.url.database
cart = session.query(Carts).get(btn.cart_id)
if cart is None:
log.ERROR("cart_edit: cart not found")
return
QMessageBox.information(
self,
"About",
f"MusicMuster {git_tag}\n\nDatabase: {dbname}",
QMessageBox.Ok
)
dlg = CartDialog(parent=self, session=session, cart=cart)
if dlg.exec():
name = dlg.ui.lineEditName.text()
if not name:
QMessageBox.warning(self, "Error", "Name required")
return
path = dlg.path
if not path:
QMessageBox.warning(self, "Error", "Filename required")
return
if cart.path and helpers.file_is_readable(cart.path):
tags = helpers.get_tags(cart.path)
cart.duration = tags['duration']
cart.enabled = dlg.ui.chkEnabled.isChecked()
cart.name = name
cart.path = path
session.add(cart)
session.commit()
self.cart_configure(cart, btn)
def carts_init(self) -> None:
"""Initialse carts data structures"""
with Session() as session:
# Number carts from 1 for humanity
for cart_number in range(1, Config.CARTS_COUNT + 1):
cart = session.query(Carts).get(cart_number)
if cart is None:
cart = Carts(session, cart_number,
name=f"Cart #{cart_number}")
btn = CartButton(self, cart)
btn.clicked.connect(self.cart_click)
# Insert button on left of cart space starting at
# location zero
self.horizontalLayout_Carts.insertWidget(cart.id - 1, btn)
# Configure button
self.cart_configure(cart, btn)
def cart_tick(self) -> None:
"""Cart clock actions"""
for i in range(self.horizontalLayout_Carts.count()):
btn = self.horizontalLayout_Carts.itemAt(i).widget()
if not btn:
continue
if btn.is_playing:
if not btn.player.is_playing():
# Cart has finished playing
btn.is_playing = False
# Setting to position 0 doesn't seem to work
btn.player = self.music.VLC.media_player_new(btn.path)
btn.player.audio_set_volume(Config.VOLUME_VLC_DEFAULT)
colour = Config.COLOUR_CART_READY
btn.setStyleSheet("background-color: " + colour + ";\n")
def clear_selection(self) -> None:
""" Clear selected row"""
@ -438,6 +557,28 @@ class Window(QMainWindow, Ui_MainWindow):
self.stop_playing(fade=True)
def about(self) -> None:
"""Get git tag and database name"""
try:
git_tag = str(
subprocess.check_output(
['git', 'describe'], stderr=subprocess.STDOUT
)
).strip('\'b\\n')
except subprocess.CalledProcessError as exc_info:
git_tag = str(exc_info.output)
with Session() as session:
dbname = session.bind.engine.url.database
QMessageBox.information(
self,
"About",
f"MusicMuster {git_tag}\n\nDatabase: {dbname}",
QMessageBox.Ok
)
def get_one_track(self, session: Session) -> Optional[Tracks]:
"""Show dialog box to select one track and return it to caller"""
@ -842,7 +983,7 @@ class Window(QMainWindow, Ui_MainWindow):
def show_current(self) -> None:
"""Scroll to show current track"""
log.debug(f"musicmuster.show_current()")
log.debug(f"KAE: musicmuster.show_current()")
if self.current_track_playlist_tab != self.visible_playlist_tab:
self.tabPlaylist.setCurrentWidget(self.current_track_playlist_tab)
self.tabPlaylist.currentWidget().scroll_current_to_top()
@ -850,7 +991,7 @@ class Window(QMainWindow, Ui_MainWindow):
def show_next(self) -> None:
"""Scroll to show next track"""
log.debug(f"musicmuster.show_next()")
log.debug(f"KAE: musicmuster.show_next()")
if self.next_track_playlist_tab != self.visible_playlist_tab:
self.tabPlaylist.setCurrentWidget(self.next_track_playlist_tab)
self.tabPlaylist.currentWidget().scroll_next_to_top()
@ -987,6 +1128,8 @@ class Window(QMainWindow, Ui_MainWindow):
# Update TOD clock
self.lblTOD.setText(datetime.now().strftime(Config.TOD_TIME_FORMAT))
# Update carts
self.cart_tick()
self.even_tick = not self.even_tick
if not self.even_tick:
@ -1079,6 +1222,43 @@ class Window(QMainWindow, Ui_MainWindow):
self.hdrNextTrack.setText("")
class CartDialog(QDialog):
"""Edit cart details"""
def __init__(self, parent: QMainWindow, session: Session,
cart: Carts) -> None:
"""
Manage carts
"""
super().__init__(parent)
self.parent = parent
self.session = session
self.ui = Ui_DialogCartEdit()
self.ui.setupUi(self)
self.path = cart.path
self.ui.lblPath.setText(self.path)
self.ui.lineEditName.setText(cart.name)
self.ui.chkEnabled.setChecked(cart.enabled)
self.ui.windowTitle = "Edit Cart " + str(cart.id)
self.ui.btnFile.clicked.connect(self.choose_file)
def choose_file(self) -> None:
"""File select"""
dlg = QFileDialog()
dlg.setFileMode(QFileDialog.ExistingFile)
dlg.setViewMode(QFileDialog.Detail)
dlg.setDirectory(Config.CART_DIRECTORY)
dlg.setNameFilter("Music files (*.flac *.mp3)")
if dlg.exec_():
self.path = dlg.selectedFiles()[0]
self.ui.lblPath.setText(self.path)
class DbDialog(QDialog):
"""Select track from database"""

View File

@ -823,17 +823,17 @@ class PlaylistTab(QTableWidget):
def scroll_current_to_top(self) -> None:
"""Scroll currently-playing row to top"""
log.debug("playlists.scroll_current_to_top()")
log.debug("KAE: playlists.scroll_current_to_top()")
current_row = self._get_current_track_row()
log.debug(f"playlists.scroll_current_to_top(), {current_row=}")
log.debug(f"KAE: playlists.scroll_current_to_top(), {current_row=}")
self._scroll_to_top(current_row)
def scroll_next_to_top(self) -> None:
"""Scroll nextly-playing row to top"""
log.debug("playlists.scroll_next_to_top()")
log.debug("KAE: playlists.scroll_next_to_top()")
next_row = self._get_next_track_row()
log.debug(f"playlists.scroll_next_to_top(), {next_row=}")
log.debug(f"KAE: playlists.scroll_next_to_top(), {next_row=}")
self._scroll_to_top(next_row)
def set_search(self, text: str) -> None:

164
app/ui/dlg_Cart.ui Normal file
View File

@ -0,0 +1,164 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DialogCartEdit</class>
<widget class="QDialog" name="DialogCartEdit">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>564</width>
<height>148</height>
</rect>
</property>
<property name="windowTitle">
<string>Carts</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="maximumSize">
<size>
<width>56</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>&amp;Name:</string>
</property>
<property name="buddy">
<cstring>lineEditName</cstring>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QLineEdit" name="lineEditName">
<property name="inputMask">
<string/>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QCheckBox" name="chkEnabled">
<property name="text">
<string>&amp;Enabled</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="maximumSize">
<size>
<width>56</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>File:</string>
</property>
<property name="buddy">
<cstring>lblPath</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="lblPath">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>301</width>
<height>41</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="btnFile">
<property name="maximumSize">
<size>
<width>31</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="2" column="1">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>116</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="2" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DialogCartEdit</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DialogCartEdit</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -13,8 +13,8 @@
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
@ -121,14 +121,8 @@
</item>
</layout>
</item>
<item>
<item row="3" column="0">
<widget class="QLabel" name="dbPath">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>

73
app/ui/dlg_cart_ui.py Normal file
View File

@ -0,0 +1,73 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'app/ui/dlg_Cart.ui'
#
# Created by: PyQt5 UI code generator 5.15.6
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_DialogCartEdit(object):
def setupUi(self, DialogCartEdit):
DialogCartEdit.setObjectName("DialogCartEdit")
DialogCartEdit.resize(564, 148)
self.gridLayout = QtWidgets.QGridLayout(DialogCartEdit)
self.gridLayout.setObjectName("gridLayout")
self.label = QtWidgets.QLabel(DialogCartEdit)
self.label.setMaximumSize(QtCore.QSize(56, 16777215))
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.lineEditName = QtWidgets.QLineEdit(DialogCartEdit)
self.lineEditName.setInputMask("")
self.lineEditName.setObjectName("lineEditName")
self.gridLayout.addWidget(self.lineEditName, 0, 1, 1, 2)
self.chkEnabled = QtWidgets.QCheckBox(DialogCartEdit)
self.chkEnabled.setObjectName("chkEnabled")
self.gridLayout.addWidget(self.chkEnabled, 0, 3, 1, 1)
self.label_2 = QtWidgets.QLabel(DialogCartEdit)
self.label_2.setMaximumSize(QtCore.QSize(56, 16777215))
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1)
self.lblPath = QtWidgets.QLabel(DialogCartEdit)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.lblPath.sizePolicy().hasHeightForWidth())
self.lblPath.setSizePolicy(sizePolicy)
self.lblPath.setMinimumSize(QtCore.QSize(301, 41))
self.lblPath.setText("")
self.lblPath.setTextFormat(QtCore.Qt.PlainText)
self.lblPath.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)
self.lblPath.setWordWrap(True)
self.lblPath.setObjectName("lblPath")
self.gridLayout.addWidget(self.lblPath, 1, 1, 1, 1)
self.btnFile = QtWidgets.QPushButton(DialogCartEdit)
self.btnFile.setMaximumSize(QtCore.QSize(31, 16777215))
self.btnFile.setObjectName("btnFile")
self.gridLayout.addWidget(self.btnFile, 1, 3, 1, 1)
spacerItem = QtWidgets.QSpacerItem(116, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.gridLayout.addItem(spacerItem, 2, 1, 1, 1)
self.buttonBox = QtWidgets.QDialogButtonBox(DialogCartEdit)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.gridLayout.addWidget(self.buttonBox, 2, 2, 1, 2)
self.label.setBuddy(self.lineEditName)
self.label_2.setBuddy(self.lblPath)
self.retranslateUi(DialogCartEdit)
self.buttonBox.accepted.connect(DialogCartEdit.accept) # type: ignore
self.buttonBox.rejected.connect(DialogCartEdit.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(DialogCartEdit)
def retranslateUi(self, DialogCartEdit):
_translate = QtCore.QCoreApplication.translate
DialogCartEdit.setWindowTitle(_translate("DialogCartEdit", "Carts"))
self.label.setText(_translate("DialogCartEdit", "&Name:"))
self.chkEnabled.setText(_translate("DialogCartEdit", "&Enabled"))
self.label_2.setText(_translate("DialogCartEdit", "File:"))
self.btnFile.setText(_translate("DialogCartEdit", "..."))

View File

@ -291,6 +291,23 @@ padding-left: 8px;</string>
</widget>
</item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_Carts">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="3" column="0">
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
@ -325,7 +342,7 @@ padding-left: 8px;</string>
</widget>
</widget>
</item>
<item row="3" column="0">
<item row="4" column="0">
<widget class="QFrame" name="frame_5">
<property name="styleSheet">
<string notr="true">background-color: rgb(192, 191, 188)</string>
@ -1132,6 +1149,11 @@ padding-left: 8px;</string>
<string>Debug</string>
</property>
</action>
<action name="actionAdd_cart">
<property name="text">
<string>Edit cart &amp;1...</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>

View File

@ -158,6 +158,11 @@ class Ui_MainWindow(object):
self.frame_4.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame_4.setObjectName("frame_4")
self.gridLayout_4.addWidget(self.frame_4, 1, 0, 1, 1)
self.horizontalLayout_Carts = QtWidgets.QHBoxLayout()
self.horizontalLayout_Carts.setObjectName("horizontalLayout_Carts")
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_Carts.addItem(spacerItem)
self.gridLayout_4.addLayout(self.horizontalLayout_Carts, 2, 0, 1, 1)
self.splitter = QtWidgets.QSplitter(self.centralwidget)
self.splitter.setOrientation(QtCore.Qt.Vertical)
self.splitter.setObjectName("splitter")
@ -171,7 +176,7 @@ class Ui_MainWindow(object):
self.tabInfolist.setTabsClosable(True)
self.tabInfolist.setMovable(True)
self.tabInfolist.setObjectName("tabInfolist")
self.gridLayout_4.addWidget(self.splitter, 2, 0, 1, 1)
self.gridLayout_4.addWidget(self.splitter, 3, 0, 1, 1)
self.frame_5 = QtWidgets.QFrame(self.centralwidget)
self.frame_5.setStyleSheet("background-color: rgb(192, 191, 188)")
self.frame_5.setFrameShape(QtWidgets.QFrame.StyledPanel)
@ -363,7 +368,7 @@ class Ui_MainWindow(object):
self.gridLayout_3.addWidget(self.btnHidePlayed, 1, 0, 1, 1)
self.horizontalLayout.addWidget(self.frame_3)
self.horizontalLayout_2.addLayout(self.horizontalLayout)
self.gridLayout_4.addWidget(self.frame_5, 3, 0, 1, 1)
self.gridLayout_4.addWidget(self.frame_5, 4, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1280, 26))
@ -482,6 +487,8 @@ class Ui_MainWindow(object):
self.actionNew_from_template.setObjectName("actionNew_from_template")
self.actionDebug = QtWidgets.QAction(MainWindow)
self.actionDebug.setObjectName("actionDebug")
self.actionAdd_cart = QtWidgets.QAction(MainWindow)
self.actionAdd_cart.setObjectName("actionAdd_cart")
self.menuFile.addAction(self.actionNewPlaylist)
self.menuFile.addAction(self.actionOpenPlaylist)
self.menuFile.addAction(self.actionClosePlaylist)
@ -617,5 +624,6 @@ class Ui_MainWindow(object):
self.actionSave_as_template.setText(_translate("MainWindow", "Save as template..."))
self.actionNew_from_template.setText(_translate("MainWindow", "New from template..."))
self.actionDebug.setText(_translate("MainWindow", "Debug"))
self.actionAdd_cart.setText(_translate("MainWindow", "Edit cart &1..."))
from infotabs import InfoTabs
import icons_rc

View File

@ -0,0 +1,41 @@
"""Add carts
Revision ID: 6730f03317df
Revises: b4f524e2140c
Create Date: 2022-09-13 19:41:33.181752
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '6730f03317df'
down_revision = 'b4f524e2140c'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('carts',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('cart_number', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=256), nullable=True),
sa.Column('duration', sa.Integer(), nullable=True),
sa.Column('path', sa.String(length=2048), nullable=True),
sa.Column('enabled', sa.Boolean(), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('cart_number')
)
op.create_index(op.f('ix_carts_duration'), 'carts', ['duration'], unique=False)
op.create_index(op.f('ix_carts_name'), 'carts', ['name'], unique=False)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f('ix_carts_name'), table_name='carts')
op.drop_index(op.f('ix_carts_duration'), table_name='carts')
op.drop_table('carts')
# ### end Alembic commands ###