django-hlsfield


Namedjango-hlsfield JSON
Version 1.0.4 PyPI version JSON
download
home_pageNone
SummaryDjango VideoField + HLSVideoField: metadata, preview frame, automatic HLS/DASH, Celery optional.
upload_time2025-09-01 07:52:52
maintainerNone
docs_urlNone
authorNone
requires_python>=3.10
licenseMIT
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

[![PyPI version](https://badge.fury.io/py/django-hlsfield.svg)](https://badge.fury.io/py/django-hlsfield)
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
[![Django 4.2+](https://img.shields.io/badge/django-4.2+-green.svg)](https://www.djangoproject.com/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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[![PyPI version](https://badge.fury.io/py/django-hlsfield.svg)](https://badge.fury.io/py/django-hlsfield)\n[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)\n[![Django 4.2+](https://img.shields.io/badge/django-4.2+-green.svg)](https://www.djangoproject.com/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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"
}
        
Elapsed time: 1.36350s