From 92a8119c17ca90eb2403431c2ffed70e7d5e9252 Mon Sep 17 00:00:00 2001 From: Matthias Meulien Date: Sat, 14 Sep 2024 22:00:47 +0200 Subject: [PATCH] Extend playlist model with status flags Refs: #177 --- NEWS.rst | 7 ++++--- argos/controllers/playlists.py | 12 +++++------ argos/dto.py | 6 +++--- argos/io.github.orontee.Argos.gresource.xml | 2 +- argos/model/__init__.py | 6 ++++-- argos/model/model.py | 18 +++++++++++++--- argos/model/playlist.py | 3 ++- argos/model/status.py | 6 ++++++ ..._box.ui => playlist_loading_tracks_box.ui} | 2 +- ...acksbox.py => playlistloadingtracksbox.py} | 10 +++++---- argos/widgets/playlistsbox.py | 21 ++++++++----------- po/POTFILES.in | 2 +- 12 files changed, 58 insertions(+), 37 deletions(-) create mode 100644 argos/model/status.py rename argos/ui/{playlist_empty_tracks_box.ui => playlist_loading_tracks_box.ui} (95%) rename argos/widgets/{playlistemptytracksbox.py => playlistloadingtracksbox.py} (79%) diff --git a/NEWS.rst b/NEWS.rst index 0c36f7b..d72bb5b 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -17,9 +17,10 @@ Added Changed ------- -- Check whether Mopidy server is reachable: Relying only on network - availability lead to UI being unresponsive when Argos runs on the - same host as the server but network becomes unavailable `#181 +- Support playlists without date of last modification `#177 + `_ + +- Check whether Mopidy server is reachable `#181 `_ Removed diff --git a/argos/controllers/playlists.py b/argos/controllers/playlists.py index 8ef3c29..67263b1 100644 --- a/argos/controllers/playlists.py +++ b/argos/controllers/playlists.py @@ -1,6 +1,7 @@ import asyncio import gettext import logging +import math import time from operator import itemgetter from typing import TYPE_CHECKING, Dict, List, Optional @@ -15,7 +16,7 @@ from argos.controllers.visitors import PlaylistTrackNameFix from argos.dto import PlaylistDTO from argos.message import Message, MessageType, consume -from argos.model import PlaylistModel, TrackModel +from argos.model import ModelFlag, PlaylistModel, TrackModel LOGGER = logging.getLogger(__name__) @@ -142,8 +143,7 @@ async def _save_playlist( if playlist is None: return None - if playlist.last_modified == -1: - # The playlist hasn't been loaded + if not (ModelFlag.TRACKS_COMPLETED & ModelFlag(playlist.props.flags)): playlist_dto = await self._http.lookup_playlist(playlist_uri) if playlist_dto is not None: await self._complete_playlist_from( @@ -244,7 +244,7 @@ async def __complete_history_playlist(self) -> None: if not self._history_playlist: return - LOGGER.info("Begin of history playlist completion") + LOGGER.debug("Begin of history playlist completion") history = await self._http.get_history() if history is None: return @@ -306,9 +306,9 @@ async def __complete_history_playlist(self) -> None: self._history_playlist.uri, name=self._history_playlist.name, tracks=parsed_history_tracks_with_duplicates, - last_modified=time.time(), + last_modified=math.floor(time.time()), ) - LOGGER.info("End of history playlist completion") + LOGGER.debug("End of history playlist completion") def _on_playlist_settings_changed( self, diff --git a/argos/dto.py b/argos/dto.py index 680a727..19f4ae8 100644 --- a/argos/dto.py +++ b/argos/dto.py @@ -246,7 +246,7 @@ class PlaylistDTO: uri: str name: str - last_modified: int + last_modified: Optional[int] tracks: List[TrackDTO] = field(default_factory=list) @@ -257,10 +257,10 @@ def factory(data: Any) -> Optional["PlaylistDTO"]: uri = data.get("uri") name = data.get("name") - last_modified = data.get("last_modified") - if uri is None or name is None or last_modified is None: + if uri is None or name is None: return None + last_modified = data.get("last_modified") dto = PlaylistDTO(uri, name, last_modified) for track_data in data.get("tracks", []): track_dto = TrackDTO.factory(track_data) diff --git a/argos/io.github.orontee.Argos.gresource.xml b/argos/io.github.orontee.Argos.gresource.xml index 5523b78..c3350b2 100644 --- a/argos/io.github.orontee.Argos.gresource.xml +++ b/argos/io.github.orontee.Argos.gresource.xml @@ -10,7 +10,7 @@ ui/library_window.ui ui/playing_box.ui ui/playing_box_empty_tracklist_box.ui - ui/playlist_empty_tracks_box.ui + ui/playlist_loading_tracks_box.ui ui/playlist_creation_dialog.ui ui/playlist_selection_dialog.ui ui/playlist_track_box.ui diff --git a/argos/model/__init__.py b/argos/model/__init__.py index 2d9db3a..1fb66f1 100644 --- a/argos/model/__init__.py +++ b/argos/model/__init__.py @@ -11,6 +11,7 @@ RandomTracksChoice, RandomTracksChoiceState, ) +from argos.model.status import ModelFlag from argos.model.track import TrackModel from argos.model.tracklist import TracklistModel, TracklistTrackModel from argos.model.utils import PlaybackState @@ -21,14 +22,15 @@ "LibraryModel", "MixerModel", "Model", + "ModelFlag", "MopidyBackend", "PlaybackModel", "PlaybackState", "PlaylistModel", + "RANDOM_TRACKS_CHOICE_STRATEGY", "RandomTracksChoice", "RandomTracksChoiceState", - "RANDOM_TRACKS_CHOICE_STRATEGY", + "TrackModel", "TracklistModel", "TracklistTrackModel", - "TrackModel", ) diff --git a/argos/model/model.py b/argos/model/model.py index 9562648..4115b9e 100644 --- a/argos/model/model.py +++ b/argos/model/model.py @@ -26,6 +26,7 @@ from argos.model.playback import PlaybackModel from argos.model.playlist import PlaylistModel, compare_playlists_func from argos.model.random import RandomTracksChoice, choose_random_tracks +from argos.model.status import ModelFlag from argos.model.track import ( TrackModel, compare_tracks_by_name_func, @@ -401,7 +402,7 @@ def complete_playlist_description( *, name: str, tracks: Sequence[TrackModel], - last_modified: float, + last_modified: Optional[int], wait_for_model_update: bool = False, ) -> None: event: Optional[threading.Event] @@ -426,17 +427,28 @@ def _complete_playlist_description() -> None: LOGGER.debug(f"Insertion of playlist with URI {playlist.uri!r}") self.playlists.insert_sorted(playlist, compare_playlists_func, None) else: - if playlist.last_modified == last_modified: + if ( + last_modified is not None + and playlist.last_modified == last_modified + ): LOGGER.debug(f"Playlist with URI {playlist_uri!r} is up-to-date") + if event is not None: + event.set() return playlist.name = name playlist.tracks.remove_all() - playlist.last_modified = last_modified + if last_modified is not None: + playlist.last_modified = last_modified + for track in tracks: playlist.tracks.append(track) + playlist.set_property( + "flags", playlist.flags | ModelFlag.TRACKS_COMPLETED.value + ) + if event is not None: event.set() diff --git a/argos/model/playlist.py b/argos/model/playlist.py index 38ef4ca..6e52ced 100644 --- a/argos/model/playlist.py +++ b/argos/model/playlist.py @@ -2,6 +2,7 @@ from gi.repository import Gio, GObject +from argos.model.status import ModelFlag from argos.model.track import TrackModel @@ -33,9 +34,9 @@ class PlaylistModel(GObject.Object): """Model for a playlist.""" uri = GObject.Property(type=str) + flags = GObject.Property(type=GObject.TYPE_INT, default=ModelFlag.NO_FLAG.value) name = GObject.Property(type=str) last_modified = GObject.Property(type=GObject.TYPE_DOUBLE, default=-1) - tracks: Gio.ListStore def __init__(self, **kwargs): diff --git a/argos/model/status.py b/argos/model/status.py new file mode 100644 index 0000000..849ebc3 --- /dev/null +++ b/argos/model/status.py @@ -0,0 +1,6 @@ +from enum import Flag, auto + + +class ModelFlag(Flag): + NO_FLAG = auto() + TRACKS_COMPLETED = auto() diff --git a/argos/ui/playlist_empty_tracks_box.ui b/argos/ui/playlist_loading_tracks_box.ui similarity index 95% rename from argos/ui/playlist_empty_tracks_box.ui rename to argos/ui/playlist_loading_tracks_box.ui index 8ba611f..dcb5d17 100644 --- a/argos/ui/playlist_empty_tracks_box.ui +++ b/argos/ui/playlist_loading_tracks_box.ui @@ -2,7 +2,7 @@ -