Compare commits
6 Commits
ab867c1a67
...
cf66cef60a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf66cef60a | ||
|
|
50b051a864 | ||
|
|
90697652b0 | ||
|
|
1363010da8 | ||
|
|
609544ddd4 | ||
|
|
b116f062e9 |
@ -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)
|
||||
|
||||
@ -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()
|
||||
|
||||
|
||||
|
||||
@ -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("")
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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:
|
||||
"""
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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
943
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@ -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"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user