def copy_rename_files(files, fromdir=None, ignorefiles=None, sourcepaths=None, op="move"): track_op_func = getattr(util, op) op_func = util.copy if sourcepaths else getattr(util, op) op_track = "transcode" if sourcepaths else op if fromdir is None: fromdir = set(f.meta["dir"] for f in files) if len(fromdir) == 1: fromdir = fromdir.pop() sourcefiles = frozenset(f.meta["name"] for f in files) else: fromdir = None if not sourcepaths: sourcepaths = [file_obj.meta["path"] for file_obj in files] if ignorefiles is None: ignorefiles = frozenset([file_obj.meta["name"] for file_obj in files]) dstdirs = set() for file_obj, src in zip(files, sourcepaths): dst = util.fsencode(file_obj.format()) if "type" in file_obj: dst = "%s.%s" % (dst, file_obj["type"]) src_p = util.fsdecode(src) dst_p = util.fsdecode(dst) if src == dst: msg( consoleformat=u" skipping %(src_p)s, already named correctly", format="skip: %(src)r", src_p=srcp_p, src=src, loglevel=INFO, ) continue dstdir = os.path.split(dst)[0] if dstdir not in dstdirs and dstdir != file_obj.meta["dir"]: try: os.makedirs(dstdir) except OSError, e: if e.errno != errno.EEXIST or not os.path.isdir(dstdir): raise dstdirs.add(dstdir) if op_track == "transcode": src = file_obj.meta["path"] msg( consoleformat=u" %(src_p)s -> %(dst_p)s", format="%(op)s: %(src)r, %(dst)r", src=src, dst=dst, src_p=src_p, dst_p=dst_p, op=op_track, loglevel=INFO, ) track_op_func(src, dst)
def check_rename_sync(albums, dirs, mode="rename", targettids=()): targettids = frozenset(targettids) if targettids: tidexpr = Expr(Config["trackid"]) else: tidexpr = None dirmap = {} dstpaths = {} wassplit = False wasconflict = False onsplit = Config["onsplit"] onconflict = Config["onconflict"] if mode != "rename": targetcodec = Config["type"] if "," in targetcodec: allowedcodecs = targetcodec.split(",") targetcodec = allowedcodecs[0] allowedcodecs = set(allowedcodecs) else: allowedcodecs = set((targetcodec,)) targetcodec = get_codec(targetcodec) postadd = {"type": targetcodec.type_, "ext": targetcodec.ext} else: postadd = () allowedcodecs = None for album in albums.values(): if all(track.meta.evaluate(tidexpr) in targettids for track in album): continue dsts = [ util.fsencode(file.format(postadd=() if allowedcodecs and file.type_ in allowedcodecs else postadd)) for file in album ] for src, dst in zip(album, dsts): srcdir = src.meta["dir"] dstdir = os.path.split(dst)[0] curdirmap = dirmap.setdefault(srcdir, dirmap_entry(set(), set())) curdirmap.dirs.add(dstdir) curdirmap.srcfiles.add(src.meta["name"]) dstpaths.setdefault(dst, []).append(src.meta["path"]) for srcdir, entry in dirmap.items(): srcdir_p = util.fsdecode(srcdir) if len(entry.dirs) > 1: if onsplit == "error": err( consoleformat=u"tracks in %(src_p)s would be placed in different target directories", format="split: src:%(src)r", src_p=srcdir_p, src=srcdir, ) wassplit = True else: skip = frozenset(entry.srcfiles) dstdir = list(entry.dirs)[0] for file_ in os.listdir(srcdir): if file_ in skip: continue src = os.path.join(srcdir, file_) dst = os.path.join(dstdir, file_) src_p = util.fsdecode(src) dsp_p = util.fsdecode(dst) dstpaths.setdefault(dst, []).append(src) for dst, srcs in dstpaths.items(): if onconflict == "error": if len(srcs) > 1: srcs_p = u", ".join(util.fsdecode(s) for s in srcs) dst_p = util.fsdecode(dst) err( consoleformat=u"files %(srcs_p)s would be copied or moved to same file %(dst_p)s", format="conflict: src: %(srcs)r, dst: %(dst)r", srcs_p=srcs_p, dst_p=dst_p, srcs=srcs, dst=dst, ) wasconflict = True elif dst == srcs[0]: continue if os.path.exists(dst): srcs_p = u", ".join(util.fsdecode(s) for s in srcs) dst_p = util.fsdecode(dst) srcs = srcs[0] if len(srcs) == 1 else srcs err( consoleformat=u"file(s) %(srcs_p)s would be copied or moved to file %(dst_p)s, which already exists", format="conflict: src: %(srcs)r, dst: %(dst)r", srcs_p=srcs_p, dst_p=dst_p, srcs=srcs, dst=dst, ) wasconflict = True if wassplit: err( consoleformat="some existing directories would be split, set onsplit to 'warn' or 'ignore' to proceed anyway", nologerror=1, ) if wasconflict: err( consoleformat="some files would conflict with each other or with existing files, set onconflict to 'warn' or 'ignore' to proceed anyway", nologerror=1, ) if wassplit or wasconflict: sys.exit(1)
def rename(*args): albums, dir_list = scan(args)[:2] check_rename_sync(albums, dir_list) util.test_splits(dir_list) onsplit = Config['onsplit'] for (dir_, files) in dir_list.items(): dir_p = util.fsdecode(dir_) msg(consoleformat=u"from dir %(dir_p)s:", format="enter: %(dir_)r", dir_=dir_, dir_p=dir_p, loglevel=INFO) dstdirs = set() moves = [] for file_ in files: src = file_.filename dst = util.fsencode(file_.format()) src_p = util.fsdecode(src) dst_p = util.fsdecode(dst) if src == dst: msg(consoleformat=u" skipping %(src_p)s, already named correctly", format="skip: %(src)r", src_p=src_p, src=src, loglevel=INFO) continue dstdir = os.path.split(dst)[0] if dstdir not in dstdirs and dstdir != dir_: try: os.makedirs(dstdir) except OSError, e: if e.errno != errno.EEXIST or not os.path.isdir(dstdir): raise dstdirs.add(dstdir) msg(consoleformat=u" %(src_p)s -> %(dst_p)s", format="move: %(src)r, %(dst)r", src=src, dst=dst, src_p=src_p, dst_p=dst_p, loglevel=INFO) util.move(src, dst) if len(dstdirs) == 1: dstdir = dstdirs.pop() for file_ in os.listdir(dir_): src = os.path.join(dir_, file_) dst = os.path.join(dstdir, file_) src_p = util.fsdecode(src) dst_p = util.fsdecode(dst) msg(consoleformat=u" %(src_p)s -> %(dst_p)s", format="move: %(src)r, %(dst)r", src=src, dst=dst, src_p=src_p, dst_p=dst_p, loglevel=INFO) util.move(src, dst) while len(os.listdir(dir_)) == 0: dir_p = util.fsdecode(dir_) msg(consoleformat=u" remove empty directory: %(dir_p)s", format="rmdir: %(dir_)r", dir_=dir_, dir_p=dir_p, loglevel=INFO) try: os.rmdir(dir_) except Exception: break newdir = os.path.split(dir_)[0] if newdir != dir_: dir_ = newdir else: break else: if onsplit == 'warn': msg(consoleformat=u"WARNING: tracks in %(dir_p)s were placed in different directories, other files may be left in the source directory", format="split: %(dir_)r", dir_=dir_, dir_p=dir_p, loglevel=WARNING)