📖 Документация: https://pankovea.github.io/url-media-probe/
Узнавайте информацию о медиафайле без полной загрузки
Минималистичный пакет для определения параметров медиафайла по URL, локальному пути или байтам без полной загрузки.
По URL скачивает минимум данных: начальный фрагмент всего 4 КБ, дальше парсер сам решает, что докачать, но всё — в пределах лимита max_total. Возможен режим «только заголовки» (max_ratio=0) — тело не скачивается вовсе, тогда мы получаем только то что сообщил сервер в заголовке
(имя файла, размер, mime-тип).
Локальные файлы и bytes по умолчанию читаются целиком (до 20 МБ) — для анимированных GIF/WebP это даёт точную длительность без экстраполяции. Лимиты для любого источника задаются одинаковыми параметрами max_total / max_ratio.
После принятия решения о скачивании целиком использует уже скачанные данные и докачивает только то, что осталось.
Сравнение аналогичных проектов
| Характеристика | tinytag | -- url-media-probe -- | hachoir | pymediainfo | ffprobe (subprocess) |
|---|---|---|---|---|---|
| Pure Python + серверлес | Да | Да (async, без бинарников) | Да | Нет (libmediainfo) | Нет (ffmpeg binary) |
| Асинхронность | Синхронный | asyncio + aiohttp | Синхронный | Синхронный | Синхронный |
| Источники данных | Файл | URL, файл, байты в памяти | Файл | Файл | URL, файл |
| Оптимизация трафика | — | head 4 KB + докачка по запросу парсера (head/tail/слайс), ограничение max_total |
— | — | Да, но может скачать весь файл |
| HTTP Range запросы | — | Начальный head прогрессивныая (4→8→..→128 KB) докачка, tail по запросу парсера (середина файла по известной позиции или хвост) | — | — | Да, но может скачать весь файл |
| Типизация | Type hints | dataclass (frozen) | — | — | JSON/dict |
| Форматы | Только аудио | Популярные аудио, видео и фото (~20) | 33 формата: аудио, видео, изображения, архивы, шрифты | Все форматы MediaInfo (100+) | Все форматы ffmpeg (100+) |
| Информативность | Базовая: duration, bitrate, sample rate, теги | Базовая: format, duration, fps, sample rate, bitrate, codec | Полная: codec, profile, bitrate, пиксели, каналы, теги | Полная: codec, profile, level, bitrate, контейнер | Полная: codec, profile, level, пиксели, каналы и т.д. |
| Чтение/запись тегов | Только чтение | — | Чтение + редактирование бинарных полей | Только чтение | Только чтение |
| Размер дистрибутива | ~33 KB | ~300 KB | ~650 KB | ~15 MB (libmediainfo) | >100 MB (ffmpeg) |
Легковесные → тяжеловесные
Примечание: hachoir помечен как «No Maintenance Intended».
Установка
pip install url-media-probe
Быстрый старт
import asyncio
from url_media_probe import MediaProbe
async def main():
probe = MediaProbe()
# По URL
info = await probe.from_url("https://example.com/video.mp4")
print(info.format) # "MP4"
print(info.width) # 1920
print(info.height) # 1080
print(info.duration) # 15.0
print(info.status) # "ok"
# Локальный файл
info = await probe.from_file("/path/to/photo.jpg")
print(info.format) # "JPEG"
# Из байтов
info = await probe.from_bytes(b"...")
print(info.format) # определяется по сигнатуре
asyncio.run(main())
Метаданные MediaInfo
info = await probe.from_url("https://example.com/audio.mp3")
# Общее
print(f"Формат: {info.format}") # "MP3"
print(f"Статус: {info.status}") # "ok" | "partial" | "error"
# Изображения
if info.width and info.height:
print(f"Размеры: {info.width}x{info.height}")
# Видео / аудио
if info.duration:
print(f"Длительность: {info.duration} сек")
if info.fps:
print(f"FPS: {info.fps}")
if info.bitrate_avg:
print(f"Битрейт: {info.bitrate_avg} kbps")
if info.sample_rate:
print(f"Sample rate: {info.sample_rate} Hz")
# Красивый вывод
print(info)
Кодеки
info = await probe.from_url("https://example.com/video.mp4")
# Краткие идентификаторы
print(info.video_codec) # "h264"
print(info.audio_codec) # "aac"
# Полные названия (из ffprobe)
print(info.video_codec_long) # "H.264 / AVC / MPEG-4 part 10"
print(info.audio_codec_long) # "Advanced Audio Coding"
Скачивание файла целиком
После инспекции from_url() можно сохранить файл целиком — библиотека
использует уже скачанные данные и докачивает по HTTP только недостающие байты
(Range-запросы), а не скачивает файл заново. Это работает в любом режиме,
включая «только заголовки» (max_ratio=0): даже если тело ещё не скачивалось,
соединение переоткроется и файл докачается.
info = await probe.from_url("https://example.com/video.mp4")
if info.status == "ok":
path = await probe.download_file("./downloads")
print(f"Сохранён: {path}")
download_file() — скачивает и сохраняет файл целиком на диск. Имя файла берётся из
info.file_name, если его нужно переопределить — передайте file_name=:
await probe.download_file("./downloads", file_name="my_video.mp4")
Лимиты чтения
Ограничения задаются параметрами max_total (максимум байт) и max_ratio (доля размера файла) во всех трёх источниках:
| Источник | По умолчанию |
|---|---|
URL (from_url) |
max_total=256 000, max_ratio=0.1 → бюджет min(256 КБ, 10% размера) |
Файл (from_file) |
max_total=20 971 520, max_ratio=1.0 — читается целиком |
bytes (from_bytes) |
max_total=20 971 520, max_ratio=1.0 — читается целиком |
Общий бюджет — минимум из абсолютного и относительного лимитов: min(max_total, file_size · max_ratio), но не меньше начального head (INITIAL_HEAD, 4 КБ). Head, tail и слайс суммарно не превышают бюджет; каждая порция ограничена остатком.
- Начальный head (URL): минимум —
INITIAL_HEAD(4 КБ) или размер файла, если он меньше. Дальше head растёт только по запросу парсера: точный размер (need_head=moov_endу MP4 с moov в начале) или прогрессивно (4 → 8 → … → 128 КБ). - Tail (хвост файла): верхняя граница —
min(64 КБ, бюджет). Изначально читается конец файла (EOF), а при необходимости растёт: назад (если парсер запросил ещё хвоста) или вперёд от вычисленной позиции (например, атомmoovу потоковых MP4). Резервирования места в бюджете нет: head минимален, и бюджет тратится только на запрошенное парсером.
max_ratio=0 или max_total=0 (URL) → режим «только заголовки»: тело не скачивается, MediaInfo(status="ok") строится по HTTP-метаданным (Content-Type, Content-Length, имя файла).
Как это работает
-
Загрузка данных --
RangeDownloaderделает HTTP запросы:- Сначала GET-запрос: читает метаданные (
Content-Type,Content-Length, имя файла) и начальный фрагмент 4 КБ. - Парсер смотрит на head и сам сообщает, что докачать: ещё head (точный размер или прогрессивно 4 -> 8 -> 16 -> ... -> 128 КБ), слайс от известной позиции (
moov) или tail — но не более общего бюджетаmin(max_total, file_size · max_ratio). - Хвост файла (tail) -- конец файла или слайс от известной позиции (
moovу MP4), растёт по запросам парсера (до 64 КБ). - Повторяет при 429/5xx ошибках.
- Всё в одном keep-alive соединении.
max_ratio=0илиmax_total=0→ режим «только заголовки»: тело не скачивается,MediaInfo(status="ok")строится по HTTP-метаданным.
Для локальных файлов и bytes по умолчанию
max_ratio=1.0иmax_total=20 МБ— данные читаются целиком. - Сначала GET-запрос: читает метаданные (
-
Парсинг -- парсеры анализируют сигнатуры байт и заголовки файлов для определения формата, размеров, длительности, FPS, sample rate, битрейта. Формат определяется исходя из данных, а не из расширения файла.
-
Результат -- dataclass
MediaInfoс полями:format,status,width,height,duration,fps,sample_rate,bitrate_nominal,bitrate_avg,video_codec,audio_codec,parse_note.
Обработка ошибок
По умолчанию библиотека Никогда не бросает исключение. Все ошибки перехватываются внутри и отражаются в status и parse_note. Для проверки результата смотрите status ("ok" | "partial" | "error") и parse_note (описание проблемы или предупреждение).
Проброс сетевых ошибок
При необходимости можно включить проброс сетевых ошибок:
import url_media_probe.media_probe as cfg
from url_media_probe import MediaProbe
# Глобально — на уровне модуля (ко всем экземплярам по умолчанию)
cfg.raise_on_network = True
probe = MediaProbe() # наследует глобальную настройку
await probe.from_url("https://example.com/broken.mp4")
# → бросает aiohttp.ClientError ( timeout, ConnectionError и т.д.)
Локально — на уровне экземпляра:
probe = MediaProbe(raise_on_network=True) # только для этого probe
probe_strict = MediaProbe(raise_on_network=False) # ловит ошибки как обычно
Ошибки парсера (формат не распознан, невалидный файл, недостаточно данных) всегда остаются в
MediaInfo(status="error", parse_note="...")— исключения не бросаются.
Поддерживаемые форматы
Изображения: JPEG, PNG, GIF, WebP (VP8/VP8L/VP8X)
Видео: MP4/MOV, AVI, MKV, WebM, OGV
Аудио: MP3, AAC, WAV, WMA, FLAC, OGG, M4A
Лицензия
LGPL-2.1
Metadata
Release files for url-media-probe 0.2.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| url_media_probe-0.2.2.tar.gz | 1.2 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| url_media_probe-0.2.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.3 MB
Release files / url_media_probe-0.2.2.tar.gz
| Download URL | url_media_probe-0.2.2.tar.gz |
|---|---|
| Size | 1.2 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
61d32c00828481ef462ef22bf369f4cb95a94e5c91b14d76c0a8cd72e6ba849e
|
|
BLAKE2b-256 checksum How to use checksums |
fdd0f2f8496dd5bc4c2fc035bba3c5e9b5b2daba27d6e06534641a17c6fc6834
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.
Transparency logRelease files / url_media_probe-0.2.2-py3-none-any.whl
| Download URL | url_media_probe-0.2.2-py3-none-any.whl |
|---|---|
| Size | 61.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
66d8d78d06522bb4b5e25c848fa20384fdc645a3565215d82ee5f43147b777e6
|
|
BLAKE2b-256 checksum How to use checksums |
f0463f00699bbef7021fb904252194b4e0b794960f09faed9d7d078f69ec810d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.
Transparency log