using System; using System.Globalization; using Jellyfin.Api.Helpers; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Dto; using MediaBrowser.Model.MediaInfo; using Microsoft.Extensions.Logging; using Moq; using Xunit; namespace Jellyfin.Api.Tests.Helpers { public class MediaInfoHelperTests { private static MediaInfoHelper CreateHelper() { return new MediaInfoHelper( Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of>(), Mock.Of(), Mock.Of()); } private static MediaSourceInfo CreateSource(Guid itemId, int bitrate, bool supportsDirectPlay = true) { return new MediaSourceInfo { Id = itemId.ToString("N", CultureInfo.InvariantCulture), Protocol = MediaProtocol.File, Bitrate = bitrate, SupportsDirectPlay = supportsDirectPlay, SupportsDirectStream = true, SupportsTranscoding = true }; } [Fact] public void SortMediaSources_PreferredItemExceedsBitrate_StaysDefault() { // The version the user was watching (the queried item) must stay the default // even when a sibling version fits the bitrate limit better, since the resume // position belongs to that exact version. var preferredItemId = Guid.NewGuid(); var preferredSource = CreateSource(preferredItemId, bitrate: 80_000_000, supportsDirectPlay: false); var siblingSource = CreateSource(Guid.NewGuid(), bitrate: 8_000_000); var result = new PlaybackInfoResponse { MediaSources = [siblingSource, preferredSource] }; CreateHelper().SortMediaSources(result, maxBitrate: 20_000_000, preferredItemId); Assert.Equal(preferredSource.Id, result.MediaSources[0].Id); } [Fact] public void SortMediaSources_NoPreferredItem_OrdersByPlayability() { var directPlay = CreateSource(Guid.NewGuid(), bitrate: 8_000_000); var transcodeOnly = CreateSource(Guid.NewGuid(), bitrate: 8_000_000, supportsDirectPlay: false); transcodeOnly.SupportsDirectStream = false; var result = new PlaybackInfoResponse { MediaSources = [transcodeOnly, directPlay] }; CreateHelper().SortMediaSources(result, maxBitrate: 20_000_000); Assert.Equal(directPlay.Id, result.MediaSources[0].Id); } [Fact] public void SortMediaSources_PreferredIdNotInSources_KeepsPlayabilityOrder() { var directPlay = CreateSource(Guid.NewGuid(), bitrate: 8_000_000); var transcodeOnly = CreateSource(Guid.NewGuid(), bitrate: 8_000_000, supportsDirectPlay: false); transcodeOnly.SupportsDirectStream = false; var result = new PlaybackInfoResponse { MediaSources = [transcodeOnly, directPlay] }; CreateHelper().SortMediaSources(result, maxBitrate: 20_000_000, Guid.NewGuid()); Assert.Equal(directPlay.Id, result.MediaSources[0].Id); } } }