mirror of
https://github.com/beetbox/beets.git
synced 2026-02-21 23:03:26 +01:00
add items to DB before moving/copying (#190)
Previously, all files would be moved/copied/deleted before the corresponding
Items and Albums were added to the database. Now, the in-place items are added
to the database; the files are moved; and then the new paths are saved to the
DB. The apply_choices coroutine now executes two database transactions per task.
This has a couple of benefits:
- %aunique{} requires album structures to be in place before the destination()
call, so this now works as expected.
- As an added bonus, the "in_album" parameter to move() and destination() --
along with its associated ugly hacks -- is no longer required.
This commit is contained in:
parent
4b253df48c
commit
2087ff6e41
3 changed files with 37 additions and 42 deletions
|
|
@ -702,29 +702,9 @@ def apply_choices(config):
|
|||
util.prune_dirs(os.path.dirname(duplicate_path),
|
||||
lib.directory)
|
||||
|
||||
# Move/copy files.
|
||||
task.old_paths = [item.path for item in items] # For deletion.
|
||||
for item in items:
|
||||
if config.copy or config.move:
|
||||
if config.move:
|
||||
# Just move the file.
|
||||
lib.move(item, False, task.is_album)
|
||||
else:
|
||||
# If it's a reimport, move the file. Otherwise, copy
|
||||
# and keep track of the old path.
|
||||
old_path = item.path
|
||||
do_copy = not bool(replaced_items[item])
|
||||
lib.move(item, do_copy, task.is_album)
|
||||
if not do_copy:
|
||||
# If we moved the item, remove the now-nonexistent
|
||||
# file from old_paths.
|
||||
task.old_paths.remove(old_path)
|
||||
|
||||
if config.write and task.should_write_tags():
|
||||
item.write()
|
||||
|
||||
# Add items to library. We consolidate this at the end to avoid
|
||||
# locking while we do the copying and tag updates.
|
||||
# Add items -- before path changes -- to the library. We add the
|
||||
# items now (rather than at the end) so that album structures
|
||||
# are in place before calls to destination().
|
||||
try:
|
||||
# Remove old items.
|
||||
for replaced in replaced_items.itervalues():
|
||||
|
|
@ -745,6 +725,34 @@ def apply_choices(config):
|
|||
finally:
|
||||
lib.save()
|
||||
|
||||
# Move/copy files.
|
||||
task.old_paths = [item.path for item in items] # For deletion.
|
||||
for item in items:
|
||||
if config.copy or config.move:
|
||||
if config.move:
|
||||
# Just move the file.
|
||||
lib.move(item, False)
|
||||
else:
|
||||
# If it's a reimport, move the file. Otherwise, copy
|
||||
# and keep track of the old path.
|
||||
old_path = item.path
|
||||
do_copy = not bool(replaced_items[item])
|
||||
lib.move(item, do_copy)
|
||||
if not do_copy:
|
||||
# If we moved the item, remove the now-nonexistent
|
||||
# file from old_paths.
|
||||
task.old_paths.remove(old_path)
|
||||
|
||||
if config.write and task.should_write_tags():
|
||||
item.write()
|
||||
|
||||
# Save new paths.
|
||||
try:
|
||||
for item in items:
|
||||
lib.store(item)
|
||||
finally:
|
||||
lib.save()
|
||||
|
||||
def fetch_art(config):
|
||||
"""A coroutine that fetches and applies album art for albums where
|
||||
appropriate.
|
||||
|
|
|
|||
|
|
@ -829,11 +829,10 @@ class Library(BaseLibrary):
|
|||
self.conn.executescript(setup_sql)
|
||||
self.conn.commit()
|
||||
|
||||
def destination(self, item, pathmod=None, in_album=False,
|
||||
fragment=False, basedir=None, platform=None):
|
||||
def destination(self, item, pathmod=None, fragment=False,
|
||||
basedir=None, platform=None):
|
||||
"""Returns the path in the library directory designated for item
|
||||
item (i.e., where the file ought to be). in_album forces the
|
||||
item to be treated as part of an album. fragment makes this
|
||||
item (i.e., where the file ought to be). fragment makes this
|
||||
method return just the path fragment underneath the root library
|
||||
directory; the path is also returned as Unicode instead of
|
||||
encoded as a bytestring. basedir can override the library's base
|
||||
|
|
@ -848,14 +847,6 @@ class Library(BaseLibrary):
|
|||
if query == PF_KEY_DEFAULT:
|
||||
continue
|
||||
query = AndQuery.from_string(query)
|
||||
if in_album:
|
||||
# If we're treating this item as a member of the item,
|
||||
# hack the query so that singleton queries always
|
||||
# observe the item to be non-singleton.
|
||||
for i, subquery in enumerate(query):
|
||||
if isinstance(subquery, SingletonQuery):
|
||||
query[i] = FalseQuery() if subquery.sense \
|
||||
else TrueQuery()
|
||||
if query.match(item):
|
||||
# The query matches the item! Use the corresponding path
|
||||
# format.
|
||||
|
|
@ -1024,7 +1015,7 @@ class Library(BaseLibrary):
|
|||
util.soft_remove(item.path)
|
||||
util.prune_dirs(os.path.dirname(item.path), self.directory)
|
||||
|
||||
def move(self, item, copy=False, in_album=False, basedir=None,
|
||||
def move(self, item, copy=False, basedir=None,
|
||||
with_album=True):
|
||||
"""Move the item to its designated location within the library
|
||||
directory (provided by destination()). Subdirectories are
|
||||
|
|
@ -1033,11 +1024,6 @@ class Library(BaseLibrary):
|
|||
|
||||
If copy is True, moving the file is copied rather than moved.
|
||||
|
||||
If in_album is True, then the track is treated as part of an
|
||||
album even if it does not yet have an album_id associated with
|
||||
it. (This allows items to be moved before they are added to the
|
||||
database, a performance optimization.)
|
||||
|
||||
basedir overrides the library base directory for the
|
||||
destination.
|
||||
|
||||
|
|
@ -1050,7 +1036,7 @@ class Library(BaseLibrary):
|
|||
side effect. You probably want to call save() to commit the DB
|
||||
transaction.
|
||||
"""
|
||||
dest = self.destination(item, in_album=in_album, basedir=basedir)
|
||||
dest = self.destination(item, basedir=basedir)
|
||||
|
||||
# Create necessary ancestry for the move.
|
||||
util.mkdirall(dest)
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ Changelog
|
|||
even on Unix platforms (this causes less surprise when using Samba shares to
|
||||
store music). To customize your character substitutions, see :ref:`the replace
|
||||
config option <replace>`.
|
||||
* Filename collisions are now avoided when moving album art.
|
||||
* :doc:`/plugins/bpd`: Use Gstreamer's ``playbin2`` element instead of the
|
||||
deprecated ``playbin``.
|
||||
* :doc:`/plugins/bpd`: Listings are now sorted (thanks once again to Matteo
|
||||
|
|
|
|||
Loading…
Reference in a new issue