Skip to content

Development ​

This page explains how to run Polyfin from source, run its tests, refresh the Jellyfin fixtures, and work on the website.

Requirements ​

  • Go 1.27.
  • Node.js 24.
  • A PostgreSQL 18 server.
  • FFmpeg 9.0 or later (ffmpeg and ffprobe), to play titles.

With POSTGRES_PASSWORD set in .env, docker compose -f compose.yaml -f compose.build.yaml up -d postgres starts a PostgreSQL server on 127.0.0.1:5432.

Commands ​

sh
export POLYFIN_DATABASE_URL=postgresql://polyfin:password@127.0.0.1:5432/polyfin
make dev                      # builds the admin app, then runs the server on :8096
npm --prefix web run dev      # optional: admin app with hot reload, proxied to :8096
make check                    # formatting, vet and tests

Tests ​

  • Database tests run when POLYFIN_TEST_DATABASE_URL points to a disposable PostgreSQL database whose role may create databases. Most database tests work in a database of their own, copied from a template database migrated once and kept for later runs, polyfin_template_ followed by a key of the migrations; the others work in a schema of their own.
  • Remux tests run when POLYFIN_TEST_FFMPEG names an ffmpeg executable with ffprobe beside it.
  • CI always provides both.
  • make check runs every package's tests under the race detector (make test), then, without it, the time bounds of a large IPTV line-up (make bounds): the race detector slows that work tenfold, and gets a tenth of the line-up. CI runs the tests of internal/jellyfin, by far the longest, in a job of their own (make test-jellyfin), and the others beside the rest of the checks (make test-others).
  • The tests of the slowest packages run in parallel. A test that changes state other tests read, such as a package variable, or that times waits of a few milliseconds, stays sequential and says why.
  • The SMB share tests run when POLYFIN_TEST_SMB names a share holding video files, its user and password in the address: smb://user:password@host:port/share/folder. The user must be allowed to write there: the change notification test adds, renames and removes files in a folder of its own, removed after. CI does not run them; WebDAV folders are tested against a server in the tests themselves.
  • make image-check builds the image and checks the version it prints; make image-health then starts it against the PostgreSQL of IMAGE_DATABASE_URL, by default the host's on port 5432 with the user, password and database polyfin, and waits for its health check to report it healthy, as CI does.

Jellyfin fixtures ​

Jellyfin API responses are checked against the JSON structure of a real Jellyfin 12.2 server, recorded in internal/jellyfin/testdata/. Jellyfin 12.3 answers the same: recorded again from it with the same scripts, its answers differ only in identifiers, dates, timings and the encoded clips' bitrates, so the 12.2 recordings stand for both.

scripts/jellyfin-fixtures.sh records them again from a disposable Jellyfin container. It requires Docker, curl and jq.

Website ​

The website is built with VitePress from docs/:

  • Each page of this documentation is one of its pages, under /docs/, with the sidebar following the sections of the documentation's index. Links that leave docs/ open the file on GitHub.
  • The landing page is in docs/.vitepress/theme/, and its videos in docs/public/videos/.
  • VitePress 1 asks for Vite 5, whose development server has security advisories fixed only in Vite 6.4.3. docs/package.json overrides it with Vite 6; the override can go once VitePress asks for a fixed Vite.
sh
npm --prefix docs ci
npm --prefix docs run dev       # the website on http://127.0.0.1:5173/polyfin/, with hot reload
npm --prefix docs run build     # fails on a link to a page that does not exist
npm --prefix docs run format    # formats the landing page's code

CI builds the website for each pull request that changes docs/. Each push of such a change to main publishes it on GitHub Pages (.github/workflows/pages.yml).