Centralize Multilang field constants
This commit is contained in:
@@ -3,6 +3,7 @@ using System.Diagnostics;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
|
using static Jellyfin.Plugin.Multilang.MultilangConstants;
|
||||||
using Jellyfin.Plugin.Multilang.Configuration;
|
using Jellyfin.Plugin.Multilang.Configuration;
|
||||||
using Jellyfin.Plugin.Multilang.Data;
|
using Jellyfin.Plugin.Multilang.Data;
|
||||||
using Jellyfin.Plugin.Multilang.Rules;
|
using Jellyfin.Plugin.Multilang.Rules;
|
||||||
@@ -450,11 +451,11 @@ public sealed class MultilangController : ControllerBase
|
|||||||
var classificationFacts = GetClassificationFacts(rules, facts);
|
var classificationFacts = GetClassificationFacts(rules, facts);
|
||||||
var category = PickCategory(rules, classificationFacts);
|
var category = PickCategory(rules, classificationFacts);
|
||||||
|
|
||||||
var title = ResolveField("title", GetActionList(rules, category, "title"), facts, byLang);
|
var title = ResolveField(TitleField, GetActionList(rules, category, TitleField), facts, byLang);
|
||||||
if (title.Change)
|
if (title.Change)
|
||||||
item["Name"] = title.Value ?? string.Empty;
|
item["Name"] = title.Value ?? string.Empty;
|
||||||
|
|
||||||
var overview = ResolveField("overview", GetActionList(rules, category, "overview"), facts, byLang);
|
var overview = ResolveField(OverviewField, GetActionList(rules, category, OverviewField), facts, byLang);
|
||||||
if (overview.Change)
|
if (overview.Change)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(overview.Value))
|
if (string.IsNullOrWhiteSpace(overview.Value))
|
||||||
@@ -463,16 +464,16 @@ public sealed class MultilangController : ControllerBase
|
|||||||
item["Overview"] = overview.Value;
|
item["Overview"] = overview.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
var tagline = ResolveField("tagline", GetActionList(rules, category, "tagline"), facts, byLang);
|
var tagline = ResolveField(TaglineField, GetActionList(rules, category, TaglineField), facts, byLang);
|
||||||
if (tagline.Change)
|
if (tagline.Change)
|
||||||
item["Taglines"] = string.IsNullOrWhiteSpace(tagline.Value) ? new JsonArray() : new JsonArray(tagline.Value);
|
item["Taglines"] = string.IsNullOrWhiteSpace(tagline.Value) ? new JsonArray() : new JsonArray(tagline.Value);
|
||||||
|
|
||||||
assets.TryGetValue(itemId, out var assetsByKind);
|
assets.TryGetValue(itemId, out var assetsByKind);
|
||||||
ApplyImageAsset(item, "Primary", ResolveAsset("poster", GetActionList(rules, category, "poster"), assetsByKind));
|
ApplyImageAsset(item, "Primary", ResolveAsset(PosterKind, GetActionList(rules, category, PosterKind), assetsByKind));
|
||||||
ApplyImageAsset(item, "Logo", ResolveAsset("logo", GetActionList(rules, category, "logo"), assetsByKind));
|
ApplyImageAsset(item, "Logo", ResolveAsset(LogoKind, GetActionList(rules, category, LogoKind), assetsByKind));
|
||||||
ApplyImageAsset(item, "Banner", ResolveAsset("banner", GetActionList(rules, category, "banner"), assetsByKind));
|
ApplyImageAsset(item, "Banner", ResolveAsset(BannerKind, GetActionList(rules, category, BannerKind), assetsByKind));
|
||||||
ApplyImageAsset(item, "Thumb", ResolveAsset("thumb", GetActionList(rules, category, "thumb"), assetsByKind));
|
ApplyImageAsset(item, "Thumb", ResolveAsset(ThumbKind, GetActionList(rules, category, ThumbKind), assetsByKind));
|
||||||
ApplyBackdropAsset(item, ResolveAsset("backdrop", GetActionList(rules, category, "backdrop"), assetsByKind));
|
ApplyBackdropAsset(item, ResolveAsset(BackdropKind, GetActionList(rules, category, BackdropKind), assetsByKind));
|
||||||
ApplyGenres(item, facts, movieGenreNames, tvGenreNames);
|
ApplyGenres(item, facts, movieGenreNames, tvGenreNames);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -503,15 +504,14 @@ public sealed class MultilangController : ControllerBase
|
|||||||
|
|
||||||
private static void AddLanguageAction(List<string> langs, string action)
|
private static void AddLanguageAction(List<string> langs, string action)
|
||||||
{
|
{
|
||||||
if (action.Equals("Original", StringComparison.OrdinalIgnoreCase))
|
if (action.Equals(OriginalAction, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
langs.Add("Original");
|
langs.Add(OriginalAction);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const string prefix = "Language:";
|
if (action.StartsWith(LanguagePrefix, StringComparison.OrdinalIgnoreCase))
|
||||||
if (action.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
|
langs.Add(action[LanguagePrefix.Length..]);
|
||||||
langs.Add(action[prefix.Length..]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static UserCategoryRule? PickCategory(UserRulesDocument rules, FactsData facts)
|
private static UserCategoryRule? PickCategory(UserRulesDocument rules, FactsData facts)
|
||||||
@@ -637,30 +637,29 @@ public sealed class MultilangController : ControllerBase
|
|||||||
{
|
{
|
||||||
foreach (var action in actions)
|
foreach (var action in actions)
|
||||||
{
|
{
|
||||||
if (action.Equals("Jellyfin", StringComparison.OrdinalIgnoreCase))
|
if (action.Equals(JellyfinAction, StringComparison.OrdinalIgnoreCase))
|
||||||
return new ResolvedText(false, null);
|
return new ResolvedText(false, null);
|
||||||
if (field.Equals("title", StringComparison.OrdinalIgnoreCase) &&
|
if (field.Equals(TitleField, StringComparison.OrdinalIgnoreCase) &&
|
||||||
action.Equals("Original", StringComparison.OrdinalIgnoreCase) &&
|
action.Equals(OriginalAction, StringComparison.OrdinalIgnoreCase) &&
|
||||||
!string.IsNullOrWhiteSpace(facts.OriginalTitle))
|
!string.IsNullOrWhiteSpace(facts.OriginalTitle))
|
||||||
return new ResolvedText(true, facts.OriginalTitle);
|
return new ResolvedText(true, facts.OriginalTitle);
|
||||||
if (action.Equals("Original", StringComparison.OrdinalIgnoreCase))
|
if (action.Equals(OriginalAction, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var originalValue = GetTranslatedField(byLang, "Original", field);
|
var originalValue = GetTranslatedField(byLang, OriginalAction, field);
|
||||||
if (!string.IsNullOrWhiteSpace(originalValue))
|
if (!string.IsNullOrWhiteSpace(originalValue))
|
||||||
return new ResolvedText(true, originalValue);
|
return new ResolvedText(true, originalValue);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const string prefix = "Language:";
|
if (!action.StartsWith(LanguagePrefix, StringComparison.OrdinalIgnoreCase))
|
||||||
if (!action.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var value = GetTranslatedField(byLang, action[prefix.Length..], field);
|
var value = GetTranslatedField(byLang, action[LanguagePrefix.Length..], field);
|
||||||
if (!string.IsNullOrWhiteSpace(value))
|
if (!string.IsNullOrWhiteSpace(value))
|
||||||
return new ResolvedText(true, value);
|
return new ResolvedText(true, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return field.Equals("title", StringComparison.OrdinalIgnoreCase)
|
return field.Equals(TitleField, StringComparison.OrdinalIgnoreCase)
|
||||||
? new ResolvedText(false, null)
|
? new ResolvedText(false, null)
|
||||||
: new ResolvedText(true, string.Empty);
|
: new ResolvedText(true, string.Empty);
|
||||||
}
|
}
|
||||||
@@ -682,26 +681,25 @@ public sealed class MultilangController : ControllerBase
|
|||||||
{
|
{
|
||||||
foreach (var action in actions)
|
foreach (var action in actions)
|
||||||
{
|
{
|
||||||
if (action.Equals("Jellyfin", StringComparison.OrdinalIgnoreCase))
|
if (action.Equals(JellyfinAction, StringComparison.OrdinalIgnoreCase))
|
||||||
return new ResolvedAsset(false, null);
|
return new ResolvedAsset(false, null);
|
||||||
if (action.Equals("Original", StringComparison.OrdinalIgnoreCase))
|
if (action.Equals(OriginalAction, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var originalValue = GetAsset(byKind, kind, "Original");
|
var originalValue = GetAsset(byKind, kind, OriginalAction);
|
||||||
if (!string.IsNullOrWhiteSpace(originalValue))
|
if (!string.IsNullOrWhiteSpace(originalValue))
|
||||||
return new ResolvedAsset(true, originalValue);
|
return new ResolvedAsset(true, originalValue);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const string prefix = "Language:";
|
if (!action.StartsWith(LanguagePrefix, StringComparison.OrdinalIgnoreCase))
|
||||||
if (!action.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var value = GetAsset(byKind, kind, action[prefix.Length..]);
|
var value = GetAsset(byKind, kind, action[LanguagePrefix.Length..]);
|
||||||
if (!string.IsNullOrWhiteSpace(value))
|
if (!string.IsNullOrWhiteSpace(value))
|
||||||
return new ResolvedAsset(true, value);
|
return new ResolvedAsset(true, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return kind.Equals("poster", StringComparison.OrdinalIgnoreCase)
|
return kind.Equals(PosterKind, StringComparison.OrdinalIgnoreCase)
|
||||||
? new ResolvedAsset(false, null)
|
? new ResolvedAsset(false, null)
|
||||||
: new ResolvedAsset(true, string.Empty);
|
: new ResolvedAsset(true, string.Empty);
|
||||||
}
|
}
|
||||||
@@ -1193,7 +1191,7 @@ public sealed class MultilangController : ControllerBase
|
|||||||
var ruleLanguages = GetNeededLanguages(rules);
|
var ruleLanguages = GetNeededLanguages(rules);
|
||||||
var debugLanguages = configuredLanguages
|
var debugLanguages = configuredLanguages
|
||||||
.Concat(ruleLanguages)
|
.Concat(ruleLanguages)
|
||||||
.Append("Original")
|
.Append(OriginalAction)
|
||||||
.Where(lang => !string.IsNullOrWhiteSpace(lang))
|
.Where(lang => !string.IsNullOrWhiteSpace(lang))
|
||||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
@@ -1211,20 +1209,19 @@ public sealed class MultilangController : ControllerBase
|
|||||||
var effectiveSortLocale = ResolveSortLocale(rules.SortLocale, clientLocale);
|
var effectiveSortLocale = ResolveSortLocale(rules.SortLocale, clientLocale);
|
||||||
var genreLocale = string.IsNullOrWhiteSpace(clientLocale) ? effectiveSortLocale : clientLocale;
|
var genreLocale = string.IsNullOrWhiteSpace(clientLocale) ? effectiveSortLocale : clientLocale;
|
||||||
|
|
||||||
string[] fields = ["title", "overview", "tagline", "poster", "logo", "banner", "thumb", "backdrop"];
|
var actionLists = ActionFields.ToDictionary(
|
||||||
var actionLists = fields.ToDictionary(
|
|
||||||
field => field,
|
field => field,
|
||||||
field => GetActionList(rules, category, field).ToArray(),
|
field => GetActionList(rules, category, field).ToArray(),
|
||||||
StringComparer.OrdinalIgnoreCase);
|
StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
var title = TraceResolveField("title", actionLists["title"], facts, byLang);
|
var title = TraceResolveField(TitleField, actionLists[TitleField], facts, byLang);
|
||||||
var overview = TraceResolveField("overview", actionLists["overview"], facts, byLang);
|
var overview = TraceResolveField(OverviewField, actionLists[OverviewField], facts, byLang);
|
||||||
var tagline = TraceResolveField("tagline", actionLists["tagline"], facts, byLang);
|
var tagline = TraceResolveField(TaglineField, actionLists[TaglineField], facts, byLang);
|
||||||
var poster = TraceResolveAsset("poster", actionLists["poster"], byKind);
|
var poster = TraceResolveAsset(PosterKind, actionLists[PosterKind], byKind);
|
||||||
var logo = TraceResolveAsset("logo", actionLists["logo"], byKind);
|
var logo = TraceResolveAsset(LogoKind, actionLists[LogoKind], byKind);
|
||||||
var banner = TraceResolveAsset("banner", actionLists["banner"], byKind);
|
var banner = TraceResolveAsset(BannerKind, actionLists[BannerKind], byKind);
|
||||||
var thumb = TraceResolveAsset("thumb", actionLists["thumb"], byKind);
|
var thumb = TraceResolveAsset(ThumbKind, actionLists[ThumbKind], byKind);
|
||||||
var backdrop = TraceResolveAsset("backdrop", actionLists["backdrop"], byKind);
|
var backdrop = TraceResolveAsset(BackdropKind, actionLists[BackdropKind], byKind);
|
||||||
var genres = ResolveGenresForDebug(facts, genreLocale);
|
var genres = ResolveGenresForDebug(facts, genreLocale);
|
||||||
|
|
||||||
return Ok(new
|
return Ok(new
|
||||||
@@ -1239,8 +1236,8 @@ public sealed class MultilangController : ControllerBase
|
|||||||
ConfiguredLanguages = configuredLanguages,
|
ConfiguredLanguages = configuredLanguages,
|
||||||
RuleLanguages = ruleLanguages,
|
RuleLanguages = ruleLanguages,
|
||||||
DebugLanguages = debugLanguages,
|
DebugLanguages = debugLanguages,
|
||||||
MatchedCategory = categoryMatch.Matched ?? new { Id = "fallback", Label = "Fallback" } as object,
|
MatchedCategory = categoryMatch.Matched ?? new { Id = "fallback", Label = FallbackAction } as object,
|
||||||
EffectiveCategory = category ?? new { Id = "fallback", Label = "Fallback" } as object,
|
EffectiveCategory = category ?? new { Id = "fallback", Label = FallbackAction } as object,
|
||||||
DuplicateCategoryLabelResolved = categoryMatch.DuplicateLabelResolved,
|
DuplicateCategoryLabelResolved = categoryMatch.DuplicateLabelResolved,
|
||||||
CategoryEvaluation = new
|
CategoryEvaluation = new
|
||||||
{
|
{
|
||||||
@@ -1311,15 +1308,15 @@ public sealed class MultilangController : ControllerBase
|
|||||||
var attempts = new List<DebugResolutionAttempt>();
|
var attempts = new List<DebugResolutionAttempt>();
|
||||||
foreach (var action in actions)
|
foreach (var action in actions)
|
||||||
{
|
{
|
||||||
if (action.Equals("Jellyfin", StringComparison.OrdinalIgnoreCase))
|
if (action.Equals(JellyfinAction, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var result = new ResolvedText(false, null);
|
var result = new ResolvedText(false, null);
|
||||||
attempts.Add(new DebugResolutionAttempt(action, "Jellyfin", string.Empty, true, true, null, "Use Jellyfin value"));
|
attempts.Add(new DebugResolutionAttempt(action, JellyfinAction, string.Empty, true, true, null, "Use Jellyfin value"));
|
||||||
return new DebugTextResolution(field, actions.ToArray(), attempts.ToArray(), result, "Jellyfin", "Jellyfin action reached");
|
return new DebugTextResolution(field, actions.ToArray(), attempts.ToArray(), result, JellyfinAction, "Jellyfin action reached");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (field.Equals("title", StringComparison.OrdinalIgnoreCase) &&
|
if (field.Equals(TitleField, StringComparison.OrdinalIgnoreCase) &&
|
||||||
action.Equals("Original", StringComparison.OrdinalIgnoreCase))
|
action.Equals(OriginalAction, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var hasOriginalTitle = !string.IsNullOrWhiteSpace(facts.OriginalTitle);
|
var hasOriginalTitle = !string.IsNullOrWhiteSpace(facts.OriginalTitle);
|
||||||
attempts.Add(new DebugResolutionAttempt(action, "OriginalTitle", "facts.original_title", hasOriginalTitle, hasOriginalTitle, facts.OriginalTitle, hasOriginalTitle ? "Original title found" : "Original title missing"));
|
attempts.Add(new DebugResolutionAttempt(action, "OriginalTitle", "facts.original_title", hasOriginalTitle, hasOriginalTitle, facts.OriginalTitle, hasOriginalTitle ? "Original title found" : "Original title missing"));
|
||||||
@@ -1332,9 +1329,9 @@ public sealed class MultilangController : ControllerBase
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.Equals("Original", StringComparison.OrdinalIgnoreCase))
|
if (action.Equals(OriginalAction, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var originalValue = GetTranslatedField(byLang, "Original", field);
|
var originalValue = GetTranslatedField(byLang, OriginalAction, field);
|
||||||
var hasOriginalValue = !string.IsNullOrWhiteSpace(originalValue);
|
var hasOriginalValue = !string.IsNullOrWhiteSpace(originalValue);
|
||||||
attempts.Add(new DebugResolutionAttempt(action, "Translation", "Original/" + field, hasOriginalValue, hasOriginalValue, originalValue, hasOriginalValue ? "Original-language translation found" : "Original-language translation missing"));
|
attempts.Add(new DebugResolutionAttempt(action, "Translation", "Original/" + field, hasOriginalValue, hasOriginalValue, originalValue, hasOriginalValue ? "Original-language translation found" : "Original-language translation missing"));
|
||||||
if (hasOriginalValue)
|
if (hasOriginalValue)
|
||||||
@@ -1346,14 +1343,13 @@ public sealed class MultilangController : ControllerBase
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const string prefix = "Language:";
|
if (!action.StartsWith(LanguagePrefix, StringComparison.OrdinalIgnoreCase))
|
||||||
if (!action.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
attempts.Add(new DebugResolutionAttempt(action, "Unknown", string.Empty, false, false, null, "Unsupported action token"));
|
attempts.Add(new DebugResolutionAttempt(action, "Unknown", string.Empty, false, false, null, "Unsupported action token"));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var lang = action[prefix.Length..];
|
var lang = action[LanguagePrefix.Length..];
|
||||||
var value = GetTranslatedField(byLang, lang, field);
|
var value = GetTranslatedField(byLang, lang, field);
|
||||||
var hasValue = !string.IsNullOrWhiteSpace(value);
|
var hasValue = !string.IsNullOrWhiteSpace(value);
|
||||||
attempts.Add(new DebugResolutionAttempt(action, "Translation", lang + "/" + field, hasValue, hasValue, value, hasValue ? "Translation found" : "Translation missing or empty"));
|
attempts.Add(new DebugResolutionAttempt(action, "Translation", lang + "/" + field, hasValue, hasValue, value, hasValue ? "Translation found" : "Translation missing or empty"));
|
||||||
@@ -1364,13 +1360,13 @@ public sealed class MultilangController : ControllerBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var fallback = field.Equals("title", StringComparison.OrdinalIgnoreCase)
|
var fallback = field.Equals(TitleField, StringComparison.OrdinalIgnoreCase)
|
||||||
? new ResolvedText(false, null)
|
? new ResolvedText(false, null)
|
||||||
: new ResolvedText(true, string.Empty);
|
: new ResolvedText(true, string.Empty);
|
||||||
var reason = field.Equals("title", StringComparison.OrdinalIgnoreCase)
|
var reason = field.Equals(TitleField, StringComparison.OrdinalIgnoreCase)
|
||||||
? "No action had data; title falls back to Jellyfin"
|
? "No action had data; title falls back to Jellyfin"
|
||||||
: "No action had data; field is cleared";
|
: "No action had data; field is cleared";
|
||||||
return new DebugTextResolution(field, actions.ToArray(), attempts.ToArray(), fallback, field.Equals("title", StringComparison.OrdinalIgnoreCase) ? "Jellyfin" : "Clear", reason);
|
return new DebugTextResolution(field, actions.ToArray(), attempts.ToArray(), fallback, field.Equals(TitleField, StringComparison.OrdinalIgnoreCase) ? JellyfinAction : ClearAction, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DebugAssetResolution TraceResolveAsset(
|
private static DebugAssetResolution TraceResolveAsset(
|
||||||
@@ -1381,16 +1377,16 @@ public sealed class MultilangController : ControllerBase
|
|||||||
var attempts = new List<DebugResolutionAttempt>();
|
var attempts = new List<DebugResolutionAttempt>();
|
||||||
foreach (var action in actions)
|
foreach (var action in actions)
|
||||||
{
|
{
|
||||||
if (action.Equals("Jellyfin", StringComparison.OrdinalIgnoreCase))
|
if (action.Equals(JellyfinAction, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var result = new ResolvedAsset(false, null);
|
var result = new ResolvedAsset(false, null);
|
||||||
attempts.Add(new DebugResolutionAttempt(action, "Jellyfin", string.Empty, true, true, null, "Use Jellyfin image"));
|
attempts.Add(new DebugResolutionAttempt(action, JellyfinAction, string.Empty, true, true, null, "Use Jellyfin image"));
|
||||||
return new DebugAssetResolution(kind, actions.ToArray(), attempts.ToArray(), result, "Jellyfin", "Jellyfin action reached");
|
return new DebugAssetResolution(kind, actions.ToArray(), attempts.ToArray(), result, JellyfinAction, "Jellyfin action reached");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.Equals("Original", StringComparison.OrdinalIgnoreCase))
|
if (action.Equals(OriginalAction, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var originalValue = GetAsset(byKind, kind, "Original");
|
var originalValue = GetAsset(byKind, kind, OriginalAction);
|
||||||
var hasOriginalValue = !string.IsNullOrWhiteSpace(originalValue);
|
var hasOriginalValue = !string.IsNullOrWhiteSpace(originalValue);
|
||||||
attempts.Add(new DebugResolutionAttempt(action, "Asset", kind + "/Original", hasOriginalValue, hasOriginalValue, originalValue, hasOriginalValue ? "Original-language asset found" : "Original-language asset missing"));
|
attempts.Add(new DebugResolutionAttempt(action, "Asset", kind + "/Original", hasOriginalValue, hasOriginalValue, originalValue, hasOriginalValue ? "Original-language asset found" : "Original-language asset missing"));
|
||||||
if (hasOriginalValue)
|
if (hasOriginalValue)
|
||||||
@@ -1402,14 +1398,13 @@ public sealed class MultilangController : ControllerBase
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const string prefix = "Language:";
|
if (!action.StartsWith(LanguagePrefix, StringComparison.OrdinalIgnoreCase))
|
||||||
if (!action.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
attempts.Add(new DebugResolutionAttempt(action, "Unknown", string.Empty, false, false, null, "Unsupported action token"));
|
attempts.Add(new DebugResolutionAttempt(action, "Unknown", string.Empty, false, false, null, "Unsupported action token"));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var lang = action[prefix.Length..];
|
var lang = action[LanguagePrefix.Length..];
|
||||||
var value = GetAsset(byKind, kind, lang);
|
var value = GetAsset(byKind, kind, lang);
|
||||||
var hasValue = !string.IsNullOrWhiteSpace(value);
|
var hasValue = !string.IsNullOrWhiteSpace(value);
|
||||||
attempts.Add(new DebugResolutionAttempt(action, "Asset", kind + "/" + lang, hasValue, hasValue, value, hasValue ? "Asset found" : "Asset missing"));
|
attempts.Add(new DebugResolutionAttempt(action, "Asset", kind + "/" + lang, hasValue, hasValue, value, hasValue ? "Asset found" : "Asset missing"));
|
||||||
@@ -1420,13 +1415,13 @@ public sealed class MultilangController : ControllerBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var fallback = kind.Equals("poster", StringComparison.OrdinalIgnoreCase)
|
var fallback = kind.Equals(PosterKind, StringComparison.OrdinalIgnoreCase)
|
||||||
? new ResolvedAsset(false, null)
|
? new ResolvedAsset(false, null)
|
||||||
: new ResolvedAsset(true, string.Empty);
|
: new ResolvedAsset(true, string.Empty);
|
||||||
var reason = kind.Equals("poster", StringComparison.OrdinalIgnoreCase)
|
var reason = kind.Equals(PosterKind, StringComparison.OrdinalIgnoreCase)
|
||||||
? "No action had data; poster falls back to Jellyfin"
|
? "No action had data; poster falls back to Jellyfin"
|
||||||
: "No action had data; image is cleared";
|
: "No action had data; image is cleared";
|
||||||
return new DebugAssetResolution(kind, actions.ToArray(), attempts.ToArray(), fallback, kind.Equals("poster", StringComparison.OrdinalIgnoreCase) ? "Jellyfin" : "Clear", reason);
|
return new DebugAssetResolution(kind, actions.ToArray(), attempts.ToArray(), fallback, kind.Equals(PosterKind, StringComparison.OrdinalIgnoreCase) ? JellyfinAction : ClearAction, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static object[] BuildMissingDataReport(
|
private static object[] BuildMissingDataReport(
|
||||||
@@ -1434,18 +1429,16 @@ public sealed class MultilangController : ControllerBase
|
|||||||
Dictionary<string, Dictionary<string, string>>? byLang,
|
Dictionary<string, Dictionary<string, string>>? byLang,
|
||||||
Dictionary<string, Dictionary<string, string>>? byKind)
|
Dictionary<string, Dictionary<string, string>>? byKind)
|
||||||
{
|
{
|
||||||
string[] textFields = ["title", "overview", "tagline"];
|
|
||||||
string[] assetKinds = ["poster", "logo", "banner", "thumb", "backdrop"];
|
|
||||||
return configuredLanguages
|
return configuredLanguages
|
||||||
.Where(lang => !string.IsNullOrWhiteSpace(lang))
|
.Where(lang => !string.IsNullOrWhiteSpace(lang))
|
||||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
.OrderBy(lang => lang, StringComparer.OrdinalIgnoreCase)
|
.OrderBy(lang => lang, StringComparer.OrdinalIgnoreCase)
|
||||||
.Select(lang =>
|
.Select(lang =>
|
||||||
{
|
{
|
||||||
var missingText = textFields
|
var missingText = TextFields
|
||||||
.Where(field => string.IsNullOrWhiteSpace(GetTranslatedField(byLang, lang, field)))
|
.Where(field => string.IsNullOrWhiteSpace(GetTranslatedField(byLang, lang, field)))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
var missingAssets = assetKinds
|
var missingAssets = AssetKinds
|
||||||
.Where(kind => string.IsNullOrWhiteSpace(GetAsset(byKind, kind, lang)))
|
.Where(kind => string.IsNullOrWhiteSpace(GetAsset(byKind, kind, lang)))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
return new
|
return new
|
||||||
@@ -1462,7 +1455,7 @@ public sealed class MultilangController : ControllerBase
|
|||||||
private static object DebugTextOutput(ResolvedText text)
|
private static object DebugTextOutput(ResolvedText text)
|
||||||
=> new
|
=> new
|
||||||
{
|
{
|
||||||
Source = text.Change ? "Multilang" : "Jellyfin",
|
Source = text.Change ? "Multilang" : JellyfinAction,
|
||||||
Value = text.Value,
|
Value = text.Value,
|
||||||
ClearsValue = text.Change && string.IsNullOrWhiteSpace(text.Value)
|
ClearsValue = text.Change && string.IsNullOrWhiteSpace(text.Value)
|
||||||
};
|
};
|
||||||
@@ -1470,7 +1463,7 @@ public sealed class MultilangController : ControllerBase
|
|||||||
private static object DebugAssetOutput(ResolvedAsset asset)
|
private static object DebugAssetOutput(ResolvedAsset asset)
|
||||||
=> new
|
=> new
|
||||||
{
|
{
|
||||||
Source = asset.Change ? "Multilang" : "Jellyfin",
|
Source = asset.Change ? "Multilang" : JellyfinAction,
|
||||||
Value = asset.Change && !string.IsNullOrWhiteSpace(asset.Value) ? ToImageTag(asset.Value) : asset.Value,
|
Value = asset.Change && !string.IsNullOrWhiteSpace(asset.Value) ? ToImageTag(asset.Value) : asset.Value,
|
||||||
ClearsValue = asset.Change && string.IsNullOrWhiteSpace(asset.Value)
|
ClearsValue = asset.Change && string.IsNullOrWhiteSpace(asset.Value)
|
||||||
};
|
};
|
||||||
@@ -1675,20 +1668,20 @@ public sealed class MultilangController : ControllerBase
|
|||||||
DefaultActionLists().Keys.All(field =>
|
DefaultActionLists().Keys.All(field =>
|
||||||
actions.TryGetValue(field, out var list) &&
|
actions.TryGetValue(field, out var list) &&
|
||||||
list.Length == 1 &&
|
list.Length == 1 &&
|
||||||
list[0].Equals("Jellyfin", StringComparison.OrdinalIgnoreCase));
|
list[0].Equals(JellyfinAction, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
private static bool HasMeaningfulLegacyActions(IReadOnlyDictionary<string, string> legacyActions)
|
private static bool HasMeaningfulLegacyActions(IReadOnlyDictionary<string, string> legacyActions)
|
||||||
=> legacyActions.Values.Any(action =>
|
=> legacyActions.Values.Any(action =>
|
||||||
!string.IsNullOrWhiteSpace(action) &&
|
!string.IsNullOrWhiteSpace(action) &&
|
||||||
!action.Equals("Fallback", StringComparison.OrdinalIgnoreCase) &&
|
!action.Equals(FallbackAction, StringComparison.OrdinalIgnoreCase) &&
|
||||||
!action.Equals("Jellyfin", StringComparison.OrdinalIgnoreCase));
|
!action.Equals(JellyfinAction, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
private static string[] LegacyActionToList(string field, IReadOnlyDictionary<string, string>? legacyActions)
|
private static string[] LegacyActionToList(string field, IReadOnlyDictionary<string, string>? legacyActions)
|
||||||
{
|
{
|
||||||
if (legacyActions is null || !legacyActions.TryGetValue(field, out var action))
|
if (legacyActions is null || !legacyActions.TryGetValue(field, out var action))
|
||||||
return ["Jellyfin"];
|
return [JellyfinAction];
|
||||||
if (string.IsNullOrWhiteSpace(action) || action.Equals("Fallback", StringComparison.OrdinalIgnoreCase))
|
if (string.IsNullOrWhiteSpace(action) || action.Equals(FallbackAction, StringComparison.OrdinalIgnoreCase))
|
||||||
return ["Jellyfin"];
|
return [JellyfinAction];
|
||||||
return [action];
|
return [action];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1714,24 +1707,23 @@ public sealed class MultilangController : ControllerBase
|
|||||||
private static string NormalizeAction(string field, string? raw, IReadOnlySet<string> allowedLanguages)
|
private static string NormalizeAction(string field, string? raw, IReadOnlySet<string> allowedLanguages)
|
||||||
{
|
{
|
||||||
var action = (raw ?? string.Empty).Trim();
|
var action = (raw ?? string.Empty).Trim();
|
||||||
if (action.Equals("Jellyfin", StringComparison.OrdinalIgnoreCase) ||
|
if (action.Equals(JellyfinAction, StringComparison.OrdinalIgnoreCase) ||
|
||||||
action.Equals("Fallback", StringComparison.OrdinalIgnoreCase))
|
action.Equals(FallbackAction, StringComparison.OrdinalIgnoreCase))
|
||||||
return action;
|
return action;
|
||||||
if (action.Equals("Original", StringComparison.OrdinalIgnoreCase))
|
if (action.Equals(OriginalAction, StringComparison.OrdinalIgnoreCase))
|
||||||
return "Original";
|
return OriginalAction;
|
||||||
if ((field is "overview" or "tagline" or "logo") &&
|
if ((field is OverviewField or TaglineField or LogoKind) &&
|
||||||
action.Equals("Clear", StringComparison.OrdinalIgnoreCase))
|
action.Equals(ClearAction, StringComparison.OrdinalIgnoreCase))
|
||||||
return "Clear";
|
return ClearAction;
|
||||||
const string prefix = "Language:";
|
if (action.StartsWith(LanguagePrefix, StringComparison.OrdinalIgnoreCase))
|
||||||
if (action.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
var lang = action[prefix.Length..].Trim();
|
var lang = action[LanguagePrefix.Length..].Trim();
|
||||||
var canonical = allowedLanguages.FirstOrDefault(l => l.Equals(lang, StringComparison.OrdinalIgnoreCase));
|
var canonical = allowedLanguages.FirstOrDefault(l => l.Equals(lang, StringComparison.OrdinalIgnoreCase));
|
||||||
if (!string.IsNullOrWhiteSpace(canonical))
|
if (!string.IsNullOrWhiteSpace(canonical))
|
||||||
return prefix + canonical;
|
return LanguagePrefix + canonical;
|
||||||
}
|
}
|
||||||
|
|
||||||
return "Fallback";
|
return FallbackAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string[] NormalizeActionList(string field, IEnumerable<string>? raw, IReadOnlySet<string> allowedLanguages)
|
private static string[] NormalizeActionList(string field, IEnumerable<string>? raw, IReadOnlySet<string> allowedLanguages)
|
||||||
@@ -1747,11 +1739,10 @@ public sealed class MultilangController : ControllerBase
|
|||||||
result.Add(normalized);
|
result.Add(normalized);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (field.Equals("title", StringComparison.OrdinalIgnoreCase) ||
|
if (RequiresJellyfinFallback(field))
|
||||||
field.Equals("poster", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
if (!result.Contains("Jellyfin", StringComparer.OrdinalIgnoreCase))
|
if (!result.Contains(JellyfinAction, StringComparer.OrdinalIgnoreCase))
|
||||||
result.Add("Jellyfin");
|
result.Add(JellyfinAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.ToArray();
|
return result.ToArray();
|
||||||
@@ -1761,48 +1752,21 @@ public sealed class MultilangController : ControllerBase
|
|||||||
{
|
{
|
||||||
var action = (raw ?? string.Empty).Trim();
|
var action = (raw ?? string.Empty).Trim();
|
||||||
if (action.Equals("J", StringComparison.OrdinalIgnoreCase))
|
if (action.Equals("J", StringComparison.OrdinalIgnoreCase))
|
||||||
return "Jellyfin";
|
return JellyfinAction;
|
||||||
if (action.Equals("O", StringComparison.OrdinalIgnoreCase))
|
if (action.Equals("O", StringComparison.OrdinalIgnoreCase))
|
||||||
return "Original";
|
return OriginalAction;
|
||||||
if (action.Equals("Jellyfin", StringComparison.OrdinalIgnoreCase))
|
if (action.Equals(JellyfinAction, StringComparison.OrdinalIgnoreCase))
|
||||||
return "Jellyfin";
|
return JellyfinAction;
|
||||||
if (action.Equals("Original", StringComparison.OrdinalIgnoreCase))
|
if (action.Equals(OriginalAction, StringComparison.OrdinalIgnoreCase))
|
||||||
return "Original";
|
return OriginalAction;
|
||||||
|
|
||||||
const string prefix = "Language:";
|
var lang = action.StartsWith(LanguagePrefix, StringComparison.OrdinalIgnoreCase)
|
||||||
var lang = action.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)
|
? action[LanguagePrefix.Length..].Trim()
|
||||||
? action[prefix.Length..].Trim()
|
|
||||||
: action;
|
: action;
|
||||||
var canonical = allowedLanguages.FirstOrDefault(l => l.Equals(lang, StringComparison.OrdinalIgnoreCase));
|
var canonical = allowedLanguages.FirstOrDefault(l => l.Equals(lang, StringComparison.OrdinalIgnoreCase));
|
||||||
return string.IsNullOrWhiteSpace(canonical) ? string.Empty : prefix + canonical;
|
return string.IsNullOrWhiteSpace(canonical) ? string.Empty : LanguagePrefix + canonical;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dictionary<string, string> DefaultFieldActions()
|
|
||||||
=> new(StringComparer.OrdinalIgnoreCase)
|
|
||||||
{
|
|
||||||
["title"] = "Fallback",
|
|
||||||
["overview"] = "Fallback",
|
|
||||||
["tagline"] = "Fallback",
|
|
||||||
["poster"] = "Fallback",
|
|
||||||
["logo"] = "Fallback",
|
|
||||||
["banner"] = "Fallback",
|
|
||||||
["thumb"] = "Fallback",
|
|
||||||
["backdrop"] = "Fallback"
|
|
||||||
};
|
|
||||||
|
|
||||||
private static Dictionary<string, string[]> DefaultActionLists()
|
|
||||||
=> new(StringComparer.OrdinalIgnoreCase)
|
|
||||||
{
|
|
||||||
["title"] = ["Jellyfin"],
|
|
||||||
["overview"] = ["Jellyfin"],
|
|
||||||
["tagline"] = ["Jellyfin"],
|
|
||||||
["poster"] = ["Jellyfin"],
|
|
||||||
["logo"] = ["Jellyfin"],
|
|
||||||
["banner"] = ["Jellyfin"],
|
|
||||||
["thumb"] = ["Jellyfin"],
|
|
||||||
["backdrop"] = ["Jellyfin"]
|
|
||||||
};
|
|
||||||
|
|
||||||
private static IReadOnlyList<string> GetActionList(UserRulesDocument rules, UserCategoryRule? category, string field)
|
private static IReadOnlyList<string> GetActionList(UserRulesDocument rules, UserCategoryRule? category, string field)
|
||||||
{
|
{
|
||||||
var actions = category is null ? rules.FallbackFieldActions : category.FieldActionLists;
|
var actions = category is null ? rules.FallbackFieldActions : category.FieldActionLists;
|
||||||
@@ -1812,7 +1776,7 @@ public sealed class MultilangController : ControllerBase
|
|||||||
if (category is not null && category.FieldActions is not null)
|
if (category is not null && category.FieldActions is not null)
|
||||||
return LegacyActionToList(field, category.FieldActions);
|
return LegacyActionToList(field, category.FieldActions);
|
||||||
|
|
||||||
return ["Jellyfin"];
|
return [JellyfinAction];
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed record ProxyRequest(
|
private sealed record ProxyRequest(
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using Jellyfin.Plugin.Multilang;
|
||||||
using Jellyfin.Plugin.Multilang.Services.Refresh;
|
using Jellyfin.Plugin.Multilang.Services.Refresh;
|
||||||
using Jellyfin.Plugin.Multilang.Services.Providers;
|
using Jellyfin.Plugin.Multilang.Services.Providers;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
@@ -217,7 +218,7 @@ DELETE FROM assets WHERE item_id = $item_id;";
|
|||||||
var allowed = allowedLanguages
|
var allowed = allowedLanguages
|
||||||
.Where(l => !string.IsNullOrWhiteSpace(l))
|
.Where(l => !string.IsNullOrWhiteSpace(l))
|
||||||
.Select(l => l.Trim())
|
.Select(l => l.Trim())
|
||||||
.Append("Original")
|
.Append(MultilangConstants.OriginalAction)
|
||||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
@@ -895,7 +896,7 @@ ON CONFLICT(user_id) DO UPDATE SET langs_json = excluded.langs_json, updated_at
|
|||||||
public ImportDatabaseResult ImportTranslationDatabase(string sourcePath, IReadOnlySet<string> liveItemIds, IReadOnlySet<string> allowedLanguages)
|
public ImportDatabaseResult ImportTranslationDatabase(string sourcePath, IReadOnlySet<string> liveItemIds, IReadOnlySet<string> allowedLanguages)
|
||||||
{
|
{
|
||||||
var allowed = allowedLanguages.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
var allowed = allowedLanguages.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
allowed.Add("Original");
|
allowed.Add(MultilangConstants.OriginalAction);
|
||||||
|
|
||||||
using var destination = Open();
|
using var destination = Open();
|
||||||
destination.Open();
|
destination.Open();
|
||||||
@@ -1134,17 +1135,7 @@ public sealed class UserRulesDocument
|
|||||||
|
|
||||||
public string[] FallbackLanguages { get; set; } = [];
|
public string[] FallbackLanguages { get; set; } = [];
|
||||||
|
|
||||||
public Dictionary<string, string[]> FallbackFieldActions { get; set; } = new(StringComparer.OrdinalIgnoreCase)
|
public Dictionary<string, string[]> FallbackFieldActions { get; set; } = MultilangConstants.DefaultActionLists();
|
||||||
{
|
|
||||||
["title"] = ["Jellyfin"],
|
|
||||||
["overview"] = ["Jellyfin"],
|
|
||||||
["tagline"] = ["Jellyfin"],
|
|
||||||
["poster"] = ["Jellyfin"],
|
|
||||||
["logo"] = ["Jellyfin"],
|
|
||||||
["banner"] = ["Jellyfin"],
|
|
||||||
["thumb"] = ["Jellyfin"],
|
|
||||||
["backdrop"] = ["Jellyfin"]
|
|
||||||
};
|
|
||||||
|
|
||||||
public bool TrustTmdbCollections { get; set; } = true;
|
public bool TrustTmdbCollections { get; set; } = true;
|
||||||
|
|
||||||
@@ -1176,29 +1167,9 @@ public sealed class UserCategoryRule
|
|||||||
|
|
||||||
public string[] Scopes { get; set; } = ["M", "S", "C"];
|
public string[] Scopes { get; set; } = ["M", "S", "C"];
|
||||||
|
|
||||||
public Dictionary<string, string> FieldActions { get; set; } = new(StringComparer.OrdinalIgnoreCase)
|
public Dictionary<string, string> FieldActions { get; set; } = MultilangConstants.DefaultFieldActions();
|
||||||
{
|
|
||||||
["title"] = "Fallback",
|
|
||||||
["overview"] = "Fallback",
|
|
||||||
["tagline"] = "Fallback",
|
|
||||||
["poster"] = "Fallback",
|
|
||||||
["logo"] = "Fallback",
|
|
||||||
["banner"] = "Fallback",
|
|
||||||
["thumb"] = "Fallback",
|
|
||||||
["backdrop"] = "Fallback"
|
|
||||||
};
|
|
||||||
|
|
||||||
public Dictionary<string, string[]> FieldActionLists { get; set; } = new(StringComparer.OrdinalIgnoreCase)
|
public Dictionary<string, string[]> FieldActionLists { get; set; } = MultilangConstants.DefaultActionLists();
|
||||||
{
|
|
||||||
["title"] = ["Jellyfin"],
|
|
||||||
["overview"] = ["Jellyfin"],
|
|
||||||
["tagline"] = ["Jellyfin"],
|
|
||||||
["poster"] = ["Jellyfin"],
|
|
||||||
["logo"] = ["Jellyfin"],
|
|
||||||
["banner"] = ["Jellyfin"],
|
|
||||||
["thumb"] = ["Jellyfin"],
|
|
||||||
["backdrop"] = ["Jellyfin"]
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class UserCategoryRequirement
|
public sealed class UserCategoryRequirement
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
namespace Jellyfin.Plugin.Multilang;
|
||||||
|
|
||||||
|
internal static class MultilangConstants
|
||||||
|
{
|
||||||
|
public const string JellyfinAction = "Jellyfin";
|
||||||
|
public const string OriginalAction = "Original";
|
||||||
|
public const string FallbackAction = "Fallback";
|
||||||
|
public const string ClearAction = "Clear";
|
||||||
|
public const string LanguagePrefix = "Language:";
|
||||||
|
|
||||||
|
public const string TitleField = "title";
|
||||||
|
public const string OverviewField = "overview";
|
||||||
|
public const string TaglineField = "tagline";
|
||||||
|
public const string PosterKind = "poster";
|
||||||
|
public const string LogoKind = "logo";
|
||||||
|
public const string BannerKind = "banner";
|
||||||
|
public const string ThumbKind = "thumb";
|
||||||
|
public const string BackdropKind = "backdrop";
|
||||||
|
|
||||||
|
public static readonly string[] TextFields = [TitleField, OverviewField, TaglineField];
|
||||||
|
public static readonly string[] AssetKinds = [PosterKind, LogoKind, BannerKind, ThumbKind, BackdropKind];
|
||||||
|
public static readonly string[] ActionFields = [TitleField, OverviewField, TaglineField, PosterKind, LogoKind, BannerKind, ThumbKind, BackdropKind];
|
||||||
|
|
||||||
|
public static bool RequiresJellyfinFallback(string field)
|
||||||
|
=> field.Equals(TitleField, StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
field.Equals(PosterKind, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
public static Dictionary<string, string> DefaultFieldActions()
|
||||||
|
=> ActionFields.ToDictionary(
|
||||||
|
field => field,
|
||||||
|
_ => FallbackAction,
|
||||||
|
StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
public static Dictionary<string, string[]> DefaultActionLists()
|
||||||
|
=> ActionFields.ToDictionary(
|
||||||
|
field => field,
|
||||||
|
_ => new[] { JellyfinAction },
|
||||||
|
StringComparer.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ using Jellyfin.Plugin.Multilang.Configuration;
|
|||||||
using Jellyfin.Plugin.Multilang.Data;
|
using Jellyfin.Plugin.Multilang.Data;
|
||||||
using Jellyfin.Plugin.Multilang.Services.Assets;
|
using Jellyfin.Plugin.Multilang.Services.Assets;
|
||||||
using Jellyfin.Plugin.Multilang.Services.Providers;
|
using Jellyfin.Plugin.Multilang.Services.Providers;
|
||||||
|
using static Jellyfin.Plugin.Multilang.MultilangConstants;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Model.Querying;
|
using MediaBrowser.Model.Querying;
|
||||||
@@ -13,8 +14,6 @@ namespace Jellyfin.Plugin.Multilang.Services.Refresh;
|
|||||||
|
|
||||||
public sealed class RefreshService
|
public sealed class RefreshService
|
||||||
{
|
{
|
||||||
private const string OriginalLanguageTag = "Original";
|
|
||||||
|
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
private readonly TranslationStore _store;
|
private readonly TranslationStore _store;
|
||||||
private readonly TmdbClient _tmdbClient;
|
private readonly TmdbClient _tmdbClient;
|
||||||
@@ -418,9 +417,9 @@ public sealed class RefreshService
|
|||||||
}
|
}
|
||||||
|
|
||||||
Log(cfg.VerboseLogging && cfg.EnableLogging, LogLevel.Information, "[{Index}/{Total}] TMDb metadata ok item={ItemId} lang={Lang}", scanIndex, totalItems, item.ItemId, lang);
|
Log(cfg.VerboseLogging && cfg.EnableLogging, LogLevel.Information, "[{Index}/{Total}] TMDb metadata ok item={ItemId} lang={Lang}", scanIndex, totalItems, item.ItemId, lang);
|
||||||
_store.UpsertTranslation(item.ItemId, lang, "title", meta.Title);
|
_store.UpsertTranslation(item.ItemId, lang, TitleField, meta.Title);
|
||||||
_store.UpsertTranslation(item.ItemId, lang, "overview", meta.Overview);
|
_store.UpsertTranslation(item.ItemId, lang, OverviewField, meta.Overview);
|
||||||
_store.UpsertTranslation(item.ItemId, lang, "tagline", meta.Tagline);
|
_store.UpsertTranslation(item.ItemId, lang, TaglineField, meta.Tagline);
|
||||||
StoreGenres(item, lang, meta);
|
StoreGenres(item, lang, meta);
|
||||||
fetchedMetadata[lang] = meta;
|
fetchedMetadata[lang] = meta;
|
||||||
firstMeta ??= meta;
|
firstMeta ??= meta;
|
||||||
@@ -451,10 +450,10 @@ public sealed class RefreshService
|
|||||||
|
|
||||||
if (originalMeta is not null)
|
if (originalMeta is not null)
|
||||||
{
|
{
|
||||||
_store.UpsertTranslation(item.ItemId, OriginalLanguageTag, "title", originalMeta.Title);
|
_store.UpsertTranslation(item.ItemId, OriginalAction, TitleField, originalMeta.Title);
|
||||||
_store.UpsertTranslation(item.ItemId, OriginalLanguageTag, "overview", originalMeta.Overview);
|
_store.UpsertTranslation(item.ItemId, OriginalAction, OverviewField, originalMeta.Overview);
|
||||||
_store.UpsertTranslation(item.ItemId, OriginalLanguageTag, "tagline", originalMeta.Tagline);
|
_store.UpsertTranslation(item.ItemId, OriginalAction, TaglineField, originalMeta.Tagline);
|
||||||
StoreGenres(item, OriginalLanguageTag, originalMeta);
|
StoreGenres(item, OriginalAction, originalMeta);
|
||||||
Log(
|
Log(
|
||||||
cfg.VerboseLogging && cfg.EnableLogging,
|
cfg.VerboseLogging && cfg.EnableLogging,
|
||||||
LogLevel.Information,
|
LogLevel.Information,
|
||||||
@@ -549,9 +548,9 @@ public sealed class RefreshService
|
|||||||
if (tmdbImages is null)
|
if (tmdbImages is null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
await StoreImageMapAsync(item.ItemId, languages, "poster", tmdbImages.Posters, cfg, updatedAt, written, cancellationToken).ConfigureAwait(false);
|
await StoreImageMapAsync(item.ItemId, languages, PosterKind, tmdbImages.Posters, cfg, updatedAt, written, cancellationToken).ConfigureAwait(false);
|
||||||
await StoreImageMapAsync(item.ItemId, languages, "logo", tmdbImages.Logos, cfg, updatedAt, written, cancellationToken).ConfigureAwait(false);
|
await StoreImageMapAsync(item.ItemId, languages, LogoKind, tmdbImages.Logos, cfg, updatedAt, written, cancellationToken).ConfigureAwait(false);
|
||||||
await StoreImageMapAsync(item.ItemId, languages, "backdrop", tmdbImages.Backdrops, cfg, updatedAt, written, cancellationToken).ConfigureAwait(false);
|
await StoreImageMapAsync(item.ItemId, languages, BackdropKind, tmdbImages.Backdrops, cfg, updatedAt, written, cancellationToken).ConfigureAwait(false);
|
||||||
Log(cfg.VerboseLogging && cfg.EnableLogging, LogLevel.Information, "TMDb artwork stored item={ItemId} langs={Languages}", item.ItemId, string.Join(",", languages));
|
Log(cfg.VerboseLogging && cfg.EnableLogging, LogLevel.Information, "TMDb artwork stored item={ItemId} langs={Languages}", item.ItemId, string.Join(",", languages));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -562,10 +561,10 @@ public sealed class RefreshService
|
|||||||
if (fanartImages is null)
|
if (fanartImages is null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
await StoreImageMapAsync(item.ItemId, languages, "poster", fanartImages.Posters, cfg, updatedAt, written, cancellationToken).ConfigureAwait(false);
|
await StoreImageMapAsync(item.ItemId, languages, PosterKind, fanartImages.Posters, cfg, updatedAt, written, cancellationToken).ConfigureAwait(false);
|
||||||
await StoreImageMapAsync(item.ItemId, languages, "logo", fanartImages.Logos, cfg, updatedAt, written, cancellationToken).ConfigureAwait(false);
|
await StoreImageMapAsync(item.ItemId, languages, LogoKind, fanartImages.Logos, cfg, updatedAt, written, cancellationToken).ConfigureAwait(false);
|
||||||
await StoreImageMapAsync(item.ItemId, languages, "banner", fanartImages.Banners, cfg, updatedAt, written, cancellationToken).ConfigureAwait(false);
|
await StoreImageMapAsync(item.ItemId, languages, BannerKind, fanartImages.Banners, cfg, updatedAt, written, cancellationToken).ConfigureAwait(false);
|
||||||
await StoreImageMapAsync(item.ItemId, languages, "thumb", fanartImages.Thumbs, cfg, updatedAt, written, cancellationToken).ConfigureAwait(false);
|
await StoreImageMapAsync(item.ItemId, languages, ThumbKind, fanartImages.Thumbs, cfg, updatedAt, written, cancellationToken).ConfigureAwait(false);
|
||||||
Log(cfg.VerboseLogging && cfg.EnableLogging, LogLevel.Information, "Fanart artwork stored item={ItemId} langs={Languages}", item.ItemId, string.Join(",", languages));
|
Log(cfg.VerboseLogging && cfg.EnableLogging, LogLevel.Information, "Fanart artwork stored item={ItemId} langs={Languages}", item.ItemId, string.Join(",", languages));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -583,8 +582,8 @@ public sealed class RefreshService
|
|||||||
{
|
{
|
||||||
foreach (var lang in languages)
|
foreach (var lang in languages)
|
||||||
{
|
{
|
||||||
var storeLang = lang.StartsWith(OriginalLanguageTag + ":", StringComparison.OrdinalIgnoreCase)
|
var storeLang = lang.StartsWith(OriginalAction + ":", StringComparison.OrdinalIgnoreCase)
|
||||||
? OriginalLanguageTag
|
? OriginalAction
|
||||||
: lang;
|
: lang;
|
||||||
var key = kind + ":" + storeLang;
|
var key = kind + ":" + storeLang;
|
||||||
if (written.Contains(key))
|
if (written.Contains(key))
|
||||||
@@ -609,13 +608,13 @@ public sealed class RefreshService
|
|||||||
if (_store.HasMissingConfiguredTranslations(item.ItemId, langs))
|
if (_store.HasMissingConfiguredTranslations(item.ItemId, langs))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
var assetPresence = _store.GetAssetPresence(item.ItemId, langs.Append(OriginalLanguageTag));
|
var assetPresence = _store.GetAssetPresence(item.ItemId, langs.Append(OriginalAction));
|
||||||
return IsLocalAssetStorage(cfg) && assetPresence.AnyRemote;
|
return IsLocalAssetStorage(cfg) && assetPresence.AnyRemote;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string[] AppendOriginalLanguage(string[] languages, string originalLanguage)
|
private static string[] AppendOriginalLanguage(string[] languages, string originalLanguage)
|
||||||
=> languages
|
=> languages
|
||||||
.Concat([OriginalLanguageTag + ":" + originalLanguage])
|
.Concat([OriginalAction + ":" + originalLanguage])
|
||||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
@@ -624,8 +623,8 @@ public sealed class RefreshService
|
|||||||
|
|
||||||
private static string ToIso639(string language)
|
private static string ToIso639(string language)
|
||||||
{
|
{
|
||||||
if (language.StartsWith(OriginalLanguageTag + ":", StringComparison.OrdinalIgnoreCase))
|
if (language.StartsWith(OriginalAction + ":", StringComparison.OrdinalIgnoreCase))
|
||||||
language = language[(OriginalLanguageTag.Length + 1)..];
|
language = language[(OriginalAction.Length + 1)..];
|
||||||
var index = language.IndexOf('-', StringComparison.Ordinal);
|
var index = language.IndexOf('-', StringComparison.Ordinal);
|
||||||
return (index > 0 ? language[..index] : language).Trim().ToLowerInvariant();
|
return (index > 0 ? language[..index] : language).Trim().ToLowerInvariant();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user