From a8c5a56c1a20946438efb553fec99b5574ecfd7b Mon Sep 17 00:00:00 2001 From: Keith Edmunds Date: Fri, 13 Oct 2023 19:01:22 +0100 Subject: [PATCH] Implent subtotal times and unplayed time --- app/models.py | 2 +- app/playlists.py | 66 ++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/app/models.py b/app/models.py index 739a568..e6b6caa 100644 --- a/app/models.py +++ b/app/models.py @@ -456,7 +456,7 @@ class PlaylistRows(Base): session.commit() @classmethod - def get_from_id_list( + def plrids_to_plrs( cls, session: scoped_session, playlist_id: int, plr_ids: List[int] ) -> List["PlaylistRows"]: """ diff --git a/app/playlists.py b/app/playlists.py index b350038..a3c041d 100644 --- a/app/playlists.py +++ b/app/playlists.py @@ -8,7 +8,7 @@ import obsws_python as obs # type: ignore from collections import namedtuple from datetime import datetime, timedelta -from typing import Any, Callable, cast, List, Optional, TYPE_CHECKING, Union +from typing import Any, Callable, cast, List, Optional, Tuple, TYPE_CHECKING, Union from PyQt6.QtCore import ( QEvent, @@ -1425,14 +1425,21 @@ class PlaylistTab(QTableWidget): return userdata_item.data(role) - def _get_section_timing_string(self, ms: int, no_end: bool = False) -> str: + def _get_section_timing_string( + self, total_time: int, unplayed_time: int, no_end: bool = False + ) -> str: """Return string describing section duration""" - duration = ms_to_mmss(ms) + total_duration = ms_to_mmss(total_time) + if unplayed_time: + unplayed_duration = ms_to_mmss(unplayed_time) + else: + unplayed_duration = "[No unplayed tracks]" caveat = "" if no_end: caveat = " (to end of playlist)" - return " [" + duration + caveat + "]" + + return f" {unplayed_duration} ({total_duration}){caveat}" def _get_selected_row(self) -> Optional[int]: """ @@ -2351,10 +2358,10 @@ class PlaylistTab(QTableWidget): def _track_time_between_rows( self, session: scoped_session, from_plr: PlaylistRows, to_plr: PlaylistRows - ) -> int: + ) -> Tuple[int, int]: """ - Returns the total duration of all tracks in rows between - from_row and to_row inclusive + Returns the (total duration of all tracks in rows between + from_row and to_row inclusive, total unplayed time in those rows) """ plr_tracks = PlaylistRows.get_rows_with_tracks( @@ -2363,8 +2370,12 @@ class PlaylistTab(QTableWidget): total_time = 0 total_time = sum([a.track.duration for a in plr_tracks if a.track.duration]) + unplayed_time = 0 + unplayed_time = sum( + [a.track.duration for a in plr_tracks if a.track.duration and not a.played] + ) - return total_time + return (total_time, unplayed_time) def _update_row_track_info( self, session: scoped_session, row: int, track: Tracks @@ -2395,25 +2406,31 @@ class PlaylistTab(QTableWidget): """ section_start_rows: List[PlaylistRows] = [] + subtotal_from: Optional[PlaylistRows] = None header_rows = [ self._get_row_plr_id(row_number) for row_number in range(self.rowCount()) if self._get_row_track_id(row_number) == 0 ] - plrs = PlaylistRows.get_from_id_list(session, self.playlist_id, header_rows) + plrs = PlaylistRows.plrids_to_plrs(session, self.playlist_id, header_rows) for plr in plrs: + # Start of timed section if plr.note.endswith("+"): section_start_rows.append(plr) + subtotal_from = plr continue + # End of timed section elif plr.note.endswith("-"): try: from_plr = section_start_rows.pop() to_plr = plr - total_time = self._track_time_between_rows( + total_time, unplayed_time = self._track_time_between_rows( session, from_plr, to_plr ) - time_str = self._get_section_timing_string(total_time) + time_str = self._get_section_timing_string( + total_time, unplayed_time + ) self._set_row_header_text( session, from_plr.plr_rownum, from_plr.note + time_str ) @@ -2430,11 +2447,30 @@ class PlaylistTab(QTableWidget): + "]" ) self._set_row_header_text(session, to_plr.plr_rownum, new_text) + subtotal_from = None except IndexError: # This ending row may have a time left from before a # starting row above was deleted, so replace content self._set_row_header_text(session, plr.plr_rownum, plr.note) continue + # Subtotal + elif plr.note.endswith("="): + if not subtotal_from: + return + from_plr = subtotal_from + to_plr = plr + total_time, unplayed_time = self._track_time_between_rows( + session, subtotal_from, to_plr + ) + time_str = self._get_section_timing_string(total_time, unplayed_time) + + if to_plr.note.strip() == "=": + leader_text = "Subtotal: " + else: + leader_text = to_plr.note[:-1] + " " + new_text = leader_text + time_str + self._set_row_header_text(session, to_plr.plr_rownum, new_text) + subtotal_from = to_plr # If we still have plrs in section_start_rows, there isn't an end # section row for them @@ -2442,8 +2478,12 @@ class PlaylistTab(QTableWidget): if possible_plr: to_plr = possible_plr for from_plr in section_start_rows: - total_time = self._track_time_between_rows(session, from_plr, to_plr) - time_str = self._get_section_timing_string(total_time, no_end=True) + total_time, unplayed_time = self._track_time_between_rows( + session, from_plr, to_plr + ) + time_str = self._get_section_timing_string( + total_time, unplayed_time, no_end=True + ) self._set_row_header_text( session, from_plr.plr_rownum, from_plr.note + time_str )