Browse Source

fix: use und language tag with local subtitles (#2925)

pull/2926/head
Jason Dove 2 months ago committed by GitHub
parent
commit
32e548285a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 66
      ErsatzTV.Scanner.Tests/Core/Metadata/LocalSubtitlesProviderTests.cs
  3. 23
      ErsatzTV.Scanner/Core/Metadata/LocalSubtitlesProvider.cs

1
CHANGELOG.md

@ -23,6 +23,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -23,6 +23,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Content with multiple sidecar subtitles would incorrectly have the subtitle metadata merged (like language)
- More rarely, content with an embedded subtitle that has stream index zero would create invalid subtitle records
- Both cases will automatically be cleaned up during the next local library scan
- Use `und` language tag with sidecar subtitles that have no language in the file name
## [26.5.1] - 2026-05-08
### Fixed

66
ErsatzTV.Scanner.Tests/Core/Metadata/LocalSubtitlesProviderTests.cs

@ -98,6 +98,8 @@ public class LocalSubtitlesProviderTests @@ -98,6 +98,8 @@ public class LocalSubtitlesProviderTests
new(@"/Movies/Avatar (2009)/Avatar (2009).en.sdh.srt"),
new(@"/Movies/Avatar (2009)/Avatar (2009).sdh.en.srt"),
new(@"/Movies/Avatar (2009)/Avatar (2009).de.srt"),
new(@"/Movies/Avatar (2009)/Avatar (2009).srt"),
new(@"/Movies/Avatar (2009)/Avatar (2009).forced.srt"),
// non-uniform (lower-case) extensions should also work
new(@"/Movies/Avatar (2009)/Avatar (2009).DE.SDH.FORCED.SRT")
@ -122,14 +124,72 @@ public class LocalSubtitlesProviderTests @@ -122,14 +124,72 @@ public class LocalSubtitlesProviderTests
@"/Movies/Avatar (2009)/Avatar (2009).mkv",
false);
result.Count.ShouldBe(7);
result.Count.ShouldBe(9);
result.Count(s => s.Language == "eng").ShouldBe(5);
result.Count(s => s.Language == "deu").ShouldBe(2);
result.Count(s => s.Forced).ShouldBe(3);
result.Count(s => s.Language == "und").ShouldBe(2);
result.Count(s => s.Forced).ShouldBe(4);
result.Count(s => s.SDH).ShouldBe(3);
result.Count(s => s.Codec == "subrip").ShouldBe(5);
result.Count(s => s.Codec == "subrip").ShouldBe(7);
result.Count(s => s.Codec == "ass").ShouldBe(2);
result.Count(s => s.Path.Contains("/Movies/Avatar (2009)")).ShouldBe(0);
}
[Test]
public void Should_Not_Mark_Forced_From_Movie_title()
{
// normally this will have a full list from the database, but we just need these two for testing
var cultures = new List<CultureInfo>
{
CultureInfo.GetCultureInfo("en-US"),
CultureInfo.GetCultureInfo("de-DE")
};
var fakeFiles = new List<FakeFileEntry>
{
new(@"/Movies/Bloodfist.III.Forced.To.Fight.1991/Bloodfist.III.Forced.To.Fight.1991.mkv"),
new(@"/Movies/Bloodfist.III.Forced.To.Fight.1991/Bloodfist.III.Forced.To.Fight.1991.eng.srt"),
new(@"/Movies/Bloodfist.III.Forced.To.Fight.1991/Bloodfist.III.Forced.To.Fight.1991.en.forced.ass"),
new(@"/Movies/Bloodfist.III.Forced.To.Fight.1991/Bloodfist.III.Forced.To.Fight.1991.forced.en.ass"),
new(@"/Movies/Bloodfist.III.Forced.To.Fight.1991/Bloodfist.III.Forced.To.Fight.1991.en.sdh.srt"),
new(@"/Movies/Bloodfist.III.Forced.To.Fight.1991/Bloodfist.III.Forced.To.Fight.1991.sdh.en.srt"),
new(@"/Movies/Bloodfist.III.Forced.To.Fight.1991/Bloodfist.III.Forced.To.Fight.1991.de.srt"),
new(@"/Movies/Bloodfist.III.Forced.To.Fight.1991/Bloodfist.III.Forced.To.Fight.1991.srt"),
new(@"/Movies/Bloodfist.III.Forced.To.Fight.1991/Bloodfist.III.Forced.To.Fight.1991.forced.srt"),
// non-uniform (lower-case) extensions should also work
new(@"/Movies/Bloodfist.III.Forced.To.Fight.1991/Bloodfist.III.Forced.To.Fight.1991.DE.SDH.FORCED.SRT")
};
var fileSystem = new MockFileSystem(o => o.SimulatingOperatingSystem(SimulationMode.Linux));
IFileSystemInitializer<MockFileSystem> init = fileSystem.Initialize();
foreach (var file in fakeFiles)
{
init.WithFile(file.Path);
}
var provider = new LocalSubtitlesProvider(
Substitute.For<IMediaItemRepository>(),
Substitute.For<IMetadataRepository>(),
fileSystem,
new LocalFileSystem(fileSystem, Substitute.For<ILogger<LocalFileSystem>>()),
Substitute.For<ILogger<LocalSubtitlesProvider>>());
List<Subtitle> result = provider.LocateExternalSubtitles(
cultures,
@"/Movies/Bloodfist.III.Forced.To.Fight.1991/Bloodfist.III.Forced.To.Fight.1991.mkv",
false);
result.Count.ShouldBe(9);
result.Count(s => s.Language == "eng").ShouldBe(5);
result.Count(s => s.Language == "deu").ShouldBe(2);
result.Count(s => s.Language == "und").ShouldBe(2);
result.Count(s => s.Forced).ShouldBe(4);
result.Count(s => s.SDH).ShouldBe(3);
result.Count(s => s.Codec == "subrip").ShouldBe(7);
result.Count(s => s.Codec == "ass").ShouldBe(2);
result.Count(s => s.Path.Contains("/Movies/Bloodfist.III.Forced.To.Fight.1991")).ShouldBe(0);
}
}

