All preview/intro management working

This commit is contained in:
Keith Edmunds 2024-06-02 17:58:20 +01:00
parent 09fdd7e4dc
commit 909fb27bed
4 changed files with 102 additions and 58 deletions

View File

@ -52,7 +52,6 @@ class Config(object):
HEADER_TITLE = "Title"
HIDE_AFTER_PLAYING_OFFSET = 5000
INFO_TAB_TITLE_LENGTH = 15
INTRO_END_GAP_MS = 1000
INTRO_SECONDS_FORMAT = ".1f"
INTRO_SECONDS_WARNING_MS = 3000
LAST_PLAYED_TODAY_STRING = "Today"
@ -78,6 +77,7 @@ class Config(object):
PLAY_SETTLE = 500000
PREVIEW_ADVANCE_MS = 5000
PREVIEW_BACK_MS = 5000
PREVIEW_END_BUFFER_MS = 1000
REPLACE_FILES_DEFAULT_SOURCE = "/home/kae/music/Singles/tmp"
RETURN_KEY_DEBOUNCE_MS = 500
ROOT = os.environ.get("ROOT") or "/home/kae/music"

View File

@ -1062,22 +1062,30 @@ class Window(QMainWindow, Ui_MainWindow):
if self.btnPreview.isChecked():
# Get track_id for first selected track if there is one
track_id = self.active_tab().get_selected_row_track_id()
if not track_id:
# Otherwise get path to next track to play
row_number_and_track_id = self.active_tab().get_selected_row_and_track_id()
if row_number_and_track_id:
row_number, track_id = row_number_and_track_id
else:
# Otherwise get track_id to next track to play
if track_sequence.next:
track_id = track_sequence.next.track_id
if not track_id:
self.btnPreview.setChecked(False)
return
row_number = track_sequence.next.row_number
if not track_id or row_number is None:
self.btnPreview.setChecked(False)
return
with db.Session() as session:
self.preview_track_player = PreviewTrackManager(session, track_id)
self.preview_track_player = PreviewTrackManager(
session=session, track_id=track_id, row_number=row_number
)
self.preview_track_player.play()
else:
if self.preview_track_player:
self.preview_track_player.stop_playing()
self.preview_track_player.stop()
self.preview_track_player = None
self.label_intro_timer.setText("0.0")
self.label_intro_timer.setStyleSheet("")
self.btnPreviewMark.setEnabled(False)
self.btnPreviewArm.setChecked(False)
@ -1089,51 +1097,45 @@ class Window(QMainWindow, Ui_MainWindow):
def preview_back(self) -> None:
"""Wind back preview file"""
self.preview_track_player.move_back(Config.PREVIEW_BACK_MS)
if self.preview_track_player:
self.preview_track_player.move_back()
def preview_end(self) -> None:
"""Advance preview file to just before end of intro"""
"""Advance preview file to Config.PREVIEW_END_BUFFER_MS before end of intro"""
return
# preview_track_path = self.preview_player.path
# if not preview_track_path:
# return
# with Session() as session:
# preview_track = Tracks.get_by_path(session, preview_track_path)
# if not preview_track or not preview_track.intro:
# return
# new_position = max(0, preview_track.intro - Config.INTRO_END_GAP_MS)
# self.preview_player.set_position(new_position)
if self.preview_track_player:
self.preview_track_player.move_to_intro_end()
def preview_fwd(self) -> None:
"""Advance preview file"""
self.preview_player.move_forward(Config.PREVIEW_ADVANCE_MS)
if self.preview_track_player:
self.preview_track_player.move_forward()
def preview_mark(self) -> None:
"""Set intro time"""
track_id = self.active_tab().get_selected_row_track_id()
row_number = self.active_tab().get_selected_row()
if track_id:
if self.preview_track_player:
track_id = self.preview_track_player.track_id
row_number = self.preview_track_player.row_number
with db.Session() as session:
track = session.get(Tracks, track_id)
if track:
# Save intro as millisends rounded to nearest 0.1
# second because editor spinbox only resolves to 0.1
# seconds
track.intro = round(self.preview_player.get_playtime() / 100) * 100
intro = round(self.preview_track_player.time_playing() / 100) * 100
track.intro = intro
session.commit()
self.preview_track_player.intro = intro
self.active_tab().source_model.refresh_row(session, row_number)
self.active_tab().source_model.invalidate_row(row_number)
def preview_start(self) -> None:
"""Advance preview file"""
"""Restart preview"""
self.preview_track_player.set_position(0)
if self.preview_track_player:
self.preview_track_player.restart()
def rename_playlist(self) -> None:
"""
@ -1504,6 +1506,24 @@ class Window(QMainWindow, Ui_MainWindow):
# currnent track ended during servicing tick
pass
# Ensure preview button is reset if preview finishes playing
if self.preview_track_player:
self.btnPreview.setChecked(self.preview_track_player.is_playing())
# Update preview timer
if self.preview_track_player.is_playing():
playtime = self.preview_track_player.time_playing()
self.label_intro_timer.setText(f"{playtime / 1000:.1f}")
if self.preview_track_player.time_remaining_intro() <= 50:
self.label_intro_timer.setStyleSheet(
f"background: {Config.COLOUR_WARNING_TIMER}"
)
else:
self.label_intro_timer.setStyleSheet("")
else:
self.label_intro_timer.setText("0.0")
self.label_intro_timer.setStyleSheet("")
self.btnPreview.setChecked(False)
def tick_1000ms(self) -> None:
"""

