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)
Exemple #3
0
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)