Advertisement
Guest User

Untitled

a guest
Apr 26th, 2015
186
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.11 KB | None | 0 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 sys
  10. import locale
  11.  
  12. from optparse import OptionParser
  13.  
  14. import mutagen
  15. import mutagen.id3
  16. from mutagen._compat import PY3, print_, text_type
  17. from mutagen._util import SignalHandler, set_win32_unicode_argv
  18.  
  19.  
  20. VERSION = (0, 3)
  21. _sig = SignalHandler()
  22.  
  23.  
  24. def getpreferredencoding():
  25. return locale.getpreferredencoding() or "utf-8"
  26.  
  27.  
  28. def isascii(string):
  29. """Checks whether a unicode string is non-empty and contains only ASCII
  30. characters.
  31. """
  32. if not string:
  33. return False
  34.  
  35. try:
  36. string.encode('ascii')
  37. except UnicodeEncodeError:
  38. return False
  39.  
  40. return True
  41.  
  42.  
  43. class ID3OptionParser(OptionParser):
  44. def __init__(self):
  45. mutagen_version = ".".join(map(str, mutagen.version))
  46. my_version = ".".join(map(str, VERSION))
  47. version = "mid3iconv %s\nUses Mutagen %s" % (
  48. my_version, mutagen_version)
  49. return OptionParser.__init__(
  50. self, version=version,
  51. usage="%prog [OPTION] [FILE]...",
  52. description=("Mutagen-based replacement the id3iconv utility, "
  53. "which converts ID3 tags from legacy encodings "
  54. "to Unicode and stores them using the ID3v2 format."))
  55.  
  56. def format_help(self, *args, **kwargs):
  57. text = OptionParser.format_help(self, *args, **kwargs)
  58. return text + "\nFiles are updated in-place, so use --dry-run first.\n"
  59.  
  60.  
  61. def update(options, filenames):
  62. encoding = options.encoding or getpreferredencoding()
  63. verbose = options.verbose
  64. noupdate = options.noupdate
  65. force_v1 = options.force_v1
  66. remove_v1 = options.remove_v1
  67.  
  68. def conv(uni):
  69. return uni.encode('iso-8859-1').decode(encoding)
  70.  
  71. for filename in filenames:
  72. with _sig.block():
  73. if verbose != "quiet":
  74. print_(u"Updating", filename)
  75.  
  76. if has_id3v1(filename) and not noupdate and force_v1:
  77. mutagen.id3.delete(filename, False, True)
  78.  
  79. try:
  80. id3 = mutagen.id3.ID3(filename)
  81. except mutagen.id3.ID3NoHeaderError:
  82. if verbose != "quiet":
  83. print_(u"No ID3 header found; skipping...")
  84. continue
  85. except Exception as err:
  86. print_(text_type(err), file=sys.stderr)
  87. continue
  88.  
  89. for tag in filter(lambda t: t.startswith(("T", "COMM")), id3):
  90. frame = id3[tag]
  91. if isinstance(frame, mutagen.id3.TimeStampTextFrame):
  92. # non-unicode fields
  93. continue
  94. try:
  95. text = frame.text
  96. except AttributeError:
  97. continue
  98. try:
  99. text = [conv(x) for x in frame.text]
  100. except (UnicodeError, LookupError):
  101. continue
  102. else:
  103. frame.text = text
  104. if not text or min(map(isascii, text)):
  105. frame.encoding = 3
  106. else:
  107. frame.encoding = 1
  108.  
  109. if verbose == "debug":
  110. print_(id3.pprint())
  111.  
  112. if not noupdate:
  113. if remove_v1:
  114. id3.save(filename, v1=False)
  115. else:
  116. id3.save(filename)
  117.  
  118.  
  119. def has_id3v1(filename):
  120. try:
  121. f = open(filename, 'rb+')
  122. f.seek(-128, 2)
  123. return f.read(3) == b"TAG"
  124. except IOError:
  125. return False
  126.  
  127.  
  128. def main(argv):
  129. parser = ID3OptionParser()
  130. parser.add_option(
  131. "-e", "--encoding", metavar="ENCODING", action="store",
  132. type="string", dest="encoding",
  133. help=("Specify original tag encoding (default is %s)" % (
  134. getpreferredencoding())))
  135. parser.add_option(
  136. "-p", "--dry-run", action="store_true", dest="noupdate",
  137. help="Do not actually modify files")
  138. parser.add_option(
  139. "--force-v1", action="store_true", dest="force_v1",
  140. help="Use an ID3v1 tag even if an ID3v2 tag is present")
  141. parser.add_option(
  142. "--remove-v1", action="store_true", dest="remove_v1",
  143. help="Remove v1 tag after processing the files")
  144. parser.add_option(
  145. "-q", "--quiet", action="store_const", dest="verbose",
  146. const="quiet", help="Only output errors")
  147. parser.add_option(
  148. "-d", "--debug", action="store_const", dest="verbose",
  149. const="debug", help="Output updated tags")
  150.  
  151. for i, arg in enumerate(sys.argv):
  152. if arg == "-v1":
  153. sys.argv[i] = "--force-v1"
  154. elif arg == "-removev1":
  155. sys.argv[i] = "--remove-v1"
  156.  
  157. (options, args) = parser.parse_args(argv[1:])
  158.  
  159. if args:
  160. update(options, args)
  161. else:
  162. parser.print_help()
  163.  
  164. if __name__ == "__main__":
  165. set_win32_unicode_argv()
  166. _sig.init()
  167. main(sys.argv)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement