Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python
- # ID3iconv is a Java based ID3 encoding convertor, here's the Python version.
- # Copyright 2006 Emfox Zhou <EmfoxZhou@gmail.com>
- #
- # This program is free software; you can redistribute it and/or modify
- # it under the terms of version 2 of the GNU General Public License as
- # published by the Free Software Foundation.
- import sys
- import locale
- from optparse import OptionParser
- import mutagen
- import mutagen.id3
- from mutagen._compat import PY3, print_, text_type
- from mutagen._util import SignalHandler, set_win32_unicode_argv
- VERSION = (0, 3)
- _sig = SignalHandler()
- def getpreferredencoding():
- return locale.getpreferredencoding() or "utf-8"
- def isascii(string):
- """Checks whether a unicode string is non-empty and contains only ASCII
- characters.
- """
- if not string:
- return False
- try:
- string.encode('ascii')
- except UnicodeEncodeError:
- return False
- return True
- 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 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:
- with _sig.block():
- if verbose != "quiet":
- print_(u"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_(u"No ID3 header found; skipping...")
- continue
- except Exception as err:
- print_(text_type(err), file=sys.stderr)
- continue
- for tag in filter(lambda t: t.startswith(("T", "COMM")), id3):
- frame = id3[tag]
- if isinstance(frame, mutagen.id3.TimeStampTextFrame):
- # non-unicode fields
- continue
- try:
- text = frame.text
- except AttributeError:
- continue
- try:
- text = [conv(x) for x in frame.text]
- except (UnicodeError, LookupError):
- continue
- else:
- frame.text = text
- if not text or min(map(isascii, text)):
- frame.encoding = 3
- else:
- frame.encoding = 1
- if verbose == "debug":
- print_(id3.pprint())
- if not noupdate:
- if remove_v1:
- id3.save(filename, v1=False)
- else:
- id3.save(filename)
- def has_id3v1(filename):
- try:
- f = open(filename, 'rb+')
- f.seek(-128, 2)
- return f.read(3) == b"TAG"
- except IOError:
- return False
- 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)" % (
- 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__":
- set_win32_unicode_argv()
- _sig.init()
- main(sys.argv)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement