Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Jellyfin/backend/Services/GameThumbService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,9 @@ private static string BuildUrl(string platform, ThumbKind kind, string name) =>
/// minus the extension. This is the filename rather than the display title, which for a game
/// in its own folder is the folder name and would not match.
/// </summary>
private static string LibretroThumbName(string romFileName)
private static string LibretroThumbName(string name)
{
var chars = (Path.GetFileNameWithoutExtension(romFileName) ?? string.Empty).ToCharArray();
var chars = name.ToCharArray();
for (var i = 0; i < chars.Length; i++)
{
if (Array.IndexOf(ReservedChars, chars[i]) >= 0)
Expand Down
8 changes: 7 additions & 1 deletion Jellyfin/backend/Services/GamesService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,13 @@ public IReadOnlyList<GameSummary> GetGames(string libraryId, string? systemId)
var systemDir = FindSystemDir(library, romPath);
var systemName = systemDir == null ? string.Empty : Path.GetFileName(systemDir);
var core = ResolveSystemCore(systemName, new List<string> { romPath });
return (core, Path.GetFileName(romPath));

// Resolve the exact No-Intro name from Rdb if available so region codes and tags (like (USA)) are included in the art URL.
var title = ResolveTitle(systemDir, romPath);
var rdb = _rdb?.TryLookup(core, romPath, title);
var name = rdb?.Name ?? Path.GetFileNameWithoutExtension(romPath);

return (core, name);
}

/// <summary>
Expand Down
Binary file modified Jellyfin/backend/Services/LaunchBoxService.cs
Binary file not shown.
45 changes: 44 additions & 1 deletion Jellyfin/backend/Services/RdbService.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.Collections.Concurrent;
using System.Globalization;
using System.Net.Http;
using System.Text;
using Microsoft.Extensions.Logging;

namespace Moonfin.Server.Services;
Expand Down Expand Up @@ -152,6 +154,40 @@ public RdbService(IHttpClientFactory httpClientFactory, ILogger<RdbService> logg
}
}

// Fallback when the exact match misses: take the closest name where one
// side is a prefix of the other, to absorb region or edition suffixes.
// Rdb keeps region parentheticals, so it allows a wider gap than LaunchBox.
if (fileName.Length >= 5)
{
RdbRecord? bestRecord = null;
var minDiff = int.MaxValue;
var ambiguous = false;
foreach (var kv in index.ByName)
{
if (kv.Key.StartsWith(fileName, StringComparison.Ordinal) ||
fileName.StartsWith(kv.Key, StringComparison.Ordinal))
{
var diff = Math.Abs(kv.Key.Length - fileName.Length);
if (diff < minDiff)
{
minDiff = diff;
bestRecord = kv.Value;
ambiguous = false;
}
else if (diff == minDiff && !ReferenceEquals(kv.Value, bestRecord))
{
// Two different games are equally close, so a common prefix
// can't be resolved to one. Skip rather than pick wrong art.
ambiguous = true;
}
}
}
if (bestRecord != null && !ambiguous && minDiff <= 45)
{
return bestRecord;
}
}

return null;
}

Expand Down Expand Up @@ -350,9 +386,16 @@ private static uint[] BuildCrcTable()

private static string NormalizeName(string value)
{
var normalizedString = value.Normalize(NormalizationForm.FormD);
var sb = new System.Text.StringBuilder(value.Length);
foreach (var ch in value)
foreach (var ch in normalizedString)
{
var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(ch);
if (unicodeCategory == UnicodeCategory.NonSpacingMark)
{
continue;
}

if (char.IsLetterOrDigit(ch))
{
sb.Append(char.ToLowerInvariant(ch));
Expand Down
Loading