Add database reference to playlist

Also lots of cleaning up so that headers and playlist track colours
correct follow which playlist has the current/next track.
This commit is contained in:
Keith Edmunds 2021-05-16 12:39:19 +01:00
parent ca9d0c75f8
commit 51cc3bfbca
4 changed files with 219 additions and 199 deletions

View File

@ -169,11 +169,11 @@ class Playlists(Base):
@staticmethod @staticmethod
def new(name): def new(name):
DEBUG(f"Playlists.new(name={name})") DEBUG(f"Playlists.new(name={name})")
pl = Playlists() playlist = Playlists()
pl.name = name playlist.name = name
session.add(pl) session.add(playlist)
session.commit() session.commit()
return pl.id return playlist
@staticmethod @staticmethod
def open(plid): def open(plid):
@ -184,11 +184,10 @@ class Playlists(Base):
p.last_used = datetime.now() p.last_used = datetime.now()
session.commit() session.commit()
def close(plid): def close(self):
"Record playlist as no longer loaded" "Record playlist as no longer loaded"
p = session.query(Playlists).filter(Playlists.id == plid).one() self.loaded = False
p.loaded = False
session.commit() session.commit()
@staticmethod @staticmethod

View File

@ -26,8 +26,6 @@ class Music:
""" """
Fade the currently playing track. Fade the currently playing track.
Return the current track position.
The actual management of fading runs in its own thread so as not The actual management of fading runs in its own thread so as not
to hold up the UI during the fade. to hold up the UI during the fade.
""" """
@ -39,13 +37,9 @@ class Music:
self.fading = True self.fading = True
position = self.player.get_position()
thread = threading.Thread(target=self._fade) thread = threading.Thread(target=self._fade)
thread.start() thread.start()
return position
def _fade(self): def _fade(self):
""" """
Implementation of fading the current track in a separate thread. Implementation of fading the current track in a separate thread.
@ -74,7 +68,7 @@ class Music:
p.audio_set_volume(int(self.max_volume * volume_factor)) p.audio_set_volume(int(self.max_volume * volume_factor))
sleep(sleep_time) sleep(sleep_time)
p.pause() p.stop()
p.release() p.release()
self.fading = False self.fading = False
@ -83,6 +77,11 @@ class Music:
return self.player.get_time() return self.player.get_time()
def get_position(self):
"Return current position"
return self.player.get_position()
def play(self, path): def play(self, path):
""" """
Start playing the track at path. Start playing the track at path.

View File

