From b4b1743510376a45f4599929ebba0258dfa3e2c5 Mon Sep 17 00:00:00 2001 From: Thomas Vander Stichele Date: Sun, 21 Jun 2020 10:57:15 -0400 Subject: [PATCH 1/2] add album_save_post_processors to plug-in API. I wanted to extend the M3U playlist plugin to automatically generate an .m3u8 when Albums get saved. To be able to do so, I needed to add album_save_post_processors so that I could get access to an album on save. File save is done in a thread, so I needed to implement a way to wait for those threads to finish by using the file_save_post_processors hook. --- picard/album.py | 17 +++++++++++++++++ picard/tagger.py | 29 +++++++++++++++++++++++++---- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/picard/album.py b/picard/album.py index 715e01f464..a3c801f2d7 100644 --- a/picard/album.py +++ b/picard/album.py @@ -753,3 +753,20 @@ def register_album_post_removal_processor(function, priority=PluginPriority.NORM def run_album_post_removal_processors(album_object): _album_post_removal_processors.run(album_object) + +_album_post_save_processors = PluginFunctions(label='album_post_save_processors') + + +def register_album_post_save_processor(function, priority=PluginPriority.NORMAL): + """Registers an album-removed processor. + Args: + function: function to call after album save, it will be passed the album object + priority: optional, PluginPriority.NORMAL by default + Returns: + None + """ + _album_post_save_processors.register(function.__module__, function, priority) + + +def run_album_post_save_processors(album_object): + _album_post_save_processors.run(album_object) diff --git a/picard/tagger.py b/picard/tagger.py index 4d9d5868ff..85fb189e3d 100644 --- a/picard/tagger.py +++ b/picard/tagger.py @@ -76,6 +76,7 @@ Album, NatAlbum, run_album_post_removal_processors, + run_album_post_save_processors, ) from picard.browser.browser import BrowserIntegration from picard.browser.filelookup import FileLookup @@ -98,7 +99,7 @@ ) from picard.dataobj import DataObject from picard.disc import Disc -from picard.file import File +from picard.file import File, register_file_post_save_processor from picard.formats import open_ as open_file from picard.i18n import setup_gettext from picard.pluginmanager import PluginManager @@ -294,6 +295,10 @@ def __init__(self, picard_args, unparsed_args, localedir, autoupdate): if self.autoupdate_enabled: self.updatecheckmanager = UpdateCheckManager(parent=self.window) + # track all file save completions for album save + self._album_saves = [] + register_file_post_save_processor(self._file_post_save) + def register_cleanup(self, func): self.exit_cleanup.append(func) @@ -658,9 +663,14 @@ def get_files_from_objects(self, objects, save=False): def save(self, objects): """Save the specified objects.""" - files = self.get_files_from_objects(objects, save=True) - for file in files: - file.save() + for o in objects: + log.debug('save object %r', o) + files = self.get_files_from_objects([o, ], save=True) + for file in files: + file.save() + if isinstance(o, Album): + # track the album and its files pending save + self._album_saves.append((o, files)) def load_album(self, album_id, discid=None): album_id = self.mbid_redirects.get(album_id, album_id) @@ -773,6 +783,17 @@ def remove(self, objects): if files: self.remove_files(files) + # run album_save hooks when the last file is saved + def _file_post_save(self, file): + for album, files in self._album_saves: + if file in files: + files.remove(file) + if not files: + log.debug("Album %r saved, running post_save_processors", album) + run_album_post_save_processors(album) + self._album_saves.remove((album, files)) + return + def _lookup_disc(self, disc, result=None, error=None): self.restore_cursor() if error is not None: From 7b41e1283b4fd740e1fe4fb3933961c72c4d489f Mon Sep 17 00:00:00 2001 From: Thomas Vander Stichele Date: Sun, 21 Jun 2020 11:07:43 -0400 Subject: [PATCH 2/2] run isort --- picard/tagger.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/picard/tagger.py b/picard/tagger.py index 85fb189e3d..1faeb2610d 100644 --- a/picard/tagger.py +++ b/picard/tagger.py @@ -99,7 +99,10 @@ ) from picard.dataobj import DataObject from picard.disc import Disc -from picard.file import File, register_file_post_save_processor +from picard.file import ( + File, + register_file_post_save_processor, +) from picard.formats import open_ as open_file from picard.i18n import setup_gettext from picard.pluginmanager import PluginManager