Name | django-hlsfield JSON |
Version |
1.0.4
JSON |
| download |
home_page | None |
Summary | Django VideoField + HLSVideoField: metadata, preview frame, automatic HLS/DASH, Celery optional. |
upload_time | 2025-09-01 07:52:52 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.10 |
license | MIT |
keywords |
adaptive
dash
django
ffmpeg
hls
streaming
video
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# django-hlsfield
[](https://badge.fury.io/py/django-hlsfield)
[](https://www.python.org/downloads/)
[](https://www.djangoproject.com/)
[](https://opensource.org/licenses/MIT)
🎥 **Автоматическое создание адаптивного видео для Django**
Django-библиотека для автоматической обработки видео с генерацией HLS/DASH стримов, превью и метаданных. Просто загрузите видео — получите адаптивный стрим с выбором качества!
## ✨ Возможности
- 📹 **VideoField** — базовое поле с извлечением метаданных и превью
- 🎬 **HLSVideoField** — автоматическая генерация HLS с несколькими качествами
- 📺 **DASHVideoField** — DASH стриминг для современных браузеров
- 🌐 **AdaptiveVideoField** — HLS + DASH одновременно для максимальной совместимости
- ☁️ **Любые Storage** — работает с локальными файлами, S3, MinIO
- ⚡ **Celery + синхронный режим** — быстрая загрузка + фоновая обработка
- 🎛️ **Готовые плееры** — HTML5 плееры с выбором качества
## 🚀 Быстрый старт
### Установка
```bash
pip install django-hlsfield
pip install django-hlsfield[all]
pip install django-hlsfield[dev]
```
**Требования:** ffmpeg и ffprobe должны быть установлены в системе
### Настройка
```python
# settings.py
INSTALLED_APPS = [
# ...
'hlsfield',
]
# Опционально: пути к бинарям
HLSFIELD_FFMPEG = "ffmpeg" # или полный путь
HLSFIELD_FFPROBE = "ffprobe"
# Качества видео (по умолчанию)
HLSFIELD_DEFAULT_LADDER = [
{"height": 360, "v_bitrate": 800, "a_bitrate": 96},
{"height": 720, "v_bitrate": 2500, "a_bitrate": 128},
{"height": 1080, "v_bitrate": 4500, "a_bitrate": 160},
]
```
## 📝 Примеры использования
### 1. Простое видео с метаданными
```python
# models.py
from django.db import models
from hlsfield import VideoField
class Video(models.Model):
title = models.CharField(max_length=200)
video = VideoField(
upload_to="videos/",
duration_field="duration", # автозаполнение длительности
width_field="width", # ширина кадра
height_field="height", # высота кадра
preview_field="preview_image" # путь к превью
)
# Поля для метаданных (опционально)
duration = models.DurationField(null=True, blank=True)
width = models.PositiveIntegerField(null=True, blank=True)
height = models.PositiveIntegerField(null=True, blank=True)
preview_image = models.CharField(max_length=500, null=True, blank=True)
# Использование
video = Video.objects.get(pk=1)
print(f"Длительность: {video.duration}")
print(f"Разрешение: {video.width}x{video.height}")
print(f"Превью: {video.video.preview_url()}")
```
### 2. HLS адаптивное видео
```python
# models.py
from hlsfield import HLSVideoField
class Lecture(models.Model):
title = models.CharField(max_length=200)
video = HLSVideoField(
upload_to="lectures/",
hls_playlist_field="hls_master" # поле для master.m3u8
)
hls_master = models.CharField(max_length=500, null=True, blank=True)
# templates/lecture_detail.html
{% if lecture.video.master_url %}
{% include "hlsfield/players/hls_player.html" with hls_url=lecture.video.master_url %}
{% else %}
<p>Видео обрабатывается...</p>
{% endif %}
```
### 3. Полный стек: HLS + DASH
```python
# models.py
from hlsfield import AdaptiveVideoField
class Movie(models.Model):
title = models.CharField(max_length=200)
video = AdaptiveVideoField(
upload_to="movies/",
hls_playlist_field="hls_playlist",
dash_manifest_field="dash_manifest",
ladder=[ # настройка качеств
{"height": 480, "v_bitrate": 1200, "a_bitrate": 96},
{"height": 720, "v_bitrate": 2500, "a_bitrate": 128},
{"height": 1080, "v_bitrate": 4500, "a_bitrate": 160},
]
)
hls_playlist = models.CharField(max_length=500, null=True, blank=True)
dash_manifest = models.CharField(max_length=500, null=True, blank=True)
# templates/movie_detail.html
{% include "hlsfield/players/universal_player.html" with hls_url=movie.video.master_url dash_url=movie.video.dash_url %}
```
### 4. Интеграция с S3
```python
# settings.py
from storages.backends.s3boto3 import S3Boto3Storage
class MediaStorage(S3Boto3Storage):
bucket_name = 'my-video-bucket'
region_name = 'us-east-1'
DEFAULT_FILE_STORAGE = 'myapp.storage.MediaStorage'
# models.py - без изменений!
class Video(models.Model):
video = HLSVideoField(upload_to="videos/") # работает с S3 автоматически
```
### 5. Настройка качества и параметров
```python
# settings.py
HLSFIELD_DEFAULT_LADDER = [
{"height": 240, "v_bitrate": 300, "a_bitrate": 64}, # мобайл
{"height": 480, "v_bitrate": 1200, "a_bitrate": 96}, # SD
{"height": 720, "v_bitrate": 2500, "a_bitrate": 128}, # HD
{"height": 1080, "v_bitrate": 4500, "a_bitrate": 160}, # Full HD
{"height": 1440, "v_bitrate": 8000, "a_bitrate": 192}, # 2K
]
HLSFIELD_SEGMENT_DURATION = 6 # длина сегментов в секундах
# models.py - кастомное качество для конкретного поля
class PremiumVideo(models.Model):
video = HLSVideoField(
ladder=[
{"height": 1080, "v_bitrate": 6000, "a_bitrate": 160},
{"height": 1440, "v_bitrate": 12000, "a_bitrate": 192},
{"height": 2160, "v_bitrate": 20000, "a_bitrate": 256}, # 4K
]
)
```
## 🔧 Настройка Celery (рекомендуется)
Без Celery обработка видео блокирует запрос. С Celery — мгновенная загрузка + фоновая обработка.
```python
# settings.py
INSTALLED_APPS = [
# ...
'hlsfield',
]
# celery.py
from celery import Celery
app = Celery('myproject')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()
# Запуск воркера
# celery -A myproject worker -l info
```
## 🎮 Готовые плееры
Библиотека включает готовые HTML-шаблоны плееров:
```html
<!-- HLS плеер -->
{% include "hlsfield/players/hls_player.html" with hls_url=video.master_url %}
<!-- DASH плеер -->
{% include "hlsfield/players/dash_player.html" with dash_url=video.dash_url %}
<!-- Универсальный (HLS + DASH + прямое MP4) -->
{% include "hlsfield/players/universal_player.html" with hls_url=... dash_url=... video_url=... %}
<!-- Адаптивный (автовыбор HLS/DASH) -->
{% include "hlsfield/players/adaptive_player.html" with hls_url=... dash_url=... %}
```
## 📁 Структура файлов
После обработки видео структура будет выглядеть так:
```
media/
└── videos/
└── abc12345/
├── my_video.mp4 # оригинал
├── preview.jpg # превью-кадр
├── meta.json # метаданные
└── hls/ # HLS артефакты
├── master.m3u8 # главный плейлист
├── v360/ # качество 360p
│ ├── index.m3u8
│ └── seg_*.ts
├── v720/ # качество 720p
│ ├── index.m3u8
│ └── seg_*.ts
└── v1080/ # качество 1080p
├── index.m3u8
└── seg_*.ts
```
## ⚙️ Конфигурация
| Настройка | По умолчанию | Описание |
|-----------|--------------|----------|
| `HLSFIELD_FFMPEG` | `"ffmpeg"` | Путь к ffmpeg |
| `HLSFIELD_FFPROBE` | `"ffprobe"` | Путь к ffprobe |
| `HLSFIELD_SEGMENT_DURATION` | `6` | Длина HLS сегментов (сек) |
| `HLSFIELD_DEFAULT_LADDER` | `[360p, 720p, 1080p]` | Качества по умолчанию |
| `HLSFIELD_SIDECAR_LAYOUT` | `"nested"` | Структура файлов |
## 🐛 Решение проблем
### FFmpeg не найден
```bash
# Ubuntu/Debian
sudo apt update && sudo apt install ffmpeg
# macOS
brew install ffmpeg
# Windows
# Скачать с https://ffmpeg.org/download.html
```
### Большие файлы зависают
```python
# settings.py - увеличить таймауты
FILE_UPLOAD_MAX_MEMORY_SIZE = 100 * 1024 * 1024 # 100MB
DATA_UPLOAD_MAX_MEMORY_SIZE = 100 * 1024 * 1024
```
### Проблемы с S3
```python
# Проверить права доступа к bucket
AWS_S3_FILE_OVERWRITE = False
AWS_DEFAULT_ACL = 'public-read' # для публичных видео
```
## 🤝 Вклад в проект
1. Fork репозитория
2. Создайте ветку: `git checkout -b feature/amazing-feature`
3. Commit изменения: `git commit -m 'Add amazing feature'`
4. Push в ветку: `git push origin feature/amazing-feature`
5. Откройте Pull Request
## 📄 Лицензия
MIT License. См. [LICENSE](LICENSE) для деталей.
## 🎯 Roadmap
- [ ] Автотесты и CI/CD
- [ ] WebVTT субтитры и превью-спрайты
- [ ] GPU-ускорение через NVENC/VAAPI
- [ ] Поддержка HEVC/AV1 кодеков
- [ ] Интеграция с CDN (CloudFront, Cloudflare)
---
**Сделано с ❤️ для Django-сообщества**
Raw data
{
"_id": null,
"home_page": null,
"name": "django-hlsfield",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "adaptive, dash, django, ffmpeg, hls, streaming, video",
"author": null,
"author_email": "akula993 <akula993@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/ff/00/2351405f4089f092f4cd16c4f5641d25c29132550ce1ff2133249959d277/django_hlsfield-1.0.4.tar.gz",
"platform": null,
"description": "# django-hlsfield\n\n[](https://badge.fury.io/py/django-hlsfield)\n[](https://www.python.org/downloads/)\n[](https://www.djangoproject.com/)\n[](https://opensource.org/licenses/MIT)\n\n\ud83c\udfa5 **\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0430\u0434\u0430\u043f\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0432\u0438\u0434\u0435\u043e \u0434\u043b\u044f Django**\n\nDjango-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432\u0438\u0434\u0435\u043e \u0441 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0435\u0439 HLS/DASH \u0441\u0442\u0440\u0438\u043c\u043e\u0432, \u043f\u0440\u0435\u0432\u044c\u044e \u0438 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445. \u041f\u0440\u043e\u0441\u0442\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u0435 \u0432\u0438\u0434\u0435\u043e \u2014 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0435 \u0430\u0434\u0430\u043f\u0442\u0438\u0432\u043d\u044b\u0439 \u0441\u0442\u0440\u0438\u043c \u0441 \u0432\u044b\u0431\u043e\u0440\u043e\u043c \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430!\n\n## \u2728 \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438\n\n- \ud83d\udcf9 **VideoField** \u2014 \u0431\u0430\u0437\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u0435 \u0441 \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0435\u043c \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043f\u0440\u0435\u0432\u044c\u044e\n- \ud83c\udfac **HLSVideoField** \u2014 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f HLS \u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430\u043c\u0438\n- \ud83d\udcfa **DASHVideoField** \u2014 DASH \u0441\u0442\u0440\u0438\u043c\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u0432\n- \ud83c\udf10 **AdaptiveVideoField** \u2014 HLS + DASH \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0434\u043b\u044f \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u0438\n- \u2601\ufe0f **\u041b\u044e\u0431\u044b\u0435 Storage** \u2014 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0444\u0430\u0439\u043b\u0430\u043c\u0438, S3, MinIO\n- \u26a1 **Celery + \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c** \u2014 \u0431\u044b\u0441\u0442\u0440\u0430\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 + \u0444\u043e\u043d\u043e\u0432\u0430\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430\n- \ud83c\udf9b\ufe0f **\u0413\u043e\u0442\u043e\u0432\u044b\u0435 \u043f\u043b\u0435\u0435\u0440\u044b** \u2014 HTML5 \u043f\u043b\u0435\u0435\u0440\u044b \u0441 \u0432\u044b\u0431\u043e\u0440\u043e\u043c \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430\n\n## \ud83d\ude80 \u0411\u044b\u0441\u0442\u0440\u044b\u0439 \u0441\u0442\u0430\u0440\u0442\n\n### \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430\n\n```bash\npip install django-hlsfield\n\npip install django-hlsfield[all]\npip install django-hlsfield[dev]\n```\n\n**\u0422\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f:** ffmpeg \u0438 ffprobe \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u044b \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435\n\n### \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\n\n```python\n# settings.py\nINSTALLED_APPS = [\n # ...\n 'hlsfield',\n]\n\n# \u041e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e: \u043f\u0443\u0442\u0438 \u043a \u0431\u0438\u043d\u0430\u0440\u044f\u043c\nHLSFIELD_FFMPEG = \"ffmpeg\" # \u0438\u043b\u0438 \u043f\u043e\u043b\u043d\u044b\u0439 \u043f\u0443\u0442\u044c\nHLSFIELD_FFPROBE = \"ffprobe\"\n\n# \u041a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 \u0432\u0438\u0434\u0435\u043e (\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e)\nHLSFIELD_DEFAULT_LADDER = [\n {\"height\": 360, \"v_bitrate\": 800, \"a_bitrate\": 96},\n {\"height\": 720, \"v_bitrate\": 2500, \"a_bitrate\": 128},\n {\"height\": 1080, \"v_bitrate\": 4500, \"a_bitrate\": 160},\n]\n```\n\n## \ud83d\udcdd \u041f\u0440\u0438\u043c\u0435\u0440\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f\n\n### 1. \u041f\u0440\u043e\u0441\u0442\u043e\u0435 \u0432\u0438\u0434\u0435\u043e \u0441 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u043c\u0438\n\n```python\n# models.py\nfrom django.db import models\nfrom hlsfield import VideoField\n\nclass Video(models.Model):\n title = models.CharField(max_length=200)\n video = VideoField(\n upload_to=\"videos/\",\n duration_field=\"duration\", # \u0430\u0432\u0442\u043e\u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0434\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438\n width_field=\"width\", # \u0448\u0438\u0440\u0438\u043d\u0430 \u043a\u0430\u0434\u0440\u0430\n height_field=\"height\", # \u0432\u044b\u0441\u043e\u0442\u0430 \u043a\u0430\u0434\u0440\u0430\n preview_field=\"preview_image\" # \u043f\u0443\u0442\u044c \u043a \u043f\u0440\u0435\u0432\u044c\u044e\n )\n\n # \u041f\u043e\u043b\u044f \u0434\u043b\u044f \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445 (\u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e)\n duration = models.DurationField(null=True, blank=True)\n width = models.PositiveIntegerField(null=True, blank=True)\n height = models.PositiveIntegerField(null=True, blank=True)\n preview_image = models.CharField(max_length=500, null=True, blank=True)\n\n# \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\nvideo = Video.objects.get(pk=1)\nprint(f\"\u0414\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c: {video.duration}\")\nprint(f\"\u0420\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435: {video.width}x{video.height}\")\nprint(f\"\u041f\u0440\u0435\u0432\u044c\u044e: {video.video.preview_url()}\")\n```\n\n### 2. HLS \u0430\u0434\u0430\u043f\u0442\u0438\u0432\u043d\u043e\u0435 \u0432\u0438\u0434\u0435\u043e\n\n```python\n# models.py\nfrom hlsfield import HLSVideoField\n\nclass Lecture(models.Model):\n title = models.CharField(max_length=200)\n video = HLSVideoField(\n upload_to=\"lectures/\",\n hls_playlist_field=\"hls_master\" # \u043f\u043e\u043b\u0435 \u0434\u043b\u044f master.m3u8\n )\n hls_master = models.CharField(max_length=500, null=True, blank=True)\n\n# templates/lecture_detail.html\n{% if lecture.video.master_url %}\n {% include \"hlsfield/players/hls_player.html\" with hls_url=lecture.video.master_url %}\n{% else %}\n <p>\u0412\u0438\u0434\u0435\u043e \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f...</p>\n{% endif %}\n```\n\n### 3. \u041f\u043e\u043b\u043d\u044b\u0439 \u0441\u0442\u0435\u043a: HLS + DASH\n\n```python\n# models.py\nfrom hlsfield import AdaptiveVideoField\n\nclass Movie(models.Model):\n title = models.CharField(max_length=200)\n video = AdaptiveVideoField(\n upload_to=\"movies/\",\n hls_playlist_field=\"hls_playlist\",\n dash_manifest_field=\"dash_manifest\",\n ladder=[ # \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\n {\"height\": 480, \"v_bitrate\": 1200, \"a_bitrate\": 96},\n {\"height\": 720, \"v_bitrate\": 2500, \"a_bitrate\": 128},\n {\"height\": 1080, \"v_bitrate\": 4500, \"a_bitrate\": 160},\n ]\n )\n hls_playlist = models.CharField(max_length=500, null=True, blank=True)\n dash_manifest = models.CharField(max_length=500, null=True, blank=True)\n\n# templates/movie_detail.html\n{% include \"hlsfield/players/universal_player.html\" with hls_url=movie.video.master_url dash_url=movie.video.dash_url %}\n```\n\n### 4. \u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0441 S3\n\n```python\n# settings.py\nfrom storages.backends.s3boto3 import S3Boto3Storage\n\nclass MediaStorage(S3Boto3Storage):\n bucket_name = 'my-video-bucket'\n region_name = 'us-east-1'\n\nDEFAULT_FILE_STORAGE = 'myapp.storage.MediaStorage'\n\n# models.py - \u0431\u0435\u0437 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439!\nclass Video(models.Model):\n video = HLSVideoField(upload_to=\"videos/\") # \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 S3 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\n```\n\n### 5. \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 \u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432\n\n```python\n# settings.py\nHLSFIELD_DEFAULT_LADDER = [\n {\"height\": 240, \"v_bitrate\": 300, \"a_bitrate\": 64}, # \u043c\u043e\u0431\u0430\u0439\u043b\n {\"height\": 480, \"v_bitrate\": 1200, \"a_bitrate\": 96}, # SD\n {\"height\": 720, \"v_bitrate\": 2500, \"a_bitrate\": 128}, # HD\n {\"height\": 1080, \"v_bitrate\": 4500, \"a_bitrate\": 160}, # Full HD\n {\"height\": 1440, \"v_bitrate\": 8000, \"a_bitrate\": 192}, # 2K\n]\n\nHLSFIELD_SEGMENT_DURATION = 6 # \u0434\u043b\u0438\u043d\u0430 \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0430\u0445\n\n# models.py - \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u043e\u0435 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u0434\u043b\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044f\nclass PremiumVideo(models.Model):\n video = HLSVideoField(\n ladder=[\n {\"height\": 1080, \"v_bitrate\": 6000, \"a_bitrate\": 160},\n {\"height\": 1440, \"v_bitrate\": 12000, \"a_bitrate\": 192},\n {\"height\": 2160, \"v_bitrate\": 20000, \"a_bitrate\": 256}, # 4K\n ]\n )\n```\n\n## \ud83d\udd27 \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 Celery (\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f)\n\n\u0411\u0435\u0437 Celery \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0432\u0438\u0434\u0435\u043e \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441. \u0421 Celery \u2014 \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u0430\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 + \u0444\u043e\u043d\u043e\u0432\u0430\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430.\n\n```python\n# settings.py\nINSTALLED_APPS = [\n # ...\n 'hlsfield',\n]\n\n# celery.py\nfrom celery import Celery\napp = Celery('myproject')\napp.config_from_object('django.conf:settings', namespace='CELERY')\napp.autodiscover_tasks()\n\n# \u0417\u0430\u043f\u0443\u0441\u043a \u0432\u043e\u0440\u043a\u0435\u0440\u0430\n# celery -A myproject worker -l info\n```\n\n## \ud83c\udfae \u0413\u043e\u0442\u043e\u0432\u044b\u0435 \u043f\u043b\u0435\u0435\u0440\u044b\n\n\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0433\u043e\u0442\u043e\u0432\u044b\u0435 HTML-\u0448\u0430\u0431\u043b\u043e\u043d\u044b \u043f\u043b\u0435\u0435\u0440\u043e\u0432:\n\n```html\n<!-- HLS \u043f\u043b\u0435\u0435\u0440 -->\n{% include \"hlsfield/players/hls_player.html\" with hls_url=video.master_url %}\n\n<!-- DASH \u043f\u043b\u0435\u0435\u0440 -->\n{% include \"hlsfield/players/dash_player.html\" with dash_url=video.dash_url %}\n\n<!-- \u0423\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 (HLS + DASH + \u043f\u0440\u044f\u043c\u043e\u0435 MP4) -->\n{% include \"hlsfield/players/universal_player.html\" with hls_url=... dash_url=... video_url=... %}\n\n<!-- \u0410\u0434\u0430\u043f\u0442\u0438\u0432\u043d\u044b\u0439 (\u0430\u0432\u0442\u043e\u0432\u044b\u0431\u043e\u0440 HLS/DASH) -->\n{% include \"hlsfield/players/adaptive_player.html\" with hls_url=... dash_url=... %}\n```\n\n## \ud83d\udcc1 \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0444\u0430\u0439\u043b\u043e\u0432\n\n\u041f\u043e\u0441\u043b\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432\u0438\u0434\u0435\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:\n\n```\nmedia/\n\u2514\u2500\u2500 videos/\n \u2514\u2500\u2500 abc12345/\n \u251c\u2500\u2500 my_video.mp4 # \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\n \u251c\u2500\u2500 preview.jpg # \u043f\u0440\u0435\u0432\u044c\u044e-\u043a\u0430\u0434\u0440\n \u251c\u2500\u2500 meta.json # \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435\n \u2514\u2500\u2500 hls/ # HLS \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u044b\n \u251c\u2500\u2500 master.m3u8 # \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u043f\u043b\u0435\u0439\u043b\u0438\u0441\u0442\n \u251c\u2500\u2500 v360/ # \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u043e 360p\n \u2502 \u251c\u2500\u2500 index.m3u8\n \u2502 \u2514\u2500\u2500 seg_*.ts\n \u251c\u2500\u2500 v720/ # \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u043e 720p\n \u2502 \u251c\u2500\u2500 index.m3u8\n \u2502 \u2514\u2500\u2500 seg_*.ts\n \u2514\u2500\u2500 v1080/ # \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u043e 1080p\n \u251c\u2500\u2500 index.m3u8\n \u2514\u2500\u2500 seg_*.ts\n```\n\n## \u2699\ufe0f \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f\n\n| \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 | \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e | \u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 |\n|-----------|--------------|----------|\n| `HLSFIELD_FFMPEG` | `\"ffmpeg\"` | \u041f\u0443\u0442\u044c \u043a ffmpeg |\n| `HLSFIELD_FFPROBE` | `\"ffprobe\"` | \u041f\u0443\u0442\u044c \u043a ffprobe |\n| `HLSFIELD_SEGMENT_DURATION` | `6` | \u0414\u043b\u0438\u043d\u0430 HLS \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u043e\u0432 (\u0441\u0435\u043a) |\n| `HLSFIELD_DEFAULT_LADDER` | `[360p, 720p, 1080p]` | \u041a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e |\n| `HLSFIELD_SIDECAR_LAYOUT` | `\"nested\"` | \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0444\u0430\u0439\u043b\u043e\u0432 |\n\n## \ud83d\udc1b \u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\n\n### FFmpeg \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\n```bash\n# Ubuntu/Debian\nsudo apt update && sudo apt install ffmpeg\n\n# macOS\nbrew install ffmpeg\n\n# Windows\n# \u0421\u043a\u0430\u0447\u0430\u0442\u044c \u0441 https://ffmpeg.org/download.html\n```\n\n### \u0411\u043e\u043b\u044c\u0448\u0438\u0435 \u0444\u0430\u0439\u043b\u044b \u0437\u0430\u0432\u0438\u0441\u0430\u044e\u0442\n```python\n# settings.py - \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0442\u044c \u0442\u0430\u0439\u043c\u0430\u0443\u0442\u044b\nFILE_UPLOAD_MAX_MEMORY_SIZE = 100 * 1024 * 1024 # 100MB\nDATA_UPLOAD_MAX_MEMORY_SIZE = 100 * 1024 * 1024\n```\n\n### \u041f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0441 S3\n```python\n# \u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043f\u0440\u0430\u0432\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a bucket\nAWS_S3_FILE_OVERWRITE = False\nAWS_DEFAULT_ACL = 'public-read' # \u0434\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0445 \u0432\u0438\u0434\u0435\u043e\n```\n\n## \ud83e\udd1d \u0412\u043a\u043b\u0430\u0434 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\n\n1. Fork \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f\n2. \u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0432\u0435\u0442\u043a\u0443: `git checkout -b feature/amazing-feature`\n3. Commit \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f: `git commit -m 'Add amazing feature'`\n4. Push \u0432 \u0432\u0435\u0442\u043a\u0443: `git push origin feature/amazing-feature`\n5. \u041e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 Pull Request\n\n## \ud83d\udcc4 \u041b\u0438\u0446\u0435\u043d\u0437\u0438\u044f\n\nMIT License. \u0421\u043c. [LICENSE](LICENSE) \u0434\u043b\u044f \u0434\u0435\u0442\u0430\u043b\u0435\u0439.\n\n## \ud83c\udfaf Roadmap\n\n- [ ] \u0410\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b \u0438 CI/CD\n- [ ] WebVTT \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044b \u0438 \u043f\u0440\u0435\u0432\u044c\u044e-\u0441\u043f\u0440\u0430\u0439\u0442\u044b\n- [ ] GPU-\u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435 \u0447\u0435\u0440\u0435\u0437 NVENC/VAAPI\n- [ ] \u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 HEVC/AV1 \u043a\u043e\u0434\u0435\u043a\u043e\u0432\n- [ ] \u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0441 CDN (CloudFront, Cloudflare)\n\n---\n\n**\u0421\u0434\u0435\u043b\u0430\u043d\u043e \u0441 \u2764\ufe0f \u0434\u043b\u044f Django-\u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0430**\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Django VideoField + HLSVideoField: metadata, preview frame, automatic HLS/DASH, Celery optional.",
"version": "1.0.4",
"project_urls": {
"Bug Reports": "https://github.com/akula993/django-hlsfield/issues",
"Changelog": "https://github.com/akula993/django-hlsfield/blob/main/CHANGELOG.md",
"Documentation": "https://django-hlsfield.readthedocs.io/",
"Funding": "https://github.com/sponsors/akula993",
"Homepage": "https://github.com/akula993/django-hlsfield",
"Issues": "https://github.com/akula993/django-hlsfield/issues",
"Repository": "https://github.com/akula993/django-hlsfield.git",
"Source Code": "https://github.com/akula993/django-hlsfield"
},
"split_keywords": [
"adaptive",
" dash",
" django",
" ffmpeg",
" hls",
" streaming",
" video"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "71d5e297c4c00ff062b44ce32fb8c2e9cbea18d1fbccb4bd39227f359ab82e7a",
"md5": "51b00661f2fd4e03ad99153e9a902cb1",
"sha256": "e37285b97407cc7d13ce34e0ca04a4f35e10018b556244e8a98baf67d219a992"
},
"downloads": -1,
"filename": "django_hlsfield-1.0.4-py3-none-any.whl",
"has_sig": false,
"md5_digest": "51b00661f2fd4e03ad99153e9a902cb1",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 123255,
"upload_time": "2025-09-01T07:52:50",
"upload_time_iso_8601": "2025-09-01T07:52:50.680529Z",
"url": "https://files.pythonhosted.org/packages/71/d5/e297c4c00ff062b44ce32fb8c2e9cbea18d1fbccb4bd39227f359ab82e7a/django_hlsfield-1.0.4-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "ff002351405f4089f092f4cd16c4f5641d25c29132550ce1ff2133249959d277",
"md5": "0239a99e93658cb16f570ce52ed1b0a7",
"sha256": "0a1ff2e56632ddcf1598bc675e3dac717793f7b0ebc0193b68d6a484e247aef7"
},
"downloads": -1,
"filename": "django_hlsfield-1.0.4.tar.gz",
"has_sig": false,
"md5_digest": "0239a99e93658cb16f570ce52ed1b0a7",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 119030,
"upload_time": "2025-09-01T07:52:52",
"upload_time_iso_8601": "2025-09-01T07:52:52.261351Z",
"url": "https://files.pythonhosted.org/packages/ff/00/2351405f4089f092f4cd16c4f5641d25c29132550ce1ff2133249959d277/django_hlsfield-1.0.4.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-09-01 07:52:52",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "akula993",
"github_project": "django-hlsfield",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"tox": true,
"lcname": "django-hlsfield"
}