diff --git a/beets/config_default.yaml b/beets/config_default.yaml index b64600c04..47afe70ce 100644 --- a/beets/config_default.yaml +++ b/beets/config_default.yaml @@ -5,6 +5,7 @@ import: write: yes copy: yes move: no + link: no delete: no resume: ask incremental: no diff --git a/beets/library.py b/beets/library.py index 3549b1778..d20ecb067 100644 --- a/beets/library.py +++ b/beets/library.py @@ -524,7 +524,7 @@ class Item(LibModel): # Files themselves. - def move_file(self, dest, copy=False): + def move_file(self, dest, copy=False, link=False): """Moves or copies the item's file, updating the path value if the move succeeds. If a file exists at ``dest``, then it is slightly modified to be unique. @@ -535,6 +535,10 @@ class Item(LibModel): util.copy(self.path, dest) plugins.send("item_copied", item=self, source=self.path, destination=dest) + elif link: + util.link(self.path, dest) + plugins.send("item_linked", item=self, source=self.path, + destination=dest) else: plugins.send("before_item_moved", item=self, source=self.path, destination=dest) @@ -813,7 +817,7 @@ class Album(LibModel): for item in self.items(): item.remove(delete, False) - def move_art(self, copy=False): + def move_art(self, copy=False, link=False): """Move or copy any existing album art so that it remains in the same directory as the items. """ @@ -831,6 +835,8 @@ class Album(LibModel): util.displayable_path(new_art))) if copy: util.copy(old_art, new_art) + elif link: + util.link(old_art, new_art) else: util.move(old_art, new_art) self.artpath = new_art diff --git a/beets/util/__init__.py b/beets/util/__init__.py index 428de312a..529bbb2f3 100644 --- a/beets/util/__init__.py +++ b/beets/util/__init__.py @@ -449,6 +449,26 @@ def move(path, dest, replace=False): traceback.format_exc()) +def link(path, dest, replace=False): + """Create a symbolic link from path to `dest`. Raises an OSError if + `dest` already exists, unless `replace` is True. Does nothing if + `path` == `dest`.""" + if (samefile(path, dest)): + return + + path = syspath(path) + dest = syspath(dest) + if os.path.exists(dest) and not replace: + raise FilesystemError('file exists', 'rename', (path, dest), + traceback.format_exc()) + try: + os.symlink(path, dest) + except OSError: + raise FilesystemError('Operating system does not support symbolic ' + 'links.', 'link', (path, dest), + traceback.format_exc()) + + def unique_path(path): """Returns a version of ``path`` that does not exist on the filesystem. Specifically, if ``path` itself already exists, then