View File

@ -631,21 +631,23 @@ class PlaylistTab(QTableView):
self.source_model.delete_rows(self.selected_model_row_numbers())
self.clear_selection()
def get_selected_row_track_id(self) -> Optional[int]:
def get_selected_row_and_track_id(self) -> Optional[tuple[int, int]]:
"""
Return the track_id of the selected row. If no row selected or selected
Return the (row_number, track_id) of the selected row. If no row selected or selected
row does not have a track, return None.
"""
log.debug("get_selected_row_track_id() called")
model_row_number = self.source_model_selected_row_number()
if model_row_number is None:
row_number = self.source_model_selected_row_number()
if row_number is None:
result = None
else:
result = self.source_model.get_row_track_id(model_row_number)
track_id = self.source_model.get_row_track_id(row_number)
if not track_id:
result = None
else:
result = (row_number, track_id)
log.debug(f"get_selected_row_track_id() returned: {result=}")
log.debug(f"get_selected_row_and_track_id() returned: {result=}")
return result

View File

@ -170,7 +170,7 @@ class _Music:
self.max_volume = Config.VLC_VOLUME_DEFAULT
self.start_dt: Optional[dt.datetime] = None
def _adjust_by_ms(self, ms: int) -> None:
def adjust_by_ms(self, ms: int) -> None:
"""Move player position by ms milliseconds"""
if not self.player:
@ -275,20 +275,6 @@ class _Music:
< dt.timedelta(microseconds=Config.PLAY_SETTLE)
)
def move_back(self, ms: int) -> None:
"""
Rewind player by ms milliseconds
"""
self._adjust_by_ms(ms * -1)
def move_forward(self, ms: int) -> None:
"""
Rewind player by ms milliseconds
"""
self._adjust_by_ms(ms)
def play(
self,
path: str,
@ -304,7 +290,7 @@ class _Music:
the start time is the same
"""
log.info(f"Music[{self.name}].play({path=}, {position=}")
log.debug(f"Music[{self.name}].play({path=}, {position=}")
if file_is_unreadable(path):
log.error(f"play({path}): path not readable")
@ -374,7 +360,7 @@ class _TrackManager:
typically the previous, current and next track.
"""
def __init__(self, session: db.Session, player_name: str, track_id: int) -> None:
def __init__(self, session: db.Session, player_name: str, track_id: int, row_number: int) -> None:
"""
Initialises data structure.
Define a player.
@ -385,6 +371,7 @@ class _TrackManager:
if not track:
raise ValueError(f"_TrackPlayer: unable to retreived {track_id=}")
self.player_name = player_name
self.row_number = row_number
self.artist = track.artist
self.bitrate = track.bitrate
@ -462,6 +449,33 @@ class _TrackManager:
return self.player.is_playing()
def move_back(self, ms: int = Config.PREVIEW_BACK_MS) -> None:
"""
Rewind player by ms milliseconds
"""
self.player.adjust_by_ms(ms * -1)
def move_forward(self, ms: int = Config.PREVIEW_ADVANCE_MS) -> None:
"""
Rewind player by ms milliseconds
"""
self.player.adjust_by_ms(ms)
def move_to_intro_end(self, buffer: int = Config.PREVIEW_END_BUFFER_MS) -> None:
"""
Move play position to 'buffer' milliseconds before end of intro.
If no intro defined, do nothing.
"""
if self.intro is None:
return
new_position = max(0, self.intro - Config.PREVIEW_END_BUFFER_MS)
self.player.adjust_by_ms(new_position - self.time_playing())
def play(self, position: Optional[float] = None) -> None:
"""Play track"""
@ -481,6 +495,13 @@ class _TrackManager:
milliseconds=update_graph_at_ms
)
def restart(self) -> None:
"""
Restart player
"""
self.player.adjust_by_ms(self.time_playing() * -1)
def stop(self, fade_seconds: int = 0) -> None:
"""
Stop this track playing
@ -575,12 +596,12 @@ class MainTrackManager(_TrackManager):
session=session,
player_name=Config.VLC_MAIN_PLAYER_NAME,
track_id=self.track_id,
row_number=plr.plr_rownum
)
# Save non-track plr info
self.plr_id: int = plr.id
self.playlist_id: int = plr.playlist_id
self.row_number: int = plr.plr_rownum
def __repr__(self) -> str:
return (
@ -594,11 +615,12 @@ class PreviewTrackManager(_TrackManager):
Manage previewing tracks
"""
def __init__(self, session: db.Session, track_id: int) -> None:
def __init__(self, session: db.Session, track_id: int, row_number: int) -> None:
super().__init__(
session=session,
player_name=Config.VLC_PREVIEW_PLAYER_NAME,
track_id=track_id,
row_number=row_number
)
def __repr__(self) -> str: