Преглед на файлове

fixes #943 - Add web client filtering by genres, parental ratings, tags and years

Luke Pulverenti преди 10 години
родител
ревизия
95eaf88abd

+ 48 - 8
MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs

@@ -193,13 +193,6 @@ namespace MediaBrowser.Api.UserLibrary
 
 
             var filters = request.GetFilters().ToList();
             var filters = request.GetFilters().ToList();
 
 
-            if (filters.Count == 0)
-            {
-                return items;
-            }
-
-            items = items.AsParallel();
-
             if (filters.Contains(ItemFilter.Dislikes))
             if (filters.Contains(ItemFilter.Dislikes))
             {
             {
                 items = items.Where(i =>
                 items = items.Where(i =>
@@ -243,9 +236,56 @@ namespace MediaBrowser.Api.UserLibrary
                 });
                 });
             }
             }
 
 
-            return items.AsEnumerable();
+            // Avoid implicitly captured closure
+            var currentRequest = request;
+            return items.Where(i => ApplyAdditionalFilters(currentRequest, i, user, false));
+        }
+
+        private bool ApplyAdditionalFilters(BaseItemsRequest request, BaseItem i, User user, bool isPreFiltered)
+        {
+            if (!isPreFiltered)
+            {
+                // Apply tag filter
+                var tags = request.GetTags();
+                if (tags.Length > 0)
+                {
+                    var hasTags = i as IHasTags;
+                    if (hasTags == null)
+                    {
+                        return false;
+                    }
+                    if (!(tags.Any(v => hasTags.Tags.Contains(v, StringComparer.OrdinalIgnoreCase))))
+                    {
+                        return false;
+                    }
+                }
+
+                // Apply official rating filter
+                var officialRatings = request.GetOfficialRatings();
+                if (officialRatings.Length > 0 && !officialRatings.Contains(i.OfficialRating ?? string.Empty))
+                {
+                    return false;
+                }
+
+                // Apply genre filter
+                var genres = request.GetGenres();
+                if (genres.Length > 0 && !(genres.Any(v => i.Genres.Contains(v, StringComparer.OrdinalIgnoreCase))))
+                {
+                    return false;
+                }
+
+                // Apply year filter
+                var years = request.GetYears();
+                if (years.Length > 0 && !(i.ProductionYear.HasValue && years.Contains(i.ProductionYear.Value)))
+                {
+                    return false;
+                }
+            }
+
+            return true;
         }
         }
 
 
+
         /// <summary>
         /// <summary>
         /// Filters the items.
         /// Filters the items.
         /// </summary>
         /// </summary>

+ 40 - 0
MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs

