diff --git a/InterceptEscapeWhenEditingTableCellInView.py b/InterceptEscapeWhenEditingTableCellInView.py index 71bbac6..c00488f 100755 --- a/InterceptEscapeWhenEditingTableCellInView.py +++ b/InterceptEscapeWhenEditingTableCellInView.py @@ -53,7 +53,6 @@ class MyTableWidget(QTableView): class MyModel(QAbstractTableModel): - def columnCount(self, index): return 2 @@ -71,7 +70,11 @@ class MyModel(QAbstractTableModel): return QVariant() def flags(self, index): - return Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsEditable + return ( + Qt.ItemFlag.ItemIsEnabled + | Qt.ItemFlag.ItemIsSelectable + | Qt.ItemFlag.ItemIsEditable + ) class MainWindow(QMainWindow): diff --git a/app/dbtables.py b/app/dbtables.py index a1fe9cd..69b84e3 100644 --- a/app/dbtables.py +++ b/app/dbtables.py @@ -66,7 +66,9 @@ class PlaydatesTable(Model): id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) lastplayed: Mapped[dt.datetime] = mapped_column(index=True) track_id: Mapped[int] = mapped_column(ForeignKey("tracks.id")) - track: Mapped["TracksTable"] = relationship("TracksTable", back_populates="playdates") + track: Mapped["TracksTable"] = relationship( + "TracksTable", back_populates="playdates" + ) def __repr__(self) -> str: return ( diff --git a/app/dialogs.py b/app/dialogs.py index ab5465e..02b0ba2 100644 --- a/app/dialogs.py +++ b/app/dialogs.py @@ -111,7 +111,9 @@ class TrackSelectDialog(QDialog): if self.add_to_header: if move_existing and existing_prd: # "and existing_prd" for mypy's benefit - self.source_model.move_track_to_header(self.new_row_number, existing_prd, note) + self.source_model.move_track_to_header( + self.new_row_number, existing_prd, note + ) else: self.source_model.add_track_to_header(self.new_row_number, track_id) # Close dialog - we can only add one track to a header @@ -119,7 +121,9 @@ class TrackSelectDialog(QDialog): else: # Adding a new track row if move_existing and existing_prd: # "and existing_prd" for mypy's benefit - self.source_model.move_track_add_note(self.new_row_number, existing_prd, note) + self.source_model.move_track_add_note( + self.new_row_number, existing_prd, note + ) else: self.source_model.insert_row(self.new_row_number, track_id, note) diff --git a/app/models.py b/app/models.py index 0d41bd3..10f9a31 100644 --- a/app/models.py +++ b/app/models.py @@ -31,14 +31,13 @@ from log import log ALCHEMICAL_DATABASE_URI = os.environ.get("ALCHEMICAL_DATABASE_URI") if ALCHEMICAL_DATABASE_URI is None: raise ValueError("ALCHEMICAL_DATABASE_URI is undefined") -if 'unittest' in sys.modules and 'sqlite' not in ALCHEMICAL_DATABASE_URI: +if "unittest" in sys.modules and "sqlite" not in ALCHEMICAL_DATABASE_URI: raise ValueError("Unit tests running on non-Sqlite database") db = Alchemical(ALCHEMICAL_DATABASE_URI) # Database classes class Carts(dbtables.CartsTable): - def __init__( self, session: Session, @@ -61,7 +60,6 @@ class Carts(dbtables.CartsTable): class NoteColours(dbtables.NoteColoursTable): - def __init__( self, session: Session, @@ -123,7 +121,6 @@ class NoteColours(dbtables.NoteColoursTable): class Playdates(dbtables.PlaydatesTable): - def __init__(self, session: Session, track_id: int) -> None: """Record that track was played""" @@ -162,7 +159,6 @@ class Playdates(dbtables.PlaydatesTable): class Playlists(dbtables.PlaylistsTable): - def __init__(self, session: Session, name: str): self.name = name session.add(self) @@ -175,11 +171,7 @@ class Playlists(dbtables.PlaylistsTable): """ session.execute( - update(Playlists) - .where( - (Playlists.id.in_(playlist_ids)) - ) - .values(tab=None) + update(Playlists).where((Playlists.id.in_(playlist_ids))).values(tab=None) ) def close(self) -> None: @@ -295,7 +287,6 @@ class Playlists(dbtables.PlaylistsTable): class PlaylistRows(dbtables.PlaylistRowsTable): - def __init__( self, session: Session, @@ -361,9 +352,7 @@ class PlaylistRows(dbtables.PlaylistRowsTable): return session.execute(stmt).unique().scalar_one() @classmethod - def deep_rows( - cls, session: Session, playlist_id: int - ) -> Sequence["PlaylistRows"]: + def deep_rows(cls, session: Session, playlist_id: int) -> Sequence["PlaylistRows"]: """ Return a list of playlist rows that include full track and lastplayed data for given playlist_id., Sequence @@ -380,9 +369,7 @@ class PlaylistRows(dbtables.PlaylistRowsTable): return session.scalars(stmt).unique().all() @staticmethod - def delete_higher_rows( - session: Session, playlist_id: int, maxrow: int - ) -> None: + def delete_higher_rows(session: Session, playlist_id: int, maxrow: int) -> None: """ Delete rows in given playlist that have a higher row number than 'maxrow' @@ -527,10 +514,21 @@ class PlaylistRows(dbtables.PlaylistRowsTable): @classmethod def insert_row( - cls, session: Session, playlist_id: int, new_row_number: int + cls, + session: Session, + playlist_id: int, + new_row_number: int, + note: str = "", + track_id: Optional[int] = None, ) -> "PlaylistRows": cls.move_rows_down(session, playlist_id, new_row_number, 1) - return cls(session, playlist_id, new_row_number) + return cls( + session, + playlist_id=playlist_id, + row_number=new_row_number, + note=note, + track_id=track_id, + ) @staticmethod def move_rows_down( @@ -574,7 +572,6 @@ class PlaylistRows(dbtables.PlaylistRowsTable): class Settings(dbtables.SettingsTable): - def __init__(self, session: Session, name: str): self.name = name session.add(self) @@ -612,7 +609,6 @@ class Settings(dbtables.SettingsTable): class Tracks(dbtables.TracksTable): - def __repr__(self) -> str: return ( f" None: """Open _write_pipe.""" @@ -187,16 +187,16 @@ class PipeClient(): self._write_pipe.write(command + EOL) # Check that read pipe is alive if PipeClient.reader_pipe_broken.is_set(): - raise RuntimeError('PipeClient: Read-pipe error.') + raise RuntimeError("PipeClient: Read-pipe error.") try: self._write_pipe.flush() if self.timer: self._start_time = time.time() - self.reply = '' + self.reply = "" PipeClient.reply_ready.clear() except IOError as err: if err.errno == errno.EPIPE: - raise RuntimeError('PipeClient: Write-pipe error.') + raise RuntimeError("PipeClient: Write-pipe error.") else: raise @@ -211,20 +211,20 @@ class PipeClient(): line = read_pipe.readline() # Stop timer as soon as we get first line of response. stop_time = time.time() - while pipe_ok and line != '\n': + while pipe_ok and line != "\n": message += line line = read_pipe.readline() - if line == '': + if line == "": # No data in read_pipe indicates that the pipe # is broken (Audacity may have crashed). PipeClient.reader_pipe_broken.set() pipe_ok = False if self.timer: xtime = (stop_time - self._start_time) * 1000 - message += f'Execution time: {xtime:.2f}ms' + message += f"Execution time: {xtime:.2f}ms" self.reply = message PipeClient.reply_ready.set() - message = '' + message = "" def read(self) -> str: """Read Audacity's reply from pipe. @@ -238,31 +238,45 @@ class PipeClient(): """ if not PipeClient.reply_ready.is_set(): - return '' + return "" return self.reply def bool_from_string(strval) -> bool: """Return boolean value from string""" - if strval.lower() in ('true', 't', '1', 'yes', 'y'): + if strval.lower() in ("true", "t", "1", "yes", "y"): return True - if strval.lower() in ('false', 'f', '0', 'no', 'n'): + if strval.lower() in ("false", "f", "0", "no", "n"): return False - raise argparse.ArgumentTypeError('Boolean value expected.') + raise argparse.ArgumentTypeError("Boolean value expected.") def main() -> None: """Interactive command-line for PipeClient""" parser = argparse.ArgumentParser() - parser.add_argument('-t', '--timeout', type=float, metavar='', default=10, - help="timeout for reply in seconds (default: 10") - parser.add_argument('-s', '--show-time', metavar='True/False', - nargs='?', type=bool_from_string, - const='t', default='t', dest='show', - help='show command execution time (default: True)') - parser.add_argument('-d', '--docs', action='store_true', - help='show documentation and exit') + parser.add_argument( + "-t", + "--timeout", + type=float, + metavar="", + default=10, + help="timeout for reply in seconds (default: 10", + ) + parser.add_argument( + "-s", + "--show-time", + metavar="True/False", + nargs="?", + type=bool_from_string, + const="t", + default="t", + dest="show", + help="show command execution time (default: True)", + ) + parser.add_argument( + "-d", "--docs", action="store_true", help="show documentation and exit" + ) args = parser.parse_args() if args.docs: @@ -271,23 +285,23 @@ def main() -> None: client: PipeClient = PipeClient() while True: - reply: str = '' + reply: str = "" message: str = input("\nEnter command or 'Q' to quit: ") start = time.time() - if message.upper() == 'Q': + if message.upper() == "Q": sys.exit(0) - elif message == '': + elif message == "": pass else: client.write(message, timer=args.show) - while reply == '': + while reply == "": time.sleep(0.1) # allow time for reply if time.time() - start > args.timeout: - reply = 'PipeClient: Reply timed-out.' + reply = "PipeClient: Reply timed-out." else: reply = client.read() print(reply) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/app/playlistmodel.py b/app/playlistmodel.py index 0643c5a..d853bee 100644 --- a/app/playlistmodel.py +++ b/app/playlistmodel.py @@ -27,6 +27,7 @@ from PyQt6.QtGui import ( # Third party imports import obsws_python as obs # type: ignore + # import snoop # type: ignore # App imports @@ -694,8 +695,9 @@ class PlaylistModel(QAbstractTableModel): < prd.plr_rownum ) ): - section_end_time = track_sequence.now.end_time + dt.timedelta( - milliseconds=duration + section_end_time = ( + track_sequence.now.end_time + + dt.timedelta(milliseconds=duration) ) end_time_str = ( ", section end time " @@ -750,7 +752,7 @@ class PlaylistModel(QAbstractTableModel): self, proposed_row_number: Optional[int], track_id: Optional[int] = None, - note: Optional[str] = None, + note: str = "", ) -> None: """ Insert a row. @@ -762,11 +764,13 @@ class PlaylistModel(QAbstractTableModel): with db.Session() as session: super().beginInsertRows(QModelIndex(), new_row_number, new_row_number) - plr = PlaylistRows.insert_row(session, self.playlist_id, new_row_number) - - plr.track_id = track_id - if note: - plr.note = note + _ = PlaylistRows.insert_row( + session=session, + playlist_id=self.playlist_id, + new_row_number=new_row_number, + note=note, + track_id=track_id, + ) self.refresh_data(session) super().endInsertRows() diff --git a/app/playlists.py b/app/playlists.py index d9d25b2..ea8791e 100644 --- a/app/playlists.py +++ b/app/playlists.py @@ -47,6 +47,7 @@ from helpers import ( from log import log from models import Settings from playlistmodel import PlaylistModel, PlaylistProxyModel + if TYPE_CHECKING: from musicmuster import Window diff --git a/app/ui/main_window_ui.py b/app/ui/main_window_ui.py index 0e2413b..99a20d2 100644 --- a/app/ui/main_window_ui.py +++ b/app/ui/main_window_ui.py @@ -15,7 +15,11 @@ class Ui_MainWindow(object): MainWindow.resize(1280, 857) MainWindow.setMinimumSize(QtCore.QSize(1280, 0)) icon = QtGui.QIcon() - icon.addPixmap(QtGui.QPixmap(":/icons/musicmuster"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) + icon.addPixmap( + QtGui.QPixmap(":/icons/musicmuster"), + QtGui.QIcon.Mode.Normal, + QtGui.QIcon.State.Off, + ) MainWindow.setWindowIcon(icon) MainWindow.setStyleSheet("") self.centralwidget = QtWidgets.QWidget(parent=MainWindow) @@ -27,39 +31,62 @@ class Ui_MainWindow(object): self.verticalLayout_3 = QtWidgets.QVBoxLayout() self.verticalLayout_3.setObjectName("verticalLayout_3") self.previous_track_2 = QtWidgets.QLabel(parent=self.centralwidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Preferred, + QtWidgets.QSizePolicy.Policy.Preferred, + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.previous_track_2.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.previous_track_2.sizePolicy().hasHeightForWidth() + ) self.previous_track_2.setSizePolicy(sizePolicy) self.previous_track_2.setMaximumSize(QtCore.QSize(230, 16777215)) font = QtGui.QFont() font.setFamily("Sans") font.setPointSize(20) self.previous_track_2.setFont(font) - self.previous_track_2.setStyleSheet("background-color: #f8d7da;\n" -"border: 1px solid rgb(85, 87, 83);") - self.previous_track_2.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter) + self.previous_track_2.setStyleSheet( + "background-color: #f8d7da;\n" "border: 1px solid rgb(85, 87, 83);" + ) + self.previous_track_2.setAlignment( + QtCore.Qt.AlignmentFlag.AlignRight + | QtCore.Qt.AlignmentFlag.AlignTrailing + | QtCore.Qt.AlignmentFlag.AlignVCenter + ) self.previous_track_2.setObjectName("previous_track_2") self.verticalLayout_3.addWidget(self.previous_track_2) self.current_track_2 = QtWidgets.QLabel(parent=self.centralwidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Preferred, + QtWidgets.QSizePolicy.Policy.Preferred, + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.current_track_2.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.current_track_2.sizePolicy().hasHeightForWidth() + ) self.current_track_2.setSizePolicy(sizePolicy) self.current_track_2.setMaximumSize(QtCore.QSize(230, 16777215)) font = QtGui.QFont() font.setFamily("Sans") font.setPointSize(20) self.current_track_2.setFont(font) - self.current_track_2.setStyleSheet("background-color: #d4edda;\n" -"border: 1px solid rgb(85, 87, 83);") - self.current_track_2.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter) + self.current_track_2.setStyleSheet( + "background-color: #d4edda;\n" "border: 1px solid rgb(85, 87, 83);" + ) + self.current_track_2.setAlignment( + QtCore.Qt.AlignmentFlag.AlignRight + | QtCore.Qt.AlignmentFlag.AlignTrailing + | QtCore.Qt.AlignmentFlag.AlignVCenter + ) self.current_track_2.setObjectName("current_track_2") self.verticalLayout_3.addWidget(self.current_track_2) self.next_track_2 = QtWidgets.QLabel(parent=self.centralwidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Preferred, + QtWidgets.QSizePolicy.Policy.Preferred, + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.next_track_2.sizePolicy().hasHeightForWidth()) @@ -69,19 +96,29 @@ class Ui_MainWindow(object): font.setFamily("Sans") font.setPointSize(20) self.next_track_2.setFont(font) - self.next_track_2.setStyleSheet("background-color: #fff3cd;\n" -"border: 1px solid rgb(85, 87, 83);") - self.next_track_2.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter) + self.next_track_2.setStyleSheet( + "background-color: #fff3cd;\n" "border: 1px solid rgb(85, 87, 83);" + ) + self.next_track_2.setAlignment( + QtCore.Qt.AlignmentFlag.AlignRight + | QtCore.Qt.AlignmentFlag.AlignTrailing + | QtCore.Qt.AlignmentFlag.AlignVCenter + ) self.next_track_2.setObjectName("next_track_2") self.verticalLayout_3.addWidget(self.next_track_2) self.horizontalLayout_3.addLayout(self.verticalLayout_3) self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout.setObjectName("verticalLayout") self.hdrPreviousTrack = QtWidgets.QLabel(parent=self.centralwidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Preferred, + QtWidgets.QSizePolicy.Policy.Preferred, + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.hdrPreviousTrack.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.hdrPreviousTrack.sizePolicy().hasHeightForWidth() + ) self.hdrPreviousTrack.setSizePolicy(sizePolicy) self.hdrPreviousTrack.setMinimumSize(QtCore.QSize(0, 0)) self.hdrPreviousTrack.setMaximumSize(QtCore.QSize(16777215, 16777215)) @@ -89,32 +126,43 @@ class Ui_MainWindow(object): font.setFamily("Sans") font.setPointSize(20) self.hdrPreviousTrack.setFont(font) - self.hdrPreviousTrack.setStyleSheet("background-color: #f8d7da;\n" -"border: 1px solid rgb(85, 87, 83);") + self.hdrPreviousTrack.setStyleSheet( + "background-color: #f8d7da;\n" "border: 1px solid rgb(85, 87, 83);" + ) self.hdrPreviousTrack.setText("") self.hdrPreviousTrack.setWordWrap(False) self.hdrPreviousTrack.setObjectName("hdrPreviousTrack") self.verticalLayout.addWidget(self.hdrPreviousTrack) self.hdrCurrentTrack = QtWidgets.QPushButton(parent=self.centralwidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Preferred, + QtWidgets.QSizePolicy.Policy.Preferred, + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.hdrCurrentTrack.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.hdrCurrentTrack.sizePolicy().hasHeightForWidth() + ) self.hdrCurrentTrack.setSizePolicy(sizePolicy) font = QtGui.QFont() font.setPointSize(20) self.hdrCurrentTrack.setFont(font) - self.hdrCurrentTrack.setStyleSheet("background-color: #d4edda;\n" -"border: 1px solid rgb(85, 87, 83);\n" -"text-align: left;\n" -"padding-left: 8px;\n" -"") + self.hdrCurrentTrack.setStyleSheet( + "background-color: #d4edda;\n" + "border: 1px solid rgb(85, 87, 83);\n" + "text-align: left;\n" + "padding-left: 8px;\n" + "" + ) self.hdrCurrentTrack.setText("") self.hdrCurrentTrack.setFlat(True) self.hdrCurrentTrack.setObjectName("hdrCurrentTrack") self.verticalLayout.addWidget(self.hdrCurrentTrack) self.hdrNextTrack = QtWidgets.QPushButton(parent=self.centralwidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Preferred, + QtWidgets.QSizePolicy.Policy.Preferred, + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.hdrNextTrack.sizePolicy().hasHeightForWidth()) @@ -122,10 +170,12 @@ class Ui_MainWindow(object): font = QtGui.QFont() font.setPointSize(20) self.hdrNextTrack.setFont(font) - self.hdrNextTrack.setStyleSheet("background-color: #fff3cd;\n" -"border: 1px solid rgb(85, 87, 83);\n" -"text-align: left;\n" -"padding-left: 8px;") + self.hdrNextTrack.setStyleSheet( + "background-color: #fff3cd;\n" + "border: 1px solid rgb(85, 87, 83);\n" + "text-align: left;\n" + "padding-left: 8px;" + ) self.hdrNextTrack.setText("") self.hdrNextTrack.setFlat(True) self.hdrNextTrack.setObjectName("hdrNextTrack") @@ -160,7 +210,12 @@ class Ui_MainWindow(object): self.cartsWidget.setObjectName("cartsWidget") self.horizontalLayout_Carts = QtWidgets.QHBoxLayout(self.cartsWidget) self.horizontalLayout_Carts.setObjectName("horizontalLayout_Carts") - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + spacerItem = QtWidgets.QSpacerItem( + 40, + 20, + QtWidgets.QSizePolicy.Policy.Expanding, + QtWidgets.QSizePolicy.Policy.Minimum, + ) self.horizontalLayout_Carts.addItem(spacerItem) self.gridLayout_4.addWidget(self.cartsWidget, 2, 0, 1, 1) self.frame_6 = QtWidgets.QFrame(parent=self.centralwidget) @@ -205,7 +260,11 @@ class Ui_MainWindow(object): self.btnPreview = QtWidgets.QPushButton(parent=self.FadeStopInfoFrame) self.btnPreview.setMinimumSize(QtCore.QSize(132, 41)) icon1 = QtGui.QIcon() - icon1.addPixmap(QtGui.QPixmap(":/icons/headphones"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) + icon1.addPixmap( + QtGui.QPixmap(":/icons/headphones"), + QtGui.QIcon.Mode.Normal, + QtGui.QIcon.State.Off, + ) self.btnPreview.setIcon(icon1) self.btnPreview.setIconSize(QtCore.QSize(30, 30)) self.btnPreview.setCheckable(True) @@ -289,10 +348,15 @@ class Ui_MainWindow(object): self.label_silent_timer.setObjectName("label_silent_timer") self.horizontalLayout.addWidget(self.frame_silent) self.widgetFadeVolume = PlotWidget(parent=self.InfoFooterFrame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Preferred, + QtWidgets.QSizePolicy.Policy.Preferred, + ) sizePolicy.setHorizontalStretch(1) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.widgetFadeVolume.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.widgetFadeVolume.sizePolicy().hasHeightForWidth() + ) self.widgetFadeVolume.setSizePolicy(sizePolicy) self.widgetFadeVolume.setMinimumSize(QtCore.QSize(0, 0)) self.widgetFadeVolume.setObjectName("widgetFadeVolume") @@ -309,7 +373,11 @@ class Ui_MainWindow(object): self.btnFade.setMinimumSize(QtCore.QSize(132, 32)) self.btnFade.setMaximumSize(QtCore.QSize(164, 16777215)) icon2 = QtGui.QIcon() - icon2.addPixmap(QtGui.QPixmap(":/icons/fade"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) + icon2.addPixmap( + QtGui.QPixmap(":/icons/fade"), + QtGui.QIcon.Mode.Normal, + QtGui.QIcon.State.Off, + ) self.btnFade.setIcon(icon2) self.btnFade.setIconSize(QtCore.QSize(30, 30)) self.btnFade.setObjectName("btnFade") @@ -317,7 +385,11 @@ class Ui_MainWindow(object): self.btnStop = QtWidgets.QPushButton(parent=self.frame) self.btnStop.setMinimumSize(QtCore.QSize(0, 36)) icon3 = QtGui.QIcon() - icon3.addPixmap(QtGui.QPixmap(":/icons/stopsign"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) + icon3.addPixmap( + QtGui.QPixmap(":/icons/stopsign"), + QtGui.QIcon.Mode.Normal, + QtGui.QIcon.State.Off, + ) self.btnStop.setIcon(icon3) self.btnStop.setObjectName("btnStop") self.verticalLayout_5.addWidget(self.btnStop) @@ -343,39 +415,69 @@ class Ui_MainWindow(object): MainWindow.setStatusBar(self.statusbar) self.actionPlay_next = QtGui.QAction(parent=MainWindow) icon4 = QtGui.QIcon() - icon4.addPixmap(QtGui.QPixmap("app/ui/../../../../.designer/backup/icon-play.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) + icon4.addPixmap( + QtGui.QPixmap("app/ui/../../../../.designer/backup/icon-play.png"), + QtGui.QIcon.Mode.Normal, + QtGui.QIcon.State.Off, + ) self.actionPlay_next.setIcon(icon4) self.actionPlay_next.setObjectName("actionPlay_next") self.actionSkipToNext = QtGui.QAction(parent=MainWindow) icon5 = QtGui.QIcon() - icon5.addPixmap(QtGui.QPixmap(":/icons/next"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) + icon5.addPixmap( + QtGui.QPixmap(":/icons/next"), + QtGui.QIcon.Mode.Normal, + QtGui.QIcon.State.Off, + ) self.actionSkipToNext.setIcon(icon5) self.actionSkipToNext.setObjectName("actionSkipToNext") self.actionInsertTrack = QtGui.QAction(parent=MainWindow) icon6 = QtGui.QIcon() - icon6.addPixmap(QtGui.QPixmap("app/ui/../../../../.designer/backup/icon_search_database.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) + icon6.addPixmap( + QtGui.QPixmap( + "app/ui/../../../../.designer/backup/icon_search_database.png" + ), + QtGui.QIcon.Mode.Normal, + QtGui.QIcon.State.Off, + ) self.actionInsertTrack.setIcon(icon6) self.actionInsertTrack.setObjectName("actionInsertTrack") self.actionAdd_file = QtGui.QAction(parent=MainWindow) icon7 = QtGui.QIcon() - icon7.addPixmap(QtGui.QPixmap("app/ui/../../../../.designer/backup/icon_open_file.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) + icon7.addPixmap( + QtGui.QPixmap("app/ui/../../../../.designer/backup/icon_open_file.png"), + QtGui.QIcon.Mode.Normal, + QtGui.QIcon.State.Off, + ) self.actionAdd_file.setIcon(icon7) self.actionAdd_file.setObjectName("actionAdd_file") self.actionFade = QtGui.QAction(parent=MainWindow) icon8 = QtGui.QIcon() - icon8.addPixmap(QtGui.QPixmap("app/ui/../../../../.designer/backup/icon-fade.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) + icon8.addPixmap( + QtGui.QPixmap("app/ui/../../../../.designer/backup/icon-fade.png"), + QtGui.QIcon.Mode.Normal, + QtGui.QIcon.State.Off, + ) self.actionFade.setIcon(icon8) self.actionFade.setObjectName("actionFade") self.actionStop = QtGui.QAction(parent=MainWindow) icon9 = QtGui.QIcon() - icon9.addPixmap(QtGui.QPixmap(":/icons/stop"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) + icon9.addPixmap( + QtGui.QPixmap(":/icons/stop"), + QtGui.QIcon.Mode.Normal, + QtGui.QIcon.State.Off, + ) self.actionStop.setIcon(icon9) self.actionStop.setObjectName("actionStop") self.action_Clear_selection = QtGui.QAction(parent=MainWindow) self.action_Clear_selection.setObjectName("action_Clear_selection") self.action_Resume_previous = QtGui.QAction(parent=MainWindow) icon10 = QtGui.QIcon() - icon10.addPixmap(QtGui.QPixmap(":/icons/previous"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) + icon10.addPixmap( + QtGui.QPixmap(":/icons/previous"), + QtGui.QIcon.Mode.Normal, + QtGui.QIcon.State.Off, + ) self.action_Resume_previous.setIcon(icon10) self.action_Resume_previous.setObjectName("action_Resume_previous") self.actionE_xit = QtGui.QAction(parent=MainWindow) @@ -422,7 +524,9 @@ class Ui_MainWindow(object): self.actionImport = QtGui.QAction(parent=MainWindow) self.actionImport.setObjectName("actionImport") self.actionDownload_CSV_of_played_tracks = QtGui.QAction(parent=MainWindow) - self.actionDownload_CSV_of_played_tracks.setObjectName("actionDownload_CSV_of_played_tracks") + self.actionDownload_CSV_of_played_tracks.setObjectName( + "actionDownload_CSV_of_played_tracks" + ) self.actionSearch = QtGui.QAction(parent=MainWindow) self.actionSearch.setObjectName("actionSearch") self.actionInsertSectionHeader = QtGui.QAction(parent=MainWindow) @@ -450,9 +554,13 @@ class Ui_MainWindow(object): self.actionResume = QtGui.QAction(parent=MainWindow) self.actionResume.setObjectName("actionResume") self.actionSearch_title_in_Wikipedia = QtGui.QAction(parent=MainWindow) - self.actionSearch_title_in_Wikipedia.setObjectName("actionSearch_title_in_Wikipedia") + self.actionSearch_title_in_Wikipedia.setObjectName( + "actionSearch_title_in_Wikipedia" + ) self.actionSearch_title_in_Songfacts = QtGui.QAction(parent=MainWindow) - self.actionSearch_title_in_Songfacts.setObjectName("actionSearch_title_in_Songfacts") + self.actionSearch_title_in_Songfacts.setObjectName( + "actionSearch_title_in_Songfacts" + ) self.actionSelect_duplicate_rows = QtGui.QAction(parent=MainWindow) self.actionSelect_duplicate_rows.setObjectName("actionSelect_duplicate_rows") self.menuFile.addAction(self.actionNewPlaylist) @@ -503,7 +611,7 @@ class Ui_MainWindow(object): self.retranslateUi(MainWindow) self.tabPlaylist.setCurrentIndex(-1) self.tabInfolist.setCurrentIndex(-1) - self.actionE_xit.triggered.connect(MainWindow.close) # type: ignore + self.actionE_xit.triggered.connect(MainWindow.close) # type: ignore QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): @@ -539,38 +647,58 @@ class Ui_MainWindow(object): self.actionFade.setShortcut(_translate("MainWindow", "Ctrl+Z")) self.actionStop.setText(_translate("MainWindow", "S&top")) self.actionStop.setShortcut(_translate("MainWindow", "Ctrl+Alt+S")) - self.action_Clear_selection.setText(_translate("MainWindow", "Clear &selection")) + self.action_Clear_selection.setText( + _translate("MainWindow", "Clear &selection") + ) self.action_Clear_selection.setShortcut(_translate("MainWindow", "Esc")) - self.action_Resume_previous.setText(_translate("MainWindow", "&Resume previous")) + self.action_Resume_previous.setText( + _translate("MainWindow", "&Resume previous") + ) self.actionE_xit.setText(_translate("MainWindow", "E&xit")) self.actionTest.setText(_translate("MainWindow", "&Test")) self.actionOpenPlaylist.setText(_translate("MainWindow", "O&pen...")) self.actionNewPlaylist.setText(_translate("MainWindow", "&New...")) self.actionTestFunction.setText(_translate("MainWindow", "&Test function")) - self.actionSkipToFade.setText(_translate("MainWindow", "&Skip to start of fade")) + self.actionSkipToFade.setText( + _translate("MainWindow", "&Skip to start of fade") + ) self.actionSkipToEnd.setText(_translate("MainWindow", "Skip to &end of track")) self.actionClosePlaylist.setText(_translate("MainWindow", "&Close")) self.actionRenamePlaylist.setText(_translate("MainWindow", "&Rename...")) self.actionDeletePlaylist.setText(_translate("MainWindow", "Dele&te...")) - self.actionMoveSelected.setText(_translate("MainWindow", "Mo&ve selected tracks to...")) + self.actionMoveSelected.setText( + _translate("MainWindow", "Mo&ve selected tracks to...") + ) self.actionExport_playlist.setText(_translate("MainWindow", "E&xport...")) self.actionSetNext.setText(_translate("MainWindow", "Set &next")) self.actionSetNext.setShortcut(_translate("MainWindow", "Ctrl+N")) - self.actionSelect_next_track.setText(_translate("MainWindow", "Select next track")) + self.actionSelect_next_track.setText( + _translate("MainWindow", "Select next track") + ) self.actionSelect_next_track.setShortcut(_translate("MainWindow", "J")) - self.actionSelect_previous_track.setText(_translate("MainWindow", "Select previous track")) + self.actionSelect_previous_track.setText( + _translate("MainWindow", "Select previous track") + ) self.actionSelect_previous_track.setShortcut(_translate("MainWindow", "K")) - self.actionSelect_played_tracks.setText(_translate("MainWindow", "Select played tracks")) - self.actionMoveUnplayed.setText(_translate("MainWindow", "Move &unplayed tracks to...")) + self.actionSelect_played_tracks.setText( + _translate("MainWindow", "Select played tracks") + ) + self.actionMoveUnplayed.setText( + _translate("MainWindow", "Move &unplayed tracks to...") + ) self.actionAdd_note.setText(_translate("MainWindow", "Add note...")) self.actionAdd_note.setShortcut(_translate("MainWindow", "Ctrl+T")) self.actionEnable_controls.setText(_translate("MainWindow", "Enable controls")) self.actionImport.setText(_translate("MainWindow", "Import track...")) self.actionImport.setShortcut(_translate("MainWindow", "Ctrl+Shift+I")) - self.actionDownload_CSV_of_played_tracks.setText(_translate("MainWindow", "Download CSV of played tracks...")) + self.actionDownload_CSV_of_played_tracks.setText( + _translate("MainWindow", "Download CSV of played tracks...") + ) self.actionSearch.setText(_translate("MainWindow", "Search...")) self.actionSearch.setShortcut(_translate("MainWindow", "/")) - self.actionInsertSectionHeader.setText(_translate("MainWindow", "Insert §ion header...")) + self.actionInsertSectionHeader.setText( + _translate("MainWindow", "Insert §ion header...") + ) self.actionInsertSectionHeader.setShortcut(_translate("MainWindow", "Ctrl+H")) self.actionRemove.setText(_translate("MainWindow", "&Remove track")) self.actionFind_next.setText(_translate("MainWindow", "Find next")) @@ -578,8 +706,12 @@ class Ui_MainWindow(object): self.actionFind_previous.setText(_translate("MainWindow", "Find previous")) self.actionFind_previous.setShortcut(_translate("MainWindow", "P")) self.action_About.setText(_translate("MainWindow", "&About")) - self.actionSave_as_template.setText(_translate("MainWindow", "Save as template...")) - self.actionNew_from_template.setText(_translate("MainWindow", "New from template...")) + 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...")) self.actionMark_for_moving.setText(_translate("MainWindow", "Mark for moving")) @@ -588,10 +720,22 @@ class Ui_MainWindow(object): self.actionPaste.setShortcut(_translate("MainWindow", "Ctrl+V")) self.actionResume.setText(_translate("MainWindow", "Resume")) self.actionResume.setShortcut(_translate("MainWindow", "Ctrl+R")) - self.actionSearch_title_in_Wikipedia.setText(_translate("MainWindow", "Search title in Wikipedia")) - self.actionSearch_title_in_Wikipedia.setShortcut(_translate("MainWindow", "Ctrl+W")) - self.actionSearch_title_in_Songfacts.setText(_translate("MainWindow", "Search title in Songfacts")) - self.actionSearch_title_in_Songfacts.setShortcut(_translate("MainWindow", "Ctrl+S")) - self.actionSelect_duplicate_rows.setText(_translate("MainWindow", "Select duplicate rows...")) + self.actionSearch_title_in_Wikipedia.setText( + _translate("MainWindow", "Search title in Wikipedia") + ) + self.actionSearch_title_in_Wikipedia.setShortcut( + _translate("MainWindow", "Ctrl+W") + ) + self.actionSearch_title_in_Songfacts.setText( + _translate("MainWindow", "Search title in Songfacts") + ) + self.actionSearch_title_in_Songfacts.setShortcut( + _translate("MainWindow", "Ctrl+S") + ) + self.actionSelect_duplicate_rows.setText( + _translate("MainWindow", "Select duplicate rows...") + ) + + from infotabs import InfoTabs from pyqtgraph import PlotWidget diff --git a/archive/audplayer.py b/archive/audplayer.py index d9442ef..7d4074e 100755 --- a/archive/audplayer.py +++ b/archive/audplayer.py @@ -49,9 +49,9 @@ def leading_silence(audio_segment, silence_threshold=-50.0, chunk_size=10): trim_ms = 0 # ms assert chunk_size > 0 # to avoid infinite loop - while ( - audio_segment[trim_ms:trim_ms + chunk_size].dBFS < silence_threshold - and trim_ms < len(audio_segment)): + while audio_segment[ + trim_ms : trim_ms + chunk_size + ].dBFS < silence_threshold and trim_ms < len(audio_segment): trim_ms += chunk_size # if there is no end it should return the length of the segment @@ -72,8 +72,9 @@ def significant_fade(audio_segment, fade_threshold=-20.0, chunk_size=10): segment_length = audio_segment.duration_seconds * 1000 # ms trim_ms = segment_length - chunk_size while ( - audio_segment[trim_ms:trim_ms + chunk_size].dBFS < fade_threshold - and trim_ms > 0): + audio_segment[trim_ms : trim_ms + chunk_size].dBFS < fade_threshold + and trim_ms > 0 + ): trim_ms -= chunk_size # if there is no trailing silence, return lenght of track (it's less @@ -94,8 +95,9 @@ def trailing_silence(audio_segment, silence_threshold=-50.0, chunk_size=10): segment_length = audio_segment.duration_seconds * 1000 # ms trim_ms = segment_length - chunk_size while ( - audio_segment[trim_ms:trim_ms + chunk_size].dBFS < silence_threshold - and trim_ms > 0): + audio_segment[trim_ms : trim_ms + chunk_size].dBFS < silence_threshold + and trim_ms > 0 + ): trim_ms -= chunk_size # if there is no trailing silence, return lenght of track (it's less @@ -124,15 +126,17 @@ def update_progress(player, talk_at, silent_at): remaining_time = total_time - elapsed_time talk_time = remaining_time - (total_time - talk_at) silent_time = remaining_time - (total_time - silent_at) - end_time = (dt.datetime.now() + timedelta( - milliseconds=remaining_time)).strftime("%H:%M:%S") + end_time = (dt.datetime.now() + timedelta(milliseconds=remaining_time)).strftime( + "%H:%M:%S" + ) print( f"\t{ms_to_mmss(elapsed_time)}/" f"{ms_to_mmss(total_time)}\t\t" f"Talk in: {ms_to_mmss(talk_time)} " f"Silent in: {ms_to_mmss(silent_time)} " - f"Ends at: {end_time} [{ms_to_mmss(remaining_time)}]" - , end="\r") + f"Ends at: {end_time} [{ms_to_mmss(remaining_time)}]", + end="\r", + ) # Print name of current song, print name of next song. Play current when @@ -163,21 +167,21 @@ def test(): test() # next_song = get_next_song -# +# # def play_track(): # r = run_aud_cmd("--current-song-length -# -# -# +# +# +# # def play(): # play_track() # songtimer_start() -# -# +# +# # print("Start playing in 3 seconds") -# +# # sleep(3) -# +# # play() diff --git a/archive/spike.py b/archive/spike.py index 5757359..b4b6ea6 100644 --- a/archive/spike.py +++ b/archive/spike.py @@ -1,5 +1,3 @@ - - # tl = Timeloop() # # @@ -48,34 +46,34 @@ # rt.stop() # better in a try/finally block to make sure the program ends! # print("End") - #def kae2(self, index): - # print(f"table header click, index={index}") +# def kae2(self, index): +# print(f"table header click, index={index}") - #def kae(self, a, b, c): - # self.data.append(f"a={a}, b={b}, c={c}") +# def kae(self, a, b, c): +# self.data.append(f"a={a}, b={b}, c={c}") - #def mousePressEvent(self, QMouseEvent): - # print("mouse press") +# def mousePressEvent(self, QMouseEvent): +# print("mouse press") - #def mouseReleaseEvent(self, QMouseEvent): - # print("mouse release") - # # QMessageBox.about( - # # self, - # # "About Sample Editor", - # # "\n".join(self.data) - # # ) - #def eventFilter(self, obj, event): - # # you could be doing different groups of actions - # # for different types of widgets and either filtering - # # the event or not. - # # Here we just check if its one of the layout widgets - # # if self.layout.indexOf(obj) != -1: - # # print(f"event received: {event.type()}") - # if event.type() == QEvent.MouseButtonPress: - # print("Widget click") - # # if I returned True right here, the event - # # would be filtered and not reach the obj, - # # meaning that I decided to handle it myself +# def mouseReleaseEvent(self, QMouseEvent): +# print("mouse release") +# # QMessageBox.about( +# # self, +# # "About Sample Editor", +# # "\n".join(self.data) +# # ) +# def eventFilter(self, obj, event): +# # you could be doing different groups of actions +# # for different types of widgets and either filtering +# # the event or not. +# # Here we just check if its one of the layout widgets +# # if self.layout.indexOf(obj) != -1: +# # print(f"event received: {event.type()}") +# if event.type() == QEvent.MouseButtonPress: +# print("Widget click") +# # if I returned True right here, the event +# # would be filtered and not reach the obj, +# # meaning that I decided to handle it myself - # # regardless, just do the default - # return super().eventFilter(obj, event) +# # regardless, just do the default +# return super().eventFilter(obj, event) diff --git a/archive/todo/todo.py b/archive/todo/todo.py index eb1aa3b..ac46aad 100644 --- a/archive/todo/todo.py +++ b/archive/todo/todo.py @@ -7,19 +7,19 @@ from PyQt5.QtCore import Qt qt_creator_file = "mainwindow.ui" Ui_MainWindow, QtBaseClass = uic.loadUiType(qt_creator_file) -tick = QtGui.QImage('tick.png') +tick = QtGui.QImage("tick.png") class TodoModel(QtCore.QAbstractListModel): def __init__(self, *args, todos=None, **kwargs): super(TodoModel, self).__init__(*args, **kwargs) self.todos = todos or [] - + def data(self, index, role): if role == Qt.DisplayRole: _, text = self.todos[index.row()] return text - + if role == Qt.DecorationRole: status, _ = self.todos[index.row()] if status: @@ -51,15 +51,15 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): and then clearing it. """ text = self.todoEdit.text() - if text: # Don't add empty strings. + if text: # Don't add empty strings. # Access the list via the model. self.model.todos.append((False, text)) - # Trigger refresh. + # Trigger refresh. self.model.layoutChanged.emit() - # Empty the input + # Empty the input self.todoEdit.setText("") self.save() - + def delete(self): indexes = self.todoView.selectedIndexes() if indexes: @@ -71,7 +71,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): # Clear the selection (as it is no longer valid). self.todoView.clearSelection() self.save() - + def complete(self): indexes = self.todoView.selectedIndexes() if indexes: @@ -79,22 +79,22 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): row = index.row() status, text = self.model.todos[row] self.model.todos[row] = (True, text) - # .dataChanged takes top-left and bottom right, which are equal + # .dataChanged takes top-left and bottom right, which are equal # for a single selection. self.model.dataChanged.emit(index, index) # Clear the selection (as it is no longer valid). self.todoView.clearSelection() self.save() - + def load(self): try: - with open('data.db', 'r') as f: + with open("data.db", "r") as f: self.model.todos = json.load(f) except Exception: pass def save(self): - with open('data.db', 'w') as f: + with open("data.db", "w") as f: data = json.dump(self.model.todos, f) @@ -102,5 +102,3 @@ app = QtWidgets.QApplication(sys.argv) window = MainWindow() window.show() app.exec_() - - diff --git a/migrations/versions/0c604bf490f8_add_played_column_to_playlist_rows.py b/migrations/versions/0c604bf490f8_add_played_column_to_playlist_rows.py index 72b9a6c..975ce92 100644 --- a/migrations/versions/0c604bf490f8_add_played_column_to_playlist_rows.py +++ b/migrations/versions/0c604bf490f8_add_played_column_to_playlist_rows.py @@ -10,23 +10,23 @@ import sqlalchemy as sa from sqlalchemy.dialects import mysql # revision identifiers, used by Alembic. -revision = '0c604bf490f8' -down_revision = '29c0d7ffc741' +revision = "0c604bf490f8" +down_revision = "29c0d7ffc741" branch_labels = None depends_on = None def upgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.add_column('playlist_rows', sa.Column('played', sa.Boolean(), nullable=False)) - op.drop_index('ix_tracks_lastplayed', table_name='tracks') - op.drop_column('tracks', 'lastplayed') + op.add_column("playlist_rows", sa.Column("played", sa.Boolean(), nullable=False)) + op.drop_index("ix_tracks_lastplayed", table_name="tracks") + op.drop_column("tracks", "lastplayed") # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.add_column('tracks', sa.Column('lastplayed', mysql.DATETIME(), nullable=True)) - op.create_index('ix_tracks_lastplayed', 'tracks', ['lastplayed'], unique=False) - op.drop_column('playlist_rows', 'played') + op.add_column("tracks", sa.Column("lastplayed", mysql.DATETIME(), nullable=True)) + op.create_index("ix_tracks_lastplayed", "tracks", ["lastplayed"], unique=False) + op.drop_column("playlist_rows", "played") # ### end Alembic commands ### diff --git a/migrations/versions/2cc37d3cf07f_add_playlist_dates_and_loaded.py b/migrations/versions/2cc37d3cf07f_add_playlist_dates_and_loaded.py index 6978768..5a39927 100644 --- a/migrations/versions/2cc37d3cf07f_add_playlist_dates_and_loaded.py +++ b/migrations/versions/2cc37d3cf07f_add_playlist_dates_and_loaded.py @@ -10,21 +10,21 @@ import sqlalchemy as sa # revision identifiers, used by Alembic. -revision = '2cc37d3cf07f' -down_revision = 'e3b04db5506f' +revision = "2cc37d3cf07f" +down_revision = "e3b04db5506f" branch_labels = None depends_on = None def upgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.add_column('playlists', sa.Column('last_used', sa.DateTime(), nullable=True)) - op.add_column('playlists', sa.Column('loaded', sa.Boolean(), nullable=True)) + op.add_column("playlists", sa.Column("last_used", sa.DateTime(), nullable=True)) + op.add_column("playlists", sa.Column("loaded", sa.Boolean(), nullable=True)) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('playlists', 'loaded') - op.drop_column('playlists', 'last_used') + op.drop_column("playlists", "loaded") + op.drop_column("playlists", "last_used") # ### end Alembic commands ### diff --git a/migrations/versions/b0983648595e_add_settings_table.py b/migrations/versions/b0983648595e_add_settings_table.py index 8820529..34ef976 100644 --- a/migrations/versions/b0983648595e_add_settings_table.py +++ b/migrations/versions/b0983648595e_add_settings_table.py @@ -10,27 +10,28 @@ import sqlalchemy as sa # revision identifiers, used by Alembic. -revision = 'b0983648595e' -down_revision = '1bc727e5e87f' +revision = "b0983648595e" +down_revision = "1bc727e5e87f" branch_labels = None depends_on = None def upgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.create_table('settings', - sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('name', sa.String(length=32), nullable=False), - sa.Column('f_datetime', sa.DateTime(), nullable=True), - sa.Column('f_int', sa.Integer(), nullable=True), - sa.Column('f_string', sa.String(length=128), nullable=True), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('name') + op.create_table( + "settings", + sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), + sa.Column("name", sa.String(length=32), nullable=False), + sa.Column("f_datetime", sa.DateTime(), nullable=True), + sa.Column("f_int", sa.Integer(), nullable=True), + sa.Column("f_string", sa.String(length=128), nullable=True), + sa.PrimaryKeyConstraint("id"), + sa.UniqueConstraint("name"), ) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.drop_table('settings') + op.drop_table("settings") # ### end Alembic commands ### diff --git a/migrations/versions/f07b96a5e60f_add_playlist_and_playtimes.py b/migrations/versions/f07b96a5e60f_add_playlist_and_playtimes.py index 5649a14..e3c3238 100644 --- a/migrations/versions/f07b96a5e60f_add_playlist_and_playtimes.py +++ b/migrations/versions/f07b96a5e60f_add_playlist_and_playtimes.py @@ -10,43 +10,54 @@ import sqlalchemy as sa # revision identifiers, used by Alembic. -revision = 'f07b96a5e60f' -down_revision = 'b0983648595e' +revision = "f07b96a5e60f" +down_revision = "b0983648595e" branch_labels = None depends_on = None def upgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.create_table('playdates', - sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('lastplayed', sa.DateTime(), nullable=True), - sa.PrimaryKeyConstraint('id') + op.create_table( + "playdates", + sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), + sa.Column("lastplayed", sa.DateTime(), nullable=True), + sa.PrimaryKeyConstraint("id"), ) - op.create_index(op.f('ix_playdates_lastplayed'), 'playdates', ['lastplayed'], unique=False) - op.create_table('playlists', - sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('name', sa.String(length=32), nullable=False), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('name') + op.create_index( + op.f("ix_playdates_lastplayed"), "playdates", ["lastplayed"], unique=False ) - op.create_table('playlistracks', - sa.Column('playlist_id', sa.Integer(), nullable=True), - sa.Column('track_id', sa.Integer(), nullable=True), - sa.ForeignKeyConstraint(['playlist_id'], ['playlists.id'], ), - sa.ForeignKeyConstraint(['track_id'], ['tracks.id'], ) + op.create_table( + "playlists", + sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), + sa.Column("name", sa.String(length=32), nullable=False), + sa.PrimaryKeyConstraint("id"), + sa.UniqueConstraint("name"), ) - op.add_column('tracks', sa.Column('playdates_id', sa.Integer(), nullable=True)) - op.create_foreign_key(None, 'tracks', 'playdates', ['playdates_id'], ['id']) + op.create_table( + "playlistracks", + sa.Column("playlist_id", sa.Integer(), nullable=True), + sa.Column("track_id", sa.Integer(), nullable=True), + sa.ForeignKeyConstraint( + ["playlist_id"], + ["playlists.id"], + ), + sa.ForeignKeyConstraint( + ["track_id"], + ["tracks.id"], + ), + ) + op.add_column("tracks", sa.Column("playdates_id", sa.Integer(), nullable=True)) + op.create_foreign_key(None, "tracks", "playdates", ["playdates_id"], ["id"]) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.drop_constraint(None, 'tracks', type_='foreignkey') - op.drop_column('tracks', 'playdates_id') - op.drop_table('playlistracks') - op.drop_table('playlists') - op.drop_index(op.f('ix_playdates_lastplayed'), table_name='playdates') - op.drop_table('playdates') + op.drop_constraint(None, "tracks", type_="foreignkey") + op.drop_column("tracks", "playdates_id") + op.drop_table("playlistracks") + op.drop_table("playlists") + op.drop_index(op.f("ix_playdates_lastplayed"), table_name="playdates") + op.drop_table("playdates") # ### end Alembic commands ### diff --git a/tests/test_misc.py b/tests/test_misc.py index 4fdff4d..de26971 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -12,10 +12,10 @@ import pytest # Mark subsequent lines to ignore E402, imports not at top of file # Set up test database before importing db # Mark subsequent lines to ignore E402, imports not at top of file -DB_FILE = '/tmp/mm.db' +DB_FILE = "/tmp/mm.db" if os.path.exists(DB_FILE): os.unlink(DB_FILE) -os.environ['ALCHEMICAL_DATABASE_URI'] = 'sqlite:///' + DB_FILE +os.environ["ALCHEMICAL_DATABASE_URI"] = "sqlite:///" + DB_FILE from models import db, Settings # noqa: E402 diff --git a/tests/test_models.py b/tests/test_models.py index 7c4dc3b..bbad41c 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -12,10 +12,10 @@ from app import helpers # Set up test database before importing db # Mark subsequent lines to ignore E402, imports not at top of file -DB_FILE = '/tmp/mm.db' +DB_FILE = "/tmp/mm.db" if os.path.exists(DB_FILE): os.unlink(DB_FILE) -os.environ['ALCHEMICAL_DATABASE_URI'] = 'sqlite:///' + DB_FILE +os.environ["ALCHEMICAL_DATABASE_URI"] = "sqlite:///" + DB_FILE from app.models import ( # noqa: E402 db, Carts, diff --git a/tests/test_playlistmodel.py b/tests/test_playlistmodel.py index 2450879..281e4c0 100644 --- a/tests/test_playlistmodel.py +++ b/tests/test_playlistmodel.py @@ -12,12 +12,13 @@ from sqlalchemy.orm.session import Session # App imports from app.log import log from app.helpers import get_file_metadata + # Set up test database before importing db # Mark subsequent lines to ignore E402, imports not at top of file -DB_FILE = '/tmp/mm.db' +DB_FILE = "/tmp/mm.db" if os.path.exists(DB_FILE): os.unlink(DB_FILE) -os.environ['ALCHEMICAL_DATABASE_URI'] = 'sqlite:///' + DB_FILE +os.environ["ALCHEMICAL_DATABASE_URI"] = "sqlite:///" + DB_FILE from app import playlistmodel # noqa: E402 from app.models import ( # noqa: E402 db, @@ -27,64 +28,83 @@ from app.models import ( # noqa: E402 ) -class TestMMMisc(unittest.TestCase): +# class TestMMMiscTracks(unittest.TestCase): +# def setUp(self): +# PLAYLIST_NAME = "tracks playlist" +# self.test_tracks = [ +# "testdata/isa.mp3", +# "testdata/isa_with_gap.mp3", +# "testdata/loser.mp3", +# "testdata/lovecats-10seconds.mp3", +# "testdata/lovecats.mp3", +# "testdata/mom.mp3", +# "testdata/sitting.mp3", +# ] + +# db.create_all() + +# # Create a playlist and model +# with db.Session() as session: +# self.playlist = Playlists(session, PLAYLIST_NAME) +# self.model = playlistmodel.PlaylistModel(self.playlist.id) + +# for row in range(len(self.test_tracks)): +# track_path = self.test_tracks[row % len(self.test_tracks)] +# metadata = get_file_metadata(track_path) +# track = Tracks(session, **metadata) +# self.model.insert_row( +# proposed_row_number=row, track_id=track.id, note=f"{row=}" +# ) + +# session.commit() + +# def tearDown(self): +# db.drop_all() + +# def test_7_row_playlist(self): +# # Test auto-created playlist + +# assert self.model.rowCount() == 7 +# assert max(self.model.playlist_rows.keys()) == 6 +# for row in range(self.model.rowCount()): +# assert row in self.model.playlist_rows +# assert self.model.playlist_rows[row].plr_rownum == row + + +class TestMMMiscRowMove(unittest.TestCase): def setUp(self): - PLAYLIST_NAME = "test playlist" - self.test_tracks = [ - "testdata/isa.mp3", - "testdata/isa_with_gap.mp3", - "testdata/loser.mp3", - "testdata/lovecats-10seconds.mp3", - "testdata/lovecats.mp3", - "testdata/mom.mp3", - "testdata/sitting.mp3", - ] + PLAYLIST_NAME = "rowmove playlist" + ROWS_TO_CREATE = 11 db.create_all() - # Create a playlist and model with db.Session() as session: self.playlist = Playlists(session, PLAYLIST_NAME) self.model = playlistmodel.PlaylistModel(self.playlist.id) - - for row in range(len(self.test_tracks)): - track_path = self.test_tracks[row % len(self.test_tracks)] - metadata = get_file_metadata(track_path) - track = Tracks(session, **metadata) - self.model.insert_row(proposed_row_number=row, track_id=track.id, note=f"{row=}") + for row in range(ROWS_TO_CREATE): + print(f"{row=}") + self.model.insert_row(proposed_row_number=row, note=str(row)) session.commit() def tearDown(self): db.drop_all() - def test_7_row_playlist(self): - # Test auto-created playlist - - assert self.model.rowCount() == 7 - assert max(self.model.playlist_rows.keys()) == 6 + def test_move_rows_test2(self): + # move row 3 to row 5 + self.model.move_rows([3], 5) + # Check we have all rows and plr_rownums are correct for row in range(self.model.rowCount()): assert row in self.model.playlist_rows assert self.model.playlist_rows[row].plr_rownum == row - - -# def test_move_rows_test2(monkeypatch, session): -# # move row 3 to row 5 -# monkeypatch.setattr(playlistmodel, "Session", session) -# model = create_model_with_playlist_rows(session, 11) -# model.move_rows([3], 5) -# # Check we have all rows and plr_rownums are correct -# for row in range(model.rowCount()): -# assert row in model.playlist_rows -# assert model.playlist_rows[row].plr_rownum == row -# if row not in [3, 4, 5]: -# assert model.playlist_rows[row].note == str(row) -# elif row == 3: -# assert model.playlist_rows[row].note == str(4) -# elif row == 4: -# assert model.playlist_rows[row].note == str(5) -# elif row == 5: -# assert model.playlist_rows[row].note == str(3) + if row not in [3, 4, 5]: + assert self.model.playlist_rows[row].note == str(row) + elif row == 3: + assert self.model.playlist_rows[row].note == str(4) + elif row == 4: + assert self.model.playlist_rows[row].note == str(5) + elif row == 5: + assert self.model.playlist_rows[row].note == str(3) # def test_move_rows_test3(monkeypatch, session):