When a stalled HLS client sends ReportPlaybackStopped with a negative
PositionTicks (e.g. HLS.js reporting position on buffer stall), the
ArgumentOutOfRangeException was thrown before GetSession was called,
causing CloseLiveStreamIfNeededAsync to never run. This left the
ILiveStream.ConsumerCount permanently incremented, permanently holding
a tuner open with no active viewer.
Fix by acquiring the session and performing live stream cleanup before
throwing the validation exception, so tuner resources are always freed
even when playback reporting fails with invalid position data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Season and episode directories/files can now include provider ID
attributes in their names (e.g. "Season 01 [tvdbid=22222]" or
"Show S01E01 [tmdbid=99999].mkv"), consistent with the existing
behavior for series folders.
Supported providers: imdbid, tvdbid, tvmazeid, tmdbid.
Adds TmdbSeasonExternalId and TmdbEpisodeExternalId so that
the TMDB season and episode IDs are surfaced in the metadata editor.
Seasons do not have their own IMDb IDs, so we don't support imdbid parsing
in SeasonResolver. Instead, generate IMDb season URLs via
ImdbExternalUrlProvider using the parent series' IMDb ID and the
season number, matching the IMDb URL format:
imdb.com/title/{seriesId}/episodes/?season={N}
Add tests for the ExternalUrlProviders.
When "replace all metadata" was issued on a film, with the Web metadata
scrapers and "save to local metadata" disabled, after changing the
.nfo file, 'Community rating' was not updated in the server, remaining
the cached value.
Fixed by changing the flag on the 'MergeData' call
(line 809 - MetadataService.cs) to use the option defined by the
user and not the erroneous absolute 'false' value.
Also, in the .nfo parser an option for 'communityrating' was added
along with value conformity verifiers.
Validation tests were added.
A direct implementation using DriveInfo directly on a path does not work
as expected. The method will return a DriveInfo object with the given
path as both the Name and the RootDirectory, which is not helpful.
Instead, add parsing logic to find the best possible match out of all
filesystems on the system for the path, including handling edge cases
involving symlinked paths in the chain.
This ensures that the resulting DeviceId is a valid filesystem, allowing
it to be used in the UI to show a better description. It also includes
the new ResolvedPath which will show, if required, what the Path
resolved to after all symlinks are interpolated.
One possible issue here is that walking all drives as-is might become
slow(er) on a system with many partitions, but even on my
partition-heavy system with over a dozen ZVOLs and remote mounts, this
takes under 0.4 seconds including runup time for `dotnet run`, so I
imagine this should be fine.
* Recognize ".m4b" as an audio-book format
- Has the resolver recognize the ".m4b" format as book
- Jellyfin reverts to seeing the file as a music file without this check
* Recognize ".m4a", ".aac", ".flac", and ".mp3" as an audio-book formats
- All the formats supported in the docs will now be marked as type "Book"
* Add ".opus" as a supported Audiobook format
---------
Co-authored-by: Louis Sandoval <louis@sandoval.family>