diff --git a/libremsonic/app.py b/libremsonic/app.py index 78e2e54..e137094 100644 --- a/libremsonic/app.py +++ b/libremsonic/app.py @@ -95,6 +95,10 @@ class LibremsonicApp(Gtk.Application): self.on_go_to_playlist, parameter_type='s') + add_action('delete-playlist', + self.on_delete_playlist, + parameter_type='s') + add_action('mute-toggle', self.on_mute_toggle) add_action( 'update-play-queue-from-server', @@ -317,6 +321,12 @@ class LibremsonicApp(Gtk.Application): self.state.selected_playlist_id = playlist_id.get_string() self.update_window() + def on_delete_playlist(self, action, playlist_id): + # Update state. + self.state.current_tab = 'playlists' + self.state.selected_playlist_id = None + self.update_window() + def on_server_list_changed(self, action, servers): self.state.config.servers = servers self.state.save() diff --git a/libremsonic/cache_manager.py b/libremsonic/cache_manager.py index f81c350..79e7855 100644 --- a/libremsonic/cache_manager.py +++ b/libremsonic/cache_manager.py @@ -250,12 +250,12 @@ class CacheManager(metaclass=Singleton): return str(abs_path) - def delete_cached(self, relative_path: Union[Path, str]): - """ - :param relative_path: The path to the cached element to delete. - Note that this can be a globed path. - """ + def delete_cached_cover_art(self, id: int): + tag = 'tag_' if self.browse_by_tags else '' + relative_path = f'cover_art/{tag}{id}_*' + abs_path = self.calculate_abs_path(relative_path) + for path in glob.glob(str(abs_path)): Path(path).unlink() @@ -275,6 +275,14 @@ class CacheManager(metaclass=Singleton): return CacheManager.executor.submit(do_get_playlists) + def invalidate_playlists_cache(self): + if not self.cache.get('playlists'): + return + + with self.cache_lock: + self.cache['playlists'] = [] + self.save_cache_info() + def get_playlist( self, playlist_id: int, @@ -301,8 +309,7 @@ class CacheManager(metaclass=Singleton): # Invalidate the cached photo if we are forcing a retrieval # from the server. if force: - self.delete_cached( - f'cover_art/{playlist_details.coverArt}_*') + self.delete_cached_cover_art(playlist.id) return playlist_details diff --git a/libremsonic/ui/common/edit_form_dialog.py b/libremsonic/ui/common/edit_form_dialog.py index 3222a7b..05787ec 100644 --- a/libremsonic/ui/common/edit_form_dialog.py +++ b/libremsonic/ui/common/edit_form_dialog.py @@ -38,13 +38,6 @@ class EditFormDialog(Gtk.Dialog): transient_for=parent, flags=0, ) - self.add_buttons( - Gtk.STOCK_CANCEL, - Gtk.ResponseType.CANCEL, - Gtk.STOCK_EDIT if editing else Gtk.STOCK_ADD, - Gtk.ResponseType.OK, - ) - if not existing_object: existing_object = self.get_default_object() @@ -111,10 +104,15 @@ class EditFormDialog(Gtk.Dialog): content_area.pack_start(content_grid, True, True, 10) # Create a box for buttons. - if len(self.extra_buttons) > 0: - button_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) - for button in self.extra_buttons: - button_box.pack_start(button, False, True, 5) - content_area.pack_start(button_box, True, True, 10) + for button, response_id in self.extra_buttons: + self.add_action_widget(button, response_id) + + self.add_buttons( + Gtk.STOCK_CANCEL, + Gtk.ResponseType.CANCEL, + Gtk.STOCK_EDIT if editing else Gtk.STOCK_ADD, + Gtk.ResponseType.OK, + ) + self.show_all() diff --git a/libremsonic/ui/playlists.py b/libremsonic/ui/playlists.py index fd12231..abc5d9d 100644 --- a/libremsonic/ui/playlists.py +++ b/libremsonic/ui/playlists.py @@ -16,24 +16,29 @@ from libremsonic.ui.common import EditFormDialog, IconButton, SpinnerImage class EditPlaylistDialog(EditFormDialog): - __gsignals__ = { - 'delete-playlist': - (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, ()), - } - entity_name: str = 'Playlist' initial_size = (350, 120) text_fields = [('Name', 'name', False), ('Comment', 'comment', False)] boolean_fields = [('Public', 'public')] - def __init__(self, *args, **kwargs): - delete_playlist = Gtk.Button(label='Delete Playlist') - delete_playlist.connect('clicked', self.on_delete_playlist_click) - self.extra_buttons = [delete_playlist] - super().__init__(*args, **kwargs) + def __init__(self, *args, playlist_id=None, **kwargs): + delete_playlist = Gtk.Button( + label='Delete Playlist', + action_name='app.delete-playlist', + action_target=GLib.Variant('s', playlist_id), + ) - def on_delete_playlist_click(self, event): - self.emit('delete-playlist') + def on_delete_playlist(e): + # Delete the playlists and invalidate caches. + CacheManager.delete_playlist(playlist_id) + CacheManager.delete_cached_cover_art(playlist_id) + CacheManager.invalidate_playlists_cache() + self.close() + + delete_playlist.connect('clicked', on_delete_playlist) + + self.extra_buttons = [(delete_playlist, Gtk.ResponseType.DELETE_EVENT)] + super().__init__(*args, **kwargs) class PlaylistsPanel(Gtk.Paned): @@ -503,14 +508,9 @@ class PlaylistDetailPanel(Gtk.Overlay): def on_playlist_edit_button_click(self, button): dialog = EditPlaylistDialog( self.get_toplevel(), - CacheManager.get_playlist(self.playlist_id).result()) - - def on_delete_playlist(e): - CacheManager.delete_playlist(self.playlist_id) - dialog.destroy() - self.update_playlist_view(force=True) - - dialog.connect('delete-playlist', on_delete_playlist) + CacheManager.get_playlist(self.playlist_id).result(), + playlist_id=self.playlist_id, + ) result = dialog.run() if result == Gtk.ResponseType.OK: @@ -521,9 +521,8 @@ class PlaylistDetailPanel(Gtk.Overlay): public=dialog.data['public'].get_active(), ) - # TODO - # cover_art_filename = f'cover_art/{playlist.coverArt}_*' - # CacheManager.delete_cached(cover_art_filename) + # Invalidate the cover art cache. + CacheManager.delete_cached_cover_art(playlist.id) self.update_playlist_view(self.playlist_id, force=True) dialog.destroy()