Merge pull request #1929 from Narfinger/parser-fix4
[Draft][Help wanted] Fix parsing of certain names and adds a default season if no season was found
This commit is contained in:
commit
61b9b4046a
|
@ -328,28 +328,32 @@ namespace Emby.Naming.Common
|
||||||
|
|
||||||
// *** End Kodi Standard Naming
|
// *** End Kodi Standard Naming
|
||||||
|
|
||||||
new EpisodeExpression(@".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})[^\\\/]*$")
|
// [bar] Foo - 1 [baz]
|
||||||
|
new EpisodeExpression(@".*?(\[.*?\])+.*?(?<seriesname>(\w+\s)+?)[-\s_]+(?<epnumber>\d+).*$"){
|
||||||
|
IsNamed=false,
|
||||||
|
},
|
||||||
|
new EpisodeExpression(@".*(\\|\/)[sS]?(?<seasonnumber>\d+)[xX](?<epnumber>\d+)[^\\\/]*$")
|
||||||
{
|
{
|
||||||
IsNamed = true
|
IsNamed = true
|
||||||
},
|
},
|
||||||
|
|
||||||
new EpisodeExpression(@".*(\\|\/)[sS](?<seasonnumber>\d{1,4})[x,X]?[eE](?<epnumber>\d{1,3})[^\\\/]*$")
|
new EpisodeExpression(@".*(\\|\/)[sS](?<seasonnumber>\d+)[x,X]?[eE](?<epnumber>\d+)[^\\\/]*$")
|
||||||
{
|
{
|
||||||
IsNamed = true
|
IsNamed = true
|
||||||
},
|
},
|
||||||
|
|
||||||
new EpisodeExpression(@".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))[^\\\/]*$")
|
new EpisodeExpression(@".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d+))[^\\\/]*$")
|
||||||
{
|
{
|
||||||
IsNamed = true
|
IsNamed = true
|
||||||
},
|
},
|
||||||
|
|
||||||
new EpisodeExpression(@".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>\d{1,4})[xX\.]?[eE](?<epnumber>\d{1,3})[^\\\/]*$")
|
new EpisodeExpression(@".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>\d{1,4})[xX\.]?[eE](?<epnumber>\d+)[^\\\/]*$")
|
||||||
{
|
{
|
||||||
IsNamed = true
|
IsNamed = true
|
||||||
},
|
},
|
||||||
|
|
||||||
// "01.avi"
|
// "01.avi"
|
||||||
new EpisodeExpression(@".*[\\\/](?<epnumber>\d{1,3})(-(?<endingepnumber>\d{2,3}))*\.\w+$")
|
new EpisodeExpression(@".*[\\\/](?<epnumber>\d+)(-(?<endingepnumber>\d+))*\.\w+$")
|
||||||
{
|
{
|
||||||
IsOptimistic = true,
|
IsOptimistic = true,
|
||||||
IsNamed = true
|
IsNamed = true
|
||||||
|
|
|
@ -1899,7 +1899,7 @@ namespace Emby.Server.Implementations.Library
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
public void UpdateItem(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken)
|
public void UpdateItem(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
UpdateItems(new [] { item }, parent, updateReason, cancellationToken);
|
UpdateItems(new[] { item }, parent, updateReason, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -2487,6 +2487,15 @@ namespace Emby.Server.Implementations.Library
|
||||||
{
|
{
|
||||||
episode.ParentIndexNumber = season.IndexNumber;
|
episode.ParentIndexNumber = season.IndexNumber;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Anime series don't generally have a season in their file name, however,
|
||||||
|
tvdb needs a season to correctly get the metadata.
|
||||||
|
Hence, a null season needs to be filled with something. */
|
||||||
|
//FIXME perhaps this would be better for tvdb parser to ask for season 1 if no season is specified
|
||||||
|
episode.ParentIndexNumber = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (episode.ParentIndexNumber.HasValue)
|
if (episode.ParentIndexNumber.HasValue)
|
||||||
{
|
{
|
||||||
|
|
|
@ -57,6 +57,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Common.Tests", "te
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.MediaEncoding.Tests", "tests\Jellyfin.MediaEncoding.Tests\Jellyfin.MediaEncoding.Tests.csproj", "{28464062-0939-4AA7-9F7B-24DDDA61A7C0}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.MediaEncoding.Tests", "tests\Jellyfin.MediaEncoding.Tests\Jellyfin.MediaEncoding.Tests.csproj", "{28464062-0939-4AA7-9F7B-24DDDA61A7C0}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Naming.Tests", "tests\Jellyfin.Naming.Tests\Jellyfin.Naming.Tests.csproj", "{3998657B-1CCC-49DD-A19F-275DC8495F57}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
@ -159,6 +161,10 @@ Global
|
||||||
{28464062-0939-4AA7-9F7B-24DDDA61A7C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{28464062-0939-4AA7-9F7B-24DDDA61A7C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{28464062-0939-4AA7-9F7B-24DDDA61A7C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{28464062-0939-4AA7-9F7B-24DDDA61A7C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{28464062-0939-4AA7-9F7B-24DDDA61A7C0}.Release|Any CPU.Build.0 = Release|Any CPU
|
{28464062-0939-4AA7-9F7B-24DDDA61A7C0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{3998657B-1CCC-49DD-A19F-275DC8495F57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{3998657B-1CCC-49DD-A19F-275DC8495F57}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{3998657B-1CCC-49DD-A19F-275DC8495F57}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{3998657B-1CCC-49DD-A19F-275DC8495F57}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -187,5 +193,6 @@ Global
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{DF194677-DFD3-42AF-9F75-D44D5A416478} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
|
{DF194677-DFD3-42AF-9F75-D44D5A416478} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
|
||||||
{28464062-0939-4AA7-9F7B-24DDDA61A7C0} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
|
{28464062-0939-4AA7-9F7B-24DDDA61A7C0} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
|
||||||
|
{3998657B-1CCC-49DD-A19F-275DC8495F57} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
54
tests/Jellyfin.Naming.Tests/EpisodePathParserTest.cs
Normal file
54
tests/Jellyfin.Naming.Tests/EpisodePathParserTest.cs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
namespace Emby.Naming.TV
|
||||||
|
{
|
||||||
|
using Emby.Naming.Common;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
public class EpisodePathParserTest
|
||||||
|
{
|
||||||
|
[Theory]
|
||||||
|
[InlineData("/media/Foo/Foo-S01E01", "Foo", 1, 1)]
|
||||||
|
[InlineData("/media/Foo - S04E011", "Foo", 4, 11)]
|
||||||
|
[InlineData("/media/Foo/Foo s01x01", "Foo", 1, 1)]
|
||||||
|
[InlineData("/media/Foo (2019)/Season 4/Foo (2019).S04E03", "Foo (2019)", 4, 3)]
|
||||||
|
public void ParseEpisodesCorrectly(string path, string name, int season, int episode)
|
||||||
|
{
|
||||||
|
NamingOptions o = new NamingOptions();
|
||||||
|
EpisodePathParser p = new EpisodePathParser(o);
|
||||||
|
var res = p.Parse(path, false);
|
||||||
|
|
||||||
|
Assert.True(res.Success);
|
||||||
|
Assert.Equal(name, res.SeriesName);
|
||||||
|
Assert.Equal(season, res.SeasonNumber);
|
||||||
|
Assert.Equal(episode, res.EpisodeNumber);
|
||||||
|
|
||||||
|
//testing other paths delimeter
|
||||||
|
var res2 = p.Parse(path.Replace("/", "\\"), false);
|
||||||
|
Assert.True(res2.Success);
|
||||||
|
Assert.Equal(name, res2.SeriesName);
|
||||||
|
Assert.Equal(season, res2.SeasonNumber);
|
||||||
|
Assert.Equal(episode, res2.EpisodeNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("/media/Foo/Foo 889", "Foo", 889)]
|
||||||
|
[InlineData("/media/Foo/[Bar] Foo Baz - 11 [1080p]", "Foo Baz", 11)]
|
||||||
|
public void ParseEpisodeWithoutSeason(string path, string name, int episode)
|
||||||
|
{
|
||||||
|
NamingOptions o = new NamingOptions();
|
||||||
|
EpisodePathParser p = new EpisodePathParser(o);
|
||||||
|
var res = p.Parse(path, true, null, null, true);
|
||||||
|
|
||||||
|
Assert.True(res.Success);
|
||||||
|
Assert.Equal(name, res.SeriesName);
|
||||||
|
Assert.True(res.SeasonNumber == null);
|
||||||
|
Assert.Equal(episode, res.EpisodeNumber);
|
||||||
|
|
||||||
|
//testing other paths delimeter
|
||||||
|
var res2 = p.Parse(path.Replace("/", "\\"), false, null, null, true);
|
||||||
|
Assert.True(res2.Success);
|
||||||
|
Assert.Equal(name, res2.SeriesName);
|
||||||
|
Assert.True(res2.SeasonNumber == null);
|
||||||
|
Assert.Equal(episode, res2.EpisodeNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj
Normal file
20
tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||||
|
<PackageReference Include="xunit" Version="2.4.0" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
||||||
|
<PackageReference Include="coverlet.collector" Version="1.0.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Emby.Naming\Emby.Naming.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
Loading…
Reference in New Issue
Block a user