Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: sampsyo/beets
...
head fork: sampsyo/beets
  • 3 commits
  • 3 files changed
  • 0 commit comments
  • 1 contributor
Commits on May 19, 2012
@sampsyo don't display difference when medium index matches
Regarding GC-335, the difference display was confusing when the track indices
were correct but used a per-disc numbering scheme.
427e201
@sampsyo show per-disc numbers in change preview (GC-335) 2ede4b3
@sampsyo do not preserve metadata during copy-move (GC-383)
The shutil.move() function attempts to copy metadata (e.g., permissions and
mtime) when copying a file across filesystems. This always fails on Samba shares
because the utime() call is never permitted by normal users. We don't care about
preserving mtimes across moves, though, so this commit eschews shutil and
reimplements the move algorithm.
b04096d
Showing with 44 additions and 23 deletions.
  1. +20 −10 beets/ui/commands.py
  2. +23 −13 beets/util/__init__.py
  3. +1 −0  docs/changelog.rst
View
30 beets/ui/commands.py
@@ -138,7 +138,8 @@ def dist_string(dist, color):
out = ui.colorize('red', out)
return out
-def show_change(cur_artist, cur_album, items, info, dist, color=True):
+def show_change(cur_artist, cur_album, items, info, dist, color=True,
+ per_disc_numbering=False):
"""Print out a representation of the changes that will be made if
tags are changed from (cur_artist, cur_album, items) to info with
distance dist.
@@ -205,7 +206,15 @@ def show_album(artist, album, partial=False):
# Get displayable LHS and RHS values.
cur_track = unicode(item.track)
- new_track = unicode(i+1)
+ if per_disc_numbering:
+ if info.mediums > 1:
+ new_track = u'{0}-{1}'.format(track_info.medium,
+ track_info.medium_index)
+ else:
+ new_track = unicode(track_info.medium_index)
+ else:
+ new_track = unicode(i + 1)
+ tracks_differ = item.track not in (i + 1, track_info.medium_index)
cur_title = item.title
new_title = track_info.title
if item.length and track_info.length:
@@ -218,9 +227,8 @@ def show_album(artist, album, partial=False):
# Possibly colorize changes.
if color:
cur_title, new_title = ui.colordiff(cur_title, new_title)
- if cur_track != new_track:
- cur_track = ui.colorize('red', cur_track)
- new_track = ui.colorize('red', new_track)
+ cur_track = ui.colorize('red', cur_track)
+ new_track = ui.colorize('red', new_track)
# Show filename (non-colorized) when title is not set.
if not item.title.strip():
@@ -228,14 +236,14 @@ def show_album(artist, album, partial=False):
if cur_title != new_title:
lhs, rhs = cur_title, new_title
- if cur_track != new_track:
+ if tracks_differ:
lhs += u' (%s)' % cur_track
rhs += u' (%s)' % new_track
print_(u" * %s -> %s" % (lhs, rhs))
else:
line = u' * %s' % item.title
display = False
- if cur_track != new_track:
+ if tracks_differ:
display = True
line += u' (%s -> %s)' % (cur_track, new_track)
if item.length and track_info.length and \
@@ -290,7 +298,7 @@ def _quiet_fall_back(config):
def choose_candidate(candidates, singleton, rec, color, timid,
cur_artist=None, cur_album=None, item=None,
- itemcount=None):
+ itemcount=None, per_disc_numbering=False):
"""Given a sorted list of candidates, ask the user for a selection
of which candidate to use. Applies to both full albums and
singletons (tracks). For albums, the candidates are `(dist, items,
@@ -423,7 +431,8 @@ def choose_candidate(candidates, singleton, rec, color, timid,
if singleton:
show_item_change(item, info, dist, color)
else:
- show_change(cur_artist, cur_album, items, info, dist, color)
+ show_change(cur_artist, cur_album, items, info, dist, color,
+ per_disc_numbering)
# Exact match => tag automatically if we're not in timid mode.
if rec == autotag.RECOMMEND_STRONG and not timid:
@@ -511,7 +520,8 @@ def choose_match(task, config):
# Ask for a choice from the user.
choice = choose_candidate(candidates, False, rec, config.color,
config.timid, task.cur_artist,
- task.cur_album, itemcount=len(task.items))
+ task.cur_album, itemcount=len(task.items),
+ per_disc_numbering=config.per_disc_numbering)
# Choose which tags to use.
if choice in (importer.action.SKIP, importer.action.ASIS,
View
36 beets/util/__init__.py
@@ -89,7 +89,7 @@ def __init__(self, reason, verb, paths, tb=None):
def get_message(self):
# Use a nicer English phrasing for some specific verbs.
- if self.verb in ('move', 'copy'):
+ if self.verb in ('move', 'copy', 'rename'):
clause = 'while {0} {1} to {2}'.format(
self._gerund(), repr(self.paths[0]), repr(self.paths[1])
)
@@ -314,10 +314,10 @@ def remove(path, soft=True):
raise FilesystemError(exc, 'delete', (path,), traceback.format_exc())
def copy(path, dest, replace=False, pathmod=os.path):
- """Copy a plain file. Permissions are not copied. If dest already
- exists, raises an OSError unless replace is True. Has no effect if
- path is the same as dest. Paths are translated to system paths
- before the syscall.
+ """Copy a plain file. Permissions are not copied. If `dest` already
+ exists, raises a FilesystemError unless `replace` is True. Has no
+ effect if `path` is the same as `dest`. Paths are translated to
+ system paths before the syscall.
"""
if samefile(path, dest):
return
@@ -332,22 +332,32 @@ def copy(path, dest, replace=False, pathmod=os.path):
traceback.format_exc())
def move(path, dest, replace=False, pathmod=os.path):
- """Rename a file. dest may not be a directory. If dest already
- exists, raises an OSError unless replace is True. Hos no effect if
- path is the same as dest. Paths are translated to system paths.
+ """Rename a file. `dest` may not be a directory. If `dest` already
+ exists, raises an OSError unless `replace` is True. Has no effect if
+ `path` is the same as `dest`. If the paths are on different
+ filesystems (or the rename otherwise fails), a copy is attempted
+ instead, in which case metadata will *not* be preserved. Paths are
+ translated to system paths.
"""
if samefile(path, dest):
return
path = syspath(path)
dest = syspath(dest)
if pathmod.exists(dest):
- raise FilesystemError('file exists', 'move', (path, dest),
+ raise FilesystemError('file exists', 'rename', (path, dest),
traceback.format_exc())
+
+ # First, try renaming the file.
try:
- shutil.move(path, dest)
- except (OSError, IOError) as exc:
- raise FilesystemError(exc, 'move', (path, dest),
- traceback.format_exc())
+ os.rename(path, dest)
+ except OSError:
+ # Otherwise, copy and delete the original.
+ try:
+ shutil.copyfile(path, dest)
+ os.remove(path)
+ except (OSError, IOError) as exc:
+ raise FilesystemError(exc, 'move', (path, dest),
+ traceback.format_exc())
def unique_path(path):
"""Returns a version of ``path`` that does not exist on the
View
1  docs/changelog.rst
@@ -19,6 +19,7 @@ Changelog
action assigned.
* New plugin event: ``library_opened`` is called when beets starts up and
opens the library database.
+* Fix a crash when moving files to a Samba share.
* :doc:`/plugins/mpdupdate`: Fix TypeError crash (thanks to Philippe Mongeau).
* When re-importing files with ``import_copy`` enabled, only files inside the
library directory are moved. Files outside the library directory are still

No commit comments for this range

Something went wrong with that request. Please try again.