Add section timing
This commit is contained in:
parent
ca385dcf54
commit
0fb1536055
@ -18,6 +18,7 @@ from PyQt5.QtWidgets import (
|
|||||||
|
|
||||||
import helpers
|
import helpers
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
from config import Config
|
from config import Config
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
@ -33,6 +34,8 @@ from models import (
|
|||||||
)
|
)
|
||||||
from dbconfig import Session
|
from dbconfig import Session
|
||||||
|
|
||||||
|
start_time_re = re.compile(r"@\d\d:\d\d\:\d\d")
|
||||||
|
|
||||||
|
|
||||||
class RowMeta:
|
class RowMeta:
|
||||||
CLEAR = 0
|
CLEAR = 0
|
||||||
@ -269,7 +272,7 @@ class PlaylistTab(QTableWidget):
|
|||||||
"""
|
"""
|
||||||
Create note
|
Create note
|
||||||
|
|
||||||
If a row is selected, set note row to be rows above. Otherwise,
|
If a row is selected, set note row to be row above. Otherwise,
|
||||||
set note row to be end of playlist.
|
set note row to be end of playlist.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -679,6 +682,8 @@ class PlaylistTab(QTableWidget):
|
|||||||
note_text: str
|
note_text: str
|
||||||
row: int
|
row: int
|
||||||
row_time: Optional[datetime]
|
row_time: Optional[datetime]
|
||||||
|
section_start_row: Optional[int] = None
|
||||||
|
section_time: int = 0
|
||||||
start_time: Optional[datetime]
|
start_time: Optional[datetime]
|
||||||
start_times_row: Optional[int]
|
start_times_row: Optional[int]
|
||||||
track: Optional[Tracks]
|
track: Optional[Tracks]
|
||||||
@ -700,12 +705,22 @@ class PlaylistTab(QTableWidget):
|
|||||||
|
|
||||||
# Render notes in correct colour
|
# Render notes in correct colour
|
||||||
if row in notes:
|
if row in notes:
|
||||||
# Extract note text
|
# Extract note text from database to ignore section timings
|
||||||
note_text = self.item(row, self.COL_TITLE).text()
|
note_text = self._get_row_notes_object(row, session).note
|
||||||
# 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:
|
||||||
next_start_time = row_time
|
next_start_time = row_time
|
||||||
|
# Does it delimit a section?
|
||||||
|
if section_start_row is not None:
|
||||||
|
if note_text.endswith("-"):
|
||||||
|
self._set_timed_section(session, section_start_row,
|
||||||
|
section_time)
|
||||||
|
section_start_row = None
|
||||||
|
section_time = 0
|
||||||
|
elif note_text.endswith("+"):
|
||||||
|
section_start_row = row
|
||||||
|
section_time = 0
|
||||||
# Set colour
|
# Set colour
|
||||||
note_colour = NoteColours.get_colour(session, note_text)
|
note_colour = NoteColours.get_colour(session, note_text)
|
||||||
if not note_colour:
|
if not note_colour:
|
||||||
@ -715,16 +730,23 @@ class PlaylistTab(QTableWidget):
|
|||||||
)
|
)
|
||||||
# Notes are always bold
|
# Notes are always bold
|
||||||
self._set_row_bold(row)
|
self._set_row_bold(row)
|
||||||
|
continue
|
||||||
|
|
||||||
# Render unplayable tracks in correct colour
|
# Render unplayable tracks in correct colour
|
||||||
elif row in unreadable:
|
if row in unreadable:
|
||||||
self._set_row_colour(
|
self._set_row_colour(
|
||||||
row, QColor(Config.COLOUR_UNREADABLE)
|
row, QColor(Config.COLOUR_UNREADABLE)
|
||||||
)
|
)
|
||||||
self._set_row_bold(row)
|
self._set_row_bold(row)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Current row is a track row
|
||||||
|
track = self._get_row_track_object(row, session)
|
||||||
|
# Add track time to section time if in timed section
|
||||||
|
if section_start_row is not None:
|
||||||
|
section_time += track.duration
|
||||||
# Render current track
|
# Render current track
|
||||||
elif row == current_row:
|
if row == current_row:
|
||||||
# Set start time
|
# Set start time
|
||||||
self._set_row_start_time(
|
self._set_row_start_time(
|
||||||
row, self.current_track_start_time)
|
row, self.current_track_start_time)
|
||||||
@ -736,7 +758,6 @@ class PlaylistTab(QTableWidget):
|
|||||||
last_played_str)
|
last_played_str)
|
||||||
|
|
||||||
# Calculate next_start_time
|
# Calculate next_start_time
|
||||||
track = self._get_row_track_object(row, session)
|
|
||||||
next_start_time = self._calculate_track_end_time(
|
next_start_time = self._calculate_track_end_time(
|
||||||
track, self.current_track_start_time)
|
track, self.current_track_start_time)
|
||||||
|
|
||||||
@ -749,9 +770,10 @@ class PlaylistTab(QTableWidget):
|
|||||||
|
|
||||||
# Make bold
|
# Make bold
|
||||||
self._set_row_bold(row)
|
self._set_row_bold(row)
|
||||||
|
continue
|
||||||
|
|
||||||
# Render next track
|
# Render next track
|
||||||
elif row == next_row:
|
if row == next_row:
|
||||||
# if there's a track playing, set start time from that
|
# if there's a track playing, set start time from that
|
||||||
if current_row:
|
if current_row:
|
||||||
start_time = self.current_track_start_time
|
start_time = self.current_track_start_time
|
||||||
@ -764,7 +786,6 @@ class PlaylistTab(QTableWidget):
|
|||||||
self._set_row_start_time(row, start_time)
|
self._set_row_start_time(row, start_time)
|
||||||
|
|
||||||
# Set end time
|
# Set end time
|
||||||
track = self._get_row_track_object(row, session)
|
|
||||||
next_start_time = self._calculate_track_end_time(
|
next_start_time = self._calculate_track_end_time(
|
||||||
track, start_time)
|
track, start_time)
|
||||||
self._set_row_end_time(row, next_start_time)
|
self._set_row_end_time(row, next_start_time)
|
||||||
@ -778,7 +799,6 @@ class PlaylistTab(QTableWidget):
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
# This is a track row other than next or current
|
# This is a track row other than next or current
|
||||||
track = self._get_row_track_object(row, session)
|
|
||||||
if row in played:
|
if row in played:
|
||||||
# Played today, so update last played column
|
# Played today, so update last played column
|
||||||
last_playedtime = Playdates.last_played(
|
last_playedtime = Playdates.last_played(
|
||||||
@ -809,6 +829,11 @@ class PlaylistTab(QTableWidget):
|
|||||||
self._set_row_colour(
|
self._set_row_colour(
|
||||||
row, QColor(Config.COLOUR_EVEN_PLAYLIST))
|
row, QColor(Config.COLOUR_EVEN_PLAYLIST))
|
||||||
|
|
||||||
|
# Have we had a section start but not end?
|
||||||
|
if section_start_row is not None:
|
||||||
|
self._set_timed_section(
|
||||||
|
session, section_start_row, section_time, no_end=True)
|
||||||
|
|
||||||
# ########## Internally called functions ##########
|
# ########## Internally called functions ##########
|
||||||
|
|
||||||
def _audacity(self, row: int) -> None:
|
def _audacity(self, row: int) -> None:
|
||||||
@ -874,7 +899,7 @@ class PlaylistTab(QTableWidget):
|
|||||||
if row in self._get_notes_rows():
|
if row in self._get_notes_rows():
|
||||||
# Save change to database
|
# Save change to database
|
||||||
DEBUG(f"Notes.update_note: saving new note text '{new_text=}'")
|
DEBUG(f"Notes.update_note: saving new note text '{new_text=}'")
|
||||||
note: Notes = self._get_notes_row_object(row, session)
|
note: Notes = self._get_row_notes_object(row, session)
|
||||||
note.update_note(session, row, new_text)
|
note.update_note(session, row, new_text)
|
||||||
# Set/clear row start time accordingly
|
# Set/clear row start time accordingly
|
||||||
start_time = self._get_note_text_time(new_text)
|
start_time = self._get_note_text_time(new_text)
|
||||||
@ -892,7 +917,7 @@ class PlaylistTab(QTableWidget):
|
|||||||
"start time"
|
"start time"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
track: Tracks = self._get_track_row_object(row, session)
|
track: Tracks = self._get_row_track_object(row, session)
|
||||||
if column == self.COL_ARTIST:
|
if column == self.COL_ARTIST:
|
||||||
track.update_artist(session, artist=new_text)
|
track.update_artist(session, artist=new_text)
|
||||||
elif column == self.COL_TITLE:
|
elif column == self.COL_TITLE:
|
||||||
@ -926,6 +951,19 @@ class PlaylistTab(QTableWidget):
|
|||||||
# Disable play controls so that keyboard input doesn't disturb playing
|
# Disable play controls so that keyboard input doesn't disturb playing
|
||||||
self.musicmuster.disable_play_next_controls()
|
self.musicmuster.disable_play_next_controls()
|
||||||
|
|
||||||
|
# If this is a note cell and it's a section start, we need to
|
||||||
|
# remove any existing section timing so user can't edit that.
|
||||||
|
# Section timing is only in display of item, not in note text in
|
||||||
|
# database. Keep it simple: if this is a note, pull text from
|
||||||
|
# database.
|
||||||
|
|
||||||
|
if self._is_note_row(row):
|
||||||
|
item = self.item(row, self.COL_TITLE)
|
||||||
|
with Session() as session:
|
||||||
|
note_object = self._get_row_notes_object(row, session)
|
||||||
|
if note_object:
|
||||||
|
item.setText(note_object.note)
|
||||||
|
|
||||||
def _clear_current_track_row(self) -> None:
|
def _clear_current_track_row(self) -> None:
|
||||||
"""
|
"""
|
||||||
Clear current row if there is one.
|
Clear current row if there is one.
|
||||||
@ -1066,14 +1104,15 @@ class PlaylistTab(QTableWidget):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_note_text_time(text: str) -> Optional[datetime]:
|
def _get_note_text_time(text: str) -> Optional[datetime]:
|
||||||
"""Return time specified at the end of text"""
|
"""Return time specified as @hh:mm:ss in text"""
|
||||||
|
|
||||||
|
match = start_time_re.search(text)
|
||||||
|
if not match:
|
||||||
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
time_length = len(Config.NOTE_TIME_FORMAT)
|
return datetime.strptime(match.group(0)[1:],
|
||||||
return datetime.strptime(
|
Config.NOTE_TIME_FORMAT)
|
||||||
text[(-time_length):],
|
|
||||||
Config.NOTE_TIME_FORMAT
|
|
||||||
)
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -1231,6 +1270,16 @@ class PlaylistTab(QTableWidget):
|
|||||||
and pos.y() >= rect.center().y() # noqa W503
|
and pos.y() >= rect.center().y() # noqa W503
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _is_note_row(self, row: int) -> bool:
|
||||||
|
"""
|
||||||
|
Return True if passed row is a note row, else False
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self._meta_get(row):
|
||||||
|
if self._meta_get(row) & (1 << RowMeta.NOTE):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def _meta_clear_attribute(self, row: int, attribute: int) -> None:
|
def _meta_clear_attribute(self, row: int, attribute: int) -> None:
|
||||||
"""Clear given metadata for row"""
|
"""Clear given metadata for row"""
|
||||||
|
|
||||||
@ -1502,6 +1551,21 @@ class PlaylistTab(QTableWidget):
|
|||||||
item: QTableWidgetItem = QTableWidgetItem(time_str)
|
item: QTableWidgetItem = QTableWidgetItem(time_str)
|
||||||
self.setItem(row, self.COL_START_TIME, item)
|
self.setItem(row, self.COL_START_TIME, item)
|
||||||
|
|
||||||
|
def _set_timed_section(self, session, start_row, ms, no_end=False):
|
||||||
|
"""Add duration to a marked section"""
|
||||||
|
|
||||||
|
duration = helpers.ms_to_mmss(ms)
|
||||||
|
note_object = self._get_row_notes_object(start_row, session)
|
||||||
|
if not note_object:
|
||||||
|
ERROR("Can't get note_object in playlists._set_timed_section")
|
||||||
|
note_text = note_object.note
|
||||||
|
caveat = ""
|
||||||
|
if no_end:
|
||||||
|
caveat = " (to end of playlist)"
|
||||||
|
display_text = note_text + ' [' + duration + caveat + ']'
|
||||||
|
item = self.item(start_row, self.COL_TITLE)
|
||||||
|
item.setText(display_text)
|
||||||
|
|
||||||
def _update_row(self, session, row: int, track: Tracks) -> None:
|
def _update_row(self, session, row: int, track: Tracks) -> None:
|
||||||
"""
|
"""
|
||||||
Update the passed row with info from the passed track.
|
Update the passed row with info from the passed track.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user