docs: add architecture, contributing guide, and trim Dockerfile comment (#4)
* docs: add architecture overview, contributing guide, and GitHub discussion draft ARCHITECTURE.md covers server layer diagram, subsystems, and runtime info. CONTRIBUTING.md covers dev setup, build, test, and submission workflow. GITHUB-DISCUSSION-DRAFT.md drafts the upstream discussion post for the HA fork. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: trim verbose comment in Dockerfile.runtime Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+1
-2
@@ -1,7 +1,6 @@
|
|||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
# Runtime-only image — the .NET publish step runs on the CI host (runner),
|
# Runtime-only image — the .NET publish step runs on the CI host (runner),
|
||||||
# not inside this Dockerfile. This avoids DinD overlay-on-overlay I/O throttling
|
# not inside this Dockerfile.
|
||||||
# which makes `dotnet publish` inside Docker-in-Docker prohibitively slow on k3s.
|
|
||||||
|
|
||||||
# ── Web client stage ──────────────────────────────────────────────────────────
|
# ── Web client stage ──────────────────────────────────────────────────────────
|
||||||
# Install jellyfin-web via the official Jellyfin apt repo.
|
# Install jellyfin-web via the official Jellyfin apt repo.
|
||||||
|
|||||||
@@ -0,0 +1,202 @@
|
|||||||
|
> **Last updated: 2026-03-04**
|
||||||
|
|
||||||
|
# Jellyfin Server Architecture
|
||||||
|
|
||||||
|
High-level overview of the Jellyfin server structure, layer responsibilities, and key subsystems.
|
||||||
|
|
||||||
|
## Runtime
|
||||||
|
|
||||||
|
| Component | Value |
|
||||||
|
|---|---|
|
||||||
|
| Framework | .NET 10 / ASP.NET Core 10 |
|
||||||
|
| Target | `net10.0` |
|
||||||
|
| Entry point | `Jellyfin.Server` |
|
||||||
|
| Version | `10.12.0` (see `SharedVersion.cs`) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Layer Diagram
|
||||||
|
|
||||||
|
```
|
||||||
|
┌───────────────────────────────────────────────────────────┐
|
||||||
|
│ HTTP Clients │
|
||||||
|
│ (Jellyfin Web, mobile apps, 3rd-party) │
|
||||||
|
└────────────────────────┬──────────────────────────────────┘
|
||||||
|
│ REST / WebSocket
|
||||||
|
┌────────────────────────▼──────────────────────────────────┐
|
||||||
|
│ Jellyfin.Api │
|
||||||
|
│ ASP.NET Core controllers, middleware, auth, Swashbuckle │
|
||||||
|
└────────────────────────┬──────────────────────────────────┘
|
||||||
|
│ Interfaces (ILibraryManager, etc.)
|
||||||
|
┌────────────────────────▼──────────────────────────────────┐
|
||||||
|
│ MediaBrowser.Controller │
|
||||||
|
│ Core domain interfaces — no implementation here │
|
||||||
|
└────────────────────────┬──────────────────────────────────┘
|
||||||
|
│ Implementations
|
||||||
|
┌────────────────────────▼──────────────────────────────────┐
|
||||||
|
│ Emby.Server.Implementations / Jellyfin.Server.Impl │
|
||||||
|
│ Library manager, item repos, scheduled tasks, HTTP server│
|
||||||
|
└────────┬───────────────────────────────┬──────────────────┘
|
||||||
|
│ │
|
||||||
|
┌────────▼────────┐ ┌────────▼────────┐
|
||||||
|
│ Jellyfin.Data │ │ MediaBrowser │
|
||||||
|
│ EF Core DbCtx │ │ MediaEncoding │
|
||||||
|
│ SQLite via │ │ FFmpeg, HLS, │
|
||||||
|
│ Microsoft.Data │ │ Trickplay │
|
||||||
|
│ .Sqlite │ └─────────────────┘
|
||||||
|
└─────────────────┘
|
||||||
|
│
|
||||||
|
┌────────▼─────────────────────────────────────────────────┐
|
||||||
|
│ MediaBrowser.Model │
|
||||||
|
│ Pure DTOs, enums, no logic (shared by all layers) │
|
||||||
|
└──────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Project Responsibilities
|
||||||
|
|
||||||
|
### `Jellyfin.Server`
|
||||||
|
|
||||||
|
Entry point. Handles:
|
||||||
|
- CLI argument parsing (`CommandLineParser`)
|
||||||
|
- Serilog configuration (console, file, Graylog sinks)
|
||||||
|
- DI container wiring (`ApplicationHost`)
|
||||||
|
- ASP.NET Core host startup
|
||||||
|
|
||||||
|
### `Jellyfin.Api`
|
||||||
|
|
||||||
|
All HTTP surface. Handles:
|
||||||
|
- ASP.NET Core controllers (`Controllers/`)
|
||||||
|
- Authentication middleware (`Auth/`)
|
||||||
|
- Swashbuckle/OpenAPI configuration
|
||||||
|
- Request/response formatting (camelCase + PascalCase JSON)
|
||||||
|
- WebSocket listeners (`WebSocketListeners/`)
|
||||||
|
|
||||||
|
Controllers inherit from `BaseJellyfinApiController` which sets default route, produces JSON, and provides typed `Ok<T>()` helpers.
|
||||||
|
|
||||||
|
### `MediaBrowser.Controller`
|
||||||
|
|
||||||
|
Core domain interfaces. Key examples:
|
||||||
|
- `ILibraryManager` — media library operations
|
||||||
|
- `IMediaEncoder` — FFmpeg wrapper
|
||||||
|
- `IProviderManager` — metadata provider coordination
|
||||||
|
- `IUserManager` — user management
|
||||||
|
- `IPlaybackManager` — playback session tracking
|
||||||
|
|
||||||
|
**No implementations live here.** This keeps the domain decoupled from infrastructure.
|
||||||
|
|
||||||
|
### `Emby.Server.Implementations`
|
||||||
|
|
||||||
|
Primary implementation assembly. Contains:
|
||||||
|
- `ApplicationHost.cs` — DI wiring and startup
|
||||||
|
- `Data/` — SQLite queries and EF Core repositories
|
||||||
|
- `Library/` — `LibraryManager`, `LibraryMonitor`
|
||||||
|
- `Images/` — image processing pipeline (SkiaSharp)
|
||||||
|
- `HttpServer/` — HTTP server wiring
|
||||||
|
|
||||||
|
### `Jellyfin.Server.Implementations`
|
||||||
|
|
||||||
|
Secondary implementation assembly split from `Emby.Server.Implementations`. Contains newer implementations using EF Core patterns.
|
||||||
|
|
||||||
|
### `Jellyfin.Data`
|
||||||
|
|
||||||
|
EF Core data models and `DbContext`. Migrations managed here.
|
||||||
|
|
||||||
|
### `MediaBrowser.Model`
|
||||||
|
|
||||||
|
Pure data-transfer objects (DTOs) and enums. No logic. Consumed by all layers and by external clients. Changes here are API-breaking.
|
||||||
|
|
||||||
|
### `MediaBrowser.Providers`
|
||||||
|
|
||||||
|
Online metadata providers:
|
||||||
|
- TMDB (movies, TV)
|
||||||
|
- MusicBrainz (audio)
|
||||||
|
- OMDB
|
||||||
|
- TV Maze, TheTVDB
|
||||||
|
|
||||||
|
Uses `IMetadataProvider<T>` interface from `MediaBrowser.Controller`.
|
||||||
|
|
||||||
|
### `MediaBrowser.MediaEncoding`
|
||||||
|
|
||||||
|
FFmpeg process management, HLS streaming, keyframe extraction, subtitle transcoding, trickplay image generation.
|
||||||
|
|
||||||
|
### `Emby.Naming`
|
||||||
|
|
||||||
|
Media file path parsing — resolves series/season/episode structure, detects extras, parses video codecs from filenames.
|
||||||
|
|
||||||
|
### `MediaBrowser.LocalMetadata` / `MediaBrowser.XbmcMetadata`
|
||||||
|
|
||||||
|
Local NFO/XML metadata providers (Kodi-compatible `.nfo` sidecar files).
|
||||||
|
|
||||||
|
### `src/Jellyfin.CodeAnalysis`
|
||||||
|
|
||||||
|
Custom Roslyn analyzer. Runs only in Debug builds. Enforces project-specific rules.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Subsystems
|
||||||
|
|
||||||
|
### Authentication
|
||||||
|
|
||||||
|
- Session-based API keys (stored in SQLite)
|
||||||
|
- Quick Connect (pairing flow)
|
||||||
|
- Auth middleware in `Jellyfin.Api/Auth/`
|
||||||
|
- Policies defined in `Jellyfin.Api/Constants/Policies.cs`
|
||||||
|
|
||||||
|
### Library Scanning
|
||||||
|
|
||||||
|
1. `LibraryMonitor` watches filesystem for changes
|
||||||
|
2. `LibraryManager` resolves paths → `BaseItem` subclasses
|
||||||
|
3. `Emby.Naming` parses filenames → metadata hints
|
||||||
|
4. `IProviderManager` fetches remote metadata and saves locally
|
||||||
|
5. Results persisted to SQLite via EF Core
|
||||||
|
|
||||||
|
### Transcoding
|
||||||
|
|
||||||
|
1. Client requests a stream via `MediaInfoController` or `DynamicHlsController`
|
||||||
|
2. `MediaInfoHelper` determines if transcoding is needed (codec matrix)
|
||||||
|
3. `MediaEncoder` spawns an FFmpeg subprocess with computed arguments
|
||||||
|
4. HLS segments or direct stream served via `AudioController` / `VideosController`
|
||||||
|
|
||||||
|
### Metrics
|
||||||
|
|
||||||
|
prometheus-net serves metrics at `/metrics`. Key meters:
|
||||||
|
- `prometheus-net.AspNetCore` — HTTP request duration/count
|
||||||
|
- `prometheus-net.DotNetRuntime` — GC, thread pool, JIT metrics
|
||||||
|
- Custom counters can be added via `Metrics.CreateCounter(...)` in any service
|
||||||
|
|
||||||
|
### Logging
|
||||||
|
|
||||||
|
Serilog pipeline:
|
||||||
|
- Console sink (structured)
|
||||||
|
- File sink (rolling, default `%APPDATA%/jellyfin/logs/`)
|
||||||
|
- Graylog GELF sink (optional, configured via `logging.json`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Database
|
||||||
|
|
||||||
|
SQLite database at `{DataDir}/data/jellyfin.db`. Accessed via:
|
||||||
|
- EF Core (`Jellyfin.Data.JellyfinDbContext`) for new data access
|
||||||
|
- `Microsoft.Data.Sqlite` direct queries for legacy paths
|
||||||
|
|
||||||
|
**All EF Core operations must use async methods** (`ToListAsync`, `FirstOrDefaultAsync`, etc.).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Test Layout
|
||||||
|
|
||||||
|
```
|
||||||
|
tests/
|
||||||
|
Jellyfin.Api.Tests/ Controller + middleware unit tests
|
||||||
|
Jellyfin.Common.Tests/ MediaBrowser.Common utilities
|
||||||
|
Jellyfin.Controller.Tests/ Interface contracts and helpers
|
||||||
|
Jellyfin.MediaEncoding.Tests/ FFmpeg argument building
|
||||||
|
Jellyfin.Naming.Tests/ File path parsing
|
||||||
|
Jellyfin.Providers.Tests/ Provider logic
|
||||||
|
Jellyfin.Server.Integration.Tests/ Full-stack HTTP tests + OpenAPI spec gen
|
||||||
|
Jellyfin.Server.Tests/ Server startup and DI tests
|
||||||
|
```
|
||||||
|
|
||||||
|
Test stack: xUnit + AutoFixture + Moq + FsCheck. See `.github/instructions/testing.instructions.md`.
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
> **Last updated: 2026-03-04**
|
||||||
|
|
||||||
|
# Contributing to Jellyfin Server
|
||||||
|
|
||||||
|
This guide covers everything you need to develop, build, test, and submit changes to the Jellyfin server.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
| Tool | Version | Notes |
|
||||||
|
|---|---|---|
|
||||||
|
| .NET SDK | 10.0.x | See `global.json` — `rollForward: latestMinor` |
|
||||||
|
| Git | any recent | `git clone` with submodules not required |
|
||||||
|
| FFmpeg | 7.x | Required for transcoding tests; install via devcontainer or manually |
|
||||||
|
| Docker | optional | For devcontainer workflow |
|
||||||
|
|
||||||
|
### macOS (Homebrew)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install dotnet
|
||||||
|
```
|
||||||
|
|
||||||
|
### Linux (Debian/Ubuntu)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
wget https://dot.net/v1/dotnet-install.sh && bash dotnet-install.sh --channel 10.0
|
||||||
|
```
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
Download the [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10) installer.
|
||||||
|
|
||||||
|
### DevContainer (recommended for new contributors)
|
||||||
|
|
||||||
|
Open the repo in VS Code and accept the "Reopen in Container" prompt. The devcontainer installs:
|
||||||
|
- .NET 10
|
||||||
|
- FFmpeg
|
||||||
|
- All recommended VS Code extensions
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build the server entry point
|
||||||
|
dotnet build Jellyfin.Server/Jellyfin.Server.csproj
|
||||||
|
|
||||||
|
# Build the entire solution (all projects)
|
||||||
|
dotnet build Jellyfin.sln
|
||||||
|
```
|
||||||
|
|
||||||
|
Debug builds activate all code analyzers (StyleCop, BannedApiAnalyzers, IDisposableAnalyzers, MultithreadingAnalyzer). **Expect build failures if your code has missing XML docs or uses banned APIs.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Run Locally
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dotnet run --project Jellyfin.Server/Jellyfin.Server.csproj \
|
||||||
|
-- --datadir /tmp/jellyfin-data --webdir /tmp/jellyfin-web --nowebclient
|
||||||
|
```
|
||||||
|
|
||||||
|
The server starts on `http://localhost:8096` by default.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Test
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run all tests (cross-platform matrix: Linux, macOS, Windows)
|
||||||
|
dotnet test Jellyfin.sln --configuration Release --verbosity minimal
|
||||||
|
|
||||||
|
# Run a single test project
|
||||||
|
dotnet test tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
|
||||||
|
|
||||||
|
# Run tests matching a name filter
|
||||||
|
dotnet test Jellyfin.sln --filter "ClassName=MyServiceTests"
|
||||||
|
|
||||||
|
# Run with code coverage
|
||||||
|
dotnet test Jellyfin.sln \
|
||||||
|
--configuration Release \
|
||||||
|
--collect:"XPlat Code Coverage" \
|
||||||
|
--settings tests/coverletArgs.runsettings
|
||||||
|
```
|
||||||
|
|
||||||
|
Coverage output: `merged/Cobertura.xml` (merged by ReportGenerator in CI).
|
||||||
|
|
||||||
|
### Regenerate OpenAPI Spec
|
||||||
|
|
||||||
|
After adding or changing any API endpoint:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dotnet test tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj \
|
||||||
|
-c Release \
|
||||||
|
--filter "Jellyfin.Server.Integration.Tests.OpenApiSpecTests"
|
||||||
|
```
|
||||||
|
|
||||||
|
Commit the updated `openapi.json` — the CI diff job will flag unintentional breaking changes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Code Style
|
||||||
|
|
||||||
|
All style rules are enforced by the compiler in Debug builds. Key rules:
|
||||||
|
|
||||||
|
- **Nullable enabled** — mark nullable types with `?`, never silence with `null!` without a comment
|
||||||
|
- **Warnings as errors** — fix every warning; do not suppress with `#pragma warning disable`
|
||||||
|
- **XML docs** — every `public` type and member must have `/// <summary>`
|
||||||
|
- **No `Task.Result`** — always `await` instead
|
||||||
|
- **Central NuGet versions** — versions in `Directory.Packages.props` only, never in `.csproj`
|
||||||
|
- **File-scoped namespaces** — use `namespace Jellyfin.Example;` (not block-scoped)
|
||||||
|
|
||||||
|
See `.github/instructions/csharp.instructions.md` for the full ruleset.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pull Request Process
|
||||||
|
|
||||||
|
1. Fork the repo and create a feature branch from `master`
|
||||||
|
2. Make your changes; ensure `dotnet build` and `dotnet test` pass locally
|
||||||
|
3. Fill out the PR template (`.github/pull_request_template.md`):
|
||||||
|
- **Changes**: 1–5 sentence summary
|
||||||
|
- **Issues**: tag with `Fixes #NNN`
|
||||||
|
4. CI runs automatically:
|
||||||
|
- `ci-tests.yml` — tests on Linux, macOS, Windows
|
||||||
|
- `ci-openapi.yml` — OpenAPI diff
|
||||||
|
- `ci-codeql-analysis.yml` — security scan
|
||||||
|
5. A maintainer will review and merge
|
||||||
|
|
||||||
|
### Title format
|
||||||
|
|
||||||
|
Use the imperative mood:
|
||||||
|
- ✅ `Add lyrics endpoint for audio items`
|
||||||
|
- ✅ `Fix null reference in LibraryController`
|
||||||
|
- ❌ `Added lyrics endpoint`
|
||||||
|
- ❌ `Fixed null reference`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Adding a New Package Dependency
|
||||||
|
|
||||||
|
1. Add the version to `Directory.Packages.props`:
|
||||||
|
```xml
|
||||||
|
<PackageVersion Include="SomePackage" Version="1.2.3" />
|
||||||
|
```
|
||||||
|
2. Add the reference to the relevant `.csproj` (no `Version=` attribute):
|
||||||
|
```xml
|
||||||
|
<PackageReference Include="SomePackage" />
|
||||||
|
```
|
||||||
|
|
||||||
|
**Never** specify both a version in `Directory.Packages.props` AND in the `.csproj` — that causes `NU1008`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Project Conventions
|
||||||
|
|
||||||
|
See `.github/instructions/` for detailed instructions per concern:
|
||||||
|
|
||||||
|
| Topic | File |
|
||||||
|
|---|---|
|
||||||
|
| C# style | `csharp.instructions.md` |
|
||||||
|
| API controllers | `api.instructions.md` |
|
||||||
|
| Tests | `testing.instructions.md` |
|
||||||
|
| CI/CD workflows | `ci-cd.instructions.md` |
|
||||||
|
| Documentation | `docs.instructions.md` |
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
# Jellyfin HA transcoding fork: Redis-backed session failover + experimental PostgreSQL provider
|
||||||
|
|
||||||
|
I've been working on a fork of Jellyfin focused on one specific problem: making HLS transcoding survive pod restarts in a multi-replica Kubernetes deployment.
|
||||||
|
|
||||||
|
## What it does
|
||||||
|
|
||||||
|
Right now, Jellyfin assumes transcode state lives in one server process. If that pod dies, active transcodes die with it. This fork adds a small HA layer so transcode ownership can survive a pod restart:
|
||||||
|
|
||||||
|
- A new `ITranscodeSessionStore` abstraction for durable transcode session tracking
|
||||||
|
- A `RedisTranscodeSessionStore` implementation with lease-based ownership
|
||||||
|
- Atomic pod takeover using a Redis Lua script when a lease expires
|
||||||
|
- Lease-aware cleanup so one pod does not delete segments another pod still needs
|
||||||
|
- A `NullTranscodeSessionStore` fallback, so single-instance deployments behave exactly like upstream with no config changes
|
||||||
|
|
||||||
|
I also added an experimental PostgreSQL provider for shared-database deployments, since SQLite is not a good fit once multiple replicas are involved.
|
||||||
|
|
||||||
|
## What the HA flow looks like
|
||||||
|
|
||||||
|
- Pod A starts an HLS transcode and registers the session in Redis
|
||||||
|
- Pod A renews the lease while it owns the session
|
||||||
|
- If Pod A dies, the lease expires
|
||||||
|
- Pod B receives the next request, atomically claims the expired lease, and resumes from the last completed segment on shared storage
|
||||||
|
- The client sees a short buffer pause instead of a hard failure
|
||||||
|
|
||||||
|
## How to run it
|
||||||
|
|
||||||
|
There are three practical modes:
|
||||||
|
|
||||||
|
### 1. Single instance
|
||||||
|
|
||||||
|
No config needed. It falls back to the no-op store automatically.
|
||||||
|
|
||||||
|
### 2. Local HA test
|
||||||
|
|
||||||
|
Run two Jellyfin instances against:
|
||||||
|
|
||||||
|
- the same Redis
|
||||||
|
- the same shared transcode directory
|
||||||
|
|
||||||
|
That is enough to test failover behavior locally.
|
||||||
|
|
||||||
|
### 3. Kubernetes / k3s
|
||||||
|
|
||||||
|
This is the intended deployment model. You need:
|
||||||
|
|
||||||
|
- 2+ Jellyfin replicas
|
||||||
|
- Redis
|
||||||
|
- shared RWX storage for transcode output
|
||||||
|
- shared media storage
|
||||||
|
- ideally PostgreSQL if you want a proper shared DB setup
|
||||||
|
|
||||||
|
The key config is:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Jellyfin:TranscodeStore:RedisConnectionString
|
||||||
|
Jellyfin:TranscodeStore:LeaseDurationSeconds
|
||||||
|
```
|
||||||
|
|
||||||
|
Repo and write-up:
|
||||||
|
|
||||||
|
- Source: https://github.com/ZoltyMat/jellyfin-ha
|
||||||
|
- Full change summary vs upstream: https://github.com/ZoltyMat/jellyfin-ha/blob/main/docs/FORK-DIFF.md
|
||||||
|
- Write-up with diagrams and k8s manifests: https://blog.zolty.systems/posts/jellyfin-ha-kubernetes
|
||||||
|
|
||||||
|
## What would be required to merge upstream
|
||||||
|
|
||||||
|
I do not expect this to be merged as-is without discussion. If there is interest, I think the realistic path is to split it into small pieces:
|
||||||
|
|
||||||
|
1. Introduce `ITranscodeSessionStore`, `TranscodeSession`, and `NullTranscodeSessionStore` only
|
||||||
|
2. Add the DI wiring with no behavior change unless configured
|
||||||
|
3. Add HLS session registration and lease renewal hooks
|
||||||
|
4. Add lease-aware cleanup in `DeleteTranscodeFileTask`
|
||||||
|
5. Add takeover logic in the HLS/session path
|
||||||
|
6. Discuss whether Redis should be the first supported distributed store, or whether the interface should land before any concrete implementation
|
||||||
|
7. Treat PostgreSQL as a separate discussion entirely
|
||||||
|
|
||||||
|
I think the HA transcode work has a better chance of review if it is separated from the PostgreSQL provider and migration tooling.
|
||||||
|
|
||||||
|
## Why I'm posting it
|
||||||
|
|
||||||
|
I'm not trying to maintain a permanent hard fork. I built this to see whether Jellyfin could be made to behave well in a replicated environment without rewriting major subsystems. The answer seems to be yes, but it needs maintainers to decide whether this kind of deployment is something upstream wants to support.
|
||||||
|
|
||||||
|
If there's interest, I'm happy to break the work into smaller PRs, clean up anything that does not match project direction, and rework the design around maintainer feedback.
|
||||||
Reference in New Issue
Block a user