@ -46,7 +46,9 @@ class Window(QMainWindow, Ui_MainWindow):
self.music = music.Music() self.music = music.Music()
self.current_track = None self.current_track = None
self.current_track_playlist = None
self.next_track = None self.next_track = None
self.next_track_playlist = None
self.previous_track = None self.previous_track = None
self.previous_track_position = None self.previous_track_position = None
self.spnVolume.setValue(Config.VOLUME_VLC_DEFAULT) self.spnVolume.setValue(Config.VOLUME_VLC_DEFAULT)
@ -54,7 +56,7 @@ class Window(QMainWindow, Ui_MainWindow):
self.menuTest.menuAction().setVisible(Config.TESTMODE) self.menuTest.menuAction().setVisible(Config.TESTMODE)
self.set_main_window_size() self.set_main_window_size()
self.current_playlist = self.tabPlaylist.currentWidget self.visible_playlist = self.tabPlaylist.currentWidget
self.load_last_playlists() self.load_last_playlists()
self.enable_play_next_controls() self.enable_play_next_controls()
@ -70,7 +72,7 @@ class Window(QMainWindow, Ui_MainWindow):
if dlg.exec_(): if dlg.exec_():
for fname in dlg.selectedFiles(): for fname in dlg.selectedFiles():
track = add_path_to_db(fname) track = add_path_to_db(fname)
self.current_playlist().add_to_playlist(track) self.visible_playlist()._add_to_playlist(track)
def set_main_window_size(self): def set_main_window_size(self):
@ -85,8 +87,8 @@ class Window(QMainWindow, Ui_MainWindow):
self.setGeometry(x, y, width, height) self.setGeometry(x, y, width, height)
def clear_selection(self): def clear_selection(self):
if self.current_playlist(): if self.visible_playlist():
self.current_playlist().clearSelection() self.visible_playlist().clearSelection()
def closeEvent(self, event): def closeEvent(self, event):
"Don't allow window to close when a track is playing" "Don't allow window to close when a track is playing"
@ -152,7 +154,8 @@ class Window(QMainWindow, Ui_MainWindow):
dlg.resize(500, 100) dlg.resize(500, 100)
ok = dlg.exec() ok = dlg.exec()
if ok: if ok:
self.current_playlist().create_playlist(dlg.textValue()) playlist = Playlists.new(dlg.textValue())
self.load_playlist(playlist)
def change_volume(self, volume): def change_volume(self, volume):
"Change player maximum volume" "Change player maximum volume"
@ -162,7 +165,7 @@ class Window(QMainWindow, Ui_MainWindow):
self.music.set_volume(volume) self.music.set_volume(volume)
def close_playlist(self): def close_playlist(self):
Playlists.close(self.current_playlist().id) self.visible_playlist().db.close()
index = self.tabPlaylist.currentIndex() index = self.tabPlaylist.currentIndex()
self.tabPlaylist.removeTab(index) self.tabPlaylist.removeTab(index)
@ -192,22 +195,25 @@ class Window(QMainWindow, Ui_MainWindow):
dlg.resize(500, 100) dlg.resize(500, 100)
ok = dlg.exec() ok = dlg.exec()
if ok: if ok:
self.current_playlist().add_note(dlg.textValue()) self.visible_playlist().add_note(dlg.textValue())
def load_last_playlists(self): def load_last_playlists(self):
"Load the playlists that we loaded at end of last session" "Load the playlists that we loaded at end of last session"
for p in Playlists.get_last_used(): for playlist in Playlists.get_last_used():
playlist = Playlist() DEBUG(f"load_last_playlists(), {playlist.name=}, {playlist.id=}")
playlist.load_playlist(p.id) self.load_playlist(playlist)
last_tab = self.tabPlaylist.addTab(playlist, p.name)
# Set last tab as active def load_playlist(self, playlist_db):
self.tabPlaylist.setCurrentIndex(last_tab) """
# Get next track Take the passed database object, create a playlist display, attach
self.next_track = Tracks.get_track( the database object, get it populated and then add tab.
self.current_playlist().get_next_track_id()) """
self.update_headers()
playlist_table = Playlist()
playlist_table.db = playlist_db
playlist_table.populate()
self.tabPlaylist.addTab(playlist_table, playlist_db.name)
def play_next(self): def play_next(self):
""" """
@ -235,38 +241,34 @@ class Window(QMainWindow, Ui_MainWindow):
f"{self.current_track.title if self.current_track else None}" f"{self.current_track.title if self.current_track else None}"
) )
# If there's currently a track playing, fade it. # Stop current track, if any
if self.music.playing(): self.stop_playing()
self.previous_track_position = self.music.fade()
self.previous_track = self.current_track
# Shuffle tracks along # Play next track
self.current_track = self.next_track self.current_track = self.next_track
self.current_track_playlist = self.next_track_playlist
self.next_track = None self.next_track = None
self.next_track_playlist = None
# Play (new) current.
self.music.play(self.current_track.path) self.music.play(self.current_track.path)
# Update metadata # Update metadata
next_track_id = self.current_playlist().started_playing_next() next_track_id = self.current_track_playlist.play_started()
if next_track_id is not None: if next_track_id is not None:
self.next_track = Tracks.get_track(next_track_id) self.next_track = Tracks.get_track(next_track_id)
self.next_track_playlist = self.current_track_playlist
# Check we can read it # Check we can read it
if not os.access(self.next_track.path, os.R_OK): if not os.access(self.next_track.path, os.R_OK):
self.show_warning( self.show_warning(
"Can't read next track", "Can't read next track",
self.next_track.path) self.next_track.path)
else: else:
self.next_track = None self.next_track = self.next_track_playlist = None
# Tell database to record it as played # Tell database to record it as played
self.current_track.update_lastplayed() self.current_track.update_lastplayed()
Playdates.add_playdate(self.current_track) Playdates.add_playdate(self.current_track)
# Remember it was played for this session
self.current_playlist().mark_track_played(self.current_track.id)
self.disable_play_next_controls() self.disable_play_next_controls()
self.update_headers() self.update_headers()
@ -286,32 +288,25 @@ class Window(QMainWindow, Ui_MainWindow):
# TODO # TODO
pass pass
def playlist_changed(self):
"The playlist has changed (probably because the user changed tabs)"
self.next_track = Tracks.get_track(
self.current_playlist().get_next_track_id())
self.update_headers()
def search_database(self): def search_database(self):
dlg = DbDialog(self) dlg = DbDialog(self)
dlg.exec() dlg.exec()
def select_playlist(self): def select_playlist(self):
# TODO don't show those that are currently open
dlg = SelectPlaylistDialog(self) dlg = SelectPlaylistDialog(self)
dlg.exec() dlg.exec()
playlist = Playlist() playlist = Playlists.get_playlist_by_id(dlg.plid)
plid = dlg.plid self.load_playlist(playlist)
dlg.close()
playlist.load_playlist(plid)
new_tab = self.tabPlaylist.addTab(playlist, Playlists.get_name(plid))
self.tabPlaylist.setCurrentIndex(new_tab)
def set_next_track(self): def set_next_track(self):
"Set selected track as next" "Set selected track as next"
next_track_id = self.current_playlist().set_selected_as_next() next_track_id = self.visible_playlist().set_selected_as_next()
if next_track_id: if next_track_id:
if self.next_track_playlist:
self.next_track_playlist.clear_next()
self.next_track_playlist = self.visible_playlist()
self.next_track = Tracks.get_track(next_track_id) self.next_track = Tracks.get_track(next_track_id)
self.update_headers() self.update_headers()
@ -323,7 +318,7 @@ class Window(QMainWindow, Ui_MainWindow):
def songfacts_search(self): def songfacts_search(self):
"Open a browser window in Songfacts searching for selected title" "Open a browser window in Songfacts searching for selected title"
title = self.current_playlist().get_selected_title() title = self.visible_playlist().get_selected_title()
if title: if title:
slug = slugify(title, replacements=([["'", ""]])) slug = slugify(title, replacements=([["'", ""]]))
url = f"https://www.songfacts.com/search/songs/{slug}" url = f"https://www.songfacts.com/search/songs/{slug}"
@ -332,15 +327,34 @@ class Window(QMainWindow, Ui_MainWindow):
def stop(self): def stop(self):
"Stop playing immediately" "Stop playing immediately"
DEBUG("musicmuster.stop()")
self.stop_playing(fade=False)
def stop_playing(self, fade=True):
"Stop playing current track"
DEBUG("musicmuster.stop_playing()")
if not self.music.playing():
return
self.previous_track_position = self.music.get_position()
if fade:
self.music.fade()
else:
self.music.stop()
self.current_track_playlist.clear_current()
# Shuffle tracks along
self.previous_track = self.current_track self.previous_track = self.current_track
self.previous_track_position = self.music.stop()
self.update_headers()
def tab_change(self): def tab_change(self):
"User has changed tabs, so refresh next track" "User has changed tabs, so refresh next track"
self.next_track = Tracks.get_track( pass
self.current_playlist().get_next_track_id())
self.update_headers()
def test_function(self): def test_function(self):
"Placeholder for test function" "Placeholder for test function"
@ -427,11 +441,12 @@ class Window(QMainWindow, Ui_MainWindow):
if self.playing: if self.playing:
self.label_end_timer.setText("00:00") self.label_end_timer.setText("00:00")
self.frame_silent.setStyleSheet("") self.frame_silent.setStyleSheet("")
self.current_track_playlist.play_stopped()
self.playing = False self.playing = False
self.previous_track = self.current_track self.previous_track = self.current_track
self.current_track = None self.current_track = None
self.current_track_playlist = None
self.previous_track_position = 0 self.previous_track_position = 0
self.current_playlist().stopped_playing()
self.update_headers() self.update_headers()
def update_headers(self): def update_headers(self):
@ -464,7 +479,7 @@ class Window(QMainWindow, Ui_MainWindow):
def wikipedia_search(self): def wikipedia_search(self):
"Open a browser window in Wikipedia searching for selected title" "Open a browser window in Wikipedia searching for selected title"
title = self.current_playlist().get_selected_title() title = self.visible_playlist().get_selected_title()
if title: if title:
str = urllib.parse.quote_plus(title) str = urllib.parse.quote_plus(title)
url = f"https://www.wikipedia.org/w/index.php?search={str}" url = f"https://www.wikipedia.org/w/index.php?search={str}"
@ -531,7 +546,7 @@ class DbDialog(QDialog):
def add_track(self, track_id): def add_track(self, track_id):
track = Tracks.track_from_id(track_id) track = Tracks.track_from_id(track_id)
self.parent().current_playlist().add_to_playlist(track) self.parent().visible_playlist()._add_to_playlist(track)
# Select search text to make it easier for next search # Select search text to make it easier for next search
self.select_searchtext() self.select_searchtext()

