Compare commits

...

6 Commits

Author SHA1 Message Date
Keith Edmunds
cf66cef60a Use dialog box to check for unintended play next track 2024-03-25 17:48:56 +00:00
Keith Edmunds
50b051a864 Improve resize rows speed 2024-03-22 14:21:37 +00:00
Keith Edmunds
90697652b0 Speed up row insertion 2024-03-21 16:57:37 +00:00
Keith Edmunds
1363010da8 More logging changes to try to debug #223 2024-03-08 23:32:50 +00:00
Keith Edmunds
609544ddd4 Implement random sort 2024-03-08 23:25:07 +00:00
Keith Edmunds
b116f062e9 Update packages, fix one bug 2024-03-01 17:58:25 +00:00
10 changed files with 535 additions and 550 deletions

View File

@ -38,7 +38,7 @@ class InfoTabs(QTabWidget):
"""Search Songfacts for title"""
slug = slugify(title, replacements=([["'", ""]]))
log.error(f"Songfacts Infotab for {title=}")
log.info(f"Songfacts Infotab for {title=}")
url = f"https://www.songfacts.com/search/songs/{slug}"
self.open_tab(url, title)
@ -47,7 +47,7 @@ class InfoTabs(QTabWidget):
"""Search Wikipedia for title"""
str = urllib.parse.quote_plus(title)
log.error(f"Wikipedia Infotab for {title=}")
log.info(f"Wikipedia Infotab for {title=}")
url = f"https://www.wikipedia.org/w/index.php?search={str}"
self.open_tab(url, title)

View File

@ -44,7 +44,7 @@ class FadeTrack(QRunnable):
sleep(1 / Config.FADEOUT_STEPS_PER_SECOND)
self.player.stop()
log.debug(f"Releasing player {self.player=}")
log.error(f"Releasing player {self.player=}")
self.player.release()

View File

