Compare commits

..

3 Commits

Author SHA1 Message Date
Keith Edmunds
976beade85 Add debug to troubleshoot issue #38 2021-08-10 18:28:20 +01:00
Keith Edmunds
bc54be237b Check tracks for readability
Check on load and on setting next track. Also provide info popup that
shows path.
2021-08-10 08:18:05 +01:00
Keith Edmunds
61e1fb1192 Make last played date 'today' when appropriate 2021-08-08 20:05:26 +01:00
5 changed files with 81 additions and 14 deletions

View File

@ -14,6 +14,7 @@ class Config(object):
COLOUR_NEXT_PLAYLIST = "#ffc107" COLOUR_NEXT_PLAYLIST = "#ffc107"
COLOUR_NOTES_PLAYLIST = "#b8daff" COLOUR_NOTES_PLAYLIST = "#b8daff"
COLOUR_PREVIOUS_HEADER = "#f8d7da" COLOUR_PREVIOUS_HEADER = "#f8d7da"
COLOUR_UNREADABLE = "#dc3545"
COLOUR_WARNING_TIMER = "#ffc107" COLOUR_WARNING_TIMER = "#ffc107"
DBFS_FADE = -12 DBFS_FADE = -12
DBFS_SILENCE = -50 DBFS_SILENCE = -50

View File

@ -18,6 +18,8 @@ def get_relative_date(past_date, reference_date=None):
return "get_relative_date() past_date is after relative_date" return "get_relative_date() past_date is after relative_date"
weeks, days = divmod((reference_date - past_date).days, 7) weeks, days = divmod((reference_date - past_date).days, 7)
if weeks == days == 0:
return "Today"
return f"{weeks} weeks, {days} days ago" return f"{weeks} weeks, {days} days ago"

View File

@ -317,10 +317,17 @@ class PlaylistTracks(Base):
else: else:
# Destination playlist has tracks; add to end # Destination playlist has tracks; add to end
new_row = max_row + 1 new_row = max_row + 1
record = session.query(PlaylistTracks).filter( try:
PlaylistTracks.playlist_id == from_playlist_id, record = session.query(PlaylistTracks).filter(
PlaylistTracks.row == row PlaylistTracks.playlist_id == from_playlist_id,
).one() PlaylistTracks.row == row).one()
except NoResultFound:
# Issue #38?
ERROR(
f"No rows matched in query: "
f"PlaylistTracks.playlist_id == {from_playlist_id}, "
f"PlaylistTracks.row == {row}"
)
record.playlist_id = to_playlist_id record.playlist_id = to_playlist_id
record.row = new_row record.row = new_row
session.commit() session.commit()

View File

@ -291,6 +291,11 @@ class Window(QMainWindow, Ui_MainWindow):
self.previous_track_position = self.music.fade() self.previous_track_position = self.music.fade()
self.end_of_track_actions() self.end_of_track_actions()
def file_is_readable(self, path):
"Return True if path is readable else False"
return os.access(self.next_track.path, os.R_OK)
def insert_note(self): def insert_note(self):
"Add non-track row to playlist" "Add non-track row to playlist"
@ -415,7 +420,7 @@ class Window(QMainWindow, Ui_MainWindow):
self.next_track = Tracks.get_track(session, next_track_id) self.next_track = Tracks.get_track(session, next_track_id)
self.next_track_playlist_tab = self.current_track_playlist_tab self.next_track_playlist_tab = self.current_track_playlist_tab
# Check we can read it # Check we can read it
if not os.access(self.next_track.path, os.R_OK): if not self.file_is_readable(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)

View File

