Browse Source

Use Helper Methods for provider url parsing

David 4 years ago
parent
commit
14cbd22fbe

+ 3 - 2
Emby.Server.Implementations/Library/PathExtensions.cs

@@ -4,6 +4,7 @@ using System;
 using System.Diagnostics.CodeAnalysis;
 using System.IO;
 using System.Text.RegularExpressions;
+using MediaBrowser.Common.Providers;
 
 namespace Emby.Server.Implementations.Library
 {
@@ -43,8 +44,8 @@ namespace Emby.Server.Implementations.Library
             // for imdbid we also accept pattern matching
             if (string.Equals(attribute, "imdbid", StringComparison.OrdinalIgnoreCase))
             {
-                var m = Regex.Match(str, "tt([0-9]{7,8})", RegexOptions.IgnoreCase);
-                return m.Success ? m.Value : null;
+                var match = ProviderIdParsers.TryParseImdbId(str, out var imdbId);
+                return match ? imdbId : null;
             }
 
             return null;

+ 119 - 0
MediaBrowser.Common/Providers/ProviderIdParsers.cs

@@ -0,0 +1,119 @@
+#nullable enable
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+
+namespace MediaBrowser.Common.Providers
+{
+    /// <summary>
+    /// Parsers for provider ids.
+    /// </summary>
+    public static class ProviderIdParsers
+    {
+        /// <summary>
+        /// Parses an IMDb id from a string.
+        /// </summary>
+        /// <param name="text">The text to parse.</param>
+        /// <param name="imdbId">The parsed IMDb id.</param>
+        /// <returns>True if parsing was successful, false otherwise.</returns>
+        public static bool TryParseImdbId(string text, [NotNullWhen(true)] out string? imdbId)
+        {
+            var span = text.AsSpan();
+            var tt = "tt".AsSpan();
+
+            while (true)
+            {
+                var ttPos = span.IndexOf(tt);
+                if (ttPos == -1)
+                {
+                    imdbId = default;
+                    return false;
+                }
+
+                span = span.Slice(ttPos + tt.Length);
+
+                int i = 0;
+                // IMDb id has a maximum of 8 digits
+                int max = span.Length > 8 ? 8 : span.Length;
+                for (; i < max; i++)
+                {
+                    var c = span[i];
+
+                    if (c < '0' || c > '9')
+                    {
+                        break;
+                    }
+                }
+
+                // IMDb id has a minimum of 7 digits
+                if (i >= 7)
+                {
+                    imdbId = string.Concat(tt, span.Slice(0, i));
+                    return true;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Parses an TMDb id from a movie url.
+        /// </summary>
+        /// <param name="text">The text with the url to parse.</param>
+        /// <param name="tmdbId">The parsed TMDb id.</param>
+        /// <returns>True if parsing was successful, false otherwise.</returns>
+        public static bool TryParseTmdbMovieId(string text, [NotNullWhen(true)] out string? tmdbId)
+            => TryParseProviderId(text, "themoviedb.org/movie/", out tmdbId);
+
+        /// <summary>
+        /// Parses an TMDb id from a series url.
+        /// </summary>
+        /// <param name="text">The text with the url to parse.</param>
+        /// <param name="tmdbId">The parsed TMDb id.</param>
+        /// <returns>True if parsing was successful, false otherwise.</returns>
+        public static bool TryParseTmdbSeriesId(string text, [NotNullWhen(true)] out string? tmdbId)
+            => TryParseProviderId(text, "themoviedb.org/tv/", out tmdbId);
+
+        /// <summary>
+        /// Parses an TVDb id from a url.
+        /// </summary>
+        /// <param name="text">The text with the url to parse.</param>
+        /// <param name="tvdbId">The parsed TVDb id.</param>
+        /// <returns>True if parsing was successful, false otherwise.</returns>
+        public static bool TryParseTvdbId(string text, [NotNullWhen(true)] out string? tvdbId)
+            => TryParseProviderId(text, "thetvdb.com/?tab=series&id=", out tvdbId);
+
+        private static bool TryParseProviderId(string text, string searchString, [NotNullWhen(true)] out string? providerId)
+        {
+            var span = text.AsSpan();
+            var searchSpan = searchString.AsSpan();
+
+            while (true)
+            {
+                var searchPos = span.IndexOf(searchSpan);
+                if (searchPos == -1)
+                {
+                    providerId = default;
+                    return false;
+                }
+
+                span = span.Slice(searchPos + searchSpan.Length);
+
+                int i = 0;
+                for (; i < span.Length; i++)
+                {
+                    var c = span[i];
+
+                    if (c < '0' || c > '9')
+                    {
+                        break;
+                    }
+                }
+
+                if (i >= 1)
+                {
+                    providerId = span.Slice(0, i).ToString();
+                    return true;
+                }
+            }
+        }
+    }
+}

+ 16 - 19
MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs

@@ -6,11 +6,12 @@ using System.Globalization;
 using System.IO;
 using System.Linq;
 using System.Text;
-using System.Text.RegularExpressions;
 using System.Threading;
 using System.Xml;
 using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Providers;
 using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Providers;
@@ -63,8 +64,6 @@ namespace MediaBrowser.XbmcMetadata.Parsers
 
         protected virtual bool SupportsUrlAfterClosingXmlTag => false;
 
-        protected virtual string TmdbRegex => "themoviedb\\.org\\/movie\\/([0-9]+)";
-
         /// <summary>
         /// Fetches metadata for an item from one xml file.
         /// </summary>
@@ -220,31 +219,29 @@ namespace MediaBrowser.XbmcMetadata.Parsers
 
         protected void ParseProviderLinks(T item, string xml)
         {
-            // IMDB:
-            // https://www.imdb.com/title/tt4154796
-            var imdbRegex = Regex.Match(xml, "tt([0-9]{7,8})", RegexOptions.Compiled);
-            if (imdbRegex.Success)
+            if (ProviderIdParsers.TryParseImdbId(xml, out var imdbId))
             {
-                item.SetProviderId(MetadataProvider.Imdb, imdbRegex.Value);
+                item.SetProviderId(MetadataProvider.Imdb, imdbId);
             }
 
-            // TMDB:
-            // https://www.themoviedb.org/movie/30287-fallo (movie)
-            // https://www.themoviedb.org/tv/1668-friends (tv)
-            var tmdbRegex = Regex.Match(xml, TmdbRegex, RegexOptions.Compiled);
-            if (tmdbRegex.Success)
+            if (item is Movie)
             {
-                item.SetProviderId(MetadataProvider.Tmdb, tmdbRegex.Groups[1].Value);
+                if (ProviderIdParsers.TryParseTmdbMovieId(xml, out var tmdbId))
+                {
+                    item.SetProviderId(MetadataProvider.Tmdb, tmdbId);
+                }
             }
 
-            // TVDB:
-            // https://www.thetvdb.com/?tab=series&id=121361
             if (item is Series)
             {
-                var tvdbRegex = Regex.Match(xml, "thetvdb\\.com\\/\\?tab=series\\&id=([0-9]+)", RegexOptions.Compiled);
-                if (tvdbRegex.Success)
+                if (ProviderIdParsers.TryParseTmdbSeriesId(xml, out var tmdbId))
+                {
+                    item.SetProviderId(MetadataProvider.Tmdb, tmdbId);
+                }
+
+                if (ProviderIdParsers.TryParseTvdbId(xml, out var tvdbId))
                 {
-                    item.SetProviderId(MetadataProvider.Tvdb, tvdbRegex.Groups[1].Value);
+                    item.SetProviderId(MetadataProvider.Tvdb, tvdbId);
                 }
             }
         }

+ 0 - 3
MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs

@@ -35,9 +35,6 @@ namespace MediaBrowser.XbmcMetadata.Parsers
         /// <inheritdoc />
         protected override bool SupportsUrlAfterClosingXmlTag => true;
 
-        /// <inheritdoc />
-        protected override string TmdbRegex => "themoviedb\\.org\\/tv\\/([0-9]+)";
-
         /// <inheritdoc />
         protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<Series> itemResult)
         {

+ 63 - 0
tests/Jellyfin.Common.Tests/Providers/ProviderIdParserTests.cs

@@ -0,0 +1,63 @@
+using MediaBrowser.Common.Providers;
+using Xunit;
+
+namespace Jellyfin.Common.Tests.Providers
+{
+    public class ProviderIdParserTests
+    {
+        [Theory]
+        [InlineData("tt123456", false, null)]
+        [InlineData("tt1234567", true, "tt1234567")]
+        [InlineData("tt12345678", true, "tt12345678")]
+        [InlineData("https://www.imdb.com/title/tt123456", false, null)]
+        [InlineData("https://www.imdb.com/title/tt1234567", true, "tt1234567")]
+        [InlineData("https://www.imdb.com/title/tt12345678", true, "tt12345678")]
+        [InlineData(@"multiline\nhttps://www.imdb.com/title/tt1234567", true, "tt1234567")]
+        [InlineData(@"multiline\nhttps://www.imdb.com/title/tt12345678", true, "tt12345678")]
+        [InlineData("Jellyfin", false, null)]
+        [InlineData("tt1234567tt7654321", true, "tt1234567")]
+        [InlineData("tt12345678tt7654321", true, "tt12345678")]
+        public void Parse_Imdb(string text, bool shouldSucceed, string? imdbId)
+        {
+            var succeeded = ProviderIdParsers.TryParseImdbId(text, out string? parsedId);
+            Assert.Equal(shouldSucceed, succeeded);
+            Assert.Equal(imdbId, parsedId);
+        }
+
+        [Theory]
+        [InlineData("https://www.themoviedb.org/movie/30287-fallo", true, "30287")]
+        [InlineData("themoviedb.org/movie/30287", true, "30287")]
+        [InlineData("https://www.themoviedb.org/movie/fallo-30287", false, null)]
+        [InlineData("https://www.themoviedb.org/tv/1668-friends", false, null)]
+        public void Parse_TmdbMovie(string text, bool shouldSucceed, string? tmdbId)
+        {
+            var succeeded = ProviderIdParsers.TryParseTmdbMovieId(text, out string? parsedId);
+            Assert.Equal(shouldSucceed, succeeded);
+            Assert.Equal(tmdbId, parsedId);
+        }
+
+        [Theory]
+        [InlineData("https://www.themoviedb.org/tv/1668-friends", true, "1668")]
+        [InlineData("themoviedb.org/tv/1668", true, "1668")]
+        [InlineData("https://www.themoviedb.org/tv/friends-1668", false, null)]
+        [InlineData("https://www.themoviedb.org/movie/30287-fallo", false, null)]
+        public void Parse_TmdbSeries(string text, bool shouldSucceed, string? tmdbId)
+        {
+            var succeeded = ProviderIdParsers.TryParseTmdbSeriesId(text, out string? parsedId);
+            Assert.Equal(shouldSucceed, succeeded);
+            Assert.Equal(tmdbId, parsedId);
+        }
+
+        [Theory]
+        [InlineData("https://www.thetvdb.com/?tab=series&id=121361", true, "121361")]
+        [InlineData("thetvdb.com/?tab=series&id=121361", true, "121361")]
+        [InlineData("thetvdb.com/?tab=series&id=Jellyfin121361", false, null)]
+        [InlineData("https://www.themoviedb.org/tv/1668-friends", false, null)]
+        public void Parse_Tvdb(string text, bool shouldSucceed, string? tvdbId)
+        {
+            var succeeded = ProviderIdParsers.TryParseTvdbId(text, out string? parsedId);
+            Assert.Equal(shouldSucceed, succeeded);
+            Assert.Equal(tvdbId, parsedId);
+        }
+    }
+}