PageRenderTime 163ms CodeModel.GetById 80ms app.highlight 2ms RepoModel.GetById 79ms app.codeStats 0ms

/tools/mid3iconv

http://mutagen.googlecode.com/
#! | 140 lines | 120 code | 20 blank | 0 comment | 0 complexity | 36b1af08f056a4aa96a38d674947070a MD5 | raw file
  1#!/usr/bin/env python
  2# ID3iconv is a Java based ID3 encoding convertor, here's the Python version.
  3# Copyright 2006 Emfox Zhou <EmfoxZhou@gmail.com>
  4#
  5# This program is free software; you can redistribute it and/or modify
  6# it under the terms of version 2 of the GNU General Public License as
  7# published by the Free Software Foundation.
  8#
  9
 10import os
 11import sys
 12import locale
 13
 14from optparse import OptionParser
 15
 16VERSION = (0, 3)
 17
 18def isascii(string):
 19    return not string or ord(max(string)) < 128
 20
 21class ID3OptionParser(OptionParser):
 22    def __init__(self):
 23        mutagen_version = ".".join(map(str, mutagen.version))
 24        my_version = ".".join(map(str, VERSION))
 25        version = "mid3iconv %s\nUses Mutagen %s" % (
 26            my_version, mutagen_version)
 27        return OptionParser.__init__(
 28            self, version=version,
 29            usage="%prog [OPTION] [FILE]...",
 30            description=("Mutagen-based replacement the id3iconv utility, "
 31                         "which converts ID3 tags from legacy encodings "
 32                         "to Unicode and stores them using the ID3v2 format."))
 33
 34    def format_help(self, *args, **kwargs):
 35        text = OptionParser.format_help(self, *args, **kwargs)
 36        return text + "\nFiles are updated in-place, so use --dry-run first.\n"
 37
 38def update(options, filenames):
 39    encoding = options.encoding or locale.getpreferredencoding()
 40    verbose = options.verbose
 41    noupdate = options.noupdate
 42    force_v1 = options.force_v1
 43    remove_v1 = options.remove_v1
 44
 45    def conv(uni):
 46        return uni.encode('iso-8859-1').decode(encoding)
 47
 48    for filename in filenames:
 49        if verbose != "quiet":
 50            print "Updating", filename
 51
 52        if has_id3v1(filename) and not noupdate and force_v1:
 53            mutagen.id3.delete(filename, False, True)
 54
 55        try: id3 = mutagen.id3.ID3(filename)
 56        except mutagen.id3.ID3NoHeaderError:
 57            if verbose != "quiet":
 58                print "No ID3 header found; skipping..."
 59            continue
 60        except Exception, err:
 61            print >>sys.stderr, str(err)
 62            continue
 63
 64        for tag in filter(lambda t: t.startswith("T"), id3):
 65            frame = id3[tag]
 66            if isinstance(frame, mutagen.id3.TimeStampTextFrame):
 67                # non-unicode fields
 68                continue
 69            try:
 70                text = frame.text
 71            except AttributeError:
 72                continue
 73            try:
 74                text = map(conv, frame.text)
 75            except (UnicodeError, LookupError):
 76                continue
 77            else:
 78                frame.text = text
 79                if not text or min(map(isascii, text)):
 80                    frame.encoding = 3
 81                else:
 82                    frame.encoding = 1
 83
 84        enc = locale.getpreferredencoding()
 85        if verbose == "debug":
 86            print id3.pprint().encode(enc, "replace")
 87
 88        if not noupdate:
 89            if remove_v1: id3.save(filename, v1=False)
 90            else: id3.save(filename)
 91
 92def has_id3v1(filename):
 93    try:
 94        f = open(filename, 'rb+')
 95        f.seek(-128, 2)
 96        return f.read(3) == "TAG"
 97    except IOError:
 98        return False
 99
100def main(argv):
101    parser = ID3OptionParser()
102    parser.add_option(
103        "-e", "--encoding", metavar="ENCODING", action="store",
104        type="string", dest="encoding",
105        help=("Specify original tag encoding (default is %s)" %(
106        locale.getpreferredencoding())))
107    parser.add_option(
108        "-p", "--dry-run", action="store_true", dest="noupdate",
109        help="Do not actually modify files")
110    parser.add_option(
111        "--force-v1", action="store_true", dest="force_v1",
112        help="Use an ID3v1 tag even if an ID3v2 tag is present")
113    parser.add_option(
114        "--remove-v1", action="store_true", dest="remove_v1",
115        help="Remove v1 tag after processing the files")
116    parser.add_option(
117        "-q", "--quiet", action="store_const", dest="verbose",
118        const="quiet", help="Only output errors")
119    parser.add_option(
120        "-d", "--debug", action="store_const", dest="verbose",
121        const="debug", help="Output updated tags")
122
123    for i, arg in enumerate(sys.argv):
124        if arg == "-v1": sys.argv[i] = "--force-v1"
125        elif arg == "-removev1": sys.argv[i] = "--remove-v1"
126
127    (options, args) = parser.parse_args(argv[1:])
128
129    if args:
130        update(options, args)
131    else:
132        parser.print_help()
133
134if __name__ == "__main__":
135    try: import mutagen, mutagen.id3
136    except ImportError:
137        # Run out of tools/
138        sys.path.append(os.path.abspath("../"))
139        import mutagen, mutagen.id3
140    main(sys.argv)