Metadata-Version: 2.4
Name: pyhlsify
Version: 0.1.0
Summary: Convert any video to adaptive-bitrate HLS (fMP4) with a single function call.
License: MIT
Project-URL: Homepage, https://github.com/yourusername/pyhlsify
Project-URL: Issues, https://github.com/yourusername/pyhlsify/issues
Keywords: hls,video,streaming,ffmpeg,adaptive-bitrate,m3u8,mp4
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Multimedia :: Video :: Conversion
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: black>=23.0; extra == "dev"
Requires-Dist: ruff>=0.1; extra == "dev"
Dynamic: license-file

# pyhlsify

Convert any video to **adaptive-bitrate HLS** (fMP4 segments) with a single Python function call.

```python
from pyhlsify import convert

master = convert("movie.mp4", "output/")
print(f"Ready to stream: {master}")
```

---

## Requirements

- Python 3.10+
- **FFmpeg** installed and available on your system `PATH`
  - Download from [ffmpeg.org](https://ffmpeg.org/download.html)
  - macOS: `brew install ffmpeg`
  - Ubuntu/Debian: `sudo apt install ffmpeg`
  - Windows: download from the FFmpeg site and add `bin/` to PATH

---

## Installation

```bash
pip install pyhlsify
```

---

## Quick Start

### One-liner conversion (default quality ladder)

```python
from pyhlsify import convert

convert("myvideo.mp4", "hls_output/")
```

This produces:

```
hls_output/
└── myvideo/
    ├── master.m3u8   ← point your player here
    ├── 1080p/
    │   ├── index.m3u8
    │   ├── init.mp4
    │   └── segment_000.m4s …
    ├── 720p/  …
    ├── 480p/  …
    └── 360p/  …
```

### Custom quality ladder

```python
from pyhlsify import convert, VariantConfig

convert(
    "myvideo.mp4",
    "hls_output/",
    variants=[
        VariantConfig("1080p", 1080, "5000k", "5350k", "7500k", "192k"),
        VariantConfig("720p",  720,  "2800k", "2996k", "4200k", "128k"),
        VariantConfig("480p",  480,  "1400k", "1498k", "2100k", "128k"),
    ],
)
```

### Parallel encoding (faster on multi-core machines)

```python
from pyhlsify import convert

convert("myvideo.mp4", "hls_output/", workers=4)
```

### Re-encode an existing output

```python
convert("myvideo.mp4", "hls_output/", overwrite=True)
```

---

## API Reference

### `convert(input_path, output_dir, variants=None, workers=1, overwrite=False)`

| Parameter    | Type                    | Default            | Description                                              |
|-------------|-------------------------|--------------------|----------------------------------------------------------|
| `input_path` | `str \| Path`          | —                  | Path to the source video file.                           |
| `output_dir` | `str \| Path`          | —                  | Directory where HLS output will be written.              |
| `variants`   | `list[VariantConfig]`  | `DEFAULT_VARIANTS` | Quality ladder. See below.                               |
| `workers`    | `int`                  | `1`                | Number of variants to encode in parallel.                |
| `overwrite`  | `bool`                 | `False`            | Re-encode even if output already exists.                 |

**Returns:** `Path` to the generated `master.m3u8`.

**Raises:**
- `FileNotFoundError` — source video not found.
- `RuntimeError` — ffmpeg not installed, or encoding failed.

---

### `VariantConfig`

```python
@dataclass
class VariantConfig:
    label:         str           # e.g. "720p"
    height:        int           # target height in pixels
    video_bitrate: str           # e.g. "2800k"
    max_bitrate:   str           # e.g. "2996k"
    buf_size:      str           # VBV buffer, e.g. "4200k"
    audio_bitrate: str           # e.g. "128k"
    bandwidth:     int | None    # optional; auto-computed when None
```

---

### `DEFAULT_VARIANTS`

| Label  | Height | Video bitrate | Audio bitrate |
|--------|--------|--------------|---------------|
| 1080p  | 1080   | 5000 kbps    | 192 kbps      |
| 720p   | 720    | 2800 kbps    | 128 kbps      |
| 480p   | 480    | 1400 kbps    | 128 kbps      |
| 360p   | 360    | 800 kbps     |  96 kbps      |

---

## Output format

- Container: **fMP4** segments (`.m4s`) with a separate init segment (`init.mp4`)
- Video codec: **H.264** (libx264, High profile, level 4.0)
- Audio codec: **AAC** (48 kHz, stereo)
- Segment duration: **4 seconds**
- Playlist type: **VOD**

---

## Publishing to PyPI

```bash
# Install build tools
pip install build twine

# Build
cd pyhlsify/
python -m build

# Upload (you need a PyPI account)
twine upload dist/*
```

---

## License

MIT