@ -155,6 +155,8 @@ class PlaylistTab(QTableWidget):
self.menu.addSeparator() self.menu.addSeparator()
act_delete = self.menu.addAction('Delete') act_delete = self.menu.addAction('Delete')
act_delete.triggered.connect(lambda: self._delete_row(row)) act_delete.triggered.connect(lambda: self._delete_row(row))
act_delete = self.menu.addAction('Info')
act_delete.triggered.connect(lambda: self._info_row(row))
return super(PlaylistTab, self).eventFilter(source, event) return super(PlaylistTab, self).eventFilter(source, event)
@ -274,6 +276,9 @@ class PlaylistTab(QTableWidget):
# Scroll to new row # Scroll to new row
self.scrollToItem(titleitem, QAbstractItemView.PositionAtCenter) self.scrollToItem(titleitem, QAbstractItemView.PositionAtCenter)
if not self._track_path_is_readable(track.id):
self._meta_set_unreadable(row)
if repaint: if repaint:
self._save_playlist(session) self._save_playlist(session)
self._repaint(clear_selection=False) self._repaint(clear_selection=False)
@ -529,11 +534,6 @@ class PlaylistTab(QTableWidget):
duration = Tracks.get_duration(session, self._get_row_id(row)) duration = Tracks.get_duration(session, self._get_row_id(row))
return start + timedelta(milliseconds=duration) return start + timedelta(milliseconds=duration)
def _can_read_track(self, track):
"Check track file is readable"
return os.access(track.path, os.R_OK)
def _context_menu(self, pos): def _context_menu(self, pos):
self.menu.exec_(self.mapToGlobal(pos)) self.menu.exec_(self.mapToGlobal(pos))
@ -608,6 +608,30 @@ class PlaylistTab(QTableWidget):
except ValueError: except ValueError:
return None return None
def _info_row(self, row):
"Display popup with info re row"
id = self._get_row_id(row)
if row in self._meta_get_notes():
note_text = self.item(row, self.COL_TITLE).text()
txt = f"Note: {note_text}"
else:
with Session() as session:
track = Tracks.get_track(session, id)
if not track:
txt = f"Track not found (track.id={id})"
else:
txt = f"""
Title: {track.title}\n
Artist: {track.artist}\n
Path: {track.path}"""
info = QMessageBox(self)
info.setIcon(QMessageBox.Information)
info.setText(txt)
info.setStandardButtons(QMessageBox.Ok)
info.setDefaultButton(QMessageBox.Cancel)
info.exec()
def _is_below(self, pos, index): def _is_below(self, pos, index):
rect = self.visualRect(index) rect = self.visualRect(index)
margin = 2 margin = 2
@ -724,6 +748,11 @@ class PlaylistTab(QTableWidget):
return self._meta_find("note", one=False) return self._meta_find("note", one=False)
def _meta_get_unreadable(self):
"Return rows marked as unreadable, or None"
return self._meta_find("unreadable", one=False)
def _meta_set_current(self, row): def _meta_set_current(self, row):
"Mark row as current track" "Mark row as current track"
@ -745,6 +774,11 @@ class PlaylistTab(QTableWidget):
self._meta_set(row, "note") self._meta_set(row, "note")
def _meta_set_unreadable(self, row):
"Mark row as unreadable"
self._meta_set(row, "unreadable")
def _meta_set(self, row, metadata): def _meta_set(self, row, metadata):
"Set row metadata" "Set row metadata"
@ -763,8 +797,9 @@ class PlaylistTab(QTableWidget):
def _set_next(self, row): def _set_next(self, row):
""" """
If passed row is track row, set that track as the next track to If passed row is track row, check track is readable and, if it is,
be played and return track_id. Otherwise return None. set that track as the next track to be played and return track_id.
Otherwise return None.
""" """
DEBUG(f"_set_next({row})") DEBUG(f"_set_next({row})")
@ -774,9 +809,12 @@ class PlaylistTab(QTableWidget):
track_id = self._get_row_id(row) track_id = self._get_row_id(row)
if track_id: if track_id:
self._meta_set_next(self.currentRow()) if self._track_path_is_readable(track_id):
self._meta_set_next(self.currentRow())
self.master_process.set_next_track(track_id)
else:
self._meta_set_unreadable(self.currentRow())
self._repaint() self._repaint()
self.master_process.set_next_track(track_id)
def _repaint(self, clear_selection=True): def _repaint(self, clear_selection=True):
"Set row colours, fonts, etc" "Set row colours, fonts, etc"
@ -793,6 +831,7 @@ class PlaylistTab(QTableWidget):
current = self._meta_get_current() current = self._meta_get_current()
next = self._meta_get_next() next = self._meta_get_next()
notes = self._meta_get_notes() notes = self._meta_get_notes()
unreadable = self._meta_get_unreadable()
# Set colours and start times # Set colours and start times
next_start_time = None next_start_time = None
@ -813,6 +852,13 @@ class PlaylistTab(QTableWidget):
) )
self._set_row_bold(row) self._set_row_bold(row)
elif row in unreadable:
# Set colour
self._set_row_colour(
row, QColor(Config.COLOUR_UNREADABLE)
)
self._set_row_bold(row)
elif row == current: elif row == current:
# Set start time # Set start time
self._set_row_start_time( self._set_row_start_time(
@ -990,3 +1036,9 @@ class PlaylistTab(QTableWidget):
time_str = "" time_str = ""
item = QTableWidgetItem(time_str) item = QTableWidgetItem(time_str)
self.setItem(row, self.COL_START_TIME, item) self.setItem(row, self.COL_START_TIME, item)
def _track_path_is_readable(self, track_id):
"Returns True if track path is readable, else False"
with Session() as session:
return os.access(Tracks.get_path(session, track_id), os.R_OK)