View File

@ -17,7 +17,7 @@ import os
from config import Config from config import Config
from datetime import datetime, timedelta from datetime import datetime, timedelta
from log import DEBUG, ERROR from log import DEBUG, ERROR
from model import Notes, Playlists, PlaylistTracks, Settings, Tracks from model import Notes, PlaylistTracks, Settings, Tracks
class Playlist(QTableWidget): class Playlist(QTableWidget):
@ -80,7 +80,6 @@ class Playlist(QTableWidget):
self.customContextMenuRequested.connect(self._context_menu) self.customContextMenuRequested.connect(self._context_menu)
self.viewport().installEventFilter(self) self.viewport().installEventFilter(self)
self.id = None
self.current_track_start_time = None self.current_track_start_time = None
self.played_tracks = [] self.played_tracks = []
@ -138,7 +137,6 @@ class Playlist(QTableWidget):
f"Moved row(s) {rows} to become row {drop_row}" f"Moved row(s) {rows} to become row {drop_row}"
) )
self._save_playlist()
self._repaint() self._repaint()
def eventFilter(self, source, event): def eventFilter(self, source, event):
@ -163,7 +161,7 @@ class Playlist(QTableWidget):
# ########## Externally called functions ########## # ########## Externally called functions ##########
def add_note(self, text): def add_note(self, note, repaint=True):
""" """
Add note to playlist Add note to playlist
@ -177,89 +175,93 @@ class Playlist(QTableWidget):
row = self.rowCount() row = self.rowCount()
DEBUG(f"playlist.add_note(): row={row}") DEBUG(f"playlist.add_note(): row={row}")
note = Notes.add_note(self.id, row, text) # Does note end with a time?
self.add_to_playlist(note, row=row) start_time = None
try:
def add_to_playlist(self, data, repaint=True, row=None): start_time = datetime.strptime(note.note[-9:], " %H:%M:%S").time()
""" DEBUG(f"Note contains valid time={start_time}")
Add data to playlist. Data may be either a Tracks object or a except ValueError:
Notes object. DEBUG(
""" f"Note on row {row} ('{note.note}') "
"does not contain valid time"
DEBUG(f"add_to_playlist(data={data}, repaint={repaint}, row={row}") )
if not row:
if self.selectionModel().hasSelection():
row = self.currentRow()
else:
row = self.rowCount()
DEBUG(f"add_to_playlist: row set to {row}")
self.insertRow(row) self.insertRow(row)
if isinstance(data, Tracks): item = QTableWidgetItem(str(note.id))
DEBUG(f"add_to_playlist: track.id={data.id}") self.setItem(row, self.COL_INDEX, item)
track = data titleitem = QTableWidgetItem(note.note)
item = QTableWidgetItem(str(track.id)) self.setItem(row, self.COL_NOTE, titleitem)
self.setItem(row, self.COL_INDEX, item) self.setSpan(row, self.COL_NOTE, self.NOTE_ROW_SPAN,
item = QTableWidgetItem(str(track.start_gap)) self.NOTE_COL_SPAN)
self.setItem(row, self.COL_MSS, item)
titleitem = QTableWidgetItem(track.title)
self.setItem(row, self.COL_TITLE, titleitem)
item = QTableWidgetItem(track.artist)
self.setItem(row, self.COL_ARTIST, item)
item = QTableWidgetItem(helpers.ms_to_mmss(track.duration))
self.setItem(row, self.COL_DURATION, item)
item = QTableWidgetItem(track.path)
self.setItem(row, self.COL_PATH, item)
elif isinstance(data, Notes):
DEBUG(f"add_to_playlist: note.id={data.id}")
note = data
# Does note end with a time? # Add start times or empty items as background
start_time = None # colour won't be set for columns without items
try: self._set_row_time(row, start_time)
start_time = datetime.strptime( item = QTableWidgetItem()
note.note[-9:], " %H:%M:%S").time() self.setItem(row, self.COL_PATH, item)
DEBUG(f"Note contains valid time={start_time}")
except ValueError:
DEBUG(
f"Note on row {row} ('{note.note}') "
"does not contain valid time"
)
item = QTableWidgetItem(str(note.id)) self._meta_set_note(row)
self.setItem(row, self.COL_INDEX, item)
titleitem = QTableWidgetItem(data.note)
self.setItem(row, self.COL_NOTE, titleitem)
self.setSpan(row, self.COL_NOTE, self.NOTE_ROW_SPAN,
self.NOTE_COL_SPAN)
# Add start times or empty items as background
# colour won't be set for columns without items
self._set_row_time(row, start_time)
item = QTableWidgetItem()
self.setItem(row, self.COL_PATH, item)
self._meta_set_note(row)
else:
ERROR(f"Unknown data passed to add_to_playlist({data})")
return
# Scroll to new row # Scroll to new row
self.scrollToItem(titleitem, QAbstractItemView.PositionAtCenter) self.scrollToItem(titleitem, QAbstractItemView.PositionAtCenter)
if repaint: if repaint:
self._save_playlist()
self._repaint(clear_selection=False) self._repaint(clear_selection=False)
def create_playlist(self, name): def add_track(self, track, repaint=True):
"Create new playlist" """
Add track to playlist
new_id = Playlists.new(name) If a row is selected, add track above. Otherwise, add to end of
self.load_playlist(new_id) playlist.
"""
if self.selectionModel().hasSelection():
row = self.currentRow()
else:
row = self.rowCount()
DEBUG(f"add_track({track=}), {row=}")
self.insertRow(row)
item = QTableWidgetItem(str(track.id))
self.setItem(row, self.COL_INDEX, item)
item = QTableWidgetItem(str(track.start_gap))
self.setItem(row, self.COL_MSS, item)
titleitem = QTableWidgetItem(track.title)
self.setItem(row, self.COL_TITLE, titleitem)
item = QTableWidgetItem(track.artist)
self.setItem(row, self.COL_ARTIST, item)
item = QTableWidgetItem(helpers.ms_to_mmss(track.duration))
self.setItem(row, self.COL_DURATION, item)
item = QTableWidgetItem(track.path)
self.setItem(row, self.COL_PATH, item)
# Add empty start time for now as background
# colour won't be set for columns without items
item = QTableWidgetItem()
self.setItem(row, self.COL_PATH, item)
# Scroll to new row
self.scrollToItem(titleitem, QAbstractItemView.PositionAtCenter)
if repaint:
self._repaint(clear_selection=False)
def clear_current(self):
"Clear current track"
self._meta_clear_current()
self._repaint(save_playlist=False)
def clear_next(self):
"Clear next track"
self._meta_clear_next()
self._repaint(save_playlist=False)
def get_next_track_id(self): def get_next_track_id(self):
"Return next track id"
next_row = self._meta_get_next() next_row = self._meta_get_next()
return self._get_row_id(next_row) return self._get_row_id(next_row)
@ -273,24 +275,30 @@ class Playlist(QTableWidget):
else: else:
return None return None
def load_playlist(self, plid): def play_started(self):
""" """
Load tracks and notes from playlist id. Update current track to be what was next, and determine next track.
Return next track_id.
If this is not the first playlist loaded, we may already have
a next track set in which case don't change it. Otherwise, set
the first non-notes row as next track to play.
""" """
DEBUG(f"load_playlist(plid={plid})") self.current_track_start_time = datetime.now()
self.id = plid current_row = self._meta_get_next()
Playlists.open(plid) self._meta_set_current(current_row)
p = Playlists.get_playlist_by_id(plid) self.played_tracks.append(current_row)
self.db = p
self.populate_playlist()
def populate_playlist(self): # Scroll to put current track in centre
scroll_to = self.item(current_row, self.COL_INDEX)
self.scrollToItem(scroll_to, QAbstractItemView.PositionAtCenter)
next_track_id = self._mark_next_track()
self._repaint(save_playlist=False)
return next_track_id
def play_stopped(self):
self._meta_clear_current()
self.current_track_start_time = None
def populate(self):
# add them in row order. We don't mandate that an item will be # add them in row order. We don't mandate that an item will be
# on its specified row, only that it will be above # on its specified row, only that it will be above
# larger-numbered row items, and below lower-numbered ones. # larger-numbered row items, and below lower-numbered ones.
@ -306,15 +314,7 @@ class Playlist(QTableWidget):
# Now add data in row order # Now add data in row order
for item in sorted(data, key=lambda x: x[0]): for item in sorted(data, key=lambda x: x[0]):
self.add_to_playlist(item[1], repaint=False) self._add_to_playlist(item[1], repaint=False)
# Set next track for this playlist
notes_rows = self._meta_get_notes()
for row in range(self.rowCount()):
if row in notes_rows:
continue
self._meta_set_next(row)
break
# Scroll to top # Scroll to top
scroll_to = self.item(0, self.COL_INDEX) scroll_to = self.item(0, self.COL_INDEX)
@ -322,9 +322,6 @@ class Playlist(QTableWidget):
self._repaint() self._repaint()
def mark_track_played(self, track_id):
self.played_tracks.append(track_id)
def set_selected_as_next(self): def set_selected_as_next(self):
""" """
Sets the selected track as the next track. Sets the selected track as the next track.
@ -335,26 +332,21 @@ class Playlist(QTableWidget):
return self._set_next(self.currentRow()) return self._set_next(self.currentRow())
def started_playing_next(self):
"""
Update current track to be what was next, and determine next track.
Return next track_id.
"""
self.current_track_start_time = datetime.now()
current_row = self._meta_get_next()
self._meta_set_current(current_row)
# Scroll to put current track in centre
scroll_to = self.item(current_row, self.COL_INDEX)
self.scrollToItem(scroll_to, QAbstractItemView.PositionAtCenter)
return self._mark_next_track()
def stopped_playing(self):
self._meta_clear_current()
self.current_track_start_time = None
# ########## Internally called functions ########## # ########## Internally called functions ##########
def _add_to_playlist(self, data, repaint=True):
"""
Add data to playlist. Data may be either a Tracks object or a
Notes object.
"""
DEBUG(f"_add_to_playlist({data=})")
if isinstance(data, Tracks):
self.add_track(data, repaint=repaint)
elif isinstance(data, Notes):
self.add_note(data, repaint=repaint)
def _calculate_next_start_time(self, row, start): def _calculate_next_start_time(self, row, start):
"Return this row's end time given its start time" "Return this row's end time given its start time"
@ -404,7 +396,7 @@ class Playlist(QTableWidget):
if row in self._meta_get_notes(): if row in self._meta_get_notes():
Notes.delete_note(id) Notes.delete_note(id)
else: else:
PlaylistTracks.remove_track(self.id, row) PlaylistTracks.remove_track(self.db.id, row)
self.removeRow(row) self.removeRow(row)
self._repaint() self._repaint()
@ -484,8 +476,6 @@ class Playlist(QTableWidget):
if not found_next_track: if not found_next_track:
return None return None
self._repaint()
track_id = self._get_row_id(row) track_id = self._get_row_id(row)
return track_id return track_id
@ -501,9 +491,19 @@ class Playlist(QTableWidget):
""" """
current_row = self._meta_get_current() current_row = self._meta_get_current()
if current_row: if current_row is not None:
self._meta_clear(current_row) self._meta_clear(current_row)
def _meta_clear_next(self):
"""
Clear next row if there is one. There may not be if
we've changed playlists
"""
next_row = self._meta_get_next()
if next_row is not None:
self._meta_clear(next_row)
def _meta_find(self, metadata, one=True): def _meta_find(self, metadata, one=True):
""" """
Search rows for metadata. Search rows for metadata.
@ -581,7 +581,10 @@ class Playlist(QTableWidget):
title = self.item(row, self.COL_TITLE).text() title = self.item(row, self.COL_TITLE).text()
else: else:
title = "" title = ""
DEBUG(f"_meta_set(row={row}, title={title}, metadata={metadata})") DEBUG(
f"playlist[{self.db.id}:{self.db.name}]._meta_set(row={row}, "
f"title={title}, metadata={metadata})"
)
if row is None: if row is None:
raise ValueError("_meta_set() with row=None") raise ValueError("_meta_set() with row=None")
@ -600,20 +603,26 @@ class Playlist(QTableWidget):
if self.item(row, self.COL_INDEX): if self.item(row, self.COL_INDEX):
self._meta_set_next(row) self._meta_set_next(row)
self._repaint() self._repaint(save_playlist=False)
return self._get_row_id(row) return self._get_row_id(row)
else: else:
return None return None
def _repaint(self, clear_selection=True): def _repaint(self, clear_selection=True, save_playlist=True):
"Set row colours, fonts, etc, and save playlist" "Set row colours, fonts, etc, and save playlist"
DEBUG(f"_repaint(clear_selection={clear_selection})") DEBUG(
f"playlist[{self.db.id}:{self.db.name}]."
f"_repaint({clear_selection=}, {save_playlist=})"
)
if clear_selection: if clear_selection:
self.clearSelection() self.clearSelection()
if save_playlist:
self._save_playlist()
current = self._meta_get_current() current = self._meta_get_current()
next = self._meta_get_next() or 0 next = self._meta_get_next()
notes = self._meta_get_notes() notes = self._meta_get_notes()
# Set colours and start times # Set colours and start times
@ -697,8 +706,6 @@ class Playlist(QTableWidget):
times in one playlist and in multiple playlists. times in one playlist and in multiple playlists.
""" """
playlist = Playlists.get_playlist_by_id(self.id)
# Notes first # Notes first
# Create dictionaries indexed by note_id # Create dictionaries indexed by note_id
playlist_notes = {} playlist_notes = {}
@ -714,7 +721,7 @@ class Playlist(QTableWidget):
playlist_notes[note_id] = row playlist_notes[note_id] = row
# Database # Database
for note in playlist.notes: for note in self.db.notes:
database_notes[note.id] = note.row database_notes[note.id] = note.row
# Notes to add to database # Notes to add to database
@ -723,14 +730,14 @@ class Playlist(QTableWidget):
for note_id in set(playlist_notes.keys()) - set(database_notes.keys()): for note_id in set(playlist_notes.keys()) - set(database_notes.keys()):
ERROR( ERROR(
f"_save_playlist(): Note.id={note_id} " f"_save_playlist(): Note.id={note_id} "
f"missing from playlist {playlist} in database" f"missing from playlist {self} in database"
) )
# Notes to remove from database # Notes to remove from database
for note_id in set(database_notes.keys()) - set(playlist_notes.keys()): for note_id in set(database_notes.keys()) - set(playlist_notes.keys()):
DEBUG( DEBUG(
f"_save_playlist(): Delete note note_id={note_id} " f"_save_playlist(): Delete note note_id={note_id} "
f"from playlist {playlist} in database" f"from playlist {self} in database"
) )
Notes.delete_note(note_id) Notes.delete_note(note_id)
@ -756,7 +763,7 @@ class Playlist(QTableWidget):
playlist_tracks[row] = self._get_row_id(row) playlist_tracks[row] = self._get_row_id(row)
# Database # Database
for track in playlist.tracks: for track in self.db.tracks:
database_tracks[track.row] = track.track_id database_tracks[track.row] = track.track_id
# Tracks rows to add to database # Tracks rows to add to database
@ -764,7 +771,7 @@ class Playlist(QTableWidget):
set(set(playlist_tracks.keys()) - set(database_tracks.keys())) set(set(playlist_tracks.keys()) - set(database_tracks.keys()))
): ):
DEBUG(f"_save_playlist(): row {row} missing from database") DEBUG(f"_save_playlist(): row {row} missing from database")
PlaylistTracks.add_track(self.id, playlist_tracks[row], row) PlaylistTracks.add_track(self.db.id, playlist_tracks[row], row)
# Track rows to remove from database # Track rows to remove from database
for row in ( for row in (
@ -775,7 +782,7 @@ class Playlist(QTableWidget):
f"_save_playlist(): row {row} in database not playlist " f"_save_playlist(): row {row} in database not playlist "
f"(track={track})" f"(track={track})"
) )
PlaylistTracks.remove_track(playlist.id, row) PlaylistTracks.remove_track(self.db.id, row)
# Track rows to update in database # Track rows to update in database
for row in ( for row in (
@ -784,11 +791,11 @@ class Playlist(QTableWidget):
if playlist_tracks[row] != database_tracks[row]: if playlist_tracks[row] != database_tracks[row]:
DEBUG( DEBUG(
"_save_playlist(): Update row={row} in database for " "_save_playlist(): Update row={row} in database for "
f"playlist {playlist} from track={database_tracks[row]} " f"playlist {self} from track={database_tracks[row]} "
f"to track={playlist_tracks[row]}" f"to track={playlist_tracks[row]}"
) )
PlaylistTracks.update_row_track( PlaylistTracks.update_row_track(
self.id, row, playlist_tracks[row]) self.db.id, row, playlist_tracks[row])
def _set_column_widths(self): def _set_column_widths(self):