From 125f6422d7a0b1b90651f2b88c9214e39aefa24a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stig=20Inge=20Lea=20Bj=C3=B8rnsen?= Date: Mon, 29 Sep 2014 22:57:15 +0200 Subject: [PATCH 1/3] Bug #911 reimport detection for the `importadded` plugin Reimports are now detected by inspecting the fields for reimported items and replaced albums in ImportTask. Reimported albums and items are skipped. --- beetsplug/importadded.py | 65 ++++++++++++++++++++++++++---------- docs/plugins/importadded.rst | 9 +++-- 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/beetsplug/importadded.py b/beetsplug/importadded.py index 8b4b7c6b5..6ee59a93d 100644 --- a/beetsplug/importadded.py +++ b/beetsplug/importadded.py @@ -1,5 +1,7 @@ -"""Populate an items `added` and `mtime` field by using the file modification -time (mtime) of the item's source file before import. +"""Populate an item's `added` and `mtime` fields by using the file +modification time (mtime) of the item's source file before import. + +Reimported albums and items are skipped. """ from __future__ import unicode_literals, absolute_import, print_function @@ -26,6 +28,26 @@ class ImportAddedPlugin(BeetsPlugin): def check_config(task, session): config['importadded']['preserve_mtimes'].get(bool) +# item.id for new items that were reimported +reimported_item_ids = None + +# album.path for old albums that were replaced by a new reimported album +replaced_album_paths = None + +def reimported_item(item): + return item.id in reimported_item_ids + +def reimported_album(album): + return album.path in replaced_album_paths + +@ImportAddedPlugin.listen('import_task_files') +def record_reimported(task, session): + global reimported_item_ids, replaced_album_paths + reimported_item_ids = set([item.id for item, replaced_items + in task.replaced_items.iteritems() + if replaced_items]) + replaced_album_paths = set(task.replaced_albums.keys()) + def write_file_mtime(path, mtime): """Write the given mtime to the destination path. @@ -34,10 +56,6 @@ def write_file_mtime(path, mtime): os.utime(util.syspath(path), (stat.st_atime, mtime)) -# key: item path in the library -# value: the file mtime of the file the item was imported from -item_mtime = dict() - def write_item_mtime(item, mtime): """Write the given mtime to an item's `mtime` field and to the mtime of the @@ -53,15 +71,16 @@ def write_item_mtime(item, mtime): item.mtime = mtime +# key: item path in the library +# value: the file mtime of the file the item was imported from +item_mtime = dict() + + @ImportAddedPlugin.listen('before_item_moved') @ImportAddedPlugin.listen('item_copied') def record_import_mtime(item, source, destination): - """Record the file mtime of an item's path before import. + """Record the file mtime of an item's path before its import. """ - if (source == destination): - # Re-import of an existing library item? - return - mtime = os.stat(util.syspath(source)).st_mtime item_mtime[destination] = mtime log.debug(u"Recorded mtime {0} for item '{1}' imported from '{2}'".format( @@ -71,26 +90,36 @@ def record_import_mtime(item, source, destination): @ImportAddedPlugin.listen('album_imported') def update_album_times(lib, album): + if reimported_album(album): + log.debug(u"Album {0} is reimported, skipping import of added " + u"dates for the album and its items.".format(album.path)) + return + album_mtimes = [] for item in album.items(): - mtime = item_mtime[item.path] - if mtime is not None: + mtime = item_mtime.pop(item.path, None) + if mtime: album_mtimes.append(mtime) if config['importadded']['preserve_mtimes'].get(bool): write_item_mtime(item, mtime) item.store() - del item_mtime[item.path] - album.added = min(album_mtimes) + log.debug(u"Import of album {0}, selected album.added={1} from item" + u" file mtimes.".format(album.album, album.added)) album.store() @ImportAddedPlugin.listen('item_imported') def update_item_times(lib, item): - mtime = item_mtime[item.path] - if mtime is not None: + if reimported_item(item): + log.debug(u"Item {0} is reimported, skipping import of added " + u"date.".format(util.displayable_path(item.path))) + return + mtime = item_mtime.pop(item.path, None) + if mtime: item.added = mtime if config['importadded']['preserve_mtimes'].get(bool): write_item_mtime(item, mtime) + log.debug(u"Import of item {0}, selected item.added={1}".format( + util.displayable_path(item.path), item.added)) item.store() - del item_mtime[item.path] diff --git a/docs/plugins/importadded.rst b/docs/plugins/importadded.rst index 5da919325..90101be56 100644 --- a/docs/plugins/importadded.rst +++ b/docs/plugins/importadded.rst @@ -12,9 +12,9 @@ The ``item.added`` field is populated as follows: * For singleton items with no album, ``item.added`` is set to the item's file mtime before it was imported. -* For items that are part of an album, ``album.added`` and ``item.added`` is +* For items that are part of an album, ``album.added`` and ``item.added`` are set to the oldest mtime of the files in the album before they were imported. - The mtime of album directories are ignored. + The mtime of album directories is ignored. This plugin can optionally be configured to also preserve mtimes:: @@ -31,3 +31,8 @@ File modification times are preserved as follows: Note that there is no ``album.mtime`` field in the database and that the mtime of album directories on disk aren't preserved. + +Reimport +-------- + +This plugin will skip reimported singleton items and reimported albums and all of their items. From 3bd3a817de00ee35608bbd952167774ed1c482da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stig=20Inge=20Lea=20Bj=C3=B8rnsen?= Date: Tue, 7 Oct 2014 22:05:44 +0200 Subject: [PATCH 2/3] Comply with PEP8. --- beetsplug/importadded.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/beetsplug/importadded.py b/beetsplug/importadded.py index 6ee59a93d..1fd4ab3e5 100644 --- a/beetsplug/importadded.py +++ b/beetsplug/importadded.py @@ -34,12 +34,15 @@ reimported_item_ids = None # album.path for old albums that were replaced by a new reimported album replaced_album_paths = None + def reimported_item(item): return item.id in reimported_item_ids + def reimported_album(album): return album.path in replaced_album_paths + @ImportAddedPlugin.listen('import_task_files') def record_reimported(task, session): global reimported_item_ids, replaced_album_paths From 79a9593cb9c667eb9ba88b17346a633203ea5322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stig=20Inge=20Lea=20Bj=C3=B8rnsen?= Date: Fri, 10 Oct 2014 22:52:54 +0200 Subject: [PATCH 3/3] Add quoting and use displayable paths in log messages --- beetsplug/importadded.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/beetsplug/importadded.py b/beetsplug/importadded.py index 1fd4ab3e5..d362005f9 100644 --- a/beetsplug/importadded.py +++ b/beetsplug/importadded.py @@ -65,7 +65,7 @@ def write_item_mtime(item, mtime): item's file. """ if mtime is None: - log.warn(u"No mtime to be preserved for item {0}" + log.warn(u"No mtime to be preserved for item '{0}'" .format(util.displayable_path(item.path))) return @@ -94,8 +94,9 @@ def record_import_mtime(item, source, destination): @ImportAddedPlugin.listen('album_imported') def update_album_times(lib, album): if reimported_album(album): - log.debug(u"Album {0} is reimported, skipping import of added " - u"dates for the album and its items.".format(album.path)) + log.debug(u"Album '{0}' is reimported, skipping import of added dates" + u" for the album and its items." + .format(util.displayable_path(album.path))) return album_mtimes = [] @@ -107,7 +108,7 @@ def update_album_times(lib, album): write_item_mtime(item, mtime) item.store() album.added = min(album_mtimes) - log.debug(u"Import of album {0}, selected album.added={1} from item" + log.debug(u"Import of album '{0}', selected album.added={1} from item" u" file mtimes.".format(album.album, album.added)) album.store() @@ -115,7 +116,7 @@ def update_album_times(lib, album): @ImportAddedPlugin.listen('item_imported') def update_item_times(lib, item): if reimported_item(item): - log.debug(u"Item {0} is reimported, skipping import of added " + log.debug(u"Item '{0}' is reimported, skipping import of added " u"date.".format(util.displayable_path(item.path))) return mtime = item_mtime.pop(item.path, None) @@ -123,6 +124,6 @@ def update_item_times(lib, item): item.added = mtime if config['importadded']['preserve_mtimes'].get(bool): write_item_mtime(item, mtime) - log.debug(u"Import of item {0}, selected item.added={1}".format( - util.displayable_path(item.path), item.added)) + log.debug(u"Import of item '{0}', selected item.added={1}" + .format(util.displayable_path(item.path), item.added)) item.store()