@ -238,13 +238,13 @@ class Window(QMainWindow, Ui_MainWindow):
else:
self.carts_init()
self.disable_selection_timing = False
self.enable_play_next_controls()
self.clock_counter = 0
self.timer10.start(10)
self.timer500.start(500)
self.timer1000.start(1000)
self.signals = MusicMusterSignals()
self.connect_signals_slots()
self.catch_return_key = False
self.load_last_playlists()
def about(self) -> None:
@ -517,7 +517,6 @@ class Window(QMainWindow, Ui_MainWindow):
self.actionDownload_CSV_of_played_tracks.triggered.connect(
self.download_played_tracks
)
self.actionEnable_controls.triggered.connect(self.enable_play_next_controls)
self.actionExport_playlist.triggered.connect(self.export_playlist_tab)
self.actionFade.triggered.connect(self.fade)
self.actionImport.triggered.connect(self.import_track)
@ -652,14 +651,6 @@ class Window(QMainWindow, Ui_MainWindow):
else:
log.error("Failed to retrieve playlist")
def disable_play_next_controls(self) -> None:
"""
Disable "play next" keyboard controls
"""
self.actionPlay_next.setEnabled(False)
self.show_status_message("Play controls: Disabled", 0)
def download_played_tracks(self) -> None:
"""Download a CSV of played tracks"""
@ -705,14 +696,6 @@ class Window(QMainWindow, Ui_MainWindow):
self.action_Clear_selection.setEnabled(enabled)
def enable_play_next_controls(self) -> None:
"""
Enable "play next" keyboard controls
"""
self.actionPlay_next.setEnabled(True)
self.show_status_message("Play controls: Enabled", 0)
def export_playlist_tab(self) -> None:
"""Export the current playlist to an m3u file"""
@ -789,7 +772,7 @@ class Window(QMainWindow, Ui_MainWindow):
self.active_proxy_model().hide_played_tracks(True)
self.btnHidePlayed.setText("Show played")
# Reset row heights
self.active_tab().resizeRowsToContents()
self.active_tab().resize_rows()
def import_track(self) -> None:
"""Import track file"""
@ -898,10 +881,14 @@ class Window(QMainWindow, Ui_MainWindow):
def insert_track(self) -> None:
"""Show dialog box to select and add track from database"""
new_row_number = (
self.active_tab().source_model_selected_row_number()
or self.active_proxy_model().rowCount()
)
with Session() as session:
dlg = TrackSelectDialog(
session=session,
new_row_number=self.active_tab().source_model_selected_row_number(),
new_row_number=new_row_number,
source_model=self.active_proxy_model(),
)
dlg.exec()
@ -1102,6 +1089,16 @@ class Window(QMainWindow, Ui_MainWindow):
- Update headers
"""
# Check for inadvertent press of 'return'
if self.catch_return_key:
if not helpers.ask_yes_no(
"Track playing",
"Really play next track now?",
default_yes=True,
parent=self,
):
return
log.info(f"play_next({position=})")
# If there is no next track set, return.
@ -1144,7 +1141,7 @@ class Window(QMainWindow, Ui_MainWindow):
self.playing = True
# Disable play next controls
self.disable_play_next_controls()
self.catch_return_key = True
# Notify model
self.active_proxy_model().current_track_started()
@ -1166,22 +1163,6 @@ class Window(QMainWindow, Ui_MainWindow):
break
sleep(0.1)
# Try making playing the last thing we do here to see whether
# the occasional short pause at the start of the track can be
# eliminated.
# # Notify model
# self.active_proxy_model().current_track_started()
# # Note that track is now playing
# self.playing = True
# # Disable play next controls
# self.disable_play_next_controls()
# # Update headers
# self.update_headers()
def preview(self) -> None:
"""
Preview selected or next track. We use a different mechanism to
@ -1287,7 +1268,7 @@ class Window(QMainWindow, Ui_MainWindow):
# Disable play controls so that 'return' in search box doesn't
# play next track
self.disable_play_next_controls()
self.catch_return_key = True
self.txtSearch.setHidden(False)
self.txtSearch.setFocus()
# Select any text that may already be there
@ -1494,16 +1475,12 @@ class Window(QMainWindow, Ui_MainWindow):
self.update_headers()
# Enable controls
self.enable_play_next_controls()
self.catch_return_key = False
def tab_change(self):
"""Called when active tab changed"""
log.info("tab_change()")
tab = self.active_tab()
if tab:
QTimer.singleShot(300, tab.resizeRowsToContents)
self.active_tab().resize_rows()
def tick_10ms(self) -> None:
"""
@ -1578,7 +1555,7 @@ class Window(QMainWindow, Ui_MainWindow):
css_silence = f"background: {Config.COLOUR_ENDING_TIMER}"
if self.frame_silent.styleSheet() != css_silence:
self.frame_silent.setStyleSheet(css_silence)
self.enable_play_next_controls()
self.catch_return_key = False
# Set warning colour on time to silence box when fade starts
elif time_to_fade <= 500:
css_fade = f"background: {Config.COLOUR_WARNING_TIMER}"
@ -1590,7 +1567,7 @@ class Window(QMainWindow, Ui_MainWindow):
self.frame_fade.setStyleSheet(
f"background: {Config.COLOUR_WARNING_TIMER}"
)
self.enable_play_next_controls()
self.catch_return_key = False
else:
self.frame_silent.setStyleSheet("")
self.frame_fade.setStyleSheet("")

View File

@ -138,10 +138,10 @@ class PipeClient():
return self
def __init__(self):
self.timer: bool = False
self._start_time: float = 0
self.timer: bool = False # type: ignore
self._start_time: float = 0 # type: ignore
self._write_pipe = None
self.reply: str = ''
self.reply: str = '' # type: ignore
if not self._write_pipe:
self._write_thread_start()
self._read_thread_start()

View File

@ -7,6 +7,7 @@ from datetime import datetime, timedelta
from enum import auto, Enum
from operator import attrgetter
from pprint import pprint
from random import shuffle
from typing import List, Optional
from PyQt6.QtCore import (
@ -254,7 +255,10 @@ class PlaylistModel(QAbstractTableModel):
"""
row_number = track_sequence.now.plr_rownum
prd = self.playlist_rows[row_number]
if row_number is not None:
prd = self.playlist_rows[row_number]
else:
prd = None
# Sanity check
if not track_sequence.now.track_id:
@ -285,8 +289,9 @@ class PlaylistModel(QAbstractTableModel):
log.error(f"Can't retrieve plr, {track_sequence.now.plr_id=}")
# Update track times
prd.start_time = track_sequence.now.start_time
prd.end_time = track_sequence.now.end_time
if prd:
prd.start_time = track_sequence.now.start_time
prd.end_time = track_sequence.now.end_time
# Update colour and times for current row
self.invalidate_row(row_number)
@ -1311,6 +1316,14 @@ class PlaylistModel(QAbstractTableModel):
self.sort_by_attribute(row_numbers, "lastplayed")
def sort_randomly(self, row_numbers: List[int]) -> None:
"""
Sort selected rows randomly
"""
shuffle(row_numbers)
self.move_rows(row_numbers, min(row_numbers))
def sort_by_title(self, row_numbers: List[int]) -> None:
"""
Sort selected rows by title
@ -1599,6 +1612,9 @@ class PlaylistProxyModel(QSortFilterProxyModel):
def sort_by_lastplayed(self, row_numbers: List[int]) -> None:
return self.source_model.sort_by_lastplayed(row_numbers)
def sort_randomly(self, row_numbers: List[int]) -> None:
return self.source_model.sort_randomly(row_numbers)
def sort_by_title(self, row_numbers: List[int]) -> None:
return self.source_model.sort_by_title(row_numbers)

View File

@ -209,7 +209,7 @@ class PlaylistTab(QTableView):
h_header.sectionResized.connect(self._column_resize)
h_header.setStretchLastSection(True)
# Setting ResizeToContents causes screen flash on load
QTimer.singleShot(300, self.resizeRowsToContents)
self.resize_rows()
# ########## Overridden class functions ##########
@ -225,7 +225,7 @@ class PlaylistTab(QTableView):
super(PlaylistTab, self).closeEditor(editor, hint)
# Optimise row heights after increasing row height for editing
self.resizeRowsToContents()
self.resize_rows()
# Update start times in case a start time in a note has been
# edited
@ -260,7 +260,7 @@ class PlaylistTab(QTableView):
self.clear_selection()
# Resize rows
self.resizeRowsToContents()
self.resize_rows()
event.accept()
@ -487,6 +487,11 @@ class PlaylistTab(QTableView):
lambda: proxy_model.sort_by_lastplayed(self.get_selected_rows()),
parent_menu=sort_menu,
)
self._add_context_menu(
"randomly",
lambda: proxy_model.sort_randomly(self.get_selected_rows()),
parent_menu=sort_menu,
)
# Info
if track_row:
@ -711,17 +716,29 @@ class PlaylistTab(QTableView):
self.source_model.rescan_track(row_number)
self.clear_selection()
def resize_rows(self, playlist_id: int) -> None:
def resize_rows(self, playlist_id: Optional[int] = None) -> None:
"""
If playlist_id is us, resize rows
"""
log.info(f"resize_rows({playlist_id=}) {self.playlist_id=}")
if playlist_id != self.playlist_id:
if playlist_id and playlist_id != self.playlist_id:
return
self.resizeRowsToContents()
# self.resizeRowsToContents()
# Suggestion from phind.com
def resize_row(row, count=1):
row_count = self.source_model.rowCount()
for todo in range(count):
if row < row_count:
self.resizeRowToContents(row)
row += 1
if row < row_count:
QTimer.singleShot(0, lambda: resize_row(row, count))
# Start resizing from row 0, 10 rows at a time
QTimer.singleShot(0, lambda: resize_row(0, 10))
def scroll_to_top(self, row_number: int) -> None:
"""

