Automatic video version choice based on user preferences and max bitrate
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -183,7 +183,7 @@ public sealed class CinemaMediaSourceManager : IMediaSourceManager
|
||||
switch (video)
|
||||
{
|
||||
case CinemaMovie movie: items = GetVideoVersionsEnumerate<CinemaMovie>(csId!, movie, videoPrimary!, ver.Versions); break;
|
||||
case CinemaEpisode episode: items = GetVideoVersionsEnumerate<CinemaEpisode>(csId!, episode, videoPrimary!, ver.Versions); break;
|
||||
case CinemaEpisode episode: items = GetVideoVersionsEnumerate<CinemaEpisode>(csId!, episode, videoPrimary!, SortVersionsByPreferences(user, ver.Versions)); break;
|
||||
default: throw new NotSupportedException(string.Format("BaseItem type '{0}' not supported in CinemaMediaSources.", video.GetType().Name));
|
||||
}
|
||||
|
||||
@@ -192,6 +192,11 @@ public sealed class CinemaMediaSourceManager : IMediaSourceManager
|
||||
// Note: Also makes sure BaseItems exist for each version
|
||||
foreach (var i in items)
|
||||
result.Add(GetVersionInfo(i, ver.Versions[idx++].Meta, thisServerBaseUri));
|
||||
|
||||
// For episodes we must choose the audio/subtitle automatically as there is no UI for it
|
||||
if (video is CinemaEpisode)
|
||||
foreach (MediaSourceInfo i in result)
|
||||
ForceByPreferences(user, i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -221,6 +226,88 @@ public sealed class CinemaMediaSourceManager : IMediaSourceManager
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Sorts media verions by preferences as episodes currently do not support multiple versions
|
||||
/// and the first one gets played.
|
||||
/// </summary>
|
||||
private static VersionEntry[] SortVersionsByPreferences(User user, VersionEntry[] items)
|
||||
{
|
||||
if (user == null)
|
||||
// We have no info about the user so nothing to sort
|
||||
return items;
|
||||
|
||||
double? bitrateLimit = IsWebshareFreeAccount ? WebshareFreeBitrate : null;
|
||||
string? audioLang = FixLangToIso(user.AudioLanguagePreference);
|
||||
string? subtitleLang = FixLangToIso(user.SubtitleLanguagePreference);
|
||||
int[] scores = new int[items.Length];
|
||||
for (int i = 0; i < items.Length; i++)
|
||||
{
|
||||
var m = items[i].Meta;
|
||||
int score = 0;
|
||||
|
||||
StreamVideo? video = m.video?.FirstOrDefault();
|
||||
if (video != null)
|
||||
{
|
||||
score += video.height / 100; // range [1..30]
|
||||
score += video.hasHdr ? 3 : 0; // HDR is plus but resolution ust rule
|
||||
}
|
||||
|
||||
if (m.subtitles != null && subtitleLang != null)
|
||||
foreach (StreamSubtitle j in m.subtitles)
|
||||
if (j.language == subtitleLang)
|
||||
{
|
||||
score += 4; // proper subtitles are preferred but much better resulution still rules
|
||||
break;
|
||||
}
|
||||
|
||||
if (m.audio != null && audioLang != null)
|
||||
foreach (StreamAudio j in m.audio)
|
||||
if (j.language == audioLang)
|
||||
{
|
||||
score += 25; // proper audio channel overrides resolution and other minor bonuses
|
||||
break;
|
||||
}
|
||||
|
||||
if (bitrateLimit != null && video != null)
|
||||
{
|
||||
double bitRate = (m.size ?? 0.0) * 8 / (video.duration ?? 1.0);
|
||||
score += bitRate / (1 + BitrateMargin) < bitrateLimit.Value ? 50 : 0; // without proper bitrate it is not playable at all
|
||||
}
|
||||
|
||||
scores[i] = score;
|
||||
}
|
||||
|
||||
Array.Sort(scores, items);
|
||||
Array.Reverse(items);
|
||||
return items;
|
||||
}
|
||||
|
||||
private static void ForceByPreferences(User user, MediaSourceInfo item) {
|
||||
if (user == null)
|
||||
// We have no info about the user so nothing to force
|
||||
return;
|
||||
|
||||
string? audioLang = FixLangToIso(user.AudioLanguagePreference);
|
||||
string? subtitleLang = FixLangToIso(user.SubtitleLanguagePreference);
|
||||
|
||||
foreach (var i in item.MediaStreams) {
|
||||
if (i.Type == MediaStreamType.Audio && audioLang != null)
|
||||
i.IsForced = audioLang == i.Language;
|
||||
else if (i.Type == MediaStreamType.Subtitle && subtitleLang != null)
|
||||
i.IsForced = subtitleLang == i.Language;
|
||||
}
|
||||
}
|
||||
|
||||
private static string? FixLangToIso(string? nonIso)
|
||||
{
|
||||
switch (nonIso)
|
||||
{
|
||||
case "cze": return "cs";
|
||||
case "eng": return "en";
|
||||
default: return nonIso;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets stream metadata for a video version (ie. for Movie or Episode).
|
||||
/// </summary>
|
||||
@@ -294,7 +381,8 @@ public sealed class CinemaMediaSourceManager : IMediaSourceManager
|
||||
primary = _libraryManager.GetItemById(primaryId);
|
||||
if (primary == null
|
||||
|| !CinemaQueryExtensions.IsCinemaExternalId(primary.ExternalId)
|
||||
|| string.IsNullOrEmpty(primary.ExternalId)) {
|
||||
|| string.IsNullOrEmpty(primary.ExternalId))
|
||||
{
|
||||
// Not a Stream Cinema video
|
||||
csId = null;
|
||||
return Task.FromResult<VersionSetEntry>(default);
|
||||
|
||||
Reference in New Issue
Block a user