Files

Personal Recordings (Jellyfin plugin)

Tracks which Jellyfin user scheduled a Live TV recording and moves completed files into {TargetRoot}/{Username}/ (default /recordings/Bram).

Jellyfin core does not store timer ownership. This plugin captures the authenticated user on TimerCreated / SeriesTimerCreated (via HttpContext) and later moves completed recordings.

Requirements

  • Jellyfin 10.11.x (ABI 10.11.0.0, net9.0)
  • Live TV recordings enabled
  • Writable target root (e.g. mount /recordings into the Jellyfin container)

Install

Catalog (Gitea)

  1. Build/release via tag (see below), or wait for CI
  2. In Jellyfin: Dashboard → Plugins → Repositories → +
  3. Repository URL (raw catalog):
https://<your-gitea>/<owner>/<repo>/raw/branch/<default>/Jellyfin/manifest.json
  1. Catalog → install Personal Recordings → restart Jellyfin

Manual

dotnet build -c Release
# copy Jellyfin.Plugin.PersonalRecordings/bin/Release/net9.0/Jellyfin.Plugin.PersonalRecordings.dll
# into <jellyfin-data>/plugins/PersonalRecordings/

Restart Jellyfin.

Configuration

Setting Default Meaning
Enabled true Master switch
Target root path /recordings Files go to {path}/{Username}/
Poll interval 60 Seconds between completion checks
Dry run false Log only, no file moves

Release (monorepo CI)

  1. Bump version (SemVer X.Y.Z)
  2. Push changes under this plugin folder

CI builds only changed plugins, creates release jellyfin/<slug>/vX.Y.Z, and updates the catalog.

Workflow: .gitea/workflows/release_jellyfin_plugin.yml

New plugins under Jellyfin/

Use Actions → Scaffold Jellyfin plugin (scaffold_jellyfin_plugin.yml) with a slug like jellyfin-plugin-myfeature. That creates boilerplate from Jellyfin/_template/ and registers the plugin in Jellyfin/manifest.json.

Notes

  • Series child timers inherit ownership from the series timer when there is no HTTP user.
  • Moves run only when timer status is Completed.
  • Sidecar files (*.nfo, images with the same basename) are moved best-effort.