@@ -96,6 +96,41 @@ namespace MediaBrowser.Api.UserLibrary
         [ApiMember(Name = "IsPlayed", Description = "Optional filter by items that are played, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
         [ApiMember(Name = "IsPlayed", Description = "Optional filter by items that are played, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
         public bool? IsPlayed { get; set; }
         public bool? IsPlayed { get; set; }
 
 
+        /// <summary>
+        /// Limit results to items containing specific genres
+        /// </summary>
+        /// <value>The genres.</value>
+        [ApiMember(Name = "Genres", Description = "Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+        public string Genres { get; set; }
+
+        [ApiMember(Name = "OfficialRatings", Description = "Optional. If specified, results will be filtered based on OfficialRating. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+        public string OfficialRatings { get; set; }
+
+        [ApiMember(Name = "Tags", Description = "Optional. If specified, results will be filtered based on tag. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+        public string Tags { get; set; }
+
+        /// <summary>
+        /// Limit results to items containing specific years
+        /// </summary>
+        /// <value>The years.</value>
+        [ApiMember(Name = "Years", Description = "Optional. If specified, results will be filtered based on production year. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+        public string Years { get; set; }
+
+        public string[] GetGenres()
+        {
+            return (Genres ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
+        }
+
+        public string[] GetTags()
+        {
+            return (Tags ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
+        }
+
+        public string[] GetOfficialRatings()
+        {
+            return (OfficialRatings ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
+        }
+
         public string[] GetMediaTypes()
         public string[] GetMediaTypes()
         {
         {
             return (MediaTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
             return (MediaTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
@@ -110,6 +145,11 @@ namespace MediaBrowser.Api.UserLibrary
         {
         {
             return (ExcludeItemTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
             return (ExcludeItemTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
         }
         }
+
+        public int[] GetYears()
+        {
+            return (Years ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();
+        }
         
         
         /// <summary>
         /// <summary>
         /// Gets the filters.
         /// Gets the filters.

+ 24 - 24
MediaBrowser.Api/UserLibrary/ItemsService.cs

@@ -46,13 +46,6 @@ namespace MediaBrowser.Api.UserLibrary
         [ApiMember(Name = "PersonTypes", Description = "Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         [ApiMember(Name = "PersonTypes", Description = "Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         public string PersonTypes { get; set; }
         public string PersonTypes { get; set; }
 
 
-        /// <summary>
-        /// Limit results to items containing specific genres
-        /// </summary>
-        /// <value>The genres.</value>
-        [ApiMember(Name = "Genres", Description = "Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
-        public string Genres { get; set; }
-
         [ApiMember(Name = "AllGenres", Description = "Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
         [ApiMember(Name = "AllGenres", Description = "Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
         public string AllGenres { get; set; }
         public string AllGenres { get; set; }
 
 
@@ -73,13 +66,6 @@ namespace MediaBrowser.Api.UserLibrary
         [ApiMember(Name = "Albums", Description = "Optional. If specified, results will be filtered based on album. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
         [ApiMember(Name = "Albums", Description = "Optional. If specified, results will be filtered based on album. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
         public string Albums { get; set; }
         public string Albums { get; set; }
 
 
-        /// <summary>
-        /// Limit results to items containing specific years
-        /// </summary>
-        /// <value>The years.</value>
-        [ApiMember(Name = "Years", Description = "Optional. If specified, results will be filtered based on production year. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
-        public string Years { get; set; }
-
         /// <summary>
         /// <summary>
         /// Gets or sets the item ids.
         /// Gets or sets the item ids.
         /// </summary>
         /// </summary>
@@ -247,11 +233,6 @@ namespace MediaBrowser.Api.UserLibrary
             return (AllGenres ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
             return (AllGenres ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
         }
         }
 
 
-        public string[] GetGenres()
-        {
-            return (Genres ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
-        }
-
         public string[] GetStudios()
         public string[] GetStudios()
         {
         {
             return (Studios ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
             return (Studios ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
@@ -262,11 +243,6 @@ namespace MediaBrowser.Api.UserLibrary
             return (PersonTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
             return (PersonTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
         }
         }
 
 
-        public int[] GetYears()
-        {
-            return (Years ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();
-        }
-
         public IEnumerable<VideoType> GetVideoTypes()
         public IEnumerable<VideoType> GetVideoTypes()
         {
         {
             var val = VideoTypes;
             var val = VideoTypes;
@@ -520,6 +496,8 @@ namespace MediaBrowser.Api.UserLibrary
                 HasThemeSong = request.HasThemeSong,
                 HasThemeSong = request.HasThemeSong,
                 HasThemeVideo = request.HasThemeVideo,
                 HasThemeVideo = request.HasThemeVideo,
                 HasTrailer = request.HasTrailer,
                 HasTrailer = request.HasTrailer,
+                Tags = request.GetTags(),
+                OfficialRatings = request.GetOfficialRatings(),
                 Genres = request.GetGenres(),
                 Genres = request.GetGenres(),
                 AllGenres = request.GetAllGenres(),
                 AllGenres = request.GetAllGenres(),
                 Studios = request.GetStudios(),
                 Studios = request.GetStudios(),
@@ -951,6 +929,28 @@ namespace MediaBrowser.Api.UserLibrary
                     }
                     }
                 }
                 }
 
 
+                // Apply tag filter
+                var tags = request.GetTags();
+                if (tags.Length > 0)
+                {
+                    var hasTags = i as IHasTags;
+                    if (hasTags == null)
+                    {
+                        return false;
+                    }
+                    if (!(tags.Any(v => hasTags.Tags.Contains(v, StringComparer.OrdinalIgnoreCase))))
+                    {
+                        return false;
+                    }
+                }
+
+                // Apply official rating filter
+                var officialRatings = request.GetOfficialRatings();
+                if (officialRatings.Length > 0 && !officialRatings.Contains(i.OfficialRating ?? string.Empty))
+                {
+                    return false;
+                }
+
                 // Apply genre filter
                 // Apply genre filter
                 var genres = request.GetGenres();
                 var genres = request.GetGenres();
                 if (genres.Length > 0 && !(genres.Any(v => i.Genres.Contains(v, StringComparer.OrdinalIgnoreCase))))
                 if (genres.Length > 0 && !(genres.Any(v => i.Genres.Contains(v, StringComparer.OrdinalIgnoreCase))))

+ 10 - 8
MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs

@@ -398,14 +398,16 @@ namespace MediaBrowser.Common.Implementations.IO
                 throw new ArgumentNullException("path");
                 throw new ArgumentNullException("path");
             }
             }
 
 
-            //if (path.IndexOf("://", StringComparison.OrdinalIgnoreCase) != -1 &&
-            //    !path.StartsWith("file://", StringComparison.OrdinalIgnoreCase))
-            //{
-            //    return false;
-            //}
-            //return true;
-
-            return Path.IsPathRooted(path);
+            // Cannot use Path.IsPathRooted because it returns false under mono when using windows-based paths, e.g. C:\\
+
+            if (path.IndexOf("://", StringComparison.OrdinalIgnoreCase) != -1 &&
+                !path.StartsWith("file://", StringComparison.OrdinalIgnoreCase))
+            {
+                return false;
+            }
+            return true;
+
+            //return Path.IsPathRooted(path);
         }
         }
     }
     }
 }
 }

+ 4 - 0
MediaBrowser.Controller/Entities/InternalItemsQuery.cs

@@ -69,9 +69,13 @@ namespace MediaBrowser.Controller.Entities
         public ImageType[] ImageTypes { get; set; }
         public ImageType[] ImageTypes { get; set; }
         public VideoType[] VideoTypes { get; set; }
         public VideoType[] VideoTypes { get; set; }
         public int[] Years { get; set; }
         public int[] Years { get; set; }
+        public string[] Tags { get; set; }
+        public string[] OfficialRatings { get; set; }
 
 
         public InternalItemsQuery()
         public InternalItemsQuery()
         {
         {
+            Tags = new string[] { };
+            OfficialRatings = new string[] { };
             SortBy = new string[] { };
             SortBy = new string[] { };
             MediaTypes = new string[] { };
             MediaTypes = new string[] { };
             IncludeItemTypes = new string[] { };
             IncludeItemTypes = new string[] { };

+ 31 - 0
MediaBrowser.Controller/Entities/UserViewBuilder.cs

@@ -870,6 +870,16 @@ namespace MediaBrowser.Controller.Entities
                 return false;
                 return false;
             }
             }
 
 
+            if (request.Tags.Length > 0)
+            {
+                return false;
+            }
+
+            if (request.OfficialRatings.Length > 0)
+            {
+                return false;
+            }
+
             return true;
             return true;
         }
         }
 
 
@@ -1405,6 +1415,12 @@ namespace MediaBrowser.Controller.Entities
                 }
                 }
             }
             }
 
 
+            // Apply official rating filter
+            if (query.OfficialRatings.Length > 0 && !query.OfficialRatings.Contains(item.OfficialRating ?? string.Empty))
+            {
+                return false;
+            }
+
             // Apply person filter
             // Apply person filter
             if (!string.IsNullOrEmpty(query.Person))
             if (!string.IsNullOrEmpty(query.Person))
             {
             {
@@ -1431,6 +1447,21 @@ namespace MediaBrowser.Controller.Entities
                         return false;
                         return false;
                     }
                     }
                 }
                 }
+            }                
+            
+            // Apply tag filter
+            var tags = query.Tags;
+            if (tags.Length > 0)
+            {
+                var hasTags = item as IHasTags;
+                if (hasTags == null)
+                {
+                    return false;
+                }
+                if (!(tags.Any(v => hasTags.Tags.Contains(v, StringComparer.OrdinalIgnoreCase))))
+                {
+                    return false;
+                }
             }
             }
 
 
             return true;
             return true;

+ 26 - 31
MediaBrowser.ServerApplication/ServerNotifyIcon.cs

@@ -1,14 +1,9 @@
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Localization;
 using MediaBrowser.Controller.Localization;
-using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
 using MediaBrowser.Server.Startup.Common.Browser;
 using MediaBrowser.Server.Startup.Common.Browser;
-using MediaBrowser.ServerApplication.Native;
 using System;
 using System;
-using System.Diagnostics;
 using System.Windows.Forms;
 using System.Windows.Forms;
 
 
 namespace MediaBrowser.ServerApplication
 namespace MediaBrowser.ServerApplication
@@ -17,18 +12,18 @@ namespace MediaBrowser.ServerApplication
     {
     {
         bool IsDisposing = false;
         bool IsDisposing = false;
         
         
-        private System.Windows.Forms.NotifyIcon notifyIcon1;
-        private System.Windows.Forms.ContextMenuStrip contextMenuStrip1;
-        private System.Windows.Forms.ToolStripMenuItem cmdExit;
-        private System.Windows.Forms.ToolStripMenuItem cmdBrowse;
-        private System.Windows.Forms.ToolStripMenuItem cmdConfigure;
-        private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
-        private System.Windows.Forms.ToolStripMenuItem cmdRestart;
-        private System.Windows.Forms.ToolStripSeparator toolStripSeparator1;
-        private System.Windows.Forms.ToolStripMenuItem cmdCommunity;
-        private System.Windows.Forms.ToolStripMenuItem cmdApiDocs;
-        private System.Windows.Forms.ToolStripMenuItem cmdSwagger;
-        private System.Windows.Forms.ToolStripMenuItem cmdGtihub;
+        private NotifyIcon notifyIcon1;
+        private ContextMenuStrip contextMenuStrip1;
+        private ToolStripMenuItem cmdExit;
+        private ToolStripMenuItem cmdBrowse;
+        private ToolStripMenuItem cmdConfigure;
+        private ToolStripSeparator toolStripSeparator2;
+        private ToolStripMenuItem cmdRestart;
+        private ToolStripSeparator toolStripSeparator1;
+        private ToolStripMenuItem cmdCommunity;
+        private ToolStripMenuItem cmdApiDocs;
+        private ToolStripMenuItem cmdSwagger;
+        private ToolStripMenuItem cmdGtihub;
 
 
         private readonly ILogger _logger;
         private readonly ILogger _logger;
         private readonly IServerApplicationHost _appHost;
         private readonly IServerApplicationHost _appHost;
@@ -61,19 +56,19 @@ namespace MediaBrowser.ServerApplication
             var components = new System.ComponentModel.Container();
             var components = new System.ComponentModel.Container();
             
             
             var resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
             var resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
-            contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(components);
-            notifyIcon1 = new System.Windows.Forms.NotifyIcon(components);
+            contextMenuStrip1 = new ContextMenuStrip(components);
+            notifyIcon1 = new NotifyIcon(components);
             
             
-            cmdExit = new System.Windows.Forms.ToolStripMenuItem();
-            cmdCommunity = new System.Windows.Forms.ToolStripMenuItem();
-            toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
-            cmdRestart = new System.Windows.Forms.ToolStripMenuItem();
-            toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
-            cmdConfigure = new System.Windows.Forms.ToolStripMenuItem();
-            cmdBrowse = new System.Windows.Forms.ToolStripMenuItem();
-            cmdApiDocs = new System.Windows.Forms.ToolStripMenuItem();
-            cmdSwagger = new System.Windows.Forms.ToolStripMenuItem();
-            cmdGtihub = new System.Windows.Forms.ToolStripMenuItem();
+            cmdExit = new ToolStripMenuItem();
+            cmdCommunity = new ToolStripMenuItem();
+            toolStripSeparator1 = new ToolStripSeparator();
+            cmdRestart = new ToolStripMenuItem();
+            toolStripSeparator2 = new ToolStripSeparator();
+            cmdConfigure = new ToolStripMenuItem();
+            cmdBrowse = new ToolStripMenuItem();
+            cmdApiDocs = new ToolStripMenuItem();
+            cmdSwagger = new ToolStripMenuItem();
+            cmdGtihub = new ToolStripMenuItem();
             
             
             // 
             // 
             // notifyIcon1
             // notifyIcon1
@@ -85,7 +80,7 @@ namespace MediaBrowser.ServerApplication
             // 
             // 
             // contextMenuStrip1
             // contextMenuStrip1
             // 
             // 
-            contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+            contextMenuStrip1.Items.AddRange(new ToolStripItem[] {
             cmdBrowse,
             cmdBrowse,
             cmdConfigure,
             cmdConfigure,
             toolStripSeparator2,
             toolStripSeparator2,
@@ -136,7 +131,7 @@ namespace MediaBrowser.ServerApplication
             // 
             // 
             // cmdApiDocs
             // cmdApiDocs
             // 
             // 
-            cmdApiDocs.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
+            cmdApiDocs.DropDownItems.AddRange(new ToolStripItem[] {
             cmdSwagger,
             cmdSwagger,
             cmdGtihub});
             cmdGtihub});
             cmdApiDocs.Name = "cmdApiDocs";
             cmdApiDocs.Name = "cmdApiDocs";