def migrate_db(replace=False): """Copy the beets library database file to the new location (e.g., from ~/.beetsmusic.blb to ~/.config/beets/library.db). """ _, srcfn = default_paths() destfn = beets.config['library'].as_filename() if not os.path.exists(srcfn) or srcfn == destfn: # Old DB does not exist or we're configured to point to the same # database. Do nothing. return if os.path.exists(destfn): if replace: log.debug(u'moving old database aside: {0}'.format( util.displayable_path(destfn) )) _displace(destfn) else: return log.debug(u'copying database from {0} to {1}'.format( util.displayable_path(srcfn), util.displayable_path(destfn) )) util.copy(srcfn, destfn) return destfn
def set_art(self, path, copy=True): """Sets the album's cover art to the image at the given path. The image is copied (or moved) into place, replacing any existing art. Sends an 'art_set' event with `self` as the sole argument. """ path = bytestring_path(path) oldart = self.artpath artdest = self.art_destination(path) if oldart and samefile(path, oldart): # Art already set. return elif samefile(path, artdest): # Art already in place. self.artpath = path return # Normal operation. if oldart == artdest: util.remove(oldart) artdest = util.unique_path(artdest) if copy: util.copy(path, artdest) else: util.move(path, artdest) self.artpath = artdest plugins.send('art_set', album=self)
def set_art(self, path, copy=True): """Sets the album's cover art to the image at the given path. The image is copied (or moved) into place, replacing any existing art. """ path = bytestring_path(path) oldart = self.artpath artdest = self.art_destination(path) if oldart and samefile(path, oldart): # Art already set. return elif samefile(path, artdest): # Art already in place. self.artpath = path return # Normal operation. if oldart == artdest: util.remove(oldart) artdest = util.unique_path(artdest) if copy: util.copy(path, artdest) else: util.move(path, artdest) self.artpath = artdest
def convert_item(lib, dest_dir): while True: item = yield dest = os.path.join(dest_dir, lib.destination(item, fragment=True)) dest = os.path.splitext(dest)[0] + '.mp3' if os.path.exists(dest): log.info(u'Skipping {0} (target file exists)'.format( util.displayable_path(item.path))) continue # Ensure that only one thread tries to create directories at a # time. (The existence check is not atomic with the directory # creation inside this function.) with _fs_lock: util.mkdirall(dest) maxbr = config['convert']['max_bitrate'].get(int) if item.format == 'MP3' and item.bitrate < 1000 * maxbr: log.info(u'Copying {0}'.format(util.displayable_path(item.path))) util.copy(item.path, dest) else: encode(item.path, dest) item.path = dest item.write() if config['convert']['embed']: album = lib.get_album(item) if album: artpath = album.artpath if artpath: _embed(artpath, [item])
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. """ if not util.samefile(self.path, dest): dest = util.unique_path(dest) if copy: 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) util.move(self.path, dest) plugins.send("item_moved", item=self, source=self.path, destination=dest) # Either copying or moving succeeded, so update the stored path. self.path = dest
def convert_item(lib, dest_dir): while True: item = yield dest = os.path.join(dest_dir, lib.destination(item, fragment=True)) dest = os.path.splitext(dest)[0] + '.mp3' if os.path.exists(dest): log.info(u'Skipping {0} (target file exists)'.format( util.displayable_path(item.path) )) continue # Ensure that only one thread tries to create directories at a # time. (The existence check is not atomic with the directory # creation inside this function.) with _fs_lock: util.mkdirall(dest) maxbr = config['convert']['max_bitrate'].get(int) if item.format == 'MP3' and item.bitrate < 1000 * maxbr: log.info(u'Copying {0}'.format(util.displayable_path(item.path))) util.copy(item.path, dest) else: encode(item.path, dest) item.path = dest item.write() if config['convert']['embed']: album = lib.get_album(item) if album: artpath = album.artpath if artpath: _embed(artpath, [item])
def move(self, copy=False, basedir=None): """Moves (or copies) all items to their destination. Any album art moves along with them. basedir overrides the library base directory for the destination. """ basedir = basedir or self._library.directory # Move items. items = list(self.items()) for item in items: item.move(self._library, copy, basedir=basedir) newdir = os.path.dirname(items[0].path) # Move art. old_art = self.artpath if old_art: new_art = self.art_destination(old_art, newdir) if new_art != old_art: if copy: util.copy(old_art, new_art) else: util.move(old_art, new_art) self.artpath = new_art if not copy: # Prune old path. util.prune_dirs(os.path.dirname(old_art), self._library.directory) # Store new item paths. We do this at the end to avoid # locking the database for too long while files are copied. for item in items: self._library.store(item)
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. """ old_art = self.artpath if not old_art: return new_art = self.art_destination(old_art) if new_art == old_art: return new_art = util.unique_path(new_art) log.debug(u'moving album art {0} to {1}', util.displayable_path(old_art), 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 # Prune old path when moving. if not copy: util.prune_dirs(os.path.dirname(old_art), self._db.directory)
def copy_album_art(self, album, dest_dir, path_formats, pretend=False): """Copies the associated cover art of the album. Album must have at least one track. """ if not album or not album.artpath: return album_item = album.items().get() # Album shouldn't be empty. if not album_item: return # Get the destination of the first item (track) of the album, we use # this function to format the path accordingly to path_formats. dest = album_item.destination(basedir=dest_dir, path_formats=path_formats) # Remove item from the path. dest = os.path.join(*util.components(dest)[:-1]) dest = album.art_destination(album.artpath, item_dir=dest) if album.artpath == dest: return if not pretend: util.mkdirall(dest) if os.path.exists(util.syspath(dest)): self._log.info("Skipping {0} (target file exists)", util.displayable_path(album.artpath)) return if pretend: self._log.info("cp {0} {1}", util.displayable_path(album.artpath), util.displayable_path(dest)) else: self._log.info("Copying cover art to {0}", util.displayable_path(dest)) util.copy(album.artpath, dest)
def convert_item(dest_dir, keep_new, path_formats, command, ext): while True: item = yield dest = item.destination(basedir=dest_dir, path_formats=path_formats) # When keeping the new file in the library, we first move the # current (pristine) file to the destination. We'll then copy it # back to its old path or transcode it to a new path. if keep_new: original = dest converted = replace_ext(item.path, ext) else: original = item.path dest = replace_ext(dest, ext) converted = dest # Ensure that only one thread tries to create directories at a # time. (The existence check is not atomic with the directory # creation inside this function.) with _fs_lock: util.mkdirall(dest) if os.path.exists(util.syspath(dest)): log.info(u'Skipping {0} (target file exists)'.format( util.displayable_path(item.path) )) continue if keep_new: log.info(u'Moving to {0}'. format(util.displayable_path(original))) util.move(item.path, original) if not should_transcode(item): # No transcoding necessary. log.info(u'Copying {0}'.format(util.displayable_path(item.path))) util.copy(original, converted) else: try: encode(command, original, converted) except subprocess.CalledProcessError: continue # Write tags from the database to the converted file. item.write(path=converted) if keep_new: # If we're keeping the transcoded file, read it again (after # writing) to get new bitrate, duration, etc. item.path = converted item.read() item.store() # Store new path and audio data. if config['convert']['embed']: album = item.get_album() if album and album.artpath: embed_item(item, album.artpath, itempath=converted) plugins.send('after_convert', item=item, dest=dest, keepnew=keep_new)
def convert_item(dest_dir, keep_new, path_formats): while True: item = yield dest = _destination(dest_dir, item, keep_new, path_formats) if os.path.exists(util.syspath(dest)): log.info(u'Skipping {0} (target file exists)'.format( util.displayable_path(item.path) )) continue # Ensure that only one thread tries to create directories at a # time. (The existence check is not atomic with the directory # creation inside this function.) with _fs_lock: util.mkdirall(dest) # When keeping the new file in the library, we first move the # current (pristine) file to the destination. We'll then copy it # back to its old path or transcode it to a new path. if keep_new: log.info(u'Moving to {0}'. format(util.displayable_path(dest))) util.move(item.path, dest) if not should_transcode(item): # No transcoding necessary. log.info(u'Copying {0}'.format(util.displayable_path(item.path))) if keep_new: util.copy(dest, item.path) else: util.copy(item.path, dest) else: if keep_new: _, ext = get_format() item.path = os.path.splitext(item.path)[0] + ext encode(dest, item.path) else: encode(item.path, dest) # Write tags from the database to the converted file. if not keep_new: item.path = dest item.write() # If we're keeping the transcoded file, read it again (after # writing) to get new bitrate, duration, etc. if keep_new: item.read() item.store() # Store new path and audio data. if config['convert']['embed']: album = item.get_album() if album: artpath = album.artpath if artpath: _embed(artpath, [item])
def copy_album_art(self, album, dest_dir, path_formats, pretend=False): """Copies or converts the associated cover art of the album. Album must have at least one track. """ if not album or not album.artpath: return album_item = album.items().get() # Album shouldn't be empty. if not album_item: return # Get the destination of the first item (track) of the album, we use # this function to format the path accordingly to path_formats. dest = album_item.destination(basedir=dest_dir, path_formats=path_formats) # Remove item from the path. dest = os.path.join(*util.components(dest)[:-1]) dest = album.art_destination(album.artpath, item_dir=dest) if album.artpath == dest: return if not pretend: util.mkdirall(dest) if os.path.exists(util.syspath(dest)): self._log.info(u"Skipping {0} (target file exists)", util.displayable_path(album.artpath)) return # Decide whether we need to resize the cover-art image. resize = False maxwidth = None if self.config["album_art_maxwidth"]: maxwidth = self.config["album_art_maxwidth"].get(int) size = ArtResizer.shared.get_size(album.artpath) self._log.debug("image size: {}", size) if size: resize = size[0] > maxwidth else: self._log.warning(u"Could not get size of image (please see " u"documentation for dependencies).") # Either copy or resize (while copying) the image. if resize: self._log.info( u"Resizing cover art from {0} to {1}", util.displayable_path(album.artpath), util.displayable_path(dest) ) if not pretend: ArtResizer.shared.resize(maxwidth, album.artpath, dest) else: if pretend: self._log.info(u"cp {0} {1}", util.displayable_path(album.artpath), util.displayable_path(dest)) else: self._log.info( u"Copying cover art to {0}", util.displayable_path(album.artpath), util.displayable_path(dest) ) util.copy(album.artpath, dest)
def convert_item(dest_dir, keep_new, path_formats): while True: item = yield dest = _destination(dest_dir, item, keep_new, path_formats) if os.path.exists(util.syspath(dest)): log.info(u'Skipping {0} (target file exists)'.format( util.displayable_path(item.path))) continue # Ensure that only one thread tries to create directories at a # time. (The existence check is not atomic with the directory # creation inside this function.) with _fs_lock: util.mkdirall(dest) # When keeping the new file in the library, we first move the # current (pristine) file to the destination. We'll then copy it # back to its old path or transcode it to a new path. if keep_new: log.info(u'Moving to {0}'.format(util.displayable_path(dest))) util.move(item.path, dest) if not should_transcode(item): # No transcoding necessary. log.info(u'Copying {0}'.format(util.displayable_path(item.path))) if keep_new: util.copy(dest, item.path) else: util.copy(item.path, dest) else: if keep_new: _, ext = get_format() item.path = os.path.splitext(item.path)[0] + ext encode(dest, item.path) else: encode(item.path, dest) # Write tags from the database to the converted file. if not keep_new: item.path = dest item.write() # If we're keeping the transcoded file, read it again (after # writing) to get new bitrate, duration, etc. if keep_new: item.read() item.store() # Store new path and audio data. if config['convert']['embed']: album = item.get_album() if album: artpath = album.artpath if artpath: _embed(artpath, [item])
def move(self, dest, copy=False): """Moves or copies the item's file, updating the path value if the move succeeds. """ if copy: util.copy(self.path, dest) else: util.move(self.path, dest) # Either copying or moving succeeded, so update the stored path. self.path = dest
def _convert(item): dest = self.destination(item) with fs_lock: util.mkdirall(dest) if self.should_transcode(item): convert.encode(self.convert_cmd, item.path, dest) else: log.debug(u'copying {0}'.format(displayable_path(dest))) util.copy(item.path, dest, replace=True) return item, dest
def _convert(item): dest = self.destination(item) with fs_lock: util.mkdirall(dest) if self.should_transcode(item): self._encode(self.convert_cmd, item.path, dest) if self._embed: embed_art(item, dest) else: log.debug(u'copying {0}'.format(displayable_path(dest))) util.copy(item.path, dest, replace=True) return item, dest
def move(self, dest, copy=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. """ if not util.samefile(self.path, dest): dest = util.unique_path(dest) if copy: util.copy(self.path, dest) else: util.move(self.path, dest) # Either copying or moving succeeded, so update the stored path. self.path = dest
def update(self, create=None): if (not os.path.isdir(syspath(self.directory)) and not self.ask_create(create)): print_(u'Skipping creation of {0}' .format(displayable_path(self.directory))) return converter = self.converter() for (item, actions) in self.items_actions(): dest = self.destination(item) path = self.get_path(item) for action in actions: if action == self.MOVE: print_(u'>{0} -> {1}'.format(displayable_path(path), displayable_path(dest))) util.mkdirall(dest) util.move(path, dest) util.prune_dirs(os.path.dirname(path), root=self.directory) self.set_path(item, dest) item.store() path = dest elif action == self.WRITE: print_(u'*{0}'.format(displayable_path(path))) item.write(path=path) elif action == self.SYNC_ART: print_(u'~{0}'.format(displayable_path(path))) self.sync_art(item, path) elif action == self.ADD: print_(u'+{0}'.format(displayable_path(dest))) converter.submit(item) elif action == self.REMOVE: print_(u'-{0}'.format(displayable_path(path))) self.remove_item(item) item.store() for item, dest in converter.as_completed(): self.set_path(item, dest) item.store() converter.shutdown() for (album, actions) in self.albums_actions(): for action in actions: dest_dir = self.album_destination(album) if action == self.COPY_ART: path = album.artpath dest = album.art_destination(path, dest_dir) util.copy(path, dest, replace=True) print_(u'$~{0}'.format(displayable_path(dest))) print_(u'$!{0}'.format(displayable_path(path)))
def _convert(item): dest = self.destination(item) with fs_lock: util.mkdirall(dest) if self.should_transcode(item): self._encode(self.convert_cmd, item.path, dest) # Don't rely on the converter to write correct/complete tags. item.write(path=dest) else: self._log.debug(u'copying {0}'.format(displayable_path(dest))) util.copy(item.path, dest, replace=True) if self._embed: self.sync_art(item, dest) return item, dest
def migrate_state(replace=False): """Copy the beets runtime state file from the old path (i.e., ~/.beetsstate) to the new path (i.e., ~/.config/beets/state.pickle). """ srcfn = os.path.expanduser(os.path.join('~', '.beetsstate')) if not os.path.exists(srcfn): return destfn = beets.config['statefile'].as_filename() if os.path.exists(destfn): if replace: _displace(destfn) else: return log.debug(u'copying state file from {0} to {1}'.format( util.displayable_path(srcfn), util.displayable_path(destfn))) util.copy(srcfn, destfn) return destfn
def migrate_state(replace=False): """Copy the beets runtime state file from the old path (i.e., ~/.beetsstate) to the new path (i.e., ~/.config/beets/state.pickle). """ srcfn = os.path.expanduser(os.path.join('~', '.beetsstate')) if not os.path.exists(srcfn): return destfn = beets.config['statefile'].as_filename() if os.path.exists(destfn): if replace: _displace(destfn) else: return log.debug(u'copying state file from {0} to {1}'.format( util.displayable_path(srcfn), util.displayable_path(destfn) )) util.copy(srcfn, destfn) return destfn
def copy_album_art(album, dest_dir, path_formats, pretend=False): """Copies the associated cover art of the album. Album must have at least one track. """ if not album or not album.artpath: return album_item = album.items().get() # Album shouldn't be empty. if not album_item: return # Get the destination of the first item (track) of the album, we use this # function to format the path accordingly to path_formats. dest = album_item.destination(basedir=dest_dir, path_formats=path_formats) # Remove item from the path. dest = os.path.join(*util.components(dest)[:-1]) dest = album.art_destination(album.artpath, item_dir=dest) if album.artpath == dest: return if not pretend: util.mkdirall(dest) if os.path.exists(util.syspath(dest)): log.info(u'Skipping {0} (target file exists)'.format( util.displayable_path(album.artpath) )) return if pretend: log.info(u'cp {0} {1}'.format( util.displayable_path(album.artpath), util.displayable_path(dest), )) else: log.info(u'Copying cover art to {0}'.format( util.displayable_path(dest))) util.copy(album.artpath, dest)
def move(self, library, copy=False, in_album=False, basedir=None): """Move the item to its designated location within the library directory (provided by destination()). Subdirectories are created as needed. If the operation succeeds, the item's path field is updated to reflect the new location. 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. Passes on appropriate exceptions if directories cannot be created or moving/copying fails. Note that one should almost certainly call store() and library.save() after this method in order to keep on-disk data consistent. """ dest = library.destination(self, in_album=in_album, basedir=basedir) # Create necessary ancestry for the move. util.mkdirall(dest) if not samefile(self.path, dest): if copy: util.copy(self.path, dest) else: util.move(self.path, dest) # Either copying or moving succeeded, so update the stored path. old_path = self.path self.path = dest # Prune vacated directory. if not copy: util.prune_dirs(os.path.dirname(old_path), library.directory)
def set_art(self, path): """Sets the album's cover art to the image at the given path. The image is copied into place, replacing any existing art. """ path = bytestring_path(path) oldart = self.artpath artdest = self.art_destination(path) if oldart and samefile(path, oldart): # Art already set. return elif samefile(path, artdest): # Art already in place. self.artpath = path return # Normal operation. if oldart == artdest: util.soft_remove(oldart) util.copy(path, artdest) self.artpath = artdest
def move_art(self, copy=False): """Move or copy any existing album art so that it remains in the same directory as the items. """ old_art = self.artpath if not old_art: return new_art = self.art_destination(old_art) if new_art == old_art: return log.debug('moving album art %s to %s' % (old_art, new_art)) if copy: util.copy(old_art, new_art) else: util.move(old_art, new_art) self.artpath = new_art # Prune old path when moving. if not copy: util.prune_dirs(os.path.dirname(old_art), self._library.directory)
def _generate_playist(self): training_name = self._get_cleaned_training_name() playlist_name = self._get_training_name() target_name = common.get_training_attribute(self.training, "target") if not common.get_target_attribute_for_training( self.training, "generate_playlist"): common.say("Playlist generation to target[{0}] was skipped " "(generate_playlist=no).".format(target_name), log_only=False) return dst_path = Path(common.get_destination_path_for_training( self.training)) dst_sub_dir = dst_path.joinpath(training_name) playlist_filename = "{}.m3u".format(playlist_name) dst = dst_sub_dir.joinpath(playlist_filename) lines = [ "# Playlist generated for training '{}' on {}". \ format(training_name, datetime.now()) ] for item in self.items: path = util.displayable_path( item.get("exportpath", item.get("path"))) if path: path = util.syspath(path) line = "{path}".format(path=path) lines.append(line) with tempfile.NamedTemporaryFile(mode='w+b', delete=False) as ntf: tmp_playlist = ntf.name for line in lines: ntf.write("{}\n".format(line).encode("utf-8")) common.say("Created playlist: {0}".format(dst), log_only=True) util.copy(tmp_playlist, dst) util.remove(tmp_playlist)
def test_successful_copy(self): util.copy(self.path, self.dest)
def convert_item(dest_dir, keep_new, path_formats, format, pretend=False): command, ext = get_format(format) item, original, converted = None, None, None while True: item = yield (item, original, converted) dest = item.destination(basedir=dest_dir, path_formats=path_formats) # When keeping the new file in the library, we first move the # current (pristine) file to the destination. We'll then copy it # back to its old path or transcode it to a new path. if keep_new: original = dest converted = item.path if should_transcode(item, format): converted = replace_ext(converted, ext) else: original = item.path if should_transcode(item, format): dest = replace_ext(dest, ext) converted = dest # Ensure that only one thread tries to create directories at a # time. (The existence check is not atomic with the directory # creation inside this function.) if not pretend: with _fs_lock: util.mkdirall(dest) if os.path.exists(util.syspath(dest)): log.info(u'Skipping {0} (target file exists)'.format( util.displayable_path(item.path) )) continue if keep_new: if pretend: log.info(u'mv {0} {1}'.format( util.displayable_path(item.path), util.displayable_path(original), )) else: log.info(u'Moving to {0}'.format( util.displayable_path(original)) ) util.move(item.path, original) if should_transcode(item, format): try: encode(command, original, converted, pretend) except subprocess.CalledProcessError: continue else: if pretend: log.info(u'cp {0} {1}'.format( util.displayable_path(original), util.displayable_path(converted), )) else: # No transcoding necessary. log.info(u'Copying {0}'.format( util.displayable_path(item.path)) ) util.copy(original, converted) if pretend: continue # Write tags from the database to the converted file. item.try_write(path=converted) if keep_new: # If we're keeping the transcoded file, read it again (after # writing) to get new bitrate, duration, etc. item.path = converted item.read() item.store() # Store new path and audio data. if config['convert']['embed']: album = item.get_album() if album and album.artpath: embed_item(item, album.artpath, itempath=converted) if keep_new: plugins.send('after_convert', item=item, dest=dest, keepnew=True) else: plugins.send('after_convert', item=item, dest=converted, keepnew=False)
def _convert(item): dest = self.destination(item) util.mkdirall(dest) util.copy(item.path, dest, replace=True) return item, dest
def convert_item(self, dest_dir, keep_new, path_formats, fmt, pretend=False): command, ext = get_format(fmt) item, original, converted = None, None, None while True: item = yield (item, original, converted) dest = item.destination(basedir=dest_dir, path_formats=path_formats) # When keeping the new file in the library, we first move the # current (pristine) file to the destination. We'll then copy it # back to its old path or transcode it to a new path. if keep_new: original = dest converted = item.path if should_transcode(item, fmt): converted = replace_ext(converted, ext) else: original = item.path if should_transcode(item, fmt): dest = replace_ext(dest, ext) converted = dest # Ensure that only one thread tries to create directories at a # time. (The existence check is not atomic with the directory # creation inside this function.) if not pretend: with _fs_lock: util.mkdirall(dest) if os.path.exists(util.syspath(dest)): self._log.info("Skipping {0} (target file exists)", util.displayable_path(item.path)) continue if keep_new: if pretend: self._log.info("mv {0} {1}", util.displayable_path(item.path), util.displayable_path(original)) else: self._log.info("Moving to {0}", util.displayable_path(original)) util.move(item.path, original) if should_transcode(item, fmt): try: self.encode(command, original, converted, pretend) except subprocess.CalledProcessError: continue else: if pretend: self._log.info("cp {0} {1}", util.displayable_path(original), util.displayable_path(converted)) else: # No transcoding necessary. self._log.info("Copying {0}", util.displayable_path(item.path)) util.copy(original, converted) if pretend: continue # Write tags from the database to the converted file. item.try_write(path=converted) if keep_new: # If we're keeping the transcoded file, read it again (after # writing) to get new bitrate, duration, etc. item.path = converted item.read() item.store() # Store new path and audio data. if self.config["embed"]: album = item.get_album() if album and album.artpath: self._log.debug("embedding album art from {}", util.displayable_path(album.artpath)) art.embed_item(self._log, item, album.artpath, itempath=converted) if keep_new: plugins.send("after_convert", item=item, dest=dest, keepnew=True) else: plugins.send("after_convert", item=item, dest=converted, keepnew=False)
def test_unsuccessful_copy(self): with self.assertRaises(util.FilesystemError): util.copy(self.path, self.otherpath)
def test_self_copy(self): util.copy(self.path, self.path) self.assertExists(self.path)
def test_successful_copy(self): util.copy(self.path, self.dest) self.assertExists(self.dest) self.assertExists(self.path)
def test_unsuccessful_copy(self): with self.assertRaises(OSError): util.copy(self.path, self.otherpath)
def _copy_items(self): training_name = self._get_cleaned_training_name() target_name = common.get_training_attribute(self.training, "target") # The copy_files is only False when it is explicitly declared so copy_files = common.get_target_attribute_for_training( self.training, "copy_files") copy_files = False if copy_files == False else True if not copy_files: common.say( "Copying to target[{0}] was skipped (copy_files=no).".format( target_name)) return increment_play_count = common.get_training_attribute( self.training, "increment_play_count") dst_path = Path(common.get_destination_path_for_training( self.training)) dst_sub_dir = dst_path.joinpath(training_name) if not os.path.isdir(dst_sub_dir): os.mkdir(dst_sub_dir) common.say("Copying to target[{0}]: {1}".format( target_name, dst_sub_dir)) cnt = 0 # todo: disable alive bar when running in verbose mode # from beets import logging as beetslogging # beets_log = beetslogging.getLogger("beets") # print(beets_log.getEffectiveLevel()) with alive_bar(len(self.items)) as bar: for item in self.items: src = util.displayable_path(item.get("path")) if not os.path.isfile(src): # todo: this is bad enough to interrupt! create option # for this common.say("File does not exist: {}".format(src)) continue fn, ext = os.path.splitext(src) gen_filename = "{0}_{1}{2}" \ .format(str(cnt).zfill(6), common.get_random_string(), ext) dst = dst_sub_dir.joinpath(gen_filename) # dst = "{0}/{1}".format(dst_path, gen_filename) common.say("Copying[{1}]: {0}".format(src, gen_filename)) if not self.cfg_dry_run: util.copy(src, dst) # store the file_name for the playlist item["exportpath"] = util.bytestring_path(gen_filename) if increment_play_count: common.increment_play_count_on_item(item) cnt += 1 bar()
def copy_album_art(self, album, dest_dir, path_formats, pretend=False, link=False, hardlink=False): """Copies or converts the associated cover art of the album. Album must have at least one track. """ if not album or not album.artpath: return album_item = album.items().get() # Album shouldn't be empty. if not album_item: return # Get the destination of the first item (track) of the album, we use # this function to format the path accordingly to path_formats. dest = album_item.destination(basedir=dest_dir, path_formats=path_formats) # Remove item from the path. dest = os.path.join(*util.components(dest)[:-1]) dest = album.art_destination(album.artpath, item_dir=dest) if album.artpath == dest: return if not pretend: util.mkdirall(dest) if os.path.exists(util.syspath(dest)): self._log.info(u'Skipping {0} (target file exists)', util.displayable_path(album.artpath)) return # Decide whether we need to resize the cover-art image. resize = False maxwidth = None if self.config['album_art_maxwidth']: maxwidth = self.config['album_art_maxwidth'].get(int) size = ArtResizer.shared.get_size(album.artpath) self._log.debug('image size: {}', size) if size: resize = size[0] > maxwidth else: self._log.warning(u'Could not get size of image (please see ' u'documentation for dependencies).') # Either copy or resize (while copying) the image. if resize: self._log.info(u'Resizing cover art from {0} to {1}', util.displayable_path(album.artpath), util.displayable_path(dest)) if not pretend: ArtResizer.shared.resize(maxwidth, album.artpath, dest) else: if pretend: msg = 'ln' if hardlink else ('ln -s' if link else 'cp') self._log.info(u'{2} {0} {1}', util.displayable_path(album.artpath), util.displayable_path(dest), msg) else: msg = 'Hardlinking' if hardlink \ else ('Linking' if link else 'Copying') self._log.info(u'{2} cover art from {0} to {1}', util.displayable_path(album.artpath), util.displayable_path(dest), msg) if hardlink: util.hardlink(album.artpath, dest) elif link: util.link(album.artpath, dest) else: util.copy(album.artpath, dest)
def convert_item(self, dest_dir, keep_new, path_formats, fmt, pretend=False, link=False, hardlink=False): """A pipeline thread that converts `Item` objects from a library. """ command, ext = get_format(fmt) item, original, converted = None, None, None while True: item = yield (item, original, converted) dest = item.destination(basedir=dest_dir, path_formats=path_formats) # When keeping the new file in the library, we first move the # current (pristine) file to the destination. We'll then copy it # back to its old path or transcode it to a new path. if keep_new: original = dest converted = item.path if should_transcode(item, fmt): converted = replace_ext(converted, ext) else: original = item.path if should_transcode(item, fmt): dest = replace_ext(dest, ext) converted = dest # Ensure that only one thread tries to create directories at a # time. (The existence check is not atomic with the directory # creation inside this function.) if not pretend: with _fs_lock: util.mkdirall(dest) if os.path.exists(util.syspath(dest)): self._log.info(u'Skipping {0} (target file exists)', util.displayable_path(item.path)) continue if keep_new: if pretend: self._log.info(u'mv {0} {1}', util.displayable_path(item.path), util.displayable_path(original)) else: self._log.info(u'Moving to {0}', util.displayable_path(original)) util.move(item.path, original) if should_transcode(item, fmt): linked = False try: self.encode(command, original, converted, pretend) except subprocess.CalledProcessError: continue else: linked = link or hardlink if pretend: msg = 'ln' if hardlink else ('ln -s' if link else 'cp') self._log.info(u'{2} {0} {1}', util.displayable_path(original), util.displayable_path(converted), msg) else: # No transcoding necessary. msg = 'Hardlinking' if hardlink \ else ('Linking' if link else 'Copying') self._log.info(u'{1} {0}', util.displayable_path(item.path), msg) if hardlink: util.hardlink(original, converted) elif link: util.link(original, converted) else: util.copy(original, converted) if pretend: continue id3v23 = self.config['id3v23'].as_choice([True, False, 'inherit']) if id3v23 == 'inherit': id3v23 = None # Write tags from the database to the converted file. item.try_write(path=converted, id3v23=id3v23) if keep_new: # If we're keeping the transcoded file, read it again (after # writing) to get new bitrate, duration, etc. item.path = converted item.read() item.store() # Store new path and audio data. if self.config['embed'] and not linked: album = item._cached_album if album and album.artpath: self._log.debug(u'embedding album art from {}', util.displayable_path(album.artpath)) art.embed_item(self._log, item, album.artpath, itempath=converted, id3v23=id3v23) if keep_new: plugins.send('after_convert', item=item, dest=dest, keepnew=True) else: plugins.send('after_convert', item=item, dest=converted, keepnew=False)
def convert_item(dest_dir, keep_new, path_formats): while True: item = yield dest = _destination(dest_dir, item, keep_new, path_formats) if os.path.exists(util.syspath(dest)): log.info(u'Skipping {0} (target file exists)'.format( util.displayable_path(item.path))) continue # Ensure that only one thread tries to create directories at a # time. (The existence check is not atomic with the directory # creation inside this function.) with _fs_lock: util.mkdirall(dest) # When keeping the new file in the library, we first move the # current (pristine) file to the destination. We'll then copy it # back to its old path or transcode it to a new path. if keep_new: log.info(u'Moving to {0}'.format(util.displayable_path(dest))) util.move(item.path, dest) original = dest _, ext = get_format() converted = os.path.splitext(item.path)[0] + ext else: original = item.path converted = dest if not should_transcode(item): # No transcoding necessary. log.info(u'Copying {0}'.format(util.displayable_path(item.path))) util.copy(original, converted) else: try: encode(original, converted) except subprocess.CalledProcessError: continue # Write tags from the database to the converted file. item.write(path=converted) if keep_new: # If we're keeping the transcoded file, read it again (after # writing) to get new bitrate, duration, etc. item.path = converted item.read() item.store() # Store new path and audio data. if config['convert']['embed']: album = item.get_album() if album: artpath = album.artpath if artpath: try: _embed(artpath, [converted]) except IOError as exc: log.warn( u'could not embed cover art in {0}: {1}'.format( util.displayable_path(item.path), exc)) plugins.send('after_convert', item=item, dest=dest, keepnew=keep_new)