Bitrail

Using the streams

Stable URLs, honest range support, and a checksum for every file. Nothing else to configure.

On this page

URL layout

Paths are predictable and permanent. A rendition that exists today will exist at the same URL with the same bytes for as long as this site does.

/media/<stream>/<stream>-<rendition>.mp4      progressive
/media/<stream>/hls/master.m3u8                 HLS master playlist
/media/<stream>/hls/<rendition>.m3u8            HLS media playlist
/media/<stream>/hls/<rendition>-init.mp4        fMP4 initialisation segment
/media/<stream>/hls/<rendition>-000.m4s         fMP4 media segments
/media/SHA256SUMS                               checksums for every media file

Streams are timecode, gradient, motion and sustained. Renditions are 360p, 720p and 1080p; the sustained stream is 1080p only.

Range requests and resume

The origin serves Accept-Ranges: bytes and honours both single and multi-range requests. This is the main reason the library exists: plenty of endpoints claim range support and then quietly return the whole file.

# first 1 MiB only
curl -r 0-1048575 -o head.bin \
  https://t1.nodavpn.org/media/sustained/sustained-1080p.mp4

# confirm the server actually honoured it
curl -sI -r 0-1023 https://t1.nodavpn.org/media/sustained/sustained-1080p.mp4 \
  | grep -i 'content-range\|206'

An interrupted download resumes correctly with curl -C - or wget -c. If your CDN or proxy breaks resume, this is a good place to find that out.

Verifying a transfer

Every media file is listed in /media/SHA256SUMS with a path relative to /media/.

cd media-download
curl -sO https://t1.nodavpn.org/media/SHA256SUMS
sha256sum -c SHA256SUMS --ignore-missing

A mismatch means something between the origin and you altered the bytes โ€” usually a transcoding proxy, occasionally a captive portal.

Using it from CI

Pull once per job, not once per test. The assets do not change, so a cached copy keyed on the checksum file is both faster and kinder.

# GitHub Actions fragment
- name: Cache test media
  uses: actions/cache@v4
  with:
    path: .media
    key: bitrail-${{ hashFiles('.media/SHA256SUMS') }}

- name: Fetch if missing
  run: |
    test -f .media/SHA256SUMS || {
      mkdir -p .media
      curl -sS --retry 3 --retry-delay 2 \
        -o .media/timecode-720p.mp4 \
        https://t1.nodavpn.org/media/timecode/timecode-720p.mp4
    }

If you need a sustained multi-gigabyte benchmark, download the sustained asset once and replay it locally in a loop. Repeatedly re-fetching it adds nothing to your measurement except someone else's egress bill.

Caching behaviour

PathCache-ControlWhy
/media/**public, max-age=31536000, immutableContents never change for a given filename
/assets/**public, max-age=604800Site styling, changes rarely
HTML pagespublic, max-age=300Short, so catalogue updates appear promptly
/media/SHA256SUMSpublic, max-age=300Must reflect new assets quickly

Media is served uncompressed. It is already compressed, and running it through gzip or zstd would only burn CPU on both ends for no gain.