Skip to main content

url-media-probe

Deploy Docs Tests

Docs

📖 Документация: 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, имя файла).

Как это работает

  1. Загрузка данных -- 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 МБ — данные читаются целиком.

  2. Парсинг -- парсеры анализируют сигнатуры байт и заголовки файлов для определения формата, размеров, длительности, FPS, sample rate, битрейта. Формат определяется исходя из данных, а не из расширения файла.

  3. Результат -- 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)

Source distribution for url-media-probe 0.2.2
File Size Uploaded
url_media_probe-0.2.2.tar.gz 1.2 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for url-media-probe 0.2.2
File Interpreter ABI Platform
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 log

Release 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

Release history Release notifications | RSS feed

This release

0.2.2 This release

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page