View File

@ -775,8 +775,6 @@ padding-left: 8px;</string>
<addaction name="actionSetNext"/>
<addaction name="action_Clear_selection"/>
<addaction name="separator"/>
<addaction name="actionEnable_controls"/>
<addaction name="separator"/>
<addaction name="actionMark_for_moving"/>
<addaction name="actionPaste"/>
</widget>

View File

@ -1,6 +1,6 @@
# Form implementation generated from reading ui file 'app/ui/main_window.ui'
#
# Created by: PyQt6 UI code generator 6.6.0
# Created by: PyQt6 UI code generator 6.6.1
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
@ -487,8 +487,6 @@ class Ui_MainWindow(object):
self.menuPlaylist.addAction(self.actionSetNext)
self.menuPlaylist.addAction(self.action_Clear_selection)
self.menuPlaylist.addSeparator()
self.menuPlaylist.addAction(self.actionEnable_controls)
self.menuPlaylist.addSeparator()
self.menuPlaylist.addAction(self.actionMark_for_moving)
self.menuPlaylist.addAction(self.actionPaste)
self.menuSearc_h.addAction(self.actionSearch)

943
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -40,7 +40,7 @@ flakehell = "^0.9.0"
pudb = "^2023.1"
sphinx = "^7.0.1"
furo = "^2023.5.20"
black = "^23.3.0"
black = "^24.2.0"
flakehell = "^0.9.0"
mypy = "^1.7.0"
pdbp = "^1.5.0"
@ -50,8 +50,8 @@ requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
[tool.mypy]
# mypy_path = "/home/kae/.cache/pypoetry/virtualenvs/musicmuster-oWgGw1IG-py3.9:/home/kae/git/musicmuster/app"
mypy_path = "/home/kae/git/musicmuster/app"
explicit_package_bases = true
[tool.pytest.ini_options]
addopts = "--exitfirst --showlocals --capture=no"