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:
parent
ca9d0c75f8
commit
51cc3bfbca
13
app/model.py
13
app/model.py
@ -169,11 +169,11 @@ class Playlists(Base):
|
||||
@staticmethod
|
||||
def new(name):
|
||||
DEBUG(f"Playlists.new(name={name})")
|
||||
pl = Playlists()
|
||||
pl.name = name
|
||||
session.add(pl)
|
||||
playlist = Playlists()
|
||||
playlist.name = name
|
||||
session.add(playlist)
|
||||
session.commit()
|
||||
return pl.id
|
||||
return playlist
|
||||
|
||||
@staticmethod
|
||||
def open(plid):
|
||||
@ -184,11 +184,10 @@ class Playlists(Base):
|
||||
p.last_used = datetime.now()
|
||||
session.commit()
|
||||
|
||||
def close(plid):
|
||||
def close(self):
|
||||
"Record playlist as no longer loaded"
|
||||
|
||||
p = session.query(Playlists).filter(Playlists.id == plid).one()
|
||||
p.loaded = False
|
||||
self.loaded = False
|
||||
session.commit()
|
||||
|
||||
@staticmethod
|
||||
|
||||
13
app/music.py
13
app/music.py
@ -26,8 +26,6 @@ class Music:
|
||||
"""
|
||||
Fade the currently playing track.
|
||||
|
||||
Return the current track position.
|
||||
|
||||
The actual management of fading runs in its own thread so as not
|
||||
to hold up the UI during the fade.
|
||||
"""
|
||||
@ -39,13 +37,9 @@ class Music:
|
||||
|
||||
self.fading = True
|
||||
|
||||
position = self.player.get_position()
|
||||
|
||||
thread = threading.Thread(target=self._fade)
|
||||
thread.start()
|
||||
|
||||
return position
|
||||
|
||||
def _fade(self):
|
||||
"""
|
||||
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))
|
||||
sleep(sleep_time)
|
||||
|
||||
p.pause()
|
||||
p.stop()
|
||||
p.release()
|
||||
self.fading = False
|
||||
|
||||
@ -83,6 +77,11 @@ class Music:
|
||||
|
||||
return self.player.get_time()
|
||||
|
||||
def get_position(self):
|
||||
"Return current position"
|
||||
|
||||
return self.player.get_position()
|
||||
|
||||
def play(self, path):
|
||||
"""
|
||||
Start playing the track at path.
|
||||
|
||||
@ -46,7 +46,9 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
|
||||
self.music = music.Music()
|
||||
self.current_track = None
|
||||
self.current_track_playlist = None
|
||||
self.next_track = None
|
||||
self.next_track_playlist = None
|
||||
self.previous_track = None
|
||||
self.previous_track_position = None
|
||||
self.spnVolume.setValue(Config.VOLUME_VLC_DEFAULT)
|
||||
@ -54,7 +56,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
self.menuTest.menuAction().setVisible(Config.TESTMODE)
|
||||
self.set_main_window_size()
|
||||
|
||||
self.current_playlist = self.tabPlaylist.currentWidget
|
||||
self.visible_playlist = self.tabPlaylist.currentWidget
|
||||
|
||||
self.load_last_playlists()
|
||||
self.enable_play_next_controls()
|
||||
@ -70,7 +72,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
if dlg.exec_():
|
||||
for fname in dlg.selectedFiles():
|
||||
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):
|
||||
|
||||
@ -85,8 +87,8 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
self.setGeometry(x, y, width, height)
|
||||
|
||||
def clear_selection(self):
|
||||
if self.current_playlist():
|
||||
self.current_playlist().clearSelection()
|
||||
if self.visible_playlist():
|
||||
self.visible_playlist().clearSelection()
|
||||
|
||||
def closeEvent(self, event):
|
||||
"Don't allow window to close when a track is playing"
|
||||
@ -152,7 +154,8 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
dlg.resize(500, 100)
|
||||
ok = dlg.exec()
|
||||
if ok:
|
||||
self.current_playlist().create_playlist(dlg.textValue())
|
||||
playlist = Playlists.new(dlg.textValue())
|
||||
self.load_playlist(playlist)
|
||||
|
||||
def change_volume(self, volume):
|
||||
"Change player maximum volume"
|
||||
@ -162,7 +165,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
self.music.set_volume(volume)
|
||||
|
||||
def close_playlist(self):
|
||||
Playlists.close(self.current_playlist().id)
|
||||
self.visible_playlist().db.close()
|
||||
index = self.tabPlaylist.currentIndex()
|
||||
self.tabPlaylist.removeTab(index)
|
||||
|
||||
@ -192,22 +195,25 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
dlg.resize(500, 100)
|
||||
ok = dlg.exec()
|
||||
if ok:
|
||||
self.current_playlist().add_note(dlg.textValue())
|
||||
self.visible_playlist().add_note(dlg.textValue())
|
||||
|
||||
def load_last_playlists(self):
|
||||
"Load the playlists that we loaded at end of last session"
|
||||
|
||||
for p in Playlists.get_last_used():
|
||||
playlist = Playlist()
|
||||
playlist.load_playlist(p.id)
|
||||
last_tab = self.tabPlaylist.addTab(playlist, p.name)
|
||||
for playlist in Playlists.get_last_used():
|
||||
DEBUG(f"load_last_playlists(), {playlist.name=}, {playlist.id=}")
|
||||
self.load_playlist(playlist)
|
||||
|
||||
# Set last tab as active
|
||||
self.tabPlaylist.setCurrentIndex(last_tab)
|
||||
# Get next track
|
||||
self.next_track = Tracks.get_track(
|
||||
self.current_playlist().get_next_track_id())
|
||||
self.update_headers()
|
||||
def load_playlist(self, playlist_db):
|
||||
"""
|
||||
Take the passed database object, create a playlist display, attach
|
||||
the database object, get it populated and then add tab.
|
||||
"""
|
||||
|
||||
playlist_table = Playlist()
|
||||
playlist_table.db = playlist_db
|
||||
playlist_table.populate()
|
||||
self.tabPlaylist.addTab(playlist_table, playlist_db.name)
|
||||
|
||||
def play_next(self):
|
||||
"""
|
||||
@ -235,38 +241,34 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
f"{self.current_track.title if self.current_track else None}"
|
||||
)
|
||||
|
||||
# If there's currently a track playing, fade it.
|
||||
if self.music.playing():
|
||||
self.previous_track_position = self.music.fade()
|
||||
self.previous_track = self.current_track
|
||||
# Stop current track, if any
|
||||
self.stop_playing()
|
||||
|
||||
# Shuffle tracks along
|
||||
# Play next track
|
||||
self.current_track = self.next_track
|
||||
self.current_track_playlist = self.next_track_playlist
|
||||
self.next_track = None
|
||||
|
||||
# Play (new) current.
|
||||
self.next_track_playlist = None
|
||||
self.music.play(self.current_track.path)
|
||||
|
||||
# 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:
|
||||
self.next_track = Tracks.get_track(next_track_id)
|
||||
self.next_track_playlist = self.current_track_playlist
|
||||
# Check we can read it
|
||||
if not os.access(self.next_track.path, os.R_OK):
|
||||
self.show_warning(
|
||||
"Can't read next track",
|
||||
self.next_track.path)
|
||||
else:
|
||||
self.next_track = None
|
||||
self.next_track = self.next_track_playlist = None
|
||||
|
||||
# Tell database to record it as played
|
||||
self.current_track.update_lastplayed()
|
||||
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.update_headers()
|
||||
|
||||
@ -286,32 +288,25 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
# TODO
|
||||
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):
|
||||
dlg = DbDialog(self)
|
||||
dlg.exec()
|
||||
|
||||
def select_playlist(self):
|
||||
# TODO don't show those that are currently open
|
||||
dlg = SelectPlaylistDialog(self)
|
||||
dlg.exec()
|
||||
playlist = Playlist()
|
||||
plid = dlg.plid
|
||||
dlg.close()
|
||||
playlist.load_playlist(plid)
|
||||
new_tab = self.tabPlaylist.addTab(playlist, Playlists.get_name(plid))
|
||||
self.tabPlaylist.setCurrentIndex(new_tab)
|
||||
playlist = Playlists.get_playlist_by_id(dlg.plid)
|
||||
self.load_playlist(playlist)
|
||||
|
||||
def set_next_track(self):
|
||||
"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 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.update_headers()
|
||||
|
||||
@ -323,7 +318,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
def songfacts_search(self):
|
||||
"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:
|
||||
slug = slugify(title, replacements=([["'", ""]]))
|
||||
url = f"https://www.songfacts.com/search/songs/{slug}"
|
||||
@ -332,15 +327,34 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
def stop(self):
|
||||
"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_position = self.music.stop()
|
||||
|
||||
self.update_headers()
|
||||
|
||||
def tab_change(self):
|
||||
"User has changed tabs, so refresh next track"
|
||||
|
||||
self.next_track = Tracks.get_track(
|
||||
self.current_playlist().get_next_track_id())
|
||||
self.update_headers()
|
||||
pass
|
||||
|
||||
def test_function(self):
|
||||
"Placeholder for test function"
|
||||
@ -427,11 +441,12 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
if self.playing:
|
||||
self.label_end_timer.setText("00:00")
|
||||
self.frame_silent.setStyleSheet("")
|
||||
self.current_track_playlist.play_stopped()
|
||||
self.playing = False
|
||||
self.previous_track = self.current_track
|
||||
self.current_track = None
|
||||
self.current_track_playlist = None
|
||||
self.previous_track_position = 0
|
||||
self.current_playlist().stopped_playing()
|
||||
self.update_headers()
|
||||
|
||||
def update_headers(self):
|
||||
@ -464,7 +479,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
def wikipedia_search(self):
|
||||
"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:
|
||||
str = urllib.parse.quote_plus(title)
|
||||
url = f"https://www.wikipedia.org/w/index.php?search={str}"
|
||||
@ -531,7 +546,7 @@ class DbDialog(QDialog):
|
||||
|
||||
def add_track(self, 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
|
||||
self.select_searchtext()
|
||||
|
||||
|
||||
275
app/playlists.py
275
app/playlists.py
@ -17,7 +17,7 @@ import os
|
||||
from config import Config
|
||||
from datetime import datetime, timedelta
|
||||
from log import DEBUG, ERROR
|
||||
from model import Notes, Playlists, PlaylistTracks, Settings, Tracks
|
||||
from model import Notes, PlaylistTracks, Settings, Tracks
|
||||
|
||||
|
||||
class Playlist(QTableWidget):
|
||||
@ -80,7 +80,6 @@ class Playlist(QTableWidget):
|
||||
self.customContextMenuRequested.connect(self._context_menu)
|
||||
self.viewport().installEventFilter(self)
|
||||
|
||||
self.id = None
|
||||
self.current_track_start_time = None
|
||||
self.played_tracks = []
|
||||
|
||||
@ -138,7 +137,6 @@ class Playlist(QTableWidget):
|
||||
f"Moved row(s) {rows} to become row {drop_row}"
|
||||
)
|
||||
|
||||
self._save_playlist()
|
||||
self._repaint()
|
||||
|
||||
def eventFilter(self, source, event):
|
||||
@ -163,7 +161,7 @@ class Playlist(QTableWidget):
|
||||
|
||||
# ########## Externally called functions ##########
|
||||
|
||||
def add_note(self, text):
|
||||
def add_note(self, note, repaint=True):
|
||||
"""
|
||||
Add note to playlist
|
||||
|
||||
@ -177,89 +175,93 @@ class Playlist(QTableWidget):
|
||||
row = self.rowCount()
|
||||
DEBUG(f"playlist.add_note(): row={row}")
|
||||
|
||||
note = Notes.add_note(self.id, row, text)
|
||||
self.add_to_playlist(note, row=row)
|
||||
|
||||
def add_to_playlist(self, data, repaint=True, row=None):
|
||||
"""
|
||||
Add data to playlist. Data may be either a Tracks object or a
|
||||
Notes object.
|
||||
"""
|
||||
|
||||
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}")
|
||||
# Does note end with a time?
|
||||
start_time = None
|
||||
try:
|
||||
start_time = datetime.strptime(note.note[-9:], " %H:%M:%S").time()
|
||||
DEBUG(f"Note contains valid time={start_time}")
|
||||
except ValueError:
|
||||
DEBUG(
|
||||
f"Note on row {row} ('{note.note}') "
|
||||
"does not contain valid time"
|
||||
)
|
||||
|
||||
self.insertRow(row)
|
||||
|
||||
if isinstance(data, Tracks):
|
||||
DEBUG(f"add_to_playlist: track.id={data.id}")
|
||||
track = data
|
||||
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)
|
||||
elif isinstance(data, Notes):
|
||||
DEBUG(f"add_to_playlist: note.id={data.id}")
|
||||
note = data
|
||||
item = QTableWidgetItem(str(note.id))
|
||||
self.setItem(row, self.COL_INDEX, item)
|
||||
titleitem = QTableWidgetItem(note.note)
|
||||
self.setItem(row, self.COL_NOTE, titleitem)
|
||||
self.setSpan(row, self.COL_NOTE, self.NOTE_ROW_SPAN,
|
||||
self.NOTE_COL_SPAN)
|
||||
|
||||
# Does note end with a time?
|
||||
start_time = None
|
||||
try:
|
||||
start_time = datetime.strptime(
|
||||
note.note[-9:], " %H:%M:%S").time()
|
||||
DEBUG(f"Note contains valid time={start_time}")
|
||||
except ValueError:
|
||||
DEBUG(
|
||||
f"Note on row {row} ('{note.note}') "
|
||||
"does not contain valid time"
|
||||
)
|
||||
# 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)
|
||||
|
||||
item = QTableWidgetItem(str(note.id))
|
||||
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
|
||||
self._meta_set_note(row)
|
||||
|
||||
# Scroll to new row
|
||||
self.scrollToItem(titleitem, QAbstractItemView.PositionAtCenter)
|
||||
|
||||
if repaint:
|
||||
self._save_playlist()
|
||||
self._repaint(clear_selection=False)
|
||||
|
||||
def create_playlist(self, name):
|
||||
"Create new playlist"
|
||||
def add_track(self, track, repaint=True):
|
||||
"""
|
||||
Add track to playlist
|
||||
|
||||
new_id = Playlists.new(name)
|
||||
self.load_playlist(new_id)
|
||||
If a row is selected, add track above. Otherwise, add to end of
|
||||
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):
|
||||
"Return next track id"
|
||||
|
||||
next_row = self._meta_get_next()
|
||||
return self._get_row_id(next_row)
|
||||
@ -273,24 +275,30 @@ class Playlist(QTableWidget):
|
||||
else:
|
||||
return None
|
||||
|
||||
def load_playlist(self, plid):
|
||||
def play_started(self):
|
||||
"""
|
||||
Load tracks and notes from playlist 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.
|
||||
Update current track to be what was next, and determine next track.
|
||||
Return next track_id.
|
||||
"""
|
||||
|
||||
DEBUG(f"load_playlist(plid={plid})")
|
||||
self.current_track_start_time = datetime.now()
|
||||
|
||||
self.id = plid
|
||||
Playlists.open(plid)
|
||||
p = Playlists.get_playlist_by_id(plid)
|
||||
self.db = p
|
||||
self.populate_playlist()
|
||||
current_row = self._meta_get_next()
|
||||
self._meta_set_current(current_row)
|
||||
self.played_tracks.append(current_row)
|
||||
|
||||
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
|
||||
# on its specified row, only that it will be above
|
||||
# larger-numbered row items, and below lower-numbered ones.
|
||||
@ -306,15 +314,7 @@ class Playlist(QTableWidget):
|
||||
|
||||
# Now add data in row order
|
||||
for item in sorted(data, key=lambda x: x[0]):
|
||||
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
|
||||
self._add_to_playlist(item[1], repaint=False)
|
||||
|
||||
# Scroll to top
|
||||
scroll_to = self.item(0, self.COL_INDEX)
|
||||
@ -322,9 +322,6 @@ class Playlist(QTableWidget):
|
||||
|
||||
self._repaint()
|
||||
|
||||
def mark_track_played(self, track_id):
|
||||
self.played_tracks.append(track_id)
|
||||
|
||||
def set_selected_as_next(self):
|
||||
"""
|
||||
Sets the selected track as the next track.
|
||||
@ -335,26 +332,21 @@ class Playlist(QTableWidget):
|
||||
|
||||
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 ##########
|
||||
|
||||
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):
|
||||
"Return this row's end time given its start time"
|
||||
|
||||
@ -404,7 +396,7 @@ class Playlist(QTableWidget):
|
||||
if row in self._meta_get_notes():
|
||||
Notes.delete_note(id)
|
||||
else:
|
||||
PlaylistTracks.remove_track(self.id, row)
|
||||
PlaylistTracks.remove_track(self.db.id, row)
|
||||
self.removeRow(row)
|
||||
|
||||
self._repaint()
|
||||
@ -484,8 +476,6 @@ class Playlist(QTableWidget):
|
||||
if not found_next_track:
|
||||
return None
|
||||
|
||||
self._repaint()
|
||||
|
||||
track_id = self._get_row_id(row)
|
||||
return track_id
|
||||
|
||||
@ -501,9 +491,19 @@ class Playlist(QTableWidget):
|
||||
"""
|
||||
|
||||
current_row = self._meta_get_current()
|
||||
if current_row:
|
||||
if current_row is not None:
|
||||
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):
|
||||
"""
|
||||
Search rows for metadata.
|
||||
@ -581,7 +581,10 @@ class Playlist(QTableWidget):
|
||||
title = self.item(row, self.COL_TITLE).text()
|
||||
else:
|
||||
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:
|
||||
raise ValueError("_meta_set() with row=None")
|
||||
|
||||
@ -600,20 +603,26 @@ class Playlist(QTableWidget):
|
||||
|
||||
if self.item(row, self.COL_INDEX):
|
||||
self._meta_set_next(row)
|
||||
self._repaint()
|
||||
self._repaint(save_playlist=False)
|
||||
return self._get_row_id(row)
|
||||
else:
|
||||
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"
|
||||
|
||||
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:
|
||||
self.clearSelection()
|
||||
if save_playlist:
|
||||
self._save_playlist()
|
||||
|
||||
current = self._meta_get_current()
|
||||
next = self._meta_get_next() or 0
|
||||
next = self._meta_get_next()
|
||||
notes = self._meta_get_notes()
|
||||
|
||||
# Set colours and start times
|
||||
@ -697,8 +706,6 @@ class Playlist(QTableWidget):
|
||||
times in one playlist and in multiple playlists.
|
||||
"""
|
||||
|
||||
playlist = Playlists.get_playlist_by_id(self.id)
|
||||
|
||||
# Notes first
|
||||
# Create dictionaries indexed by note_id
|
||||
playlist_notes = {}
|
||||
@ -714,7 +721,7 @@ class Playlist(QTableWidget):
|
||||
playlist_notes[note_id] = row
|
||||
|
||||
# Database
|
||||
for note in playlist.notes:
|
||||
for note in self.db.notes:
|
||||
database_notes[note.id] = note.row
|
||||
|
||||
# Notes to add to database
|
||||
@ -723,14 +730,14 @@ class Playlist(QTableWidget):
|
||||
for note_id in set(playlist_notes.keys()) - set(database_notes.keys()):
|
||||
ERROR(
|
||||
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
|
||||
for note_id in set(database_notes.keys()) - set(playlist_notes.keys()):
|
||||
DEBUG(
|
||||
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)
|
||||
|
||||
@ -756,7 +763,7 @@ class Playlist(QTableWidget):
|
||||
playlist_tracks[row] = self._get_row_id(row)
|
||||
|
||||
# Database
|
||||
for track in playlist.tracks:
|
||||
for track in self.db.tracks:
|
||||
database_tracks[track.row] = track.track_id
|
||||
|
||||
# Tracks rows to add to database
|
||||
@ -764,7 +771,7 @@ class Playlist(QTableWidget):
|
||||
set(set(playlist_tracks.keys()) - set(database_tracks.keys()))
|
||||
):
|
||||
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
|
||||
for row in (
|
||||
@ -775,7 +782,7 @@ class Playlist(QTableWidget):
|
||||
f"_save_playlist(): row {row} in database not playlist "
|
||||
f"(track={track})"
|
||||
)
|
||||
PlaylistTracks.remove_track(playlist.id, row)
|
||||
PlaylistTracks.remove_track(self.db.id, row)
|
||||
|
||||
# Track rows to update in database
|
||||
for row in (
|
||||
@ -784,11 +791,11 @@ class Playlist(QTableWidget):
|
||||
if playlist_tracks[row] != database_tracks[row]:
|
||||
DEBUG(
|
||||
"_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]}"
|
||||
)
|
||||
PlaylistTracks.update_row_track(
|
||||
self.id, row, playlist_tracks[row])
|
||||
self.db.id, row, playlist_tracks[row])
|
||||
|
||||
def _set_column_widths(self):
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user