Merge pull request #17254 from sjakub/attribute_aliases
Add additional attribute aliases and improve attribute detection
This commit is contained in:
@@ -29,17 +29,41 @@ namespace Emby.Server.Implementations.Library
|
||||
throw new ArgumentException("String can't be empty.", nameof(attribute));
|
||||
}
|
||||
|
||||
var attributeIndex = str.IndexOf(attribute, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
// Must be at least 3 characters after the attribute =, ], any character,
|
||||
// then we offset it by 1, because we want the index and not length.
|
||||
var maxIndex = str.Length - attribute.Length - 2;
|
||||
while (attributeIndex > -1 && attributeIndex < maxIndex)
|
||||
// Allow tmdb as an alias for tmdbid, tvdb for tvdbid, etc.
|
||||
// The code below only supports aliases for attributes in the form of "<alias>id".
|
||||
ReadOnlySpan<char> shortAttr = attribute switch
|
||||
{
|
||||
var attributeEnd = attributeIndex + attribute.Length;
|
||||
_ when attribute.Equals("tmdbid", StringComparison.OrdinalIgnoreCase) => "tmdb",
|
||||
_ when attribute.Equals("tvdbid", StringComparison.OrdinalIgnoreCase) => "tvdb",
|
||||
_ when attribute.Equals("imdbid", StringComparison.OrdinalIgnoreCase) => "imdb",
|
||||
_ => ReadOnlySpan<char>.Empty
|
||||
};
|
||||
|
||||
for (int strIndex = 0, attributeIndex = 0; attributeIndex > -1;)
|
||||
{
|
||||
// We may want to use imdbid pattern matching later, so we don't want to modify the original 'str'.
|
||||
var subStr = str[strIndex..];
|
||||
int attributeEnd = 0;
|
||||
|
||||
if (shortAttr.Length > 0)
|
||||
{
|
||||
// If we are using an alias it should be shorter (and a prefix), so let's search for that.
|
||||
attributeIndex = subStr.IndexOf(shortAttr, StringComparison.OrdinalIgnoreCase);
|
||||
attributeEnd = attributeIndex + shortAttr.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
attributeIndex = subStr.IndexOf(attribute, StringComparison.OrdinalIgnoreCase);
|
||||
attributeEnd = attributeIndex + attribute.Length;
|
||||
}
|
||||
|
||||
// The next iteration should start at the end of the attribute we just found.
|
||||
// If attributeIndex < 0, the loop will end and strIndex won't be used again.
|
||||
strIndex += attributeEnd;
|
||||
|
||||
if (attributeIndex > 0)
|
||||
{
|
||||
var attributeOpener = str[attributeIndex - 1];
|
||||
var attributeOpener = subStr[attributeIndex - 1];
|
||||
var attributeCloser = attributeOpener switch
|
||||
{
|
||||
'[' => ']',
|
||||
@@ -47,20 +71,37 @@ namespace Emby.Server.Implementations.Library
|
||||
'{' => '}',
|
||||
_ => '\0'
|
||||
};
|
||||
if (attributeCloser != '\0' && (str[attributeEnd] == '=' || str[attributeEnd] == '-'))
|
||||
{
|
||||
var closingIndex = str[attributeEnd..].IndexOf(attributeCloser);
|
||||
|
||||
// Must be at least 1 character before the closing bracket.
|
||||
if (closingIndex > 1)
|
||||
if (attributeCloser != '\0')
|
||||
{
|
||||
if (shortAttr.Length > 0
|
||||
&& attributeEnd + 1 < subStr.Length
|
||||
&& (subStr[attributeEnd] is 'i' or 'I')
|
||||
&& (subStr[attributeEnd + 1] is 'd' or 'D'))
|
||||
{
|
||||
return str[(attributeEnd + 1)..(attributeEnd + closingIndex)].Trim().ToString();
|
||||
// We were searching for a shortened attribute, but it's followed by "id" - let's skip it.
|
||||
attributeEnd += 2;
|
||||
}
|
||||
|
||||
// attributeEnd points at '='.
|
||||
// We need at least 1 more character and the closing bracket after that.
|
||||
if (attributeEnd + 2 < subStr.Length && (subStr[attributeEnd] is '=' or '-'))
|
||||
{
|
||||
var closingIndex = subStr[attributeEnd..].IndexOf(attributeCloser);
|
||||
|
||||
// Must be at least 1 character before the closing bracket.
|
||||
if (closingIndex > 1)
|
||||
{
|
||||
var trimmed = subStr[(attributeEnd + 1)..(attributeEnd + closingIndex)].Trim();
|
||||
|
||||
if (trimmed.Length > 0)
|
||||
{
|
||||
return trimmed.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
str = str[attributeEnd..];
|
||||
attributeIndex = str.IndexOf(attribute, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
// for imdbid we also accept pattern matching
|
||||
@@ -70,16 +111,6 @@ namespace Emby.Server.Implementations.Library
|
||||
return match ? imdbId.ToString() : null;
|
||||
}
|
||||
|
||||
// Allow tmdb as an alias for tmdbid
|
||||
if (attribute.Equals("tmdbid", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var tmdbValue = str.GetAttributeValue("tmdb");
|
||||
if (tmdbValue is not null)
|
||||
{
|
||||
return tmdbValue;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,44 +9,105 @@ namespace Jellyfin.Server.Implementations.Tests.Library
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("Superman: Red Son [imdbid=tt10985510]", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son [imdb=tt10985510]", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son [imdbid-tt10985510]", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son [imdb-tt10985510]", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son - tt10985510", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son {imdbid=tt10985510}", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son {imdb=tt10985510}", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son {imdbid-tt10985510}", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son {imdb-tt10985510}", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son (imdbid=tt10985510)", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son (imdb=tt10985510)", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son (imdbid-tt10985510)", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son (imdb-tt10985510)", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son", "imdbid", null)]
|
||||
[InlineData("Superman: Red Son [imdbid1=tt11111111][imdbid=tt10985510]", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son [imdbid1=tt11111111][imdb=tt10985510]", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son {imdbid1=tt11111111}(imdbid=tt10985510)", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son {imdbid1=tt11111111}(imdb=tt10985510)", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son (imdbid1-tt11111111)[imdbid=tt10985510]", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son (imdbid1-tt11111111)[imdb=tt10985510]", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son [tmdbid=618355][imdbid=tt10985510]", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son [tmdbid=618355][imdb=tt10985510]", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son [tmdbid-618355]{imdbid-tt10985510}", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son [tmdbid-618355]{imdb-tt10985510}", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son (tmdbid-618355)[imdbid-tt10985510]", "tmdbid", "618355")]
|
||||
[InlineData("Superman: Red Son (tmdbid-618355)[imdb-tt10985510]", "tmdbid", "618355")]
|
||||
[InlineData("Superman: Red Son [providera-id=1]", "providera-id", "1")]
|
||||
[InlineData("Superman: Red Son [providerb-id=2]", "providerb-id", "2")]
|
||||
[InlineData("Superman: Red Son [providera id=4]", "providera id", "4")]
|
||||
[InlineData("Superman: Red Son [providerb id=5]", "providerb id", "5")]
|
||||
[InlineData("Superman: Red Son [provider=99][providerid=5]", "providerid", "5")]
|
||||
[InlineData("Superman: Red Son [tmdbid=3]", "tmdbid", "3")]
|
||||
[InlineData("Superman: Red Son [tvdbid-6]", "tvdbid", "6")]
|
||||
[InlineData("Superman: Red Son [tmdb=3]", "tmdbid", "3")]
|
||||
[InlineData("Superman: Red Son [tmdbid-3]", "tmdbid", "3")]
|
||||
[InlineData("Superman: Red Son [tmdb-3]", "tmdbid", "3")]
|
||||
[InlineData("Superman: Red Son {tmdbid=3}", "tmdbid", "3")]
|
||||
[InlineData("Superman: Red Son {tmdb=3}", "tmdbid", "3")]
|
||||
[InlineData("Superman: Red Son {tmdbid-3}", "tmdbid", "3")]
|
||||
[InlineData("Superman: Red Son {tmdb-3}", "tmdbid", "3")]
|
||||
[InlineData("Superman: Red Son (tmdbid=6)", "tmdbid", "6")]
|
||||
[InlineData("Superman: Red Son (tmdb=6)", "tmdbid", "6")]
|
||||
[InlineData("Superman: Red Son (tmdbid-6)", "tmdbid", "6")]
|
||||
[InlineData("Superman: Red Son (tmdb-6)", "tmdbid", "6")]
|
||||
[InlineData("Superman: Red Son [tvdbid=6]", "tvdbid", "6")]
|
||||
[InlineData("Superman: Red Son [tvdb=6]", "tvdbid", "6")]
|
||||
[InlineData("Superman: Red Son [tvdbid-6]", "tvdbid", "6")]
|
||||
[InlineData("Superman: Red Son [tvdb-6]", "tvdbid", "6")]
|
||||
[InlineData("Superman: Red Son {tvdbid=3}", "tvdbid", "3")]
|
||||
[InlineData("Superman: Red Son {tvdb=3}", "tvdbid", "3")]
|
||||
[InlineData("Superman: Red Son {tvdbid-3}", "tvdbid", "3")]
|
||||
[InlineData("Superman: Red Son {tvdb-3}", "tvdbid", "3")]
|
||||
[InlineData("Superman: Red Son (tvdbid=6)", "tvdbid", "6")]
|
||||
[InlineData("Superman: Red Son (tvdb=6)", "tvdbid", "6")]
|
||||
[InlineData("Superman: Red Son (tvdbid-6)", "tvdbid", "6")]
|
||||
[InlineData("Superman: Red Son (tvdb-6)", "tvdbid", "6")]
|
||||
[InlineData("[tmdbid=618355]", "tmdbid", "618355")]
|
||||
[InlineData("[tmdb=618355]", "tmdbid", "618355")]
|
||||
[InlineData("{tmdbid=618355}", "tmdbid", "618355")]
|
||||
[InlineData("{tmdb=618355}", "tmdbid", "618355")]
|
||||
[InlineData("(tmdbid=618355)", "tmdbid", "618355")]
|
||||
[InlineData("(tmdb=618355)", "tmdbid", "618355")]
|
||||
[InlineData("[tmdbid-618355]", "tmdbid", "618355")]
|
||||
[InlineData("[tmdb-618355]", "tmdbid", "618355")]
|
||||
[InlineData("{tmdbid-618355)", "tmdbid", null)]
|
||||
[InlineData("{tmdb-618355)", "tmdbid", null)]
|
||||
[InlineData("[tmdbid-618355}", "tmdbid", null)]
|
||||
[InlineData("[tmdb-618355}", "tmdbid", null)]
|
||||
[InlineData("tmdbid=111111][tmdbid=618355]", "tmdbid", "618355")]
|
||||
[InlineData("tmdbid=111111][tmdb=618355]", "tmdbid", "618355")]
|
||||
[InlineData("[tmdbid=618355]tmdbid=111111]", "tmdbid", "618355")]
|
||||
[InlineData("[tmdb=618355]tmdbid=111111]", "tmdbid", "618355")]
|
||||
[InlineData("tmdbid=618355]", "tmdbid", null)]
|
||||
[InlineData("tmdb=618355]", "tmdbid", null)]
|
||||
[InlineData("[tmdbid=618355", "tmdbid", null)]
|
||||
[InlineData("[tmdb=618355", "tmdbid", null)]
|
||||
[InlineData("tmdbid=618355", "tmdbid", null)]
|
||||
[InlineData("tmdb=618355", "tmdbid", null)]
|
||||
[InlineData("tmdbid=", "tmdbid", null)]
|
||||
[InlineData("tmdb=", "tmdbid", null)]
|
||||
[InlineData("tmdbid", "tmdbid", null)]
|
||||
[InlineData("tmdb", "tmdbid", null)]
|
||||
[InlineData("[tmdbid= ][tmdbid=223344]", "tmdbid", "223344")]
|
||||
[InlineData("[tmdb= ][tmdb=223344]", "tmdbid", "223344")]
|
||||
[InlineData("[tmdbid= ][tmdb=223344]", "tmdbid", "223344")]
|
||||
[InlineData("[tmdb= ][tmdbid=223344]", "tmdbid", "223344")]
|
||||
[InlineData("[tmdbid=][imdbid=tt10985510]", "tmdbid", null)]
|
||||
[InlineData("[tmdb=][imdbid=tt10985510]", "tmdbid", null)]
|
||||
[InlineData("[tmdbid-][imdbid-tt10985510]", "tmdbid", null)]
|
||||
[InlineData("[tmdb-][imdbid-tt10985510]", "tmdbid", null)]
|
||||
[InlineData("Superman: Red Son [tmdbid-618355][tmdbid=1234567]", "tmdbid", "618355")]
|
||||
[InlineData("Superman: Red Son [tmdb-618355][tmdbid=1234567]", "tmdbid", "618355")]
|
||||
[InlineData("{tmdbid=}{imdbid=tt10985510}", "tmdbid", null)]
|
||||
[InlineData("{tmdb=}{imdbid=tt10985510}", "tmdbid", null)]
|
||||
[InlineData("(tmdbid-)(imdbid-tt10985510)", "tmdbid", null)]
|
||||
[InlineData("(tmdb-)(imdbid-tt10985510)", "tmdbid", null)]
|
||||
[InlineData("Superman: Red Son {tmdbid-618355}{tmdbid=1234567}", "tmdbid", "618355")]
|
||||
[InlineData("Superman: Red Son {tmdb-618355}{tmdbid=1234567}", "tmdbid", "618355")]
|
||||
[InlineData("Superman: Red Son - tt10985510 [imdbid1=tt11]", "imdbid", "tt10985510")]
|
||||
[InlineData("Superman: Red Son [tmdb=618355][tmdbid1=1]", "tmdbid", "618355")]
|
||||
[InlineData("Superman: Red Son [tmdb=618355][tmdbid=12345]", "tmdbid", "618355")]
|
||||
public void GetAttributeValue_ValidArgs_Correct(string input, string attribute, string? expectedResult)
|
||||
{
|
||||
Assert.Equal(expectedResult, PathExtensions.GetAttributeValue(input, attribute));
|
||||
|
||||
Reference in New Issue
Block a user