summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormikeos <mike.osipov@gmail.com>2013-07-24 21:07:41 +0400
committermikeos <mike.osipov@gmail.com>2013-07-24 21:07:41 +0400
commita14955d8a5741ec382d9b128b69053cf4141f993 (patch)
tree9e9fcfc983d05ea794e842c8a29da344bc21f701
parentad7ed713f4a968dbdb7ddc149e56677c6cc5fd2a (diff)
replace illegal characters in filename
-rw-r--r--TODO2
-rw-r--r--config.py3
-rwxr-xr-xcutter94
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)