1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
|
import os import sys import locale from optparse import OptionParser VERSION = (0, 1) def isascii(string): return not string or min(string) < '/x127' class ID3OptionParser(OptionParser): def __init__(self): mutagen_version = ".".join(map(str, mutagen.version)) my_version = ".".join(map(str, VERSION)) version = "mid3iconv %s/nUses Mutagen %s" % ( my_version, mutagen_version) return OptionParser.__init__( self, version=version, usage="%prog [OPTION] [FILE]...", description=("Mutagen-based replacement the id3iconv utility, " "which converts ID3 tags from legacy encodings " "to Unicode and stores them using the ID3v2 format.")) def format_help(self, *args, **kwargs): text = OptionParser.format_help(self, *args, **kwargs) return text + "/nFiles are updated in-place, so use --dry-run first./n" def update(options, filenames): encoding = options.encoding or locale.getpreferredencoding() verbose = options.verbose noupdate = options.noupdate force_v1 = options.force_v1 remove_v1 = options.remove_v1 def conv(uni): return uni.encode('iso-8859-1').decode(encoding) for filename in filenames: if verbose != "quiet": print "Updating", filename if has_id3v1(filename) and not noupdate and force_v1: mutagen.id3.delete(filename, False, True) try: id3 = mutagen.id3.ID3(filename) except mutagen.id3.ID3NoHeaderError: if verbose != "quiet": print "No ID3 header found; skipping..." continue except Exception, err: if verbose != "quiet": print str(err) continue for tag in filter(lambda t: t.startswith("T"), id3): if tag == "TDRC": continue frame = id3[tag] try: text = map(conv, frame.text) except (UnicodeError, LookupError): continue else: frame.text = text if min(map(isascii, text)): frame.encoding = 3 else: frame.encoding = 1 enc = locale.getpreferredencoding() if verbose == "debug": print id3.pprint().encode(enc, "replace") if not noupdate: if remove_v1: id3.save(filename, v1=False) else: id3.save(filename) def has_id3v1(filename): f = open(filename, 'rb+') try: f.seek(-128, 2) except IOError: pass else: return (f.read(3) == "TAG") def main(argv): parser = ID3OptionParser() parser.add_option( "-e", "--encoding", metavar="ENCODING", action="store", type="string", dest="encoding", help=("Specify original tag encoding (default is %s)" %( locale.getpreferredencoding()))) parser.add_option( "-p", "--dry-run", action="store_true", dest="noupdate", help="Do not actually modify files") parser.add_option( "--force-v1", action="store_true", dest="force_v1", help="Use an ID3v1 tag even if an ID3v2 tag is present") parser.add_option( "--remove-v1", action="store_true", dest="remove_v1", help="Remove v1 tag after processing the files") parser.add_option( "-q", "--quiet", action="store_const", dest="verbose", const="quiet", help="Only output errors") parser.add_option( "-d", "--debug", action="store_const", dest="verbose", const="debug", help="Output updated tags") for i, arg in enumerate(sys.argv): if arg == "-v1": sys.argv[i] = "--force-v1" elif arg == "-removev1": sys.argv[i] = "--remove-v1" (options, args) = parser.parse_args(argv[1:]) if args: update(options, args) else: parser.print_help() if __name__ == "__main__": try: import mutagen, mutagen.id3 except ImportError: sys.path.append(os.path.abspath("../")) import mutagen, mutagen.id3 main(sys.argv)
|