Commit Graph

27 Commits

Author SHA1 Message Date
unkin-agent baa16b6586 fix: make transcode leases ownership-checked and cleanup-aware
Cleanup never matched a live session because the controller registered empty
manifest and segment paths, renewal was a read-modify-write that could revert a
takeover, and the takeover script compared an ISO date to a number, so it errored.

- populate the session record's manifest and segment paths from the playlist path
- renew the lease via a Lua compare-and-set on the owning pod
- store the lease expiry as unix milliseconds so the scripts can compare it
- retain the session record past its lease so an orphan can still be taken over
- test the Redis store against a real Redis, including the renew-vs-takeover race
- drop the live stream record nothing ever read back
2026-09-12 10:19:29 +10:00
unkin-agent 6ccabd4c72 feat(hls): register transcode sessions and renew their lease
A transcode that is not in the store is invisible to the other replicas, so the
HLS entry points have to publish and hold the lease themselves.

- register the play session in the store when ffmpeg starts
- renew the lease on a background loop and delete the session when it ends
- shorten segments and bound the playlist window when resuming a stored session
- add RecoverySegmentLengthSeconds and RecoverySegmentBufferCount encoding options
2026-09-11 23:56:35 +10:00
gnattu e2586eed9b Fix concurrent ffmpeg segment racing
This is a nasty one. The failure mode is:

1. Request A started FFmpeg and waited for a segment.
2. Request B requested an earlier or far away segment.
3. Jellyfin thought FFmpeg should to restart at a different position.
4. Request B killed the existing transcoding job.
5. Killing that job cancelled the same token request A was using.
6. The cancellation produced http 500 to request A.

To fix this:

we lock transcoding job state changes and segment handling per playlist, and use a thread safe counter to track how many http responses are still using each job’s segments. A job is only stopped or replaced once that counter reaches zero.
2026-08-05 00:33:42 +08:00
Cody Robibero 635fd0433d Merge pull request #17370 from zerafachris/fix/item-update-null-optional-fields
fix: don't throw ArgumentNullException on partial UpdateItem payloads (#17366)
2026-07-21 18:17:22 -04:00
Cody Robibero 370170bab0 Merge pull request #17369 from Shadowghost/harden-startup-wizard
Prevent unauthenticated re-run of the startup wizard on misconfiguration
2026-07-21 18:17:08 -04:00
zerafachris 53e58d8b1b Make ItemUpdateController.UpdateItem internal instead of reflection
Addresses review feedback from @Bond-009 on PR #17370: the test helper
InvokeUpdateItem was invoking the private UpdateItem(BaseItemDto, BaseItem)
method via reflection. Jellyfin.Api.csproj already grants
InternalsVisibleTo("Jellyfin.Api.Tests"), so the method is changed to
internal and the test now calls it directly, removing the
GetMethod/Invoke boilerplate.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-21 08:51:30 +02:00
zerafachris 5cd3d7ebb7 fix: don't throw ArgumentNullException on partial UpdateItem payloads (#17366)
BaseItemDto.Genres, .Tags, and .ProviderIds are plain auto-properties with
no default initializer, so they deserialize to null when a client omits
them from a partial POST /Items/{itemId} body. The OpenAPI spec documents
every BaseItemDto field as optional, but ItemUpdateController.UpdateItem
fed these three properties straight into Distinct()/Select()/ToList()
without a null check, so a request that (for example) only sets Tags
throws ArgumentNullException("source") once it reaches the unguarded
Genres line, before Tags is even processed.

Guard all three assignments with the same "if (request.X is not null)"
pattern already used for the neighboring Studios/Taglines/ProductionLocations
fields in this method, so omitted fields are left unchanged instead of
crashing the request.

Adds ItemUpdateControllerTests covering the reported repro (only Tags
supplied) and a companion case asserting existing Genres/ProviderIds are
preserved when omitted from the payload.

Signed-off-by: zerafachris <christopher.zerafa@blocklabs.io>
2026-07-17 17:20:30 +02:00
Shadowghost 62a5ded920 Prevent unauthenticated re-run of the startup wizard on misconfiguration 2026-07-17 17:14:27 +02:00
Marc Brooks 95cebffa87 Add tests
Also fixed a sibling directory that matches the prefix.
2026-06-28 16:26:35 -05:00
Shadowghost bd70e0ca34 Upgrade to xunit v3 2026-04-19 18:41:39 +02:00
JPVenson fe2596dc0e Add Full system backup feature (#13945) 2025-05-18 18:39:04 -06:00
Bond-009 e9729a536f Use pattern matching for null checks (#13793)
Fix the few that slipped through
2025-03-31 17:38:25 -06:00
JPVenson 42bdb22bfb Fixed namespaces 2025-03-25 16:45:00 +01:00
beakerandjake d82d025b24 Add unit test for log file not found 2024-02-03 19:10:08 -07:00
Bond_009 7bf831da62 Fix tests 2023-12-18 22:02:31 +01:00
Bond_009 0fd36a5bf1 Fix warnings in test projects 2023-11-14 21:14:23 +01:00
Chris H 3fd505a454 Validate AuthenticationProviderId and PasswordResetProviderId (#10553) 2023-11-10 07:51:44 -07:00
Stepan Goremykin 26958162d0 Remove unused using directives 2023-04-06 19:17:28 +02:00
Bond_009 60f41b80f6 Verify ContentType of uploaded images 2023-02-16 15:08:01 +01:00
KonH b6bf43af45 Fix warning: Using directive is not required by the code and can be safely removed (#2149) 2021-10-03 10:49:41 +07:00
ianjazz246 19b8bcaec4 Use TheoryData instead of MemberData and ClassData 2021-09-11 13:31:24 -07:00
Fernando Fernández 3d0b1ccae6 Remove all unused usings 2021-09-06 21:15:30 +02:00
Bond_009 56ac64e70a Minor improvements
* properly dispose CancellationTokenSource
* rewrite DynamicHlsController.GetSegmentLengths
* remove dead code
2021-05-08 00:33:24 +02:00
Bond_009 fa8bfece4e Split integration tests from unit tests 2021-03-09 14:17:59 +01:00
Bond_009 baadc48f43 Address comments 2021-02-22 16:27:02 +01:00
Bond_009 ec3237ba55 Fix tests 2021-02-22 13:46:40 +01:00
Bond_009 57102090d3 Add tests for DashboardController 2021-02-22 13:15:29 +01:00