PageRenderTime 20ms CodeModel.GetById 6ms RepoModel.GetById 1ms app.codeStats 0ms

/tools/mid3iconv

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