Merge pull request #520 from silb/importmtimes_plugin

Add a plugin for preserving file modification times during copy imports.
This commit is contained in:
Adrian Sampson 2014-05-13 21:53:47 -07:00
commit 12ea97cabd
3 changed files with 133 additions and 0 deletions

97
beetsplug/importadded.py Normal file
View file

@ -0,0 +1,97 @@
"""Populate an items `added` and `mtime` field by using the file modification
time (mtime) of the item's source file before import.
"""
from __future__ import unicode_literals, absolute_import, print_function
import logging
import os
from beets import config
from beets import util
from beets.plugins import BeetsPlugin
log = logging.getLogger('beets')
class ImportAddedPlugin(BeetsPlugin):
def __init__(self):
super(ImportAddedPlugin, self).__init__()
self.config.add({
'preserve_mtimes': False,
})
@ImportAddedPlugin.listen('import_task_start')
def check_config(task, session):
config['importadded']['preserve_mtimes'].get(bool)
def write_file_mtime(path, mtime):
"""Write the given mtime to the destination path.
"""
stat = os.stat(util.syspath(path))
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
item's file.
"""
if mtime is None:
log.warn("No mtime to be preserved for item "
+ util.displayable_path(item.path))
return
# The file's mtime on disk must be in sync with the item's mtime
write_file_mtime(util.syspath(item.path), mtime)
item.mtime = mtime
@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.
"""
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('Recorded mtime %s for item "%s" imported from "%s"',
mtime,
util.displayable_path(destination),
util.displayable_path(source))
@ImportAddedPlugin.listen('album_imported')
def update_album_times(lib, album):
album_mtimes = []
for item in album.items():
mtime = item_mtime[item.path]
if mtime is not None:
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)
album.store()
@ImportAddedPlugin.listen('item_imported')
def update_item_times(lib, item):
mtime = item_mtime[item.path]
if mtime is not None:
item.added = mtime
if config['importadded']['preserve_mtimes'].get(bool):
write_item_mtime(item, mtime)
item.store()
del item_mtime[item.path]

View file

@ -0,0 +1,33 @@
ImportAdded Plugin
==================
The ``importadded`` plugin is useful when an existing collection is imported
and the time when albums and items were added should be preserved.
The :abbr:`mtime (modification time)` of files that are imported into the
library are assumed to represent the time when the items were originally
added.
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
set to the oldest mtime of the files in the album before they were imported.
The mtime of album directories are ignored.
This plugin can optionally be configured to also preserve mtimes::
importadded:
preserve_mtimes: yes # default: no
File modification times are preserved as follows:
* For all items:
* ``item.mtime`` is set to the mtime of the file
from which the item is imported from.
* The mtime of the file ``item.path`` is set to ``item.mtime``.
Note that there is no ``album.mtime`` field in the database and that the mtime
of album directories on disk aren't preserved.

View file

@ -59,6 +59,7 @@ by typing ``beet version``.
ftintitle
keyfinder
bucket
importadded
Autotagger Extensions
---------------------
@ -91,6 +92,8 @@ Metadata
statistics (last_played, play_count, skip_count, rating).
* :doc:`keyfinder`: Use the `KeyFinder`_ program to detect the musical
key from the audio.
* :doc:`importadded`: Use file modification times for guessing the value for
the `added` field in the database.
.. _Acoustic Attributes: http://developer.echonest.com/acoustic-attributes.html
.. _the Echo Nest: http://www.echonest.com