Compare commits

..

3 Commits

Author SHA1 Message Date
Keith Edmunds
70287d15a6 Implement search of playlist 2022-04-17 13:10:21 +01:00
Keith Edmunds
871598efe6 Code cleanup 2022-04-17 11:30:49 +01:00
Keith Edmunds
f143bd7fe9 Rebase from dev 2022-04-17 10:44:15 +01:00
5 changed files with 83 additions and 9 deletions

View File

@ -495,8 +495,8 @@ class Tracks(Base):
path: str, path: str,
title: Optional[str] = None, title: Optional[str] = None,
artist: Optional[str] = None, artist: Optional[str] = None,
duration: Optional[int] = None, duration: int = 0,
start_gap: Optional[int] = None, start_gap: int = 0,
fade_at: Optional[int] = None, fade_at: Optional[int] = None,
silence_at: Optional[int] = None, silence_at: Optional[int] = None,
mtime: Optional[float] = None, mtime: Optional[float] = None,

View File

@ -20,6 +20,7 @@ from PyQt5.QtWidgets import (
QFileDialog, QFileDialog,
QInputDialog, QInputDialog,
QLabel, QLabel,
QLineEdit,
QListWidgetItem, QListWidgetItem,
QMainWindow, QMainWindow,
) )
@ -63,7 +64,6 @@ class Window(QMainWindow, Ui_MainWindow):
self.timer: QTimer = QTimer() self.timer: QTimer = QTimer()
self.even_tick: bool = True self.even_tick: bool = True
self.playing: bool = False self.playing: bool = False
self.connect_signals_slots()
self.disable_play_next_controls() self.disable_play_next_controls()
self.music: music.Music = music.Music() self.music: music.Music = music.Music()
@ -79,6 +79,9 @@ class Window(QMainWindow, Ui_MainWindow):
self.set_main_window_size() self.set_main_window_size()
self.lblSumPlaytime: QLabel = QLabel("") self.lblSumPlaytime: QLabel = QLabel("")
self.statusbar.addPermanentWidget(self.lblSumPlaytime) self.statusbar.addPermanentWidget(self.lblSumPlaytime)
self.txtSearch = QLineEdit()
self.statusbar.addWidget(self.txtSearch)
self.txtSearch.setHidden(True)
self.visible_playlist_tab: Callable[[], PlaylistTab] = \ self.visible_playlist_tab: Callable[[], PlaylistTab] = \
self.tabPlaylist.currentWidget self.tabPlaylist.currentWidget
@ -87,6 +90,7 @@ class Window(QMainWindow, Ui_MainWindow):
self.enable_play_next_controls() self.enable_play_next_controls()
self.check_audacity() self.check_audacity()
self.timer.start(Config.TIMER_MS) self.timer.start(Config.TIMER_MS)
self.connect_signals_slots()
def set_main_window_size(self) -> None: def set_main_window_size(self) -> None:
"""Set size of window from database""" """Set size of window from database"""
@ -182,6 +186,7 @@ class Window(QMainWindow, Ui_MainWindow):
self.actionNewPlaylist.triggered.connect(self.create_playlist) self.actionNewPlaylist.triggered.connect(self.create_playlist)
self.actionOpenPlaylist.triggered.connect(self.open_playlist) self.actionOpenPlaylist.triggered.connect(self.open_playlist)
self.actionPlay_next.triggered.connect(self.play_next) self.actionPlay_next.triggered.connect(self.play_next)
self.actionSearch.triggered.connect(self.search_playlist)
self.actionSearch_database.triggered.connect(self.search_database) self.actionSearch_database.triggered.connect(self.search_database)
self.actionSelect_next_track.triggered.connect(self.select_next_row) self.actionSelect_next_track.triggered.connect(self.select_next_row)
self.actionSelect_played_tracks.triggered.connect(self.select_played) self.actionSelect_played_tracks.triggered.connect(self.select_played)
@ -203,6 +208,8 @@ class Window(QMainWindow, Ui_MainWindow):
self.btnStop.clicked.connect(self.stop) self.btnStop.clicked.connect(self.stop)
self.spnVolume.valueChanged.connect(self.change_volume) self.spnVolume.valueChanged.connect(self.change_volume)
self.tabPlaylist.tabCloseRequested.connect(self.close_tab) self.tabPlaylist.tabCloseRequested.connect(self.close_tab)
self.txtSearch.returnPressed.connect(self.search_playlist_return)
self.txtSearch.textChanged.connect(self.search_playlist_update)
self.timer.timeout.connect(self.tick) self.timer.timeout.connect(self.tick)
@ -621,9 +628,27 @@ class Window(QMainWindow, Ui_MainWindow):
dlg = DbDialog(self, session) dlg = DbDialog(self, session)
dlg.exec() dlg.exec()
def open_playlist(self) -> None: def search_playlist(self):
"""Select and activate existing playlist""" """Show text box to search playlist"""
self.disable_play_next_controls()
self.txtSearch.setHidden(False)
self.txtSearch.setFocus()
def search_playlist_return(self):
"""Close off search box when return pressed"""
self.txtSearch.setText("")
self.txtSearch.setHidden(True)
self.enable_play_next_controls()
self.visible_playlist_tab().set_filter("")
def search_playlist_update(self):
"""Update search when search string changes"""
self.visible_playlist_tab().set_filter(self.txtSearch.text())
def open_playlist(self):
with Session() as session: with Session() as session:
playlists = Playlists.get_closed(session) playlists = Playlists.get_closed(session)
dlg = SelectPlaylistDialog(self, playlists=playlists, dlg = SelectPlaylistDialog(self, playlists=playlists,

View File

@ -136,6 +136,7 @@ class PlaylistTab(QTableWidget):
self.itemSelectionChanged.connect(self._select_event) self.itemSelectionChanged.connect(self._select_event)
self.row_filter: Optional[str] = None
self.editing_cell: bool = False self.editing_cell: bool = False
self.selecting_in_progress = False self.selecting_in_progress = False
self.cellChanged.connect(self._cell_changed) self.cellChanged.connect(self._cell_changed)
@ -664,6 +665,13 @@ class PlaylistTab(QTableWidget):
self.selecting_in_progress = False self.selecting_in_progress = False
self._select_event() self._select_event()
def set_filter(self, text: Optional[str]) -> None:
"""Filter rows to only show those containing text"""
self.row_filter = text
with Session() as session:
self.update_display(session)
def set_selected_as_next(self) -> None: def set_selected_as_next(self) -> None:
"""Sets the select track as next to play""" """Sets the select track as next to play"""
@ -723,6 +731,14 @@ class PlaylistTab(QTableWidget):
if row in notes: if row in notes:
# Extract note text from database to ignore section timings # Extract note text from database to ignore section timings
note_text = self._get_row_notes_object(row, session).note note_text = self._get_row_notes_object(row, session).note
if self.row_filter:
if self.row_filter not in note_text:
self.hideRow(row)
continue
else:
self.showRow(row)
else:
self.showRow(row)
# Does the note have a start time? # Does the note have a start time?
row_time = self._get_note_text_time(note_text) row_time = self._get_note_text_time(note_text)
if row_time: if row_time:
@ -762,6 +778,20 @@ class PlaylistTab(QTableWidget):
if section_start_row is not None: if section_start_row is not None:
section_time += track.duration section_time += track.duration
# Render current track # Render current track
if self.row_filter:
try:
if (track.title
and self.row_filter not in track.title
and track.artist
and self.row_filter not in track.artist):
self.hideRow(row)
continue
else:
self.showRow(row)
except TypeError:
print(f"TypeError: {track=}")
else:
self.showRow(row)
if row == current_row: if row == current_row:
# Set start time # Set start time
self._set_row_start_time( self._set_row_start_time(
@ -876,6 +906,7 @@ class PlaylistTab(QTableWidget):
def _context_menu(self, pos): # review def _context_menu(self, pos): # review
assert self.menu
self.menu.exec_(self.mapToGlobal(pos)) self.menu.exec_(self.mapToGlobal(pos))
def _copy_path(self, row: int) -> None: def _copy_path(self, row: int) -> None:

View File

@ -782,8 +782,6 @@ border: 1px solid rgb(85, 87, 83);</string>
<addaction name="actionAdd_note"/> <addaction name="actionAdd_note"/>
<addaction name="action_Clear_selection"/> <addaction name="action_Clear_selection"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionSelect_previous_track"/>
<addaction name="actionSelect_next_track"/>
<addaction name="actionSetNext"/> <addaction name="actionSetNext"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionSelect_unplayed_tracks"/> <addaction name="actionSelect_unplayed_tracks"/>
@ -792,6 +790,11 @@ border: 1px solid rgb(85, 87, 83);</string>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionDownload_CSV_of_played_tracks"/> <addaction name="actionDownload_CSV_of_played_tracks"/>
<addaction name="actionExport_playlist"/> <addaction name="actionExport_playlist"/>
<addaction name="separator"/>
<addaction name="actionSelect_next_track"/>
<addaction name="actionSelect_previous_track"/>
<addaction name="separator"/>
<addaction name="actionSearch"/>
</widget> </widget>
<widget class="QMenu" name="menu_Music"> <widget class="QMenu" name="menu_Music">
<property name="title"> <property name="title">
@ -1032,6 +1035,14 @@ border: 1px solid rgb(85, 87, 83);</string>
<string>Download CSV of played tracks...</string> <string>Download CSV of played tracks...</string>
</property> </property>
</action> </action>
<action name="actionSearch">
<property name="text">
<string>Search...</string>
</property>
<property name="shortcut">
<string>/</string>
</property>
</action>
</widget> </widget>
<resources> <resources>
<include location="icons.qrc"/> <include location="icons.qrc"/>

View File

@ -448,6 +448,8 @@ class Ui_MainWindow(object):
self.actionImport.setObjectName("actionImport") self.actionImport.setObjectName("actionImport")
self.actionDownload_CSV_of_played_tracks = QtWidgets.QAction(MainWindow) self.actionDownload_CSV_of_played_tracks = QtWidgets.QAction(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 = QtWidgets.QAction(MainWindow)
self.actionSearch.setObjectName("actionSearch")
self.menuFile.addAction(self.actionImport) self.menuFile.addAction(self.actionImport)
self.menuFile.addSeparator() self.menuFile.addSeparator()
self.menuFile.addAction(self.actionE_xit) self.menuFile.addAction(self.actionE_xit)
@ -462,8 +464,6 @@ class Ui_MainWindow(object):
self.menuPlaylist.addAction(self.actionAdd_note) self.menuPlaylist.addAction(self.actionAdd_note)
self.menuPlaylist.addAction(self.action_Clear_selection) self.menuPlaylist.addAction(self.action_Clear_selection)
self.menuPlaylist.addSeparator() self.menuPlaylist.addSeparator()
self.menuPlaylist.addAction(self.actionSelect_previous_track)
self.menuPlaylist.addAction(self.actionSelect_next_track)
self.menuPlaylist.addAction(self.actionSetNext) self.menuPlaylist.addAction(self.actionSetNext)
self.menuPlaylist.addSeparator() self.menuPlaylist.addSeparator()
self.menuPlaylist.addAction(self.actionSelect_unplayed_tracks) self.menuPlaylist.addAction(self.actionSelect_unplayed_tracks)
@ -472,6 +472,11 @@ class Ui_MainWindow(object):
self.menuPlaylist.addSeparator() self.menuPlaylist.addSeparator()
self.menuPlaylist.addAction(self.actionDownload_CSV_of_played_tracks) self.menuPlaylist.addAction(self.actionDownload_CSV_of_played_tracks)
self.menuPlaylist.addAction(self.actionExport_playlist) self.menuPlaylist.addAction(self.actionExport_playlist)
self.menuPlaylist.addSeparator()
self.menuPlaylist.addAction(self.actionSelect_next_track)
self.menuPlaylist.addAction(self.actionSelect_previous_track)
self.menuPlaylist.addSeparator()
self.menuPlaylist.addAction(self.actionSearch)
self.menu_Music.addAction(self.actionPlay_next) self.menu_Music.addAction(self.actionPlay_next)
self.menu_Music.addAction(self.actionSkip_next) self.menu_Music.addAction(self.actionSkip_next)
self.menu_Music.addAction(self.actionFade) self.menu_Music.addAction(self.actionFade)
@ -560,4 +565,6 @@ class Ui_MainWindow(object):
self.actionImport.setText(_translate("MainWindow", "Import...")) self.actionImport.setText(_translate("MainWindow", "Import..."))
self.actionImport.setShortcut(_translate("MainWindow", "Ctrl+Shift+I")) 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", "/"))
import icons_rc import icons_rc