mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-05-13 08:37:07 +00:00
Merge 1f59adbbc7 into 27a3ccb7e4
This commit is contained in:
commit
474ca7b688
5 changed files with 75 additions and 38 deletions
|
|
@ -1598,6 +1598,16 @@ namespace MediaBrowser.Controller.Entities
|
|||
return lang;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the preferred image languages as an array (e.g., ["en", "de", "fr", "nolang"]).
|
||||
/// </summary>
|
||||
/// <returns>Array of preferred image languages.</returns>
|
||||
public string[] GetPreferredImageLanguages()
|
||||
{
|
||||
var libraryOptions = LibraryManager.GetLibraryOptions(this);
|
||||
return libraryOptions.PreferredImageLanguages;
|
||||
}
|
||||
|
||||
public virtual bool IsSaveLocalMetadataEnabled()
|
||||
{
|
||||
if (SourceType == SourceType.Channel)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ namespace MediaBrowser.Model.Configuration
|
|||
|
||||
public LibraryOptions()
|
||||
{
|
||||
PreferredImageLanguages = Array.Empty<string>();
|
||||
TypeOptions = Array.Empty<TypeOptions>();
|
||||
DisabledSubtitleFetchers = Array.Empty<string>();
|
||||
DisabledMediaSegmentProviders = Array.Empty<string>();
|
||||
|
|
@ -79,6 +80,13 @@ namespace MediaBrowser.Model.Configuration
|
|||
/// <value>The preferred metadata language.</value>
|
||||
public string? PreferredMetadataLanguage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the preferred image languages as an array (e.g., ["en", "de", "fr", "nolang"]).
|
||||
/// If empty, PreferredMetadataLanguage will be used as fallback.
|
||||
/// </summary>
|
||||
/// <value>The preferred image languages.</value>
|
||||
public string[] PreferredImageLanguages { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the metadata country code.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -11,46 +11,47 @@ namespace MediaBrowser.Model.Extensions
|
|||
public static class EnumerableExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Orders <see cref="RemoteImageInfo"/> by requested language in descending order, then "en", then no language, over other non-matches.
|
||||
/// Orders <see cref="RemoteImageInfo"/> by preferred languages in descending order.
|
||||
/// </summary>
|
||||
/// <param name="remoteImageInfos">The remote image infos.</param>
|
||||
/// <param name="requestedLanguage">The requested language for the images.</param>
|
||||
/// <param name="requestedMetadataLanguage">The requested metadata language for fallback if no preferred languages are specified.</param>
|
||||
/// <param name="preferredImageLanguages">Array of preferred image languages (e.g., ["en", "de", "fr", "nolang"]). If null or empty, uses requestedLanguage.</param>
|
||||
/// <returns>The ordered remote image infos.</returns>
|
||||
public static IEnumerable<RemoteImageInfo> OrderByLanguageDescending(this IEnumerable<RemoteImageInfo> remoteImageInfos, string requestedLanguage)
|
||||
public static IEnumerable<RemoteImageInfo> OrderByLanguageDescending(
|
||||
this IEnumerable<RemoteImageInfo> remoteImageInfos,
|
||||
string requestedMetadataLanguage,
|
||||
string[]? preferredImageLanguages)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(requestedLanguage))
|
||||
if (string.IsNullOrWhiteSpace(requestedMetadataLanguage))
|
||||
{
|
||||
// Default to English if no requested language is specified.
|
||||
requestedLanguage = "en";
|
||||
requestedMetadataLanguage = "en";
|
||||
}
|
||||
|
||||
string[] languages = preferredImageLanguages?.Length > 0
|
||||
? preferredImageLanguages
|
||||
: [requestedMetadataLanguage, "en"];
|
||||
|
||||
return remoteImageInfos.OrderByDescending(i =>
|
||||
{
|
||||
// Image priority ordering:
|
||||
// - Images that match the requested language
|
||||
// - TODO: Images that match the original language
|
||||
// - Images in English
|
||||
// - Images with no language
|
||||
// - Images that match preferred image languages (in order of preference)
|
||||
// - Images with no language if nolang is not in preferred image languages
|
||||
// - Images that don't match the requested language
|
||||
|
||||
if (string.Equals(requestedLanguage, i.Language, StringComparison.OrdinalIgnoreCase))
|
||||
for (int index = 0; index < languages.Length; index++)
|
||||
{
|
||||
return 4;
|
||||
if (string.Equals(languages[index], i.Language, StringComparison.OrdinalIgnoreCase) ||
|
||||
(string.Equals(languages[index], "nolang", StringComparison.OrdinalIgnoreCase) && string.IsNullOrEmpty(i.Language)))
|
||||
{
|
||||
// Return a high priority value, with earlier languages getting higher values
|
||||
return 1 + (languages.Length - index);
|
||||
}
|
||||
}
|
||||
|
||||
if (string.Equals(i.Language, "en", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(i.Language))
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return string.IsNullOrEmpty(i.Language) ? 1 : 0;
|
||||
})
|
||||
.ThenByDescending(i => Math.Round(i.CommunityRating ?? 0, 1) )
|
||||
.ThenByDescending(i => Math.Round(i.CommunityRating ?? 0, 1))
|
||||
.ThenByDescending(i => i.VoteCount ?? 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,6 +155,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
|
||||
var typeName = item.GetType().Name;
|
||||
var typeOptions = libraryOptions.GetTypeOptions(typeName) ?? new TypeOptions { Type = typeName };
|
||||
var preferredImageLanguages = libraryOptions.PreferredImageLanguages.ToList();
|
||||
|
||||
// track library limits, adding buffer to allow lazy replacing of current images
|
||||
var backdropLimit = typeOptions.GetLimit(ImageType.Backdrop) + oldBackdropImages.Length;
|
||||
|
|
@ -164,7 +165,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
{
|
||||
if (provider is IRemoteImageProvider remoteProvider)
|
||||
{
|
||||
await RefreshFromProvider(item, remoteProvider, refreshOptions, typeOptions, backdropLimit, downloadedImages, result, cancellationToken).ConfigureAwait(false);
|
||||
await RefreshFromProvider(item, remoteProvider, refreshOptions, typeOptions, preferredImageLanguages, backdropLimit, downloadedImages, result, cancellationToken).ConfigureAwait(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -266,6 +267,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
/// <param name="provider">The provider.</param>
|
||||
/// <param name="refreshOptions">The refresh options.</param>
|
||||
/// <param name="savedOptions">The saved options.</param>
|
||||
/// <param name="preferredImageLanguages">The preferred image languages.</param>
|
||||
/// <param name="backdropLimit">The backdrop limit.</param>
|
||||
/// <param name="downloadedImages">The downloaded images.</param>
|
||||
/// <param name="result">The result.</param>
|
||||
|
|
@ -276,6 +278,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
IRemoteImageProvider provider,
|
||||
ImageRefreshOptions refreshOptions,
|
||||
TypeOptions savedOptions,
|
||||
List<string> preferredImageLanguages,
|
||||
int backdropLimit,
|
||||
List<ImageType> downloadedImages,
|
||||
RefreshResult result,
|
||||
|
|
@ -297,11 +300,13 @@ namespace MediaBrowser.Providers.Manager
|
|||
|
||||
_logger.LogDebug("Running {Provider} for {Item}", provider.GetType().Name, item.Path ?? item.Name);
|
||||
|
||||
var includeAllLanguages = preferredImageLanguages.Count == 0;
|
||||
|
||||
var images = await _providerManager.GetAvailableRemoteImages(
|
||||
item,
|
||||
new RemoteImageQuery(provider.Name)
|
||||
{
|
||||
IncludeAllLanguages = true,
|
||||
IncludeAllLanguages = includeAllLanguages,
|
||||
IncludeDisabledProviders = false,
|
||||
},
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
|
|
|||
|
|
@ -303,9 +303,10 @@ namespace MediaBrowser.Providers.Manager
|
|||
providers = providers.Where(i => i.GetSupportedImages(item).Contains(query.ImageType.Value));
|
||||
}
|
||||
|
||||
var preferredLanguage = item.GetPreferredMetadataLanguage();
|
||||
var preferredMetadataLanguage = item.GetPreferredMetadataLanguage();
|
||||
var preferredImageLanguages = item.GetPreferredImageLanguages();
|
||||
|
||||
var tasks = providers.Select(i => GetImages(item, i, preferredLanguage, query.IncludeAllLanguages, cancellationToken, query.ImageType));
|
||||
var tasks = providers.Select(i => GetImages(item, i, preferredMetadataLanguage, preferredImageLanguages, query.IncludeAllLanguages, cancellationToken, query.ImageType));
|
||||
|
||||
var results = await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
||||
|
|
@ -317,7 +318,8 @@ namespace MediaBrowser.Providers.Manager
|
|||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="provider">The provider.</param>
|
||||
/// <param name="preferredLanguage">The preferred language.</param>
|
||||
/// <param name="preferredMetadataLanguage">The preferred language.</param>
|
||||
/// <param name="preferredImageLanguages">The preferred image languages.</param>
|
||||
/// <param name="includeAllLanguages">Whether to include all languages in results.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <param name="type">The type.</param>
|
||||
|
|
@ -325,12 +327,14 @@ namespace MediaBrowser.Providers.Manager
|
|||
private async Task<IEnumerable<RemoteImageInfo>> GetImages(
|
||||
BaseItem item,
|
||||
IRemoteImageProvider provider,
|
||||
string preferredLanguage,
|
||||
string preferredMetadataLanguage,
|
||||
string[] preferredImageLanguages,
|
||||
bool includeAllLanguages,
|
||||
CancellationToken cancellationToken,
|
||||
ImageType? type = null)
|
||||
{
|
||||
bool hasPreferredLanguage = !string.IsNullOrWhiteSpace(preferredLanguage);
|
||||
bool hasPreferredMetadataLanguage = !string.IsNullOrWhiteSpace(preferredMetadataLanguage);
|
||||
bool hasPreferredImageLanguages = preferredImageLanguages?.Length > 0;
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -341,17 +345,26 @@ namespace MediaBrowser.Providers.Manager
|
|||
result = result.Where(i => i.Type == type.Value);
|
||||
}
|
||||
|
||||
if (!includeAllLanguages && hasPreferredLanguage)
|
||||
if (!includeAllLanguages)
|
||||
{
|
||||
// Filter out languages that do not match the preferred languages.
|
||||
//
|
||||
// TODO: should exception case of "en" (English) eventually be removed?
|
||||
result = result.Where(i => string.IsNullOrWhiteSpace(i.Language) ||
|
||||
string.Equals(preferredLanguage, i.Language, StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(i.Language, "en", StringComparison.OrdinalIgnoreCase));
|
||||
if (hasPreferredImageLanguages)
|
||||
{
|
||||
// Filter out languages that do not match the preferred image languages.
|
||||
result = result.Where(i => string.IsNullOrWhiteSpace(i.Language) ||
|
||||
preferredImageLanguages!.Contains(i.Language, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
else if (hasPreferredMetadataLanguage)
|
||||
{
|
||||
// Fallback to metadata language if no image languages configured
|
||||
//
|
||||
// TODO: should exception case of "en" (English) eventually be removed?
|
||||
result = result.Where(i => string.IsNullOrWhiteSpace(i.Language) ||
|
||||
string.Equals(preferredMetadataLanguage, i.Language, StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(i.Language, "en", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
|
||||
return result.OrderByLanguageDescending(preferredLanguage);
|
||||
return result.OrderByLanguageDescending(preferredMetadataLanguage, preferredImageLanguages);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue