Compare commits

..

No commits in common. "b46830f010bac4cee57c3428f3d461c9b3c02433" and "c5f094443a493ac9a20c355ab51953c09373660f" have entirely different histories.

5 changed files with 57 additions and 163 deletions

View File

@ -6,15 +6,12 @@ class Config(object):
AUDIO_SEGMENT_CHUNK_SIZE = 10
COLOUR_CURRENT_HEADER = "#d4edda"
COLOUR_CURRENT_PLAYLIST = "#28a745"
COLOUR_CURRENT_TAB = "#248f24"
COLOUR_ODD_PLAYLIST = "#f2f2f2"
COLOUR_ENDING_TIMER = "#dc3545"
COLOUR_EVEN_PLAYLIST = "#d9d9d9"
COLOUR_LONG_START = "#dc3545"
COLOUR_NORMAL_TAB = "#000000"
COLOUR_NEXT_HEADER = "#fff3cd"
COLOUR_NEXT_PLAYLIST = "#ffc107"
COLOUR_NEXT_TAB = "#b38600"
COLOUR_NOTES_PLAYLIST = "#b8daff"
COLOUR_PREVIOUS_HEADER = "#f8d7da"
COLOUR_UNREADABLE = "#dc3545"

View File

@ -1,6 +1,5 @@
#!/usr/bin/python3
import os.path
import sqlalchemy
from datetime import datetime
@ -80,7 +79,7 @@ class Notes(Base):
Update note details. If text=None, don't change text.
"""
DEBUG(f"Notes.update_note(id={id}, row={row}, text={text})")
DEBUG(f"update_note(id={id}, row={row}, text={text})")
note = session.query(cls).filter(cls.id == id).one()
note.row = row
@ -501,7 +500,8 @@ class Tracks(Base):
DEBUG(f"Tracks.get_track_from_filename({filename=})")
try:
track = session.query(Tracks).filter(Tracks.path.ilike(
f'%{os.path.sep}{filename}')).one()
# TODO: filename separator is hardcoded here
f'%/{filename}')).one()
return track
except (NoResultFound, MultipleResultsFound):
return None

View File

@ -11,7 +11,7 @@ from datetime import datetime, timedelta
from log import DEBUG, EXCEPTION
from PyQt5.QtCore import Qt, QTimer, QUrl
from PyQt5.QtGui import QColor, QFontMetrics, QPainter
from PyQt5.QtGui import QFontMetrics, QPainter
from PyQt5.QtWebEngineWidgets import QWebEngineView as QWebView
from PyQt5.QtWidgets import (
QApplication,
@ -132,9 +132,7 @@ class Window(QMainWindow, Ui_MainWindow):
if self.music.playing():
DEBUG("closeEvent() ignored as music is playing")
event.ignore()
helpers.show_warning(
"Track playing",
"Can't close application while track is playing")
# TODO notify user
else:
DEBUG("closeEvent() accepted")
@ -155,12 +153,7 @@ class Window(QMainWindow, Ui_MainWindow):
if record.f_int != self.y():
record.update(session, {'f_int': self.y()})
# Find a playlist tab (as opposed to an info tab) and
# save column widths
if self.current_track_playlist_tab:
self.current_track_playlist_tab.close(session)
elif self.next_track_playlist_tab:
self.next_track_playlist_tab.close(session)
self.visible_playlist_tab().close(session)
event.accept()
@ -480,8 +473,6 @@ class Window(QMainWindow, Ui_MainWindow):
# Play next track
self.current_track = self.next_track
self.current_track_playlist_tab = self.next_track_playlist_tab
self.set_tab_colour(self.current_track_playlist_tab,
QColor(Config.COLOUR_CURRENT_TAB))
self.next_track = None
self.next_track_playlist_tab = None
DEBUG(
@ -503,12 +494,6 @@ class Window(QMainWindow, Ui_MainWindow):
else:
self.next_track = self.next_track_playlist_tab = None
if self.next_track_playlist_tab and (
self.current_track_playlist_tab !=
self.next_track_playlist_tab):
self.set_tab_colour(self.next_track_playlist_tab,
QColor(Config.COLOUR_NEXT_TAB))
# Tell database to record it as played
self.current_track.update_lastplayed()
Playdates.add_playdate(session, self.current_track)
@ -526,6 +511,12 @@ class Window(QMainWindow, Ui_MainWindow):
silence_at - self.current_track.fade_at
))
def play_previous(self):
"Resume playing last track"
# TODO
pass
def search_database(self):
with Session() as session:
dlg = DbDialog(self, session)
@ -562,32 +553,12 @@ class Window(QMainWindow, Ui_MainWindow):
if not next_track_id:
next_track_id = (
self.visible_playlist_tab().set_selected_as_next())
if not next_track_id:
return
# The next track has been selected on the currently-visible
# playlist. However, there may already be a 'next track'
# selected on another playlist that the user is overriding,
# in which case we need to reset that playlist.
if next_track_id:
if self.next_track_playlist_tab != self.visible_playlist_tab():
# We need to reset the ex-next-track playlist
if self.next_track_playlist_tab:
self.next_track_playlist_tab.clear_next()
# Reset tab colour if it NOT the current playing tab
if (self.next_track_playlist_tab !=
self.current_track_playlist_tab):
self.set_tab_colour(self.next_track_playlist_tab,
QColor(Config.COLOUR_NORMAL_TAB))
self.next_track_playlist_tab = self.visible_playlist_tab()
# self.next_track_playlist_tab is now set to correct
# playlist
if (self.next_track_playlist_tab !=
self.current_track_playlist_tab):
self.set_tab_colour(self.next_track_playlist_tab,
QColor(Config.COLOUR_NEXT_TAB))
self.next_track = Tracks.get_track(session, next_track_id)
self.update_headers()
def select_unplayed(self):
@ -595,14 +566,6 @@ class Window(QMainWindow, Ui_MainWindow):
self.visible_playlist_tab().select_unplayed_tracks()
def set_tab_colour(self, widget, colour):
"""
Find the tab containing the widget and set the text colour
"""
idx = self.tabPlaylist.indexOf(widget)
self.tabPlaylist.tabBar().setTabTextColor(idx, colour)
def song_info_search(self):
"""
Open browser tabs for Wikipedia, searching for
@ -637,13 +600,6 @@ class Window(QMainWindow, Ui_MainWindow):
DEBUG(f"musicmuster.stop_playing({fade=})", True)
if self.current_track_playlist_tab == self.next_track_playlist_tab:
self.set_tab_colour(self.current_track_playlist_tab,
QColor(Config.COLOUR_NEXT_TAB))
else:
self.set_tab_colour(self.current_track_playlist_tab,
QColor(Config.COLOUR_NORMAL_TAB))
if not self.music.playing():
DEBUG("musicmuster.stop_playing(): not playing", True)
self.end_of_track_actions()
@ -675,7 +631,7 @@ class Window(QMainWindow, Ui_MainWindow):
if not self.playing():
return
self.music.set_position(self.current_track.silence_at - 1000)
self.music.set_position(self.get_current_silence_at() - 1000)
def test_skip_to_fade(self):
"Skip current track to 1 second before fade"
@ -683,7 +639,7 @@ class Window(QMainWindow, Ui_MainWindow):
if not self.music.playing():
return
self.music.set_position(self.current_track.fade_at - 1000)
self.music.set_position(self.get_current_fade_at() - 1000)
def tick(self):
"""

View File

@ -17,7 +17,7 @@ import os
from config import Config
from datetime import datetime, timedelta
from helpers import get_relative_date, open_in_audacity
from helpers import get_relative_date, open_in_audacity, show_warning
from log import DEBUG, ERROR
from model import (
Notes, Playdates, Playlists, PlaylistTracks, Session, Settings, Tracks
@ -172,31 +172,23 @@ class PlaylistTab(QTableWidget):
if item is not None:
row = item.row()
DEBUG(f"playlist.eventFilter(): Right-click on row {row}")
current = row == self._meta_get_current()
next = row == self._meta_get_next()
self.menu = QMenu(self)
act_info = self.menu.addAction('Info')
act_info.triggered.connect(lambda: self._info_row(row))
self.menu.addSeparator()
if row not in self._meta_get_notes():
if not current and not next:
act_setnext = self.menu.addAction("Set next")
act_setnext.triggered.connect(
lambda: self._set_next(row))
act_setnext.triggered.connect(lambda: self._set_next(row))
act_copypath = self.menu.addAction("Copy track path")
act_copypath.triggered.connect(
lambda: self._copy_path(row))
if not current:
act_rescan = self.menu.addAction("Rescan track")
act_rescan.triggered.connect(lambda: self._rescan(row))
act_audacity = self.menu.addAction(
"Open track in Audacity")
act_audacity.triggered.connect(
lambda: self._audacity(row))
if not current and not next:
act_audacity.triggered.connect(lambda: self._audacity(row))
self.menu.addSeparator()
act_delete = self.menu.addAction('Delete')
act_delete.triggered.connect(self._delete_rows)
act_info = self.menu.addAction('Info')
act_info.triggered.connect(lambda: self._info_row(row))
return super(PlaylistTab, self).eventFilter(source, event)
@ -232,12 +224,10 @@ class PlaylistTab(QTableWidget):
start_time = None
try:
start_time = datetime.strptime(note.note[-9:], " %H:%M:%S").time()
DEBUG(
f"playlist.inset_note(): Note contains valid time={start_time}"
)
DEBUG(f"Note contains valid time={start_time}")
except ValueError:
DEBUG(
f"playlist.inset_note(): Note on row {row} ('{note.note}') "
f"Note on row {row} ('{note.note}') "
"does not contain valid time"
)
@ -623,9 +613,6 @@ class PlaylistTab(QTableWidget):
if not self.editing_cell:
return
# If we update start time, _cell_changed will be called
if column not in [self.COL_TITLE, self.COL_ARTIST]:
return
new = self.item(row, column).text()
@ -634,28 +621,7 @@ class PlaylistTab(QTableWidget):
row_id = self._get_row_id(row)
with Session() as session:
if row in self._meta_get_notes():
# Save change to database
DEBUG(
f"Notes.update_note: saving new note text '{new=}'",
True
)
Notes.update_note(session, row_id, row, new)
# Set/clear row start time accordingly
try:
start_dt = datetime.strptime(new[-9:], " %H:%M:%S")
start_time = start_dt.time()
self._set_row_start_time(row, start_time)
DEBUG(
f"_cell_changed:Note {new} contains valid "
f"time={start_time}"
)
except ValueError:
# Reset row start time in case it used to have one
self._set_row_start_time(row, None)
DEBUG(
f"_cell_changed:Note {new} does not contain "
"start time"
)
else:
track = Tracks.get_track(session, row_id)
if column == self.COL_ARTIST:
@ -673,11 +639,6 @@ class PlaylistTab(QTableWidget):
def _cell_edit_ended(self):
DEBUG("_cell_edit_ended()")
self.editing_cell = False
# Call repaint to update start times, such as when a note has
# been edited
self._repaint()
self.master_process.enable_play_next_controls()
def _delete_rows(self):
@ -691,14 +652,22 @@ class PlaylistTab(QTableWidget):
with Session() as session:
for row in rows:
if row == self._meta_get_current():
show_warning("Silly", "Can't delete playing track")
return
elif row == self._meta_get_next():
show_warning("Safety", "Can't delete next track")
return
title = self.item(row, self.COL_TITLE).text()
msg = QMessageBox(self)
msg.setIcon(QMessageBox.Warning)
msg.setText(f"Delete '{title}'?")
msg.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel)
msg.setDefaultButton(QMessageBox.Cancel)
msg.setWindowTitle("Delete row")
# Store list of rows to delete
# Store list of notes
if msg.exec() == QMessageBox.Yes:
rows_to_delete.append(row)
@ -965,17 +934,13 @@ class PlaylistTab(QTableWidget):
return None
track_id = self._get_row_id(row)
if not track_id:
return None
if track_id:
if self._track_path_is_readable(track_id):
self._meta_set_next(row)
self.master_process.set_next_track(track_id)
else:
self._meta_set_unreadable(row)
track_id = None
self._repaint()
return track_id
def _repaint(self, clear_selection=True):
@ -998,18 +963,6 @@ class PlaylistTab(QTableWidget):
# Set colours and start times
next_start_time = None
# Don't change start times for tracks that have been played.
# For unplayed tracks, if there's a 'current' or 'next'
# track marked, populate start times from then onwards. If
# neither, populate start times from first note with a start
# time.
if current and next:
start_times_row = min(current, next)
else:
start_times_row = current or next
if not start_times_row:
start_times_row = 0
# Cycle through all rows
for row in range(self.rowCount()):
# We can't calculate start times until next_start_time is
@ -1090,16 +1043,12 @@ class PlaylistTab(QTableWidget):
self._set_row_not_bold(row)
else:
# Set start/end times only if we haven't played it yet
if next_start_time and row >= start_times_row:
if next_start_time:
self._set_row_start_time(row, next_start_time)
next_start_time = self._calculate_next_start_time(
session, row, next_start_time)
# Set end time
self._set_row_end_time(row, next_start_time)
else:
# Clear start and end time
self._set_row_start_time(row, None)
self._set_row_end_time(row, None)
# Don't dim unplayed tracks
self._set_row_bold(row)
@ -1199,6 +1148,9 @@ class PlaylistTab(QTableWidget):
If multiple rows are selected, display sum of durations in status bar.
"""
# Clear label
self.master_process.lblSumPlaytime.setText("")
rows = set([item.row() for item in self.selectedItems()])
notes = self._meta_get_notes()
ms = 0
@ -1211,8 +1163,6 @@ class PlaylistTab(QTableWidget):
if ms > 0:
self.master_process.lblSumPlaytime.setText(
f"Selected duration: {helpers.ms_to_mmss(ms)}")
else:
self.master_process.lblSumPlaytime.setText("")
def _set_column_widths(self):
# Column widths from settings

View File

@ -6,7 +6,6 @@ import shutil
import tempfile
from config import Config
from helpers import show_warning
from log import DEBUG, INFO
from model import Notes, Playdates, PlaylistTracks, Session, Tracks
from mutagen.flac import FLAC
@ -370,23 +369,15 @@ def update_meta(session, track, artist=None, title=None):
INFO(f"File type {ftype} not implemented")
return
# Update tags
f = tag_handler(track.path)
try:
if artist:
f["artist"] = artist
if title:
f["title"] = title
f.save()
except TypeError:
show_warning("TAG error", "Can't update tag. Try editing in Audacity")
# Update database
with Session() as session:
if artist:
f["artist"] = artist
Tracks.update_artist(session, track.id, artist)
if title:
f["title"] = title
Tracks.update_title(session, track.id, title)
f.save()
if __name__ == '__main__' and '__file__' in globals():