23
ErsatzTV.Scanner/Core/Metadata/LocalSubtitlesProvider.cs

@ -138,32 +138,35 @@ public class LocalSubtitlesProvider : ILocalSubtitlesProvider @@ -138,32 +138,35 @@ public class LocalSubtitlesProvider : ILocalSubtitlesProvider
continue;
}
string language = _fileSystem.Path.GetFileName(lowerFile);
string fileNameWithoutExtension = _fileSystem.Path.GetFileNameWithoutExtension(lowerFile);
string suffix = fileNameWithoutExtension[withoutExtension.Length..].ToLowerInvariant();
var forced = false;
var sdh = false;
if (lowerFile.Contains(".forced."))
if (suffix.Contains(".forced"))
{
forced = true;
language = language.Replace(".forced", string.Empty);
suffix = suffix.Replace(".forced", string.Empty);
}
if (lowerFile.Contains(".sdh"))
if (suffix.Contains(".sdh"))
{
sdh = true;
language = language.Replace(".sdh", string.Empty);
suffix = suffix.Replace(".sdh", string.Empty);
}
if (lowerFile.Contains(".cc."))
if (suffix.Contains(".cc"))
{
sdh = true;
language = language.Replace(".cc", string.Empty);
suffix = suffix.Replace(".cc", string.Empty);
}
language = language
.Replace($"{withoutExtension.ToLowerInvariant()}.", string.Empty)[..3]
.Replace(".", string.Empty);
// use und when no language is present
string language = suffix.Replace(".", string.Empty);
language = string.IsNullOrWhiteSpace(language)
? "und"
: language[..Math.Min(3, language.Length)];
Option<CultureInfo> maybeCulture = languageCodes.Find(ci =>
ci.TwoLetterISOLanguageName == language || ci.ThreeLetterISOLanguageName == language);

Loading…
Cancel
Save