Skip to content

Commit

Permalink
Merge branch '0.8.x'
Browse files Browse the repository at this point in the history
* 0.8.x:
  fix: ID3 v2.3 to v2.4 date conversion
  fix: Match mp3 mime-types against all possible mime-types
  • Loading branch information
nicfit committed Sep 18, 2019
2 parents bdfe08c + 3758cc5 commit 28a082e
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 29 deletions.
13 changes: 8 additions & 5 deletions src/eyed3/core.py
Expand Up @@ -79,13 +79,16 @@ def load(path, tag_version=None):
else:
raise IOError("file not found: %s" % path)

mtype = guessMimetype(path)
log.debug("File mime-type: %s" % mtype)
mtypes = guessMimetype(path, all_types=True)
log.debug(f"File mime-type: {mtypes}")

if (mtype in mp3.MIME_TYPES or
(mtype in mp3.OTHER_MIME_TYPES and path.suffix.lower() in mp3.EXTENSIONS)):
if set(mtypes).intersection(set(mp3.MIME_TYPES)):
return mp3.Mp3AudioFile(path, tag_version)
elif mtype == "application/x-id3":
elif (set(mtypes).intersection(set(mp3.OTHER_MIME_TYPES)) and
path.suffix.lower() in mp3.EXTENSIONS):
# Same as above, but mp3 was not typed detected; making this odd/special
return mp3.Mp3AudioFile(path, tag_version)
elif "application/x-id3" in mtypes:
return id3.TagFile(path, tag_version)
else:
return None
Expand Down
29 changes: 16 additions & 13 deletions src/eyed3/id3/tag.py
Expand Up @@ -1057,6 +1057,7 @@ def _saveV2Tag(self, version, encoding, max_padding):

def _convertFrames(self, std_frames, convert_list, version):
"""Maps frame incompatibilities between ID3 v2.3 and v2.4.
The items in ``std_frames`` need no conversion, but the list/frames
may be edited if necessary (e.g. a converted frame replaces a frame
in the list). The items in ``convert_list`` are the frames to convert
Expand All @@ -1078,6 +1079,14 @@ def _convertFrames(self, std_frames, convert_list, version):
date_frames[f.id] = f

if date_frames:
def fidHandled(fid):
# A duplicate text frame (illegal ID3 but oft seen) may exist. The date_frames dict
# will have one, but the flist has multiple, hence the loop.
for frame in list(flist):
if frame.id == fid:
flist.remove(frame)
del date_frames[fid]

if version == ID3_V2_4:
if b"TORY" in date_frames or b"XDOR" in date_frames:
# XDOR -> TDOR (full date)
Expand All @@ -1087,8 +1096,7 @@ def _convertFrames(self, std_frames, convert_list, version):
converted_frames.append(DateFrame(b"TDOR", date))
for fid in (b"TORY", b"XDOR"):
if fid in flist:
flist.remove(date_frames[fid])
del date_frames[fid]
fidHandled(fid)

# TYER, TDAT, TIME -> TDRC
if (b"TYER" in date_frames or b"TDAT" in date_frames or
Expand All @@ -1098,16 +1106,14 @@ def _convertFrames(self, std_frames, convert_list, version):
converted_frames.append(DateFrame(b"TDRC", date))
for fid in [b"TYER", b"TDAT", b"TIME"]:
if fid in date_frames:
flist.remove(date_frames[fid])
del date_frames[fid]
fidHandled(fid)

elif version == ID3_V2_3:
if b"TDOR" in date_frames:
date = date_frames[b"TDOR"].date
if date:
converted_frames.append(DateFrame(b"TORY", str(date.year)))
flist.remove(date_frames[b"TDOR"])
del date_frames[b"TDOR"]
fidHandled(b"TDOR")

if b"TDRC" in date_frames:
date = date_frames[b"TDRC"].date
Expand All @@ -1127,16 +1133,14 @@ def _convertFrames(self, std_frames, convert_list, version):
converted_frames.append(TextFrame(b"TIME",
date_str))

flist.remove(date_frames[b"TDRC"])
del date_frames[b"TDRC"]
fidHandled(b"TDRC")

if b"TDRL" in date_frames:
# TDRL -> XDOR
date = date_frames[b"TDRL"].date
if date:
converted_frames.append(DateFrame(b"XDOR", str(date)))
flist.remove(date_frames[b"TDRL"])
del date_frames[b"TDRL"]
fidHandled(b"TDRL")

# All other date frames have no conversion
for fid in date_frames:
Expand Down Expand Up @@ -1171,9 +1175,8 @@ def _convertFrames(self, std_frames, convert_list, version):
if len(flist) != 0:
unconverted = ", ".join([f.id.decode("ascii") for f in flist])
if version[0] != 1:
raise TagException("Unable to covert the following frames to "
"version %s: %s" % (versionToString(version),
unconverted))
raise TagException("Unable to convert the following frames to "
f"version {versionToString(version)}: {unconverted}")

# Some frames in converted_frames may replace/edit frames in std_frames.
for cframe in converted_frames:
Expand Down
30 changes: 19 additions & 11 deletions src/eyed3/utils/__init__.py
Expand Up @@ -31,32 +31,40 @@ def os_walk_unpack(w):

class MagicTypes(magic.Magic):
def __init__(self):
magic.Magic.__init__(self, mime=True, mime_encoding=False,
keep_going=False)
magic.Magic.__init__(self, mime=True, mime_encoding=False, keep_going=True)

def guess_type(self, filename):
def guess_type(self, filename, all_types=False):
if os.path.splitext(filename)[1] in ID3_MIME_TYPE_EXTENSIONS:
return ID3_MIME_TYPE
return ID3_MIME_TYPE if not all_types else [ID3_MIME_TYPE]
try:
return self.from_file(filename)
types = self.from_file(filename)
except UnicodeEncodeError:
# https://github.com/ahupp/python-magic/pull/144
return self.from_file(filename.encode("utf-8", 'surrogateescape'))
types = self.from_file(filename.encode("utf-8", 'surrogateescape'))

delim = r"\012- "
if all_types:
return types.split(delim)
else:
return types.split(delim)[0]



_mime_types = MagicTypes()


def guessMimetype(filename, with_encoding=False):
"""Return the mime-type for ``filename``. If ``with_encoding`` is True
the encoding is included and a 2-tuple is returned, (mine, enc)."""
def guessMimetype(filename, with_encoding=False, all_types=False):
"""Return the mime-type for ``filename`` (or list of possible types when `all_types` is True).
If ``with_encoding`` is True the encoding is included and a 2-tuple is returned, (mine, enc).
"""

filename = str(filename) if isinstance(filename, pathlib.Path) else filename
mime = _mime_types.guess_type(filename)
mime = _mime_types.guess_type(filename, all_types=all_types)
if not with_encoding:
return mime
else:
warnings.warn("File character encoding no lopng return, value is None",
warnings.warn("File character encoding no longer returned, value is None",
UserWarning, stacklevel=2)
return mime, None

Expand Down

0 comments on commit 28a082e

Please sign in to comment.