Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions .github/workflows/deploy-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: Deploy Docs

on:
push:
branches:
- main
paths:
- "site-docs/**"
- "zensical.toml"
- "requirements-docs.txt"
- ".github/workflows/deploy-docs.yml"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: pages
cancel-in-progress: false

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Configure Pages
uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0

- name: Set up Python
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: "3.11"

- name: Install docs dependencies
run: python -m pip install -r requirements-docs.txt

- name: Build site
run: zensical build --strict

- name: Upload Pages artifact
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
with:
path: site/

deploy:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
contents: read
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ __pycache__/
.DS_Store
.idea/
.vscode/

# Generated Zensical site output
/site/
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
**ffmpegfyMe** is a Dockerized Python CLI tool for downloading streaming media (e.g. `.m3u8`) using `ffmpeg`.
It offers interactive or batch downloading, progress tracking, retry logic, and state persistence.

[Documentation](https://fnayou.github.io/ffmpegfyMe/)

---

## Features
Expand Down
1 change: 1 addition & 0 deletions requirements-docs.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
zensical==0.0.72
48 changes: 48 additions & 0 deletions site-docs/authentication.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Authentication

Protected sources may require HTTP header or cookie auth.

## Environment references

Auth values use exact environment references such as `${API_TOKEN}`.

```json
{
"headers": {
"Authorization": "${API_TOKEN}"
},
"cookies": "${SESSION_COOKIE}"
}
```

A prefix such as `Bearer ${API_TOKEN}` is invalid. References must be exact.

Header values map header names to references.

`cookies` takes one reference.

## Configuration

Compose loads a git-ignored `.env` file and injects values via `env_file`.

A direct local Python run needs the variables exported in the process environment.

## Secrets

- No real secrets in examples.
- Use placeholder values only.
- Credentials do not belong in the manifest; only `${ENV_NAME}` placeholders.

## Privacy

- The CLI redacts HTTP(S) URLs and resolved header/cookie values from displayed
FFmpeg output.
- Progress state stores item status/output and an identity key, not raw manifest
URLs or credentials.

## Caveats

- Signed URLs remain in plaintext in the manifest file. Protect that file and avoid sharing or committing URLs that contain credentials.
- Local processes may inspect credential-bearing FFmpeg arguments while FFmpeg runs.

See [Reliability](reliability.md) for state and retries.
21 changes: 21 additions & 0 deletions site-docs/community.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Community

## Participate

- Report issues via GitHub Issues.
- Review the community health files.

## Community and license files

- [Code of Conduct](https://github.com/fnayou/ffmpegfyMe/blob/main/CODE_OF_CONDUCT.md)
- [Contributing](https://github.com/fnayou/ffmpegfyMe/blob/main/CONTRIBUTING.md)
- [Security](https://github.com/fnayou/ffmpegfyMe/blob/main/SECURITY.md)
- [Support](https://github.com/fnayou/ffmpegfyMe/blob/main/SUPPORT.md)
- [License](https://github.com/fnayou/ffmpegfyMe/blob/main/LICENSE)

## Project links

- Repository: <https://github.com/fnayou/ffmpegfyMe>
- Issues: <https://github.com/fnayou/ffmpegfyMe/issues>

Public documentation lives in `site-docs/`. Repository-internal guidance is not published.
44 changes: 44 additions & 0 deletions site-docs/getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Getting Started

## Prerequisites

- Python 3.11+
- FFmpeg installed and available on `PATH`
- Docker Engine and Docker Compose (optional, for container use)

## Docker Compose

The project provides a Compose service named `ffmpegfy-me`.

```bash
docker compose build
docker compose run --rm ffmpegfy-me
```

The service mounts `in/`, `out/`, and `progress/`, and optionally loads a
git-ignored `.env` file for credentials.

## Direct local use

```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python ffmpegfyMe.py
```

FFmpeg must be on `PATH`.

## Input, output, and progress

- Place one or more JSON manifest files in `in/`. The app lists `in/*.json` and prompts you to choose one.
- The app prompts for an output directory. Its default is `out/<manifest-name>/`, where `<manifest-name>` is the selected file name without `.json`.
- Per-item progress is stored in `progress/<manifest-name>_state.json`.

## Interactive prompts

ffmpegfyMe has no command-line argument parser and no command flags.

Use the interactive prompts to configure batches and overwrite behavior.

See [Manifest](manifest.md) for the input format.
37 changes: 37 additions & 0 deletions site-docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# ffmpegfyMe

**ffmpegfyMe** is an interactive or batch Python wrapper around
[FFmpeg](https://ffmpeg.org/) for downloading HTTP and HTTPS media streams,
commonly HLS playlists, and saving them into local media files.

## What it does

- Downloads HTTP/HTTPS media streams, commonly HLS (`.m3u8`) playlists.
- Copies the stream into an `.mp4` or `.mkv` container using FFmpeg stream copy
(`-c copy`).
- Supports interactive or batch mode, progress tracking, retries, and saved state.

## Why use it

- One tool wraps the heavy lifting: playlist handling, retries, progress, and state.
- Stream copy means no transcoding step.
- Works with Docker or a local Python environment.

## Workflow at a glance

1. Add one or more JSON manifests to `in/`.
2. Run ffmpegfyMe and choose a manifest when prompted.
3. Choose an output directory or accept the `out/<manifest-name>/` default.

See [Getting Started](getting-started.md) for setup and
[Manifest](manifest.md) for the input format.

## MP4/MKV and stream copy

ffmpegfyMe does **not** transcode. FFmpeg uses stream copy (`-c copy`).

Success depends on the source streams being compatible with the chosen container.
An `.mp4` or `.mkv` output is required; unsupported codec or container combinations
fail and are reported per item.

See [Troubleshooting](troubleshooting.md) for common failures.
51 changes: 51 additions & 0 deletions site-docs/manifest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Manifest

The manifest is a JSON list of items. Each item requires `url` and `output`.

## Fields

| Field | Required | Notes |
|---|---|---|
| `url` | yes | HTTP(S) media URL, commonly an `.m3u8` playlist |
| `output` | yes | Output filename, not a path; must end in `.mp4` or `.mkv` |
| `id` | no | Optional stable identifier, subject to the format and length limit below |
| `headers` | no | Optional header names mapped to environment references |
| `cookies` | no | Optional single environment reference |

## Rules

- Unknown fields are rejected.
- Duplicate IDs are rejected.
- Duplicate output destinations are rejected (case-insensitive).
- Only HTTP and HTTPS URLs are allowed.
- Userinfo in URLs is rejected.
- Unsafe output paths are rejected.
- Output extensions other than MP4/MKV are rejected.
- Output is a filename, not a path.

## Processing limits

- Input URLs must use HTTP or HTTPS. Playlist segments may use HTTP, HTTPS, TCP, TLS, or crypto protocols.
- Subtitle and data streams are not copied. Media streams are copied without transcoding.
- Stable IDs must match `[A-Za-z0-9][A-Za-z0-9._-]*` and be no longer than 128 characters.
- Header names must be valid HTTP token names and unique without regard to case.

## Stable IDs

An explicit `id` must be safe and public.

Without an explicit `id`, identity is derived from the URL and output.

## Example

```json
[
{
"url": "https://cdn.example.com/video1.m3u8",
"output": "video1.mp4",
"id": "video-1"
}
]
```

Use placeholder URLs and identifiers only.
35 changes: 35 additions & 0 deletions site-docs/reliability.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Reliability

## Retries

The app makes an initial attempt plus up to two retries. Backoff waits are 1.5–2.5 seconds before the first retry and 5–7 seconds before the second.

Inactivity timeouts and other FFmpeg download failures use this retry policy. Authentication configuration errors, FFmpeg process-start errors, and failures to move a completed output into place are not retried.

## Inactivity timeout

- Default inactivity timeout: 60 seconds.
- Any FFmpeg output resets the timer.
- Set with `FFMPEG_INACTIVITY_TIMEOUT`.
- Must be a finite positive number.

Invalid, non-finite, zero, and negative values produce a clear error before batch processing.

## No total-download cap

There is no total-download time limit by default.

## Progress and state

- Per-item progress lives under `progress/`.
- Legacy `last_index` state is detected and requires an explicit reset choice.

A successful item is skipped only when its saved state says success and the output
file still exists.

Existing outputs are never silently overwritten.

- Manual mode asks before overwrite.
- Automatic mode records a conflict/failure and continues.

See [Troubleshooting](troubleshooting.md).
52 changes: 52 additions & 0 deletions site-docs/stylesheets/catppuccin.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* Catppuccin Macchiato for Zensical (Material) */
[data-md-color-scheme="macchiato"] {
color-scheme: dark;

--md-default-fg-color: #cad3f5;
--md-default-fg-color--light: #b8c0e0;
--md-default-fg-color--lighter: #a5adcb;
--md-default-fg-color--lightest: #6e738d;
--md-default-bg-color: #24273a;
--md-default-bg-color--light: #24273a;
--md-default-bg-color--lighter: #1e2030;
--md-default-bg-color--lightest: #181926;
--md-typeset-color: #cad3f5;
--md-typeset-a-color: #8aadf4;

--md-code-fg-color: #cad3f5;
--md-code-bg-color: #1e2030;
--md-code-bg-color--light: #1e2030;
--md-code-bg-color--lighter: #181926;
--md-code-hl-color: #8aadf4;
--md-code-hl-color--light: rgba(138, 173, 244, 0.1);
--md-code-hl-comment-color: #6e738d;
--md-code-hl-constant-color: #f5a97f;
--md-code-hl-function-color: #8aadf4;
--md-code-hl-generic-color: #b8c0e0;
--md-code-hl-keyword-color: #c6a0f6;
--md-code-hl-name-color: #cad3f5;
--md-code-hl-number-color: #f5a97f;
--md-code-hl-operator-color: #91d7e3;
--md-code-hl-punctuation-color: #b8c0e0;
--md-code-hl-special-color: #f5bde6;
--md-code-hl-string-color: #a6da95;
--md-code-hl-variable-color: #ee99a0;

--md-primary-fg-color: #8aadf4;
--md-primary-bg-color: #24273a;
--md-primary-bg-color--light: #24273a;
--md-accent-fg-color: #8aadf4;
--md-accent-bg-color: #24273a;
--md-accent-bg-color--light: #24273a;
--md-accent-fg-color--transparent: rgba(138, 173, 244, 0.1);

--md-admonition-bg-color: #363a4f;
--md-admonition-fg-color: #cad3f5;
--md-typeset-mark-color: #5b6078;
--md-typeset-kbd-color: #cad3f5;
--md-typeset-kbd-border-color: #6e738d;
--md-typeset-kbd-accent-color: #363a4f;

--md-footer-bg-color: #1e2030;
--md-footer-bg-color--dark: #181926;
}
Loading
Loading