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 _record_items(self, lib, basename, items): """Records relative paths to the given items for each feed format """ feedsdir = bytestring_path(self.config['dir'].as_filename()) formats = self.config['formats'].as_str_seq() relative_to = self.config['relative_to'].get() \ or self.config['dir'].as_filename() relative_to = bytestring_path(relative_to) paths = [] for item in items: if self.config['absolute_path']: paths.append(item.path) else: try: relpath = os.path.relpath(item.path, relative_to) except ValueError: # On Windows, it is sometimes not possible to construct a # relative path (if the files are on different disks). relpath = item.path paths.append(relpath) if 'm3u' in formats: m3u_basename = bytestring_path( self.config['m3u_name'].as_str()) m3u_path = os.path.join(feedsdir, m3u_basename) _write_m3u(m3u_path, paths) if 'm3u_multi' in formats: m3u_path = _build_m3u_filename(basename) _write_m3u(m3u_path, paths) if 'link' in formats: for path in paths: dest = os.path.join(feedsdir, os.path.basename(path)) if not os.path.exists(syspath(dest)): link(path, dest) if 'echo' in formats: self._log.info(u"Location of imported music:") for path in paths: self._log.info(u" {0}", path)
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 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 create_symlink(self, item): dest = self.destination(item) util.mkdirall(dest) link = (os.path.relpath(item.path, os.path.dirname(dest)) if self.relativelinks == self.LINK_RELATIVE else item.path) util.link(link, dest)
def create_symlink(self, item): dest = self.destination(item) util.mkdirall(dest) util.link(item.path, dest)