Files
jellyfin-plugin-floatplane/README.md
claude 2a883c02de
All checks were successful
release / build-release (push) Successful in 1m19s
Tests: xUnit project with HAR fixtures (50 tests); fix relative delivery/HLS URLs resolving to file:// on Linux
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-25 09:42:50 +01:00

5.1 KiB

jellyfin-plugin-floatplane

A Jellyfin server plugin that exposes your Floatplane subscriptions (creators → channels → videos, plus live streams) inside Jellyfin and all its clients, so Floatplane content shows up next to the rest of the library on the Pi5 server and plays through the normal Jellyfin players.

Status (2026-10-25): browsing works (verified against a local Jellyfin 10.10.7); playback proxy is implemented but still needs a real session cookie to be verified. See doc/plan.md for milestones and doc/floatplane-api-notes.md for the API.

The plugin is a pure managed .NET assembly (AnyCPU IL), so one build runs on both linux-x64 (dev box) and linux-arm64 (the Pi5).

Prerequisites

Target What to install
Arch / Garuda (dev box) sudo pacman -S dotnet-sdk-8.0 (Jellyfin 10.10.x = .NET 8) — for Jellyfin 12.x use dotnet-sdk (.NET 10)
Debian / Ubuntu apt install dotnet-sdk-8.0 from the Microsoft repo
Pi5 (runtime only) nothing — the plugin runs inside the existing linuxserver/jellyfin container

Optional, for local testing: Docker (to run a throw-away Jellyfin of the same version as the Pi5 with the plugin folder mounted).

Build

git clone https://gitea.brasse-pc.eu/brasse/jellyfin-plugin-floatplane.git
cd jellyfin-plugin-floatplane
scripts/package.sh            # → build/Floatplane_<ver>/ (DLL + meta.json), build/floatplane_<ver>.zip (+ .md5)

The VS Code build task (Ctrl+Shift+B) runs the same script. Plain dotnet build works too (jellyfin-plugin-floatplane.sln).

Install

From the plugin repository (recommended): Dashboard → Plugins → Repositories → add

https://gitea.brasse-pc.eu/brasse/jellyfin-plugin-floatplane/releases/download/latest/manifest.json

then Catalog → Channels → Floatplane → Install → restart Jellyfin.

Manual, on the Pi5 (linuxserver image):

curl -fsSL https://gitea.brasse-pc.eu/brasse/jellyfin-plugin-floatplane/releases/download/latest/install-pi5.sh | sh -s -- --dry-run
# then without --dry-run; it installs into /srv/docker/jellyfin/data/plugins/ and restarts the container

Manual, from a local build:

# linuxserver image keeps data under /config/data (container path);
# host path on the Pi5: /srv/docker/jellyfin/data/plugins/ (infra-Doc services/media-stack.md)
cp -r build/Floatplane_0.1.0.0 /srv/docker/jellyfin/data/plugins/
docker restart jellyfin

The Pi5 runs Jellyfin 10.10.7 but lscr.io/linuxserver/jellyfin:latest is already 12.3 (.NET 10). Pin the tag (10.10.7ubu2404-ls80) before any docker pull, or the plugin becomes NotSupported overnight.

Then Dashboard → Plugins → Floatplane → paste your sails.sid cookie (the page explains where to find it) → Validate → Save. A "Floatplane" channel appears under My Media: creators → sub-channels → videos. Without a cookie you can still browse creators listed under "Extra creators" (public data); playback needs the cookie.

How it works (short)

  • FloatplaneChannel (IChannel) lists creators → sub-channels → posts from Floatplane's public listing API; ids are creator:…, channel:…, post:….
  • On play, IRequiresMediaInfoCallback fetches the post (login) and hands Jellyfin signed URLs to the plugin's own Floatplane/Stream/… endpoints.
  • The stream endpoint calls delivery/info (cached, throttled to ~2/min), fetches the HLS playlist, and rewrites it: the AES-128 key URI points back at the plugin (which fetches the key with the cookie), segments go straight to the CDN. ffmpeg then remuxes (stream copy) for the client.
  • A scheduled task refreshes the catalogue and bumps the channel cache key.

Test

dotnet test            # unit tests (models, HLS rewriter, API client with fixtures from the HAR)

The test host needs the ASP.NET Core 8 shared runtime (the plugin references Jellyfin's controllers): on Arch sudo pacman -S aspnet-runtime-8.0.

Local end-to-end test with a disposable Jellyfin matching the Pi5 version:

mkdir -p .jellyfin-test/config/data/plugins
cp -r build .jellyfin-test/config/data/plugins/Floatplane_0.1.0.0   # writable copy, not :ro
docker run --rm -p 8096:8096 -v $PWD/.jellyfin-test/config:/config \
  lscr.io/linuxserver/jellyfin:10.10.7ubu2404-ls80
# logs: .jellyfin-test/config/log/log_*.log ; plugin status: Dashboard → Plugins

Docs

  • doc/plan.md — goal, stack, milestones, roadmap
  • doc/floatplane-api-notes.md — endpoints, auth, HLS/AES-128 playback flow
  • doc/research/jellyfin-plugin-research.md — plugin API research (10.10 vs 12.x, channels, proxy pattern, packaging, paths)
  • doc/research/floatplane-api-research.md — community API docs, OAuth device flow, DPoP, rate limits, other clients
  • doc/research/reference-sources/ — snapshots of other clients' source for study (chaosflix is the template to follow)
  • doc/har/ — the captured browser session (gitignored, contains credentials)
  • Gitea wiki (once the repo exists) — architecture and design decisions