From 8a10fca21255fee635d67463d559532c4509026f Mon Sep 17 00:00:00 2001 From: Aymen Fnayou Date: Sun, 25 Oct 2026 07:07:10 +0100 Subject: [PATCH 1/2] docs: publish searchable project site --- .github/workflows/deploy-docs.yml | 61 ++++++++++++++++++++++++++++ .gitignore | 3 ++ README.md | 2 + requirements-docs.txt | 1 + site-docs/authentication.md | 48 ++++++++++++++++++++++ site-docs/community.md | 21 ++++++++++ site-docs/getting-started.md | 44 ++++++++++++++++++++ site-docs/index.md | 37 +++++++++++++++++ site-docs/manifest.md | 44 ++++++++++++++++++++ site-docs/reliability.md | 35 ++++++++++++++++ site-docs/stylesheets/catppuccin.css | 24 +++++++++++ site-docs/troubleshooting.md | 39 ++++++++++++++++++ zensical.toml | 28 +++++++++++++ 13 files changed, 387 insertions(+) create mode 100644 .github/workflows/deploy-docs.yml create mode 100644 requirements-docs.txt create mode 100644 site-docs/authentication.md create mode 100644 site-docs/community.md create mode 100644 site-docs/getting-started.md create mode 100644 site-docs/index.md create mode 100644 site-docs/manifest.md create mode 100644 site-docs/reliability.md create mode 100644 site-docs/stylesheets/catppuccin.css create mode 100644 site-docs/troubleshooting.md create mode 100644 zensical.toml diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml new file mode 100644 index 0000000..a9fc084 --- /dev/null +++ b/.github/workflows/deploy-docs.yml @@ -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 diff --git a/.gitignore b/.gitignore index 1314a9f..a2734c4 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ __pycache__/ .DS_Store .idea/ .vscode/ + +# Generated Zensical site output +/site/ diff --git a/README.md b/README.md index 54a6b3d..adbfba5 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/requirements-docs.txt b/requirements-docs.txt new file mode 100644 index 0000000..0d62b74 --- /dev/null +++ b/requirements-docs.txt @@ -0,0 +1 @@ +zensical==0.0.72 diff --git a/site-docs/authentication.md b/site-docs/authentication.md new file mode 100644 index 0000000..7d26d48 --- /dev/null +++ b/site-docs/authentication.md @@ -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 + +- Sensitive signed URLs may expose credentials in logs or state; handle with care. +- Local processes may inspect credential-bearing FFmpeg arguments while FFmpeg runs. + +See [Reliability](reliability.md) for state and retries. diff --git a/site-docs/community.md b/site-docs/community.md new file mode 100644 index 0000000..46602a5 --- /dev/null +++ b/site-docs/community.md @@ -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: +- Issues: + +Public documentation lives in `site-docs/`. Repository-internal guidance is not published. diff --git a/site-docs/getting-started.md b/site-docs/getting-started.md new file mode 100644 index 0000000..107024b --- /dev/null +++ b/site-docs/getting-started.md @@ -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 up +``` + +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 the JSON manifest at `in/stream-list.json`. +- Outputs are written to `out/`. +- Per-item progress state is kept under `progress/`. + +## 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. diff --git a/site-docs/index.md b/site-docs/index.md new file mode 100644 index 0000000..c3ba794 --- /dev/null +++ b/site-docs/index.md @@ -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. Create a manifest at `in/stream-list.json`. +2. Run ffmpegfyMe. +3. Finished files appear in `out/`. + +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. diff --git a/site-docs/manifest.md b/site-docs/manifest.md new file mode 100644 index 0000000..a5d0084 --- /dev/null +++ b/site-docs/manifest.md @@ -0,0 +1,44 @@ +# Manifest + +The manifest is a JSON list of items. Each item requires `url` and `output`. + +## Fields + +| Field | Required | Optional | Notes | +|---|---|---|---| +| `url` | yes | no | HTTP(S) media URL, commonly an `.m3u8` playlist | +| `output` | yes | no | Output filename, not a path; must end in `.mp4` or `.mkv` | +| `id` | no | no | Safe, public stable identifier | +| `headers` | no | no | Header references, e.g. auth headers | +| `cookies` | no | no | Cookie 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. + +## 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. diff --git a/site-docs/reliability.md b/site-docs/reliability.md new file mode 100644 index 0000000..60e5068 --- /dev/null +++ b/site-docs/reliability.md @@ -0,0 +1,35 @@ +# Reliability + +## Retries + +The app makes an initial attempt plus up to two retries, with short backoff delays. + +A timed-out attempt is retried under the same policy as other failures. + +## 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). diff --git a/site-docs/stylesheets/catppuccin.css b/site-docs/stylesheets/catppuccin.css new file mode 100644 index 0000000..cf16aef --- /dev/null +++ b/site-docs/stylesheets/catppuccin.css @@ -0,0 +1,24 @@ +/* Catppuccin Macchiato for Zensical (Material) */ +[data-md-color-scheme="macchiato"] { + --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-primary-fg-color: #8aadf4; + --md-primary-bg-color: #8aadf4; + --md-primary-bg-color--light: #8aadf4; + --md-accent-fg-color: #8aadf4; + --md-accent-bg-color: #8aadf4; + --md-accent-fg-color--transparent: rgba(138, 173, 244, 0.1); + --md-footer-bg-color: #1e2030; +} diff --git a/site-docs/troubleshooting.md b/site-docs/troubleshooting.md new file mode 100644 index 0000000..bd52d09 --- /dev/null +++ b/site-docs/troubleshooting.md @@ -0,0 +1,39 @@ +# Troubleshooting + +## Missing FFmpeg + +Check FFmpeg is installed and on `PATH`. + +```bash +ffmpeg -version +``` + +## Invalid manifest, URL, or output + +Check JSON validity, required fields, HTTP(S) URLs, output extension, and filename-only output rule. + +## Missing auth environment values + +Check that required `${ENV_NAME}` references are exported or present in `.env`. + +## Output conflicts + +Existing outputs are never silently overwritten. + +Manual mode asks before overwrite. Automatic mode records a conflict/failure and continues. + +## Inactivity timeouts + +Default is 60 seconds. Any FFmpeg output resets it. + +Set `FFMPEG_INACTIVITY_TIMEOUT` to a finite positive number. + +## Unsupported codecs/container combinations + +ffmpegfyMe does not transcode. Stream copy (`-c copy`) requires source and container compatibility. + +## Saved or legacy progress + +Check `progress/` state. Legacy `last_index` state requires an explicit reset choice. + +See [Reliability](reliability.md). diff --git a/zensical.toml b/zensical.toml new file mode 100644 index 0000000..0bf7998 --- /dev/null +++ b/zensical.toml @@ -0,0 +1,28 @@ +[project] +site_name = "ffmpegfyMe" +site_url = "https://fnayou.github.io/ffmpegfyMe/" +site_description = "Interactive or batch Python wrapper around FFmpeg for downloading HTTP and HTTPS media streams, commonly HLS playlists, and copying them into MP4 or MKV containers." +docs_dir = "site-docs" +site_dir = "site" +repo_url = "https://github.com/fnayou/ffmpegfyMe" + +nav = [ + { "Home" = "index.md" }, + { "Getting Started" = "getting-started.md" }, + { "Manifest" = "manifest.md" }, + { "Authentication" = "authentication.md" }, + { "Reliability" = "reliability.md" }, + { "Troubleshooting" = "troubleshooting.md" }, + { "Community" = "community.md" }, +] + +extra_css = ["stylesheets/catppuccin.css"] + +[project.theme] +language = "en" +palette = [ + { scheme = "macchiato", primary = "custom", accent = "custom" }, +] + +[project.theme.icon] +repo = "fontawesome/brands/github" From fc29991bbdb4ab0568f6a9a6e22cb8dfb3fa10b8 Mon Sep 17 00:00:00 2001 From: Aymen Fnayou Date: Sun, 25 Oct 2026 07:22:07 +0100 Subject: [PATCH 2/2] docs: clarify usage and limits --- site-docs/authentication.md | 2 +- site-docs/getting-started.md | 8 +++---- site-docs/index.md | 6 ++--- site-docs/manifest.md | 21 +++++++++++------ site-docs/reliability.md | 4 ++-- site-docs/stylesheets/catppuccin.css | 34 +++++++++++++++++++++++++--- site-docs/troubleshooting.md | 2 +- 7 files changed, 56 insertions(+), 21 deletions(-) diff --git a/site-docs/authentication.md b/site-docs/authentication.md index 7d26d48..bc6214b 100644 --- a/site-docs/authentication.md +++ b/site-docs/authentication.md @@ -42,7 +42,7 @@ A direct local Python run needs the variables exported in the process environmen ## Caveats -- Sensitive signed URLs may expose credentials in logs or state; handle with care. +- 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. diff --git a/site-docs/getting-started.md b/site-docs/getting-started.md index 107024b..81bd938 100644 --- a/site-docs/getting-started.md +++ b/site-docs/getting-started.md @@ -12,7 +12,7 @@ The project provides a Compose service named `ffmpegfy-me`. ```bash docker compose build -docker compose up +docker compose run --rm ffmpegfy-me ``` The service mounts `in/`, `out/`, and `progress/`, and optionally loads a @@ -31,9 +31,9 @@ FFmpeg must be on `PATH`. ## Input, output, and progress -- Place the JSON manifest at `in/stream-list.json`. -- Outputs are written to `out/`. -- Per-item progress state is kept under `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//`, where `` is the selected file name without `.json`. +- Per-item progress is stored in `progress/_state.json`. ## Interactive prompts diff --git a/site-docs/index.md b/site-docs/index.md index c3ba794..a93db5d 100644 --- a/site-docs/index.md +++ b/site-docs/index.md @@ -19,9 +19,9 @@ commonly HLS playlists, and saving them into local media files. ## Workflow at a glance -1. Create a manifest at `in/stream-list.json`. -2. Run ffmpegfyMe. -3. Finished files appear in `out/`. +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//` default. See [Getting Started](getting-started.md) for setup and [Manifest](manifest.md) for the input format. diff --git a/site-docs/manifest.md b/site-docs/manifest.md index a5d0084..abd224e 100644 --- a/site-docs/manifest.md +++ b/site-docs/manifest.md @@ -4,13 +4,13 @@ The manifest is a JSON list of items. Each item requires `url` and `output`. ## Fields -| Field | Required | Optional | Notes | -|---|---|---|---| -| `url` | yes | no | HTTP(S) media URL, commonly an `.m3u8` playlist | -| `output` | yes | no | Output filename, not a path; must end in `.mp4` or `.mkv` | -| `id` | no | no | Safe, public stable identifier | -| `headers` | no | no | Header references, e.g. auth headers | -| `cookies` | no | no | Cookie reference | +| 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 @@ -23,6 +23,13 @@ The manifest is a JSON list of items. Each item requires `url` and `output`. - 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. diff --git a/site-docs/reliability.md b/site-docs/reliability.md index 60e5068..1ce421f 100644 --- a/site-docs/reliability.md +++ b/site-docs/reliability.md @@ -2,9 +2,9 @@ ## Retries -The app makes an initial attempt plus up to two retries, with short backoff delays. +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. -A timed-out attempt is retried under the same policy as other failures. +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 diff --git a/site-docs/stylesheets/catppuccin.css b/site-docs/stylesheets/catppuccin.css index cf16aef..20c823d 100644 --- a/site-docs/stylesheets/catppuccin.css +++ b/site-docs/stylesheets/catppuccin.css @@ -1,5 +1,7 @@ /* 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; @@ -10,15 +12,41 @@ --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: #8aadf4; - --md-primary-bg-color--light: #8aadf4; + --md-primary-bg-color: #24273a; + --md-primary-bg-color--light: #24273a; --md-accent-fg-color: #8aadf4; - --md-accent-bg-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; } diff --git a/site-docs/troubleshooting.md b/site-docs/troubleshooting.md index bd52d09..9deb021 100644 --- a/site-docs/troubleshooting.md +++ b/site-docs/troubleshooting.md @@ -14,7 +14,7 @@ Check JSON validity, required fields, HTTP(S) URLs, output extension, and filena ## Missing auth environment values -Check that required `${ENV_NAME}` references are exported or present in `.env`. +For Compose, check that required `${ENV_NAME}` values are present in `.env`. For direct local Python runs, export each variable in the shell before starting the app; local Python use does not load `.env`. ## Output conflicts