From a14955d8a5741ec382d9b128b69053cf4141f993 Mon Sep 17 00:00:00 2001 From: mikeos Date: Wed, 24 Jul 2013 21:07:41 +0400 Subject: replace illegal characters in filename --- TODO | 2 +- config.py | 3 +- cutter | 94 +++++++++++++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 77 insertions(+), 22 deletions(-) diff --git a/TODO b/TODO index 474585f..910885b 100644 --- a/TODO +++ b/TODO @@ -4,4 +4,4 @@ OK 3. write tags to the splitted files OK 4. specify output file format including path OK 5. add support of config file with default options OK 6. copy file instead of convert if possible -7. substitute odd symbols in track names +OK 7. substitute odd symbols in track names diff --git a/config.py b/config.py index 6345c7d..d24c418 100644 --- a/config.py +++ b/config.py @@ -50,4 +50,5 @@ SAMPLE_RATE = cfg.getint("output", "sample_rate") CHANNELS = cfg.getint("output", "channels") BITS_PER_SAMPLE = cfg.getint("output", "bits_per_sample") -FILENAME_FORMAT = cfg.get("encoding", "format", DEFAULT_FILENAME_FORMAT) +FILENAME_FORMAT = cfg.get("filename", "format", DEFAULT_FILENAME_FORMAT) +CONVERT_CHARS = cfg.getbool("filename", "convert_chars", False) diff --git a/cutter b/cutter index 46e0a90..415fee1 100755 --- a/cutter +++ b/cutter @@ -13,6 +13,17 @@ import collections import sys import os +ILLEGAL_CHARACTERS_MAP = { + u"\\": u"-", + u":": u"-", + u"*": u"+", + u"?": u"_", + u'"': u"'", + u"<": u"(", + u">": u")", + u"|": u"-" +} + progname = os.path.basename(sys.argv[0]) def printf(fmt, *args): @@ -36,7 +47,7 @@ except Exception as err: printerr("import config failed: %s", err) sys.exit(0) -def quote(s, ch = "\""): +def quote(s, ch = '"'): return s if " " not in s else ch + s + ch def msf(ts): @@ -124,10 +135,6 @@ def parse_args(): enc = OptionGroup(parser, "Encoding options") - enc.add_option("--format", - dest="fmt", default=config.FILENAME_FORMAT, - help="the format string for new filenames") - enc.add_option("-d", "--dir", dest="dir", default=config.DIR, help="output directory") @@ -137,6 +144,22 @@ def parse_args(): parser.add_option_group(enc) + fname = OptionGroup(parser, "Filename options") + + fname.add_option("--format", + dest="fmt", default=config.FILENAME_FORMAT, + help="the format string for new filenames") + + fname.add_option("--convert-chars", + dest="convert_chars", action="store_true", + help="replace illegal characters in filename") + + fname.add_option("--no-convert-chars", + dest="convert_chars", action="store_false", + help="do not replace characters in filename") + + parser.add_option_group(fname) + format = OptionGroup(parser, "Output format") format.add_option("-r", "--sample-rate", type="int", @@ -161,17 +184,27 @@ def parse_args(): return parser.parse_args() -def verify_options(opt): +def process_options(opt): if opt.compression is not None and opt.compression < 0 or opt.compression > 8: printerr("invalid compression value %d, must be in range 0 .. 8", opt.compression) sys.exit(1) - opt.dir = u"." if not opt.dir else to_unicode(opt.dir) - opt.fmt = to_unicode(opt.fmt) + if not opt.dir: + opt.dir = u"." + else: + opt.dir = to_unicode(os.path.normpath(opt.dir)) + opt.fmt = to_unicode(opt.fmt) if not os.path.basename(opt.fmt): printerr("invalid format option \"%s\"", opt.fmt) sys.exit(1) + else: + opt.fmt = os.path.normpath(opt.fmt) + if opt.fmt.startswith("/"): + opt.fmt = opt.fmt[1:] + + if opt.convert_chars is None: + opt.convert_chars = config.CONVERT_CHARS def get_encoder_formart(opt, info): cmd = "flac sox - " @@ -196,6 +229,9 @@ def mkdir(path): printerr("make dir %s failed: %s", quote(path), err) sys.exit(1) +def convert_characters(path): + return "".join([ILLEGAL_CHARACTERS_MAP.get(ch, ch) for ch in path]) + class StreamInfo: __mapping = { b"Channels:": "channels", @@ -238,6 +274,25 @@ class CueSplitter: self.name = name self.tags = tags + @staticmethod + def format_by_tags(fmt, tags, replace=False): + if replace: + def conv(var): + if isinstance(var, str): + return var.replace("/", "-") + return var + + tags = {k: conv(v) for k, v in tags.items()} + + try: + return fmt.format(year=tags["date"], **tags) + except KeyError as err: + printerr("invalid format key: %s", err) + sys.exit(1) + except ValueError as err: + printerr("invalid format option: %s", err) + sys.exit(1) + def __init__(self, cue, opt): self.cue = cue self.opt = opt @@ -255,11 +310,10 @@ class CueSplitter: "albumartist": self.opt.albumartist } - try: - tmp = os.path.dirname(opt.fmt).format(**self.tags) - except KeyError as err: - printerr("invalid format key: %s", err) - sys.exit(1) + tmp = self.format_by_tags(os.path.dirname(opt.fmt), self.tags, True) + + if opt.convert_chars: + tmp = convert_characters(tmp) self.dest = os.path.join(opt.dir, tmp) track_fmt = os.path.basename(opt.fmt) @@ -282,15 +336,15 @@ class CueSplitter: "artist": self.opt.artist or track.get("performer") or self.cue.get("performer"), "composer": self.opt.composer or track.get("songwriter") + or self.cue.get("songwriter") }) - try: - name = fmt.format(**tags) + "." + self.TRACK_SUFFIX - except KeyError as err: - printerr("invalid format key: %s", err) - sys.exit(1) + name = self.format_by_tags(fmt, tags).replace("/", "-") + + if self.opt.convert_chars: + name = convert_characters(name) - return self.TrackInfo(name, tags) + return self.TrackInfo(name + "." + self.TRACK_SUFFIX, tags) def find_realfile(self, name): if not name.endswith(".wav"): @@ -494,7 +548,7 @@ class CueSplitter: def main(): options, args = parse_args() - verify_options(options) + process_options(options) if len(args) != 1: printf("Usage: %s [options] cuefile\n", progname) -- cgit v1.2.3-70-g09d2