-
Notifications
You must be signed in to change notification settings - Fork 56
Feat file info #149
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Pankovea
wants to merge
62
commits into
love-apples:main
Choose a base branch
from
Pankovea:feat_file_info
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Feat file info #149
Changes from 58 commits
Commits
Show all changes
62 commits
Select commit
Hold shift + click to select a range
356231a
add: FileInspector -> FileInfo
Pankovea 2b16f31
fix: ruff
Pankovea e2dbd7f
fix: NamedBytesIO
Pankovea 1c4c299
add: tests for bot.get_file_info
Pankovea 4e53713
fix: copilot review
Pankovea ee46a4c
fix: Сборка строки FileInfo.__str__
Pankovea 6306369
fix: Сборка строки FileInfo.str (2)
Pankovea ba23730
Merge branch 'main' into feat_file_info
Pankovea fbb5f81
fix: some copilot comments
Pankovea 9d432cd
fix: Оптимизированы сетевые запросы
Pankovea 0e395ac
fix: Оправка headers c auth
Pankovea ca30328
refactor: Оптимизация
Pankovea 9b9923d
fix: mp4 m4a sample_rate detection
Pankovea 487056c
refactor: Отказ от планирования загрузки. Парсеры рулят.
Pankovea ee82d03
fix: Опечатка в комментарии: «Провеирть» → «Проверить».
Pankovea aec25b2
Fix typo in file_inspector.py documentation
Pankovea 8e30263
fix: Опечатка в сообщении исключения: «отсутвует» → «отсутствует».
Pankovea 8eedc5d
fix: Неверное положение скобок в расчёте file_size
Pankovea ebff36e
fix: Проверка на утечку авторизации смотреть так же в self.session
Pankovea 53761c2
fix: max_total, ограничивал только внутри одного вызова
Pankovea 59172b2
fix: tests
Pankovea 6819c2c
fix: ruff
Pankovea 7f580f8
fix: tests
Pankovea cc07b14
fix: tests
Pankovea dfa714f
fix: tests
Pankovea 28d3582
fix: tests
Pankovea 791a0dd
fix: tests
Pankovea e299fb2
fix: Оптимизация _webp_parse
Pankovea 1af49e7
add: tests to test_file_info.py
Pankovea d8d3763
Merge commit '28b7c446bf6191c0e19a601055fd21d91b393de9' into feat_fil…
Pankovea 0e0711a
fix: tests
Pankovea 9f551f2
fix: ruff
Pankovea cf55c4b
add: test_file_info_class.py,
Pankovea 025e87c
add: FileInspector to utils\__init__.py
Pankovea 2f3a4d9
add: Документация и примеры
Pankovea d47f736
fix: circular import
Pankovea 3bb8793
Merge branch 'main' into feat_file_info
Pankovea 3b9d974
Merge branch 'main' into feat_file_info
Pankovea 7a4ba1f
fix: anyio -> aiofiles чтобы не добавлять зависимостей
Pankovea 14c3f26
remove: FileInfo.__eq__
Pankovea 8a0cfa0
fix: RangeDownloader._expand_head теперь обновляет _downloaded
Pankovea af35636
fix: RuntimeWarning на мок-сессиях
Pankovea f6ee59a
ruff
Pankovea 7a88ce6
add: Удобная обёртка над :class:`File_inspector
Pankovea dcde4ac
remove: Bot.get_file_info
Pankovea 0ec337f
add: UrlStr
Pankovea d011e55
refactor: RangeReader.meta: FileMeta
Pankovea 6059fab
add: FileInspector.full_file_save()
Pankovea 89f124e
ruff 901 TooComplex для file_inspector в pyproject.toml
Pankovea 404e54a
ruff
Pankovea 4b5ba34
ruff
Pankovea e76a022
add: UrlStr.full_file_save(file_path)
Pankovea 52b7a72
imports: inspect_bytes, inspect_file, inspect_url
Pankovea a9c8293
fix: Примеры для FileInfo
Pankovea 551d73d
fix: tests
Pankovea 4cffcd4
ruff
Pankovea 271ed7e
add: HLS / M3U parsing
Pankovea b7c6301
ruff
Pankovea 520bed1
fix: Орфография и докстринги
Pankovea c1a1eea
fix: FileInfo.__str__ проверка на наличие параметра через is not None
Pankovea 4da6289
fix: Вынесение FileInspector во внешний иморт
Pankovea 05547a7
fix: миграция FileInspector → MediaProbe, исправление доков
Pankovea File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,165 @@ | ||
| # Получение метаинформации о медиафайлах | ||
|
|
||
| Библиотека `maxapi` позволяет извлекать метаданные медиафайлов (формат, размеры, длительность, битрейт) по URL **без полной загрузки**, локальному пути или байтам в памяти. | ||
| Анализирует сигнатуры и заголовки в первых и последних байтах файла. Скачивает минимум данных, докачивает | ||
| только если не хватило. | ||
|
|
||
| Это полезно для: | ||
|
|
||
| - Быстрой проверки типа файла перед скачиванием. | ||
| - Получения размеров изображений/видео для отображения в UI. | ||
| - Определения длительности аудио/видео для превью. | ||
|
|
||
| ## Поддерживаемые форматы | ||
|
|
||
| FileInspector распознает метаданные для популярных медиаформатов: | ||
| * Изображения: JPEG, PNG, GIF, WebP (VP8/VP8L/VP8X) | ||
| * Видео: MP4/MOV, AVI, MKV, WEBM, OGV | ||
| * Аудио: MP3, AAC, WAV, WMA, FLAC, OGG, M4A | ||
|
|
||
| Для каждого формата извлекаются поля (если доступно): | ||
| width, height, duration, fps, sample_rate, bitrate | ||
|
|
||
| ## Быстрый старт: `bot.get_file_info()` | ||
|
|
||
| Самый простой способ — использовать метод `bot.get_file_info()`, который принимает URL файла и возвращает `FileInfo`: | ||
|
|
||
| ```python | ||
| from maxapi import Bot | ||
|
|
||
| bot = Bot(token="YOUR_TOKEN") | ||
|
|
||
| # Получаем метаинформацию о файле по URL | ||
| info = await bot.get_file_info( | ||
| "https://example.com/video.mp4", | ||
| timeout=10, # таймаут в секундах (опционально) | ||
| ) | ||
|
|
||
| print(info) | ||
|
|
||
| # Или отдельно по интересующим полям | ||
| print(f"Формат: {info.format}") | ||
| print(f"Размеры: {info.width}x{info.height}") | ||
| print(f"Длительность: {info.duration} сек") | ||
| print(f"Статус: {info.status}") # ok, partial или error | ||
| if info.status != "ok": | ||
| print(f" Комментарий парсера: {info.parse_note}") | ||
| ``` | ||
|
|
||
| ## Анализ файла на диске или байт в памяти | ||
|
|
||
| ```python | ||
| from maxapi.utils import FileInspector | ||
| inspector = FileInspector() | ||
| file_info = await inspector.inspect_file("/path/to/video.avi") | ||
| file_info = await inspector.inspect_bytes(downloaded_bytes) | ||
| # Следующий метод интегрирован в bot.get_file_info(url) | ||
| file_info = await inspector.inspect_url("https://example.com/photo.jpg") | ||
| ``` | ||
|
|
||
| FileInspector можно использовать повторно для других файлов. | ||
| При этом он помнит последние скачанные данные и последний FileInfo: | ||
|
|
||
| ```python | ||
| if inspector.last_file_info: | ||
| print(inspector.last_file_info) | ||
| print("Скачано начало файла", len(inspector.last_head), "байт") | ||
| if inspector.last_tail: | ||
| print("Скачано конца файла", len(inspector.last_tail), "байт") | ||
| ``` | ||
|
|
||
| ## Обработка статусов | ||
|
|
||
| Метод возвращает FileInfo со статусом: | ||
| * `ok` — все ключевые метаданные успешно извлечены. | ||
| * `partial` — часть данных получена, но чего-то не хватает (например, длительность для MP4 с moov в конце файла). | ||
| * `error` — произошла ошибка (сеть, HTML-страница вместо файла) и не удалось определить даже размер файла. | ||
|
|
||
| ```python | ||
| info = await bot.get_file_info(url) | ||
|
|
||
| if info.status == "ok": | ||
| print(f"Полные метаданные: {info.format}, {info.width}x{info.height}") | ||
| elif info.status == "partial": | ||
| print(f"Частичные данные: {info.format}, примечание: {info.parse_note}") | ||
| else: | ||
| print(f"Ошибка: {info.parse_note}") | ||
| ``` | ||
|
|
||
| ## Как это работает? | ||
|
|
||
| FileInspector использует частичную загрузку: | ||
| * HEAD-запрос для получения Content-Type и Content-Length. | ||
|
Pankovea marked this conversation as resolved.
Outdated
|
||
| * Скачивание хвоста 64 КБ — для форматов, где метаданные в конце (MP4 с moov в конце, | ||
| OGG с длительностью в последней грануле). | ||
| * Чтение начала файла от 4 до 256 КБ в зависимости от формата. | ||
|
|
||
| Если сервер не поддерживает Range-запросы, FileInspector адаптируется и работает с тем, что есть, | ||
| возвращая статус partial при невозможности определить некоторые поля. | ||
|
|
||
| ## Безопасность и авторизация | ||
|
|
||
| Если вы передаете aiohttp.ClientSession с заголовками авторизации (Authorization, Cookie), они не будут отправлены на сторонние домены по умолчанию. Это защита от утечки токенов. | ||
| Чтобы разрешить отправку авторизации на внешний URL: | ||
|
|
||
| ```python | ||
| from maxapi.utils import FileInspector | ||
| inspector = FileInspector() | ||
| info = await inspector.inspect_url( | ||
| "https://external.com/private.mp4", | ||
| session=session_with_auth, | ||
| allow_external_auth=True, # явно разрешаем | ||
| ) | ||
| ``` | ||
|
|
||
| Доверенные домены (**oneme.ru**, **okcdn.ru**) всегда принимают авторизацию без этого флага. | ||
|
|
||
| ## Пример в боте: команда /info | ||
|
|
||
| Добавим команду, которая показывает метаинформацию о файле из reply-сообщения: | ||
|
|
||
| ```python | ||
| import asyncio | ||
| from maxapi import Bot, Dispatcher | ||
| from maxapi.types import Message | ||
|
|
||
| bot = Bot(token="ваш_токен") | ||
| dp = Dispatcher() | ||
|
|
||
| @dp.message_created(commands=["info"]) | ||
| async def cmd_info(event: MessageCreated): | ||
| replied_body = event.message.link.message if event.message.link else None | ||
| if not replied_body or not replied_body.attachments: | ||
| await event.message.answer("ℹ️ Ответьте этой командой на сообщение с файлом.") | ||
| return | ||
|
|
||
| first_url = None | ||
| # Получаем URL вложений до первого успеха | ||
| if replied_body.attachments: | ||
| for att in replied_body.attachments: | ||
| if hasattr(att, "url"): | ||
| file_info = await bot.get_file_info(att.url) | ||
| if file_info.status == "ok": | ||
| # Собрать отдельные интересующие поля | ||
| # text = f"Формат: {file_info.format}\n" | ||
| # if file_info.width and file_info.height: | ||
| # text += f"Размеры: {file_info.width}x{file_info.height}\n" | ||
| # if file_info.duration: | ||
| # text += f"Длительность: {file_info.duration} сек\n" | ||
| # if file_info.sample_rate: | ||
| # text += f"Частота сэмплов: {file_info.sample_rate} Гц\n" | ||
| # text += f"Статус: {file_info.status}" | ||
| # Или просто: | ||
| text = str(file_info) | ||
| await event.message.answer(text) | ||
| return | ||
|
|
||
| await event.message.answer("Вложение не найдено") | ||
| return | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| asyncio.run(dp.start_polling(bot)) | ||
| ``` | ||
|
|
||
| Более подробный пример (05_media_bot.py)[https://github.com/love-apples/maxapi/blob/main/examples/05_media_bot.py] | ||
|
Pankovea marked this conversation as resolved.
Outdated
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| # File Inspector | ||
|
|
||
| ::: maxapi.utils.file_inspector | ||
| options: | ||
| show_root_heading: true | ||
| members_order: source | ||
| filters: | ||
| - "!^_" |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.