/usr/lib/pypy/dist-packages/mutagen/_tools/mid3iconv.py is in pypy-mutagen 1.36-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | # -*- coding: utf-8 -*-
# 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
import mutagen
import mutagen.id3
from mutagen._senf import argv, print_, fsnative
from mutagen._compat import text_type
from ._util import SignalHandler, OptionParser
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:
with open(filename, 'rb+') as f:
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(argv):
if arg == "-v1":
argv[i] = fsnative(u"--force-v1")
elif arg == "-removev1":
argv[i] = fsnative(u"--remove-v1")
(options, args) = parser.parse_args(argv[1:])
if args:
update(options, args)
else:
parser.print_help()
def entry_point():
_sig.init()
return main(argv)
|