Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ v0.13.0
- Add a mapping compatible with Plex and ffmpeg for the "original date"
fields.
- Remove an unnecessary dependency on `six`.
- Replace `imghdr` with `filetype` to support Python 3.13.

v0.12.0
'''''''
Expand Down
47 changes: 5 additions & 42 deletions mediafile.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@
import codecs
import datetime
import enum
import filetype
import functools
import imghdr
import logging
import math
import os
Expand Down Expand Up @@ -78,8 +78,6 @@
'wav': 'WAVE',
}

PREFERRED_IMAGE_EXTENSIONS = {'jpeg': 'jpg'}


# Exceptions.

Expand Down Expand Up @@ -346,52 +344,17 @@ def _sc_encode(gain, peak):


# Cover art and other images.
def _imghdr_what_wrapper(data):
"""A wrapper around imghdr.what to account for jpeg files that can only be
identified as such using their magic bytes
See #1545
See https://github.com/file/file/blob/master/magic/Magdir/jpeg#L12
"""
# imghdr.what returns none for jpegs with only the magic bytes, so
# _wider_test_jpeg is run in that case. It still returns None if it didn't
# match such a jpeg file.
return imghdr.what(None, h=data) or _wider_test_jpeg(data)


def _wider_test_jpeg(data):
"""Test for a jpeg file following the UNIX file implementation which
uses the magic bytes rather than just looking for the bytes that
represent 'JFIF' or 'EXIF' at a fixed position.
"""
if data[:2] == b'\xff\xd8':
return 'jpeg'


def image_mime_type(data):
"""Return the MIME type of the image data (a bytestring).
"""
# This checks for a jpeg file with only the magic bytes (unrecognized by
# imghdr.what). imghdr.what returns none for that type of file, so
# _wider_test_jpeg is run in that case. It still returns None if it didn't
# match such a jpeg file.
kind = _imghdr_what_wrapper(data)
if kind in ['gif', 'jpeg', 'png', 'tiff', 'bmp']:
return 'image/{0}'.format(kind)
elif kind == 'pgm':
return 'image/x-portable-graymap'
elif kind == 'pbm':
return 'image/x-portable-bitmap'
elif kind == 'ppm':
return 'image/x-portable-pixmap'
elif kind == 'xbm':
return 'image/x-xbitmap'
else:
return 'image/x-{0}'.format(kind)
return filetype.guess_mime(data)


def image_extension(data):
ext = _imghdr_what_wrapper(data)
return PREFERRED_IMAGE_EXTENSIONS.get(ext, ext)
ext = filetype.guess_extension(data)
# imghdr returned "tiff", so we should keep returning it with filetype.
return ext if ext != 'tif' else 'tiff'


class ImageType(enum.Enum):
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ home-page = "https://github.com/beetbox/mediafile"
description-file = "README.rst"
requires = [
"mutagen>=1.46",
"filetype>=1.2.0",
]
requires-python = ">=3.7"
classifiers = [
Expand Down
Binary file removed test/rsrc/only-magic-bytes.jpg
Binary file not shown.
11 changes: 0 additions & 11 deletions test/test_mediafile_edge.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,6 @@ def test_old_ape_version_bitrate(self):
f = mediafile.MediaFile(media_file)
self.assertEqual(f.bitrate, 0)

def test_only_magic_bytes_jpeg(self):
# Some jpeg files can only be recognized by their magic bytes and as
# such aren't recognized by imghdr. Ensure that this still works thanks
# to our own follow up mimetype detection based on
# https://github.com/file/file/blob/master/magic/Magdir/jpeg#L12
magic_bytes_file = os.path.join(_common.RSRC, b'only-magic-bytes.jpg')
with open(magic_bytes_file, 'rb') as f:
jpg_data = f.read()
self.assertEqual(
mediafile._imghdr_what_wrapper(jpg_data), 'jpeg')

def test_soundcheck_non_ascii(self):
# Make sure we don't crash when the iTunes SoundCheck field contains
# non-ASCII binary data.
Expand Down
Loading