Metadata-Version: 2.4
Name: pretix-video-header
Version: 1.1.1
Summary: Replace the image / gif with a HTML5 video element
Author-email: Daniel Malik <mail@fronbasal.de>
Maintainer-email: Daniel Malik <mail@fronbasal.de>
License: Apache
Project-URL: homepage, https://git.binarycollective.de/binary-pretix-plugins/pretix-video-header
Project-URL: repository, https://git.binarycollective.de/binary-pretix-plugins/pretix-video-header
Keywords: pretix
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

---
title: Pretix Video Header
---

A plugin for [pretix](https://github.com/pretix/pretix) that shows a video banner on the event
shop page: a fixed-aspect box at the bottom of the page into which the banner plays **in the page
itself** — no iframe, no third-party requests, no layout shift.

## How it works

- **HLS is the primary mode.** The banner plays an HLS **master playlist** (any source: your own
  CDN, a video platform, or the
  [video header service](https://git.binarycollective.de/binary-hls-header) master playlist) with
  **adaptive bitrate**: on fast connections the top variant, on slow ones the lower-bitrate
  variants. All variants are the *same resolution* (the service encodes a same-resolution,
  multi-bitrate ladder), so quality never visibly shrinks — only the bitrate steps down.
- **Playback is handled by the page.** A self-hosted, pinned copy of
  [hls.js](https://github.com/video-dev/hls.js) (1.7.4, bundled in `static/pretix_video/js/`) plays
  the master where supported; Safari and iOS use native HLS. If the stream cannot be played at all,
  a direct video URL (if configured) is the last resort.
- **No CLS.** The box reserves its space up front via CSS `aspect-ratio` (the *Banner aspect
  ratio* setting, default `1140 / 240`), so the page layout is final before the first frame
  arrives. The video is letterboxed inside with `object-fit: contain`.

## Settings

Event settings → *Video Header*:

| Field | Meaning |
| --- | --- |
| **HLS stream URL (master playlist)** | The m3u8 the banner plays. Primary mode; any HLS source works. |
| **Banner aspect ratio** | CSS aspect ratio of the banner box, e.g. `1140 / 240` (default) or `16 / 9`. Use the ratio of the encoded banner for a tight fit. |
| **Direct video URL (fallback)** | A direct MP4/WebM link. Used when no HLS stream is set, and as a last resort if the stream cannot play. |
| **Autoplay / Loop / Muted / Show controls** | Playback behaviour. The shop-header defaults are autoplay, loop, muted. |

## Using it with the video header service

1. Upload the clip in the
   [video header service](https://git.binarycollective.de/binary-hls-header) UI and wait for the
   encode to succeed.
2. Open the header's detail view. The **Pretix plugin** section shows exactly the two values the
   event settings ask for — **Master playlist** (the immutable
   `…/assets/<header_id>/<revision>/master.m3u8` URL) and **Aspect ratio** — each with a copy
   button.
3. Paste them into *HLS stream URL (master playlist)* and *Banner aspect ratio*.

No service URL, header ID or iframe is involved: the shop page fetches the playlist and segments
directly, and the master URL stays valid across re-encodes of the same revision.

## Content security policy

The plugin adds only what the media needs:

- `media-src` for the stream/video origin (native `<video>` playback),
- `connect-src` for the **HLS** origin only (hls.js fetches the playlist and segments via XHR).

No inline scripts are used — `hls.min.js` and `video-header.js` are same-origin static files — so
no `script-src` exception is required. If your pretix instance rewrites the CSP, keep those two
directives for the stream origin.

## Migration notes (1.1.0)

- The service-iframe mode (`Service URL` + `Header ID`) is **removed**: embeds via an iframe caused
  layout shift and a second full playback stack. Use the master playlist URL instead (see above).
- The legacy "replace the event logo" inline script is **removed**; the banner is its own
  fixed-aspect box regardless of mode.
- Settings that stored `service_url`/`header_id` keep working (the values are ignored); re-point
  the event at the master playlist URL.

# Development setup

1.  Make sure that you have a working [pretix development
    setup](https://docs.pretix.eu/en/latest/development/setup.html).
2.  Clone this repository.
3.  Activate the virtual environment you use for pretix development.
4.  Execute `python setup.py develop` within this directory to register
    this application with pretix's plugin registry.
5.  Execute `make` within this directory to compile translations.
6.  Restart your local pretix server. You can now use the plugin from
    this repository for your events by enabling it in the 'plugins'
    tab in the settings.

## Tests and style

Tests run under pretix's test settings (`pytest tests`, see `.gitlab-ci.yml`). They cover the
settings form, the rendered banner markup and the bundled player assets.

This plugin has CI set up to enforce a few code style rules. To check
locally, you need these packages installed:

    pip install flake8 isort black

To check your plugin for rule violations, run:

    black --check .
    isort -c .
    flake8 .

You can auto-fix some of these issues by running:

    isort .
    black .

New or changed user-facing strings pick up translations on the next
`make localegen` / Weblate pass; until then they fall back to English.

# License

Copyright 2025 Daniel Malik

Released under the terms of the Apache License 2.0
