Извлекать обложку из удаленного mp3

Мне нужно извлечь обложку из удаленного mp3-файла и сохранить его в файл без загрузки всего mp3. Но у меня нет успеха с этим. Я попытался загрузить первые 100 байтов файла, например:

import urllib2
from mutagen.mp3 import MP3

req = urllib2.Request('http://www.stephaniequinn.com/Music/Commercial%20DEMO%20-%2001.mp3')
req.headers['Range'] = 'bytes=%s-%s' % (0, 100)
response = urllib2.urlopen(req)
headers = response.info()
print headers.type
print headers.maintype

data = response.read()
print len(data)

Я читал о том, что теги id 3 находятся в последних 128 байтах mp3. Теперь мне нужна помощь, чтобы загрузить только последние байты, которые содержат обложку apic, и извлечь изображение.

спасибо за помощь мне

2 ответа

Решение

Скрытое изображение находится в начале файла в теге id3v2.

Вот хакерское решение: читать до тех пор, пока не будет прочитан весь файл или мутаген не выдаст ошибку. Это прочитало бы весь файл в случае, если mp3 не mp3. В идеале вы должны передать его в виде доступного файла, который выполняет буферизацию, возможно, для этого есть библиотека.

# Python 2 or 3
try:
    import urllib2 as request
except ImportError:
    from urllib import request
from io import BytesIO
from mutagen import MutagenError
from mutagen.mp3 import MP3


def get_mp3(url):
    """
    Args:
        url (str)
    Returns:
        mutagen.mp3.MP3
    Raises:
        mutagen.MutagenError
        EnvironmentError
    """

    r = request.urlopen(url)
    try:
        size = 128
        filelike = BytesIO()
        while 1:
            data = r.read(size)
            size *= 2
            filelike.seek(0, 2)
            filelike.write(data)
            filelike.seek(0)
            try:
                return MP3(filelike)
            except MutagenError:
                if not data:
                    raise
                pass
    finally:
        r.close()

try:
    f = get_mp3("http://web.ist.utl.pt/antonio.afonso/www.aadsm.net/libraries/id3/music/Bruno_Walter_-_01_-_Beethoven_Symphony_No_1_Menuetto.mp3")
except (MutagenError, EnvironmentError):
    pass
else:
    if f.tags:
        for frame in f.tags.getall("APIC"):
            print(frame.pprint())

Теги ID3 обычно располагаются перед файлами mp3, а не сзади. Я проверил несколько случайных mp3-файлов из интернета, и у них были все теги ID3 впереди, хотя формат mp3 позволяет им иметь его в конце.

Если вы хотите загрузить только абсолютный минимум байтов (так как вы не хотите тратить трафик пользователей мобильных телефонов), вам необходимо:

  1. частично загрузите 10 байтов и убедитесь, что теги ID3 находятся перед файлом. Если нет: загрузите весь файл
  2. извлечь размер из байта 6-9 (обратите внимание, что у байтов самый левый бит всегда установлен в ноль, как описано на id3.org)
  3. сделать свежую частичную загрузку размера, который вы только что вычислили

После этого вы загрузите полные теги ID3 и сможете их извлечь. Теперь у mutagen есть ограничение на то, что вам также необходимо скачать первый аудиофрейм в формате mp3, в противном случае он выдаст исключение: mutagen.mp3.HeaderNotFoundError: can't sync to an MPEG frame, Если это ограничение подходит вам, я разместил решение Python по аналогичному вопросу (на самом деле это, вероятно, дубликат, я вижу, вы также скопировали исходный код вопроса в ваш вопрос).

Если вы абсолютно хотите минимизировать размер загружаемого файла, вам, вероятно, стоит попробовать несколько других модулей, которые, надеюсь, не требуют также загружать первый аудиокадр.

Другие вопросы по тегам