Browse Source

unified the two sorting api's

LukePulverenti 12 years ago
parent
commit
31d079f1ba
30 changed files with 676 additions and 660 deletions
  1. 6 259
      MediaBrowser.Api/UserLibrary/ItemsService.cs
  2. 3 70
      MediaBrowser.Controller/Entities/Folder.cs
  3. 0 5
      MediaBrowser.Controller/Library/DtoBuilder.cs
  4. 14 1
      MediaBrowser.Controller/Library/ILibraryManager.cs
  5. 2 2
      MediaBrowser.Controller/MediaBrowser.Controller.csproj
  6. 0 248
      MediaBrowser.Controller/Sorting/BaseItemComparer.cs
  7. 17 0
      MediaBrowser.Controller/Sorting/IBaseItemComparer.cs
  8. 16 0
      MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs
  9. 0 33
      MediaBrowser.Controller/Sorting/SortOrder.cs
  10. 0 7
      MediaBrowser.Model/DTO/BaseItemDto.cs
  11. 0 5
      MediaBrowser.Model/DTO/ItemFields.cs
  12. 1 7
      MediaBrowser.Model/DTO/ItemQuery.cs
  13. 22 10
      MediaBrowser.Model/DTO/ItemSortBy.cs
  14. 68 1
      MediaBrowser.Server.Implementations/Library/LibraryManager.cs
  15. 11 0
      MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
  16. 46 0
      MediaBrowser.Server.Implementations/Sorting/AlbumArtistComparer.cs
  17. 46 0
      MediaBrowser.Server.Implementations/Sorting/AlbumComparer.cs
  18. 46 0
      MediaBrowser.Server.Implementations/Sorting/ArtistComparer.cs
  19. 29 0
      MediaBrowser.Server.Implementations/Sorting/CommunityRatingComparer.cs
  20. 33 0
      MediaBrowser.Server.Implementations/Sorting/DateCreatedComparer.cs
  21. 56 0
      MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs
  22. 52 0
      MediaBrowser.Server.Implementations/Sorting/PremiereDateComparer.cs
  23. 52 0
      MediaBrowser.Server.Implementations/Sorting/ProductionYearComparer.cs
  24. 33 0
      MediaBrowser.Server.Implementations/Sorting/RandomComparer.cs
  25. 32 0
      MediaBrowser.Server.Implementations/Sorting/RuntimeComparer.cs
  26. 33 0
      MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs
  27. 2 1
      MediaBrowser.ServerApplication/ApplicationHost.cs
  28. 52 10
      MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs
  29. 4 1
      MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
  30. BIN
      MediaBrowser.ServerApplication/MediaBrowser.ServerApplication_TemporaryKey.pfx

+ 6 - 259
MediaBrowser.Api/UserLibrary/ItemsService.cs

@@ -1,5 +1,4 @@
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
@@ -81,12 +80,6 @@ namespace MediaBrowser.Api.UserLibrary
         /// <value>The index by.</value>
         /// <value>The index by.</value>
         public string IndexBy { get; set; }
         public string IndexBy { get; set; }
 
 
-        /// <summary>
-        /// The dynamic, localized sort function name
-        /// </summary>
-        /// <value>The dynamic sort by.</value>
-        public string DynamicSortBy { get; set; }
-
         /// <summary>
         /// <summary>
         /// What to sort the results by
         /// What to sort the results by
         /// </summary>
         /// </summary>
@@ -254,7 +247,7 @@ namespace MediaBrowser.Api.UserLibrary
                 return ((Folder)item).GetRecursiveChildren(user);
                 return ((Folder)item).GetRecursiveChildren(user);
             }
             }
 
 
-            return ((Folder)item).GetChildren(user, request.IndexBy, request.DynamicSortBy, GetSortOrder(request));
+            return ((Folder)item).GetChildren(user, request.IndexBy);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -266,58 +259,9 @@ namespace MediaBrowser.Api.UserLibrary
         /// <returns>IEnumerable{BaseItem}.</returns>
         /// <returns>IEnumerable{BaseItem}.</returns>
         private IEnumerable<BaseItem> ApplySortOrder(GetItems request, IEnumerable<BaseItem> items, User user)
         private IEnumerable<BaseItem> ApplySortOrder(GetItems request, IEnumerable<BaseItem> items, User user)
         {
         {
-            var isFirst = true;
-            var descending = (GetSortOrder(request) ?? SortOrder.Ascending) == SortOrder.Descending;
+            var orderBy = GetOrderBy(request).ToArray();
 
 
-            IOrderedEnumerable<BaseItem> orderedItems = null;
-
-            foreach (var orderBy in GetOrderBy(request).Select(o => GetComparer(o, user)))
-            {
-                if (isFirst)
-                {
-                    orderedItems = descending ? items.OrderByDescending(i => i, orderBy) : items.OrderBy(i => i, orderBy);
-                }
-                else
-                {
-                    orderedItems = descending ? orderedItems.ThenByDescending(i => i, orderBy) : orderedItems.ThenBy(i => i, orderBy);
-                }
-
-                isFirst = false;
-            }
-
-            return orderedItems ?? items;
-        }
-
-        /// <summary>
-        /// Gets the comparer.
-        /// </summary>
-        /// <param name="sortBy">The sort by.</param>
-        /// <param name="user">The user.</param>
-        /// <returns>IComparer{BaseItem}.</returns>
-        /// <exception cref="System.ArgumentException"></exception>
-        private IComparer<BaseItem> GetComparer(ItemSortBy sortBy, User user)
-        {
-            switch (sortBy)
-            {
-                case ItemSortBy.Album:
-                    return new AlbumComparer();
-                case ItemSortBy.AlbumArtist:
-                    return new AlbumArtistComparer();
-                case ItemSortBy.Artist:
-                    return new ArtistComparer();
-                case ItemSortBy.Random:
-                    return new RandomComparer();
-                case ItemSortBy.DateCreated:
-                    return new DateCreatedComparer();
-                case ItemSortBy.SortName:
-                    return new SortNameComparer();
-                case ItemSortBy.PremiereDate:
-                    return new PremiereDateComparer();
-                case ItemSortBy.DatePlayed:
-                    return new DatePlayedComparer { User = user };
-                default:
-                    throw new ArgumentException();
-            }
+            return orderBy.Length == 0 ? items : _libraryManager.Sort(items, user, orderBy, GetSortOrder(request) ?? SortOrder.Ascending);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -575,16 +519,16 @@ namespace MediaBrowser.Api.UserLibrary
         /// </summary>
         /// </summary>
         /// <param name="request">The request.</param>
         /// <param name="request">The request.</param>
         /// <returns>IEnumerable{ItemSortBy}.</returns>
         /// <returns>IEnumerable{ItemSortBy}.</returns>
-        private IEnumerable<ItemSortBy> GetOrderBy(GetItems request)
+        private IEnumerable<string> GetOrderBy(GetItems request)
         {
         {
             var val = request.SortBy;
             var val = request.SortBy;
 
 
             if (string.IsNullOrEmpty(val))
             if (string.IsNullOrEmpty(val))
             {
             {
-                return new ItemSortBy[] { };
+                return new string[] { };
             }
             }
 
 
-            return val.Split(',').Select(v => (ItemSortBy)Enum.Parse(typeof(ItemSortBy), v, true));
+            return val.Split(',');
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -621,201 +565,4 @@ namespace MediaBrowser.Api.UserLibrary
             return x.DateCreated.CompareTo(y.DateCreated);
             return x.DateCreated.CompareTo(y.DateCreated);
         }
         }
     }
     }
-
-    /// <summary>
-    /// Class RandomComparer
-    /// </summary>
-    public class RandomComparer : IComparer<BaseItem>
-    {
-        /// <summary>
-        /// Compares the specified x.
-        /// </summary>
-        /// <param name="x">The x.</param>
-        /// <param name="y">The y.</param>
-        /// <returns>System.Int32.</returns>
-        public int Compare(BaseItem x, BaseItem y)
-        {
-            return Guid.NewGuid().CompareTo(Guid.NewGuid());
-        }
-    }
-
-    /// <summary>
-    /// Class SortNameComparer
-    /// </summary>
-    public class SortNameComparer : IComparer<BaseItem>
-    {
-        /// <summary>
-        /// Compares the specified x.
-        /// </summary>
-        /// <param name="x">The x.</param>
-        /// <param name="y">The y.</param>
-        /// <returns>System.Int32.</returns>
-        public int Compare(BaseItem x, BaseItem y)
-        {
-            return string.Compare(x.SortName, y.SortName, StringComparison.CurrentCultureIgnoreCase);
-        }
-    }
-
-    /// <summary>
-    /// Class AlbumArtistComparer
-    /// </summary>
-    public class AlbumArtistComparer : IComparer<BaseItem>
-    {
-        /// <summary>
-        /// Compares the specified x.
-        /// </summary>
-        /// <param name="x">The x.</param>
-        /// <param name="y">The y.</param>
-        /// <returns>System.Int32.</returns>
-        public int Compare(BaseItem x, BaseItem y)
-        {
-            return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase);
-        }
-
-        /// <summary>
-        /// Gets the value.
-        /// </summary>
-        /// <param name="x">The x.</param>
-        /// <returns>System.String.</returns>
-        private string GetValue(BaseItem x)
-        {
-            var audio = x as Audio;
-
-            return audio == null ? string.Empty : audio.AlbumArtist;
-        }
-    }
-
-    /// <summary>
-    /// Class AlbumComparer
-    /// </summary>
-    public class AlbumComparer : IComparer<BaseItem>
-    {
-        /// <summary>
-        /// Compares the specified x.
-        /// </summary>
-        /// <param name="x">The x.</param>
-        /// <param name="y">The y.</param>
-        /// <returns>System.Int32.</returns>
-        public int Compare(BaseItem x, BaseItem y)
-        {
-            return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase);
-        }
-
-        /// <summary>
-        /// Gets the value.
-        /// </summary>
-        /// <param name="x">The x.</param>
-        /// <returns>System.String.</returns>
-        private string GetValue(BaseItem x)
-        {
-            var audio = x as Audio;
-
-            return audio == null ? string.Empty : audio.Album;
-        }
-    }
-
-    /// <summary>
-    /// Class ArtistComparer
-    /// </summary>
-    public class ArtistComparer : IComparer<BaseItem>
-    {
-        /// <summary>
-        /// Compares the specified x.
-        /// </summary>
-        /// <param name="x">The x.</param>
-        /// <param name="y">The y.</param>
-        /// <returns>System.Int32.</returns>
-        public int Compare(BaseItem x, BaseItem y)
-        {
-            return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase);
-        }
-
-        /// <summary>
-        /// Gets the value.
-        /// </summary>
-        /// <param name="x">The x.</param>
-        /// <returns>System.String.</returns>
-        private string GetValue(BaseItem x)
-        {
-            var audio = x as Audio;
-
-            return audio == null ? string.Empty : audio.Artist;
-        }
-    }
-
-    /// <summary>
-    /// Class PremiereDateComparer
-    /// </summary>
-    public class PremiereDateComparer : IComparer<BaseItem>
-    {
-        /// <summary>
-        /// Compares the specified x.
-        /// </summary>
-        /// <param name="x">The x.</param>
-        /// <param name="y">The y.</param>
-        /// <returns>System.Int32.</returns>
-        public int Compare(BaseItem x, BaseItem y)
-        {
-            return GetDate(x).CompareTo(GetDate(y));
-        }
-
-        /// <summary>
-        /// Gets the date.
-        /// </summary>
-        /// <param name="x">The x.</param>
-        /// <returns>DateTime.</returns>
-        private DateTime GetDate(BaseItem x)
-        {
-            if (x.PremiereDate.HasValue)
-            {
-                return x.PremiereDate.Value;
-            }
-
-            if (x.ProductionYear.HasValue)
-            {
-                return new DateTime(x.ProductionYear.Value, 1, 1, 0, 0, 0, DateTimeKind.Utc);
-            }
-            return DateTime.MaxValue;
-        }
-    }
-
-    /// <summary>
-    /// Class DatePlayedComparer
-    /// </summary>
-    public class DatePlayedComparer : IComparer<BaseItem>
-    {
-        /// <summary>
-        /// Gets or sets the user.
-        /// </summary>
-        /// <value>The user.</value>
-        public User User { get; set; }
-
-        /// <summary>
-        /// Compares the specified x.
-        /// </summary>
-        /// <param name="x">The x.</param>
-        /// <param name="y">The y.</param>
-        /// <returns>System.Int32.</returns>
-        public int Compare(BaseItem x, BaseItem y)
-        {
-            return GetDate(x).CompareTo(GetDate(y));
-        }
-
-        /// <summary>
-        /// Gets the date.
-        /// </summary>
-        /// <param name="x">The x.</param>
-        /// <returns>DateTime.</returns>
-        private DateTime GetDate(BaseItem x)
-        {
-            var userdata = x.GetUserData(User, false);
-
-            if (userdata != null && userdata.LastPlayedDate.HasValue)
-            {
-                return userdata.LastPlayedDate.Value;
-            }
-
-            return DateTime.MinValue;
-        }
-    }
 }
 }

+ 3 - 70
MediaBrowser.Controller/Entities/Folder.cs

@@ -13,7 +13,6 @@ using System.Linq;
 using System.Runtime.Serialization;
 using System.Runtime.Serialization;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
-using SortOrder = MediaBrowser.Controller.Sorting.SortOrder;
 
 
 namespace MediaBrowser.Controller.Entities
 namespace MediaBrowser.Controller.Entities
 {
 {
@@ -177,63 +176,6 @@ namespace MediaBrowser.Controller.Entities
             }
             }
         }
         }
 
 
-        #region Sorting
-
-        /// <summary>
-        /// The _sort by options
-        /// </summary>
-        private Dictionary<string, IComparer<BaseItem>> _sortByOptions;
-        /// <summary>
-        /// Dictionary of sort options - consists of a display value (localized) and an IComparer of BaseItem
-        /// </summary>
-        /// <value>The sort by options.</value>
-        [IgnoreDataMember]
-        public Dictionary<string, IComparer<BaseItem>> SortByOptions
-        {
-            get { return _sortByOptions ?? (_sortByOptions = GetSortByOptions()); }
-        }
-
-        /// <summary>
-        /// Returns the valid set of sort by options for this folder type.
-        /// Override or extend to modify.
-        /// </summary>
-        /// <returns>Dictionary{System.StringIComparer{BaseItem}}.</returns>
-        protected virtual Dictionary<string, IComparer<BaseItem>> GetSortByOptions()
-        {
-            return new Dictionary<string, IComparer<BaseItem>> {            
-                {LocalizedStrings.Instance.GetString("NameDispPref"), new BaseItemComparer(SortOrder.Name, Logger)},
-                {LocalizedStrings.Instance.GetString("DateDispPref"), new BaseItemComparer(SortOrder.Date, Logger)},
-                {LocalizedStrings.Instance.GetString("RatingDispPref"), new BaseItemComparer(SortOrder.Rating, Logger)},
-                {LocalizedStrings.Instance.GetString("RuntimeDispPref"), new BaseItemComparer(SortOrder.Runtime, Logger)},
-                {LocalizedStrings.Instance.GetString("YearDispPref"), new BaseItemComparer(SortOrder.Year, Logger)}
-            };
-
-        }
-
-        /// <summary>
-        /// Get a sorting comparer by name
-        /// </summary>
-        /// <param name="name">The name.</param>
-        /// <returns>IComparer{BaseItem}.</returns>
-        private IComparer<BaseItem> GetSortingFunction(string name)
-        {
-            IComparer<BaseItem> sorting;
-            SortByOptions.TryGetValue(name ?? "", out sorting);
-            return sorting ?? new BaseItemComparer(SortOrder.Name, Logger);
-        }
-
-        /// <summary>
-        /// Get the list of sort by choices for this folder (localized).
-        /// </summary>
-        /// <value>The sort by option strings.</value>
-        [IgnoreDataMember]
-        public IEnumerable<string> SortByOptionStrings
-        {
-            get { return SortByOptions.Keys; }
-        }
-
-        #endregion
-
         #region Indexing
         #region Indexing
 
 
         /// <summary>
         /// <summary>
@@ -877,11 +819,9 @@ namespace MediaBrowser.Controller.Entities
         /// </summary>
         /// </summary>
         /// <param name="user">The user.</param>
         /// <param name="user">The user.</param>
         /// <param name="indexBy">The index by.</param>
         /// <param name="indexBy">The index by.</param>
-        /// <param name="sortBy">The sort by.</param>
-        /// <param name="sortOrder">The sort order.</param>
         /// <returns>IEnumerable{BaseItem}.</returns>
         /// <returns>IEnumerable{BaseItem}.</returns>
         /// <exception cref="System.ArgumentNullException"></exception>
         /// <exception cref="System.ArgumentNullException"></exception>
-        public virtual IEnumerable<BaseItem> GetChildren(User user, string indexBy = null, string sortBy = null, Model.Entities.SortOrder? sortOrder = null)
+        public virtual IEnumerable<BaseItem> GetChildren(User user, string indexBy = null)
         {
         {
             if (user == null)
             if (user == null)
             {
             {
@@ -889,7 +829,7 @@ namespace MediaBrowser.Controller.Entities
             }
             }
 
 
             //the true root should return our users root folder children
             //the true root should return our users root folder children
-            if (IsPhysicalRoot) return user.RootFolder.GetChildren(user, indexBy, sortBy, sortOrder);
+            if (IsPhysicalRoot) return user.RootFolder.GetChildren(user, indexBy);
 
 
             IEnumerable<BaseItem> result = null;
             IEnumerable<BaseItem> result = null;
 
 
@@ -904,14 +844,7 @@ namespace MediaBrowser.Controller.Entities
                 result = ActualChildren.Where(c => c.IsVisible(user));
                 result = ActualChildren.Where(c => c.IsVisible(user));
             }
             }
 
 
-            if (string.IsNullOrEmpty(sortBy))
-            {
-                return result;
-            }
-
-            return sortOrder.HasValue && sortOrder.Value == Model.Entities.SortOrder.Descending
-                       ? result.OrderByDescending(i => i, GetSortingFunction(sortBy))
-                       : result.OrderBy(i => i, GetSortingFunction(sortBy));
+            return result;
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 0 - 5
MediaBrowser.Controller/Library/DtoBuilder.cs

@@ -373,11 +373,6 @@ namespace MediaBrowser.Controller.Library
                 {
                 {
                     dto.IndexOptions = folder.IndexByOptionStrings.ToArray();
                     dto.IndexOptions = folder.IndexByOptionStrings.ToArray();
                 }
                 }
-
-                if (fields.Contains(ItemFields.SortOptions))
-                {
-                    dto.SortOptions = folder.SortByOptionStrings.ToArray();
-                }
             }
             }
 
 
             // Add audio info
             // Add audio info

+ 14 - 1
MediaBrowser.Controller/Library/ILibraryManager.cs

@@ -1,6 +1,7 @@
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Resolvers;
 using MediaBrowser.Controller.Resolvers;
+using MediaBrowser.Controller.Sorting;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
@@ -158,7 +159,19 @@ namespace MediaBrowser.Controller.Library
         /// <param name="pluginFolders">The plugin folders.</param>
         /// <param name="pluginFolders">The plugin folders.</param>
         /// <param name="resolvers">The resolvers.</param>
         /// <param name="resolvers">The resolvers.</param>
         /// <param name="introProviders">The intro providers.</param>
         /// <param name="introProviders">The intro providers.</param>
+        /// <param name="itemComparers">The item comparers.</param>
         void AddParts(IEnumerable<IResolverIgnoreRule> rules, IEnumerable<IVirtualFolderCreator> pluginFolders,
         void AddParts(IEnumerable<IResolverIgnoreRule> rules, IEnumerable<IVirtualFolderCreator> pluginFolders,
-                      IEnumerable<IItemResolver> resolvers, IEnumerable<IIntroProvider> introProviders);
+                      IEnumerable<IItemResolver> resolvers, IEnumerable<IIntroProvider> introProviders, IEnumerable<IBaseItemComparer> itemComparers);
+
+        /// <summary>
+        /// Sorts the specified items.
+        /// </summary>
+        /// <param name="items">The items.</param>
+        /// <param name="user">The user.</param>
+        /// <param name="sortBy">The sort by.</param>
+        /// <param name="sortOrder">The sort order.</param>
+        /// <returns>IEnumerable{BaseItem}.</returns>
+        IEnumerable<BaseItem> Sort(IEnumerable<BaseItem> items, User user, IEnumerable<string> sortBy,
+                                   SortOrder sortOrder);
     }
     }
 }
 }

+ 2 - 2
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -185,8 +185,8 @@
     <Compile Include="Providers\FolderProviderFromXml.cs" />
     <Compile Include="Providers\FolderProviderFromXml.cs" />
     <Compile Include="Providers\ImageFromMediaLocationProvider.cs" />
     <Compile Include="Providers\ImageFromMediaLocationProvider.cs" />
     <Compile Include="Providers\MediaInfo\FFProbeVideoInfoProvider.cs" />
     <Compile Include="Providers\MediaInfo\FFProbeVideoInfoProvider.cs" />
-    <Compile Include="Sorting\BaseItemComparer.cs" />
-    <Compile Include="Sorting\SortOrder.cs" />
+    <Compile Include="Sorting\IBaseItemComparer.cs" />
+    <Compile Include="Sorting\IUserBaseItemComparer.cs" />
     <Compile Include="Updates\IInstallationManager.cs" />
     <Compile Include="Updates\IInstallationManager.cs" />
     <Compile Include="Weather\IWeatherProvider.cs" />
     <Compile Include="Weather\IWeatherProvider.cs" />
     <Compile Include="Providers\BaseItemXmlParser.cs" />
     <Compile Include="Providers\BaseItemXmlParser.cs" />

+ 0 - 248
MediaBrowser.Controller/Sorting/BaseItemComparer.cs

@@ -1,248 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Collections.Generic;
-
-namespace MediaBrowser.Controller.Sorting {
-    /// <summary>
-    /// Class BaseItemComparer
-    /// </summary>
-    public class BaseItemComparer : IComparer<BaseItem> {
-        /// <summary>
-        /// The _order
-        /// </summary>
-        private readonly SortOrder _order;
-        /// <summary>
-        /// The _property name
-        /// </summary>
-        private readonly string _propertyName;
-        /// <summary>
-        /// The _compare culture
-        /// </summary>
-        private readonly StringComparison _compareCulture = StringComparison.CurrentCultureIgnoreCase;
-
-        /// <summary>
-        /// Gets or sets the logger.
-        /// </summary>
-        /// <value>The logger.</value>
-        private ILogger Logger { get; set; }
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="BaseItemComparer" /> class.
-        /// </summary>
-        /// <param name="order">The order.</param>
-        /// <param name="logger">The logger.</param>
-        public BaseItemComparer(SortOrder order, ILogger logger) {
-            _order = order;
-            Logger = logger;
-        }
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="BaseItemComparer" /> class.
-        /// </summary>
-        /// <param name="order">The order.</param>
-        /// <param name="compare">The compare.</param>
-        /// <param name="logger">The logger.</param>
-        public BaseItemComparer(SortOrder order, StringComparison compare, ILogger logger)
-        {
-            _order = order;
-            _compareCulture = compare;
-            Logger = logger;
-        }
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="BaseItemComparer" /> class.
-        /// </summary>
-        /// <param name="property">The property.</param>
-        /// <param name="logger">The logger.</param>
-        public BaseItemComparer(string property, ILogger logger)
-        {
-            _order = SortOrder.Custom;
-            _propertyName = property;
-            Logger = logger;
-        }
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="BaseItemComparer" /> class.
-        /// </summary>
-        /// <param name="property">The property.</param>
-        /// <param name="compare">The compare.</param>
-        /// <param name="logger">The logger.</param>
-        public BaseItemComparer(string property, StringComparison compare, ILogger logger)
-        {
-            _order = SortOrder.Custom;
-            _propertyName = property;
-            _compareCulture = compare;
-            Logger = logger;
-        }
-
-        #region IComparer<BaseItem> Members
-
-        /// <summary>
-        /// Compares the specified x.
-        /// </summary>
-        /// <param name="x">The x.</param>
-        /// <param name="y">The y.</param>
-        /// <returns>System.Int32.</returns>
-        public int Compare(BaseItem x, BaseItem y) {
-            int compare = 0;
-
-            switch (_order) {
-
-                case SortOrder.Date:
-                    compare = -x.DateCreated.CompareTo(y.DateCreated);
-                    break;
-
-                case SortOrder.Year:
-
-                    var xProductionYear = x.ProductionYear ?? 0;
-                    var yProductionYear = y.ProductionYear ?? 0;
-
-
-                    compare = yProductionYear.CompareTo(xProductionYear); 
-                    break;
-
-                case SortOrder.Rating:
-
-                    var xRating = x.CommunityRating ?? 0;
-                    var yRating = y.CommunityRating ?? 0;
-
-                    compare = yRating.CompareTo(xRating);
-                    break;
-
-                case SortOrder.Runtime:
-                    var xRuntime = x.RunTimeTicks ?? 0;
-                    var yRuntime = y.RunTimeTicks ?? 0;
-
-                    compare = xRuntime.CompareTo(yRuntime);
-                    break;
-
-                case SortOrder.Custom:
-
-                    Logger.Debug("Sorting on custom field " + _propertyName);
-                    var yProp = y.GetType().GetProperty(_propertyName);
-                    var xProp = x.GetType().GetProperty(_propertyName);
-                    if (yProp == null || xProp == null) break;
-                    var yVal = yProp.GetValue(y, null);
-                    var xVal = xProp.GetValue(x,null);
-                    if (yVal == null && xVal == null) break;
-                    if (yVal == null) return 1;
-                    if (xVal == null) return -1;
-                    compare = String.Compare(xVal.ToString(), yVal.ToString(),_compareCulture);
-                    break;
-
-                default:
-                    compare = 0;
-                    break;
-            }
-
-            if (compare == 0) {
-
-                var name1 = x.SortName ?? x.Name ?? "";
-                var name2 = y.SortName ?? y.Name ?? "";
-
-                //if (Config.Instance.EnableAlphanumericSorting)
-                    compare = AlphaNumericCompare(name1, name2,_compareCulture);
-                //else
-                //    compare = String.Compare(name1,name2,_compareCulture);
-            }
-
-            return compare;
-        }
-
-
-        #endregion
-
-        /// <summary>
-        /// Alphas the numeric compare.
-        /// </summary>
-        /// <param name="s1">The s1.</param>
-        /// <param name="s2">The s2.</param>
-        /// <param name="compareCulture">The compare culture.</param>
-        /// <returns>System.Int32.</returns>
-        private int AlphaNumericCompare(string s1, string s2, StringComparison compareCulture) {
-            // http://dotnetperls.com/Content/Alphanumeric-Sorting.aspx
-
-            int len1 = s1.Length;
-            int len2 = s2.Length;
-            int marker1 = 0;
-            int marker2 = 0;
-
-            // Walk through two the strings with two markers.
-            while (marker1 < len1 && marker2 < len2) {
-                char ch1 = s1[marker1];
-                char ch2 = s2[marker2];
-
-                // Some buffers we can build up characters in for each chunk.
-                var space1 = new char[len1];
-                var loc1 = 0;
-                var space2 = new char[len2];
-                var loc2 = 0;
-
-                // Walk through all following characters that are digits or
-                // characters in BOTH strings starting at the appropriate marker.
-                // Collect char arrays.
-                do {
-                    space1[loc1++] = ch1;
-                    marker1++;
-
-                    if (marker1 < len1) {
-                        ch1 = s1[marker1];
-                    } else {
-                        break;
-                    }
-                } while (char.IsDigit(ch1) == char.IsDigit(space1[0]));
-
-                do {
-                    space2[loc2++] = ch2;
-                    marker2++;
-
-                    if (marker2 < len2) {
-                        ch2 = s2[marker2];
-                    } else {
-                        break;
-                    }
-                } while (char.IsDigit(ch2) == char.IsDigit(space2[0]));
-
-                // If we have collected numbers, compare them numerically.
-                // Otherwise, if we have strings, compare them alphabetically.
-                var str1 = new string(space1);
-                var str2 = new string(space2);
-                
-                var result = 0;
-
-                //biggest int - 2147483647
-                if (char.IsDigit(space1[0]) && char.IsDigit(space2[0]) /*&& str1.Length < 10 && str2.Length < 10*/) //this assumed the entire string was a number...
-                {
-                    int thisNumericChunk;
-                    var isValid = false;
-
-                    if (int.TryParse(str1.Substring(0, str1.Length > 9 ? 10 : str1.Length), out thisNumericChunk))
-                    {
-                        int thatNumericChunk;
-                        
-                        if (int.TryParse(str2.Substring(0, str2.Length > 9 ? 10 : str2.Length), out thatNumericChunk))
-                        {
-                            isValid = true;
-                            result = thisNumericChunk.CompareTo(thatNumericChunk);
-                        }
-                    }
-                    
-                    if (!isValid)
-                    {
-                        Logger.Error("Error comparing numeric strings: " + str1 + "/" + str2);
-                        result = String.Compare(str1, str2, compareCulture);
-                    }
-                    
-                } else {
-                    result = String.Compare(str1,str2,compareCulture);
-                }
-
-                if (result != 0) {
-                    return result;
-                }
-            }
-            return len1 - len2;
-        }
-    }
-}

+ 17 - 0
MediaBrowser.Controller/Sorting/IBaseItemComparer.cs

@@ -0,0 +1,17 @@
+using MediaBrowser.Controller.Entities;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.Sorting
+{
+    /// <summary>
+    /// Interface IBaseItemComparer
+    /// </summary>
+    public interface IBaseItemComparer : IComparer<BaseItem>
+    {
+        /// <summary>
+        /// Gets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        string Name { get; }
+    }
+}

+ 16 - 0
MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs

@@ -0,0 +1,16 @@
+using MediaBrowser.Controller.Entities;
+
+namespace MediaBrowser.Controller.Sorting
+{
+    /// <summary>
+    /// Represents a BaseItem comparer that requires a User to perform it's comparison
+    /// </summary>
+    public interface IUserBaseItemComparer : IBaseItemComparer
+    {
+        /// <summary>
+        /// Gets or sets the user.
+        /// </summary>
+        /// <value>The user.</value>
+        User User { get; set; }
+    }
+}

+ 0 - 33
MediaBrowser.Controller/Sorting/SortOrder.cs

@@ -1,33 +0,0 @@
-
-namespace MediaBrowser.Controller.Sorting {
-    /// <summary>
-    /// Enum SortOrder
-    /// </summary>
-    public enum SortOrder {
-
-        /// <summary>
-        /// Sort by name
-        /// </summary>
-        Name,
-        /// <summary>
-        /// Sort by date added to the library
-        /// </summary>
-        Date,
-        /// <summary>
-        /// Sort by community rating
-        /// </summary>
-        Rating,
-        /// <summary>
-        /// Sort by runtime
-        /// </summary>
-        Runtime,
-        /// <summary>
-        /// Sort by year
-        /// </summary>
-        Year,
-        /// <summary>
-        /// Custom sort order added by plugins
-        /// </summary>
-        Custom
-    }
-}

+ 0 - 7
MediaBrowser.Model/DTO/BaseItemDto.cs

@@ -315,13 +315,6 @@ namespace MediaBrowser.Model.Dto
         [ProtoMember(52)]
         [ProtoMember(52)]
         public List<DayOfWeek> AirDays { get; set; }
         public List<DayOfWeek> AirDays { get; set; }
 
 
-        /// <summary>
-        /// Gets or sets the sort options.
-        /// </summary>
-        /// <value>The sort options.</value>
-        [ProtoMember(53)]
-        public string[] SortOptions { get; set; }
-
         /// <summary>
         /// <summary>
         /// Gets or sets the index options.
         /// Gets or sets the index options.
         /// </summary>
         /// </summary>

+ 0 - 5
MediaBrowser.Model/DTO/ItemFields.cs

@@ -86,11 +86,6 @@ namespace MediaBrowser.Model.Dto
         /// </summary>
         /// </summary>
         SortName,
         SortName,
 
 
-        /// <summary>
-        /// The fields that the server supports sorting on
-        /// </summary>
-        SortOptions,
-
         /// <summary>
         /// <summary>
         /// The studios of the item
         /// The studios of the item
         /// </summary>
         /// </summary>

+ 1 - 7
MediaBrowser.Model/DTO/ItemQuery.cs

@@ -36,7 +36,7 @@ namespace MediaBrowser.Model.Dto
         /// What to sort the results by
         /// What to sort the results by
         /// </summary>
         /// </summary>
         /// <value>The sort by.</value>
         /// <value>The sort by.</value>
-        public ItemSortBy[] SortBy { get; set; }
+        public string[] SortBy { get; set; }
 
 
         /// <summary>
         /// <summary>
         /// The sort order to return results with
         /// The sort order to return results with
@@ -116,12 +116,6 @@ namespace MediaBrowser.Model.Dto
         /// <value>The index by.</value>
         /// <value>The index by.</value>
         public string IndexBy { get; set; }
         public string IndexBy { get; set; }
 
 
-        /// <summary>
-        /// The dynamic, localized sort function name
-        /// </summary>
-        /// <value>The dynamic sort by.</value>
-        public string DynamicSortBy { get; set; }
-
         /// <summary>
         /// <summary>
         /// Gets or sets the image types.
         /// Gets or sets the image types.
         /// </summary>
         /// </summary>

+ 22 - 10
MediaBrowser.Model/DTO/ItemSortBy.cs

@@ -2,41 +2,53 @@
 namespace MediaBrowser.Model.Dto
 namespace MediaBrowser.Model.Dto
 {
 {
     /// <summary>
     /// <summary>
-    /// Enum ItemSortBy
+    /// These represent sort orders that are known by the core
     /// </summary>
     /// </summary>
-    public enum ItemSortBy
+    public static class ItemSortBy
     {
     {
         /// <summary>
         /// <summary>
         /// The album
         /// The album
         /// </summary>
         /// </summary>
-        Album,
+        public const string Album = "Album";
         /// <summary>
         /// <summary>
         /// The album artist
         /// The album artist
         /// </summary>
         /// </summary>
-        AlbumArtist,
+        public const string AlbumArtist = "AlbumArtist";
         /// <summary>
         /// <summary>
         /// The artist
         /// The artist
         /// </summary>
         /// </summary>
-        Artist,
+        public const string Artist = "Artist";
         /// <summary>
         /// <summary>
         /// The date created
         /// The date created
         /// </summary>
         /// </summary>
-        DateCreated,
+        public const string DateCreated = "DateCreated";
         /// <summary>
         /// <summary>
         /// The date played
         /// The date played
         /// </summary>
         /// </summary>
-        DatePlayed,
+        public const string DatePlayed = "DatePlayed";
         /// <summary>
         /// <summary>
         /// The premiere date
         /// The premiere date
         /// </summary>
         /// </summary>
-        PremiereDate,
+        public const string PremiereDate = "PremiereDate";
         /// <summary>
         /// <summary>
         /// The sort name
         /// The sort name
         /// </summary>
         /// </summary>
-        SortName,
+        public const string SortName = "SortName";
         /// <summary>
         /// <summary>
         /// The random
         /// The random
         /// </summary>
         /// </summary>
-        Random
+        public const string Random = "Random";
+        /// <summary>
+        /// The runtime
+        /// </summary>
+        public const string Runtime = "Runtime";
+        /// <summary>
+        /// The community rating
+        /// </summary>
+        public const string CommunityRating = "CommunityRating";
+        /// <summary>
+        /// The production year
+        /// </summary>
+        public const string ProductionYear = "ProductionYear";
     }
     }
 }
 }

+ 68 - 1
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -9,6 +9,7 @@ using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Resolvers;
 using MediaBrowser.Controller.Resolvers;
 using MediaBrowser.Controller.ScheduledTasks;
 using MediaBrowser.Controller.ScheduledTasks;
+using MediaBrowser.Controller.Sorting;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Server.Implementations.Library.Resolvers;
 using MediaBrowser.Server.Implementations.Library.Resolvers;
@@ -22,6 +23,7 @@ using System.IO;
 using System.Linq;
 using System.Linq;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
+using SortOrder = MediaBrowser.Model.Entities.SortOrder;
 
 
 namespace MediaBrowser.Server.Implementations.Library
 namespace MediaBrowser.Server.Implementations.Library
 {
 {
@@ -54,6 +56,12 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <value>The entity resolvers enumerable.</value>
         /// <value>The entity resolvers enumerable.</value>
         private IEnumerable<IItemResolver> EntityResolvers { get; set; }
         private IEnumerable<IItemResolver> EntityResolvers { get; set; }
 
 
+        /// <summary>
+        /// Gets or sets the comparers.
+        /// </summary>
+        /// <value>The comparers.</value>
+        private IEnumerable<IBaseItemComparer> Comparers { get; set; }
+
         #region LibraryChanged Event
         #region LibraryChanged Event
         /// <summary>
         /// <summary>
         /// Fires whenever any validation routine adds or removes items.  The added and removed items are properties of the args.
         /// Fires whenever any validation routine adds or removes items.  The added and removed items are properties of the args.
@@ -124,12 +132,14 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <param name="pluginFolders">The plugin folders.</param>
         /// <param name="pluginFolders">The plugin folders.</param>
         /// <param name="resolvers">The resolvers.</param>
         /// <param name="resolvers">The resolvers.</param>
         /// <param name="introProviders">The intro providers.</param>
         /// <param name="introProviders">The intro providers.</param>
-        public void AddParts(IEnumerable<IResolverIgnoreRule> rules, IEnumerable<IVirtualFolderCreator> pluginFolders, IEnumerable<IItemResolver> resolvers, IEnumerable<IIntroProvider> introProviders)
+        /// <param name="itemComparers">The item comparers.</param>
+        public void AddParts(IEnumerable<IResolverIgnoreRule> rules, IEnumerable<IVirtualFolderCreator> pluginFolders, IEnumerable<IItemResolver> resolvers, IEnumerable<IIntroProvider> introProviders, IEnumerable<IBaseItemComparer> itemComparers)
         {
         {
             EntityResolutionIgnoreRules = rules;
             EntityResolutionIgnoreRules = rules;
             PluginFolderCreators = pluginFolders;
             PluginFolderCreators = pluginFolders;
             EntityResolvers = resolvers.OrderBy(i => i.Priority).ToArray();
             EntityResolvers = resolvers.OrderBy(i => i.Priority).ToArray();
             IntroProviders = introProviders;
             IntroProviders = introProviders;
+            Comparers = itemComparers;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -702,5 +712,62 @@ namespace MediaBrowser.Server.Implementations.Library
         {
         {
             return IntroProviders.SelectMany(i => i.GetIntros(item, user));
             return IntroProviders.SelectMany(i => i.GetIntros(item, user));
         }
         }
+
+        /// <summary>
+        /// Sorts the specified sort by.
+        /// </summary>
+        /// <param name="items">The items.</param>
+        /// <param name="user">The user.</param>
+        /// <param name="sortBy">The sort by.</param>
+        /// <param name="sortOrder">The sort order.</param>
+        /// <returns>IEnumerable{BaseItem}.</returns>
+        public IEnumerable<BaseItem> Sort(IEnumerable<BaseItem> items, User user, IEnumerable<string> sortBy, SortOrder sortOrder)
+        {
+            var isFirst = true;
+
+            IOrderedEnumerable<BaseItem> orderedItems = null;
+
+            foreach (var orderBy in sortBy.Select(o => GetComparer(o, user)).Where(c => c != null))
+            {
+                if (isFirst)
+                {
+                    orderedItems = sortOrder == SortOrder.Descending ? items.OrderByDescending(i => i, orderBy) : items.OrderBy(i => i, orderBy);
+                }
+                else
+                {
+                    orderedItems = sortOrder == SortOrder.Descending ? orderedItems.ThenByDescending(i => i, orderBy) : orderedItems.ThenBy(i => i, orderBy);
+                }
+
+                isFirst = false;
+            }
+
+            return orderedItems ?? items;
+        }
+
+        /// <summary>
+        /// Gets the comparer.
+        /// </summary>
+        /// <param name="name">The name.</param>
+        /// <param name="user">The user.</param>
+        /// <returns>IBaseItemComparer.</returns>
+        private IBaseItemComparer GetComparer(string name, User user)
+        {
+            var comparer = Comparers.FirstOrDefault(c => string.Equals(name, c.Name, StringComparison.OrdinalIgnoreCase));
+
+            if (comparer != null)
+            {
+                // If it requires a user, create a new one, and assign the user
+                if (comparer is IUserBaseItemComparer)
+                {
+                    var userComparer = (IUserBaseItemComparer)Activator.CreateInstance(comparer.GetType());
+
+                    userComparer.User = user;
+
+                    return userComparer;
+                }
+            }
+
+            return comparer;
+        }
     }
     }
 }
 }

+ 11 - 0
MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj

@@ -139,6 +139,17 @@
     <Compile Include="ServerApplicationPaths.cs" />
     <Compile Include="ServerApplicationPaths.cs" />
     <Compile Include="ServerManager\ServerManager.cs" />
     <Compile Include="ServerManager\ServerManager.cs" />
     <Compile Include="ServerManager\WebSocketConnection.cs" />
     <Compile Include="ServerManager\WebSocketConnection.cs" />
+    <Compile Include="Sorting\AlbumArtistComparer.cs" />
+    <Compile Include="Sorting\AlbumComparer.cs" />
+    <Compile Include="Sorting\ArtistComparer.cs" />
+    <Compile Include="Sorting\CommunityRatingComparer.cs" />
+    <Compile Include="Sorting\DateCreatedComparer.cs" />
+    <Compile Include="Sorting\DatePlayedComparer.cs" />
+    <Compile Include="Sorting\PremiereDateComparer.cs" />
+    <Compile Include="Sorting\ProductionYearComparer.cs" />
+    <Compile Include="Sorting\RandomComparer.cs" />
+    <Compile Include="Sorting\RuntimeComparer.cs" />
+    <Compile Include="Sorting\SortNameComparer.cs" />
     <Compile Include="Sqlite\SQLiteDisplayPreferencesRepository.cs" />
     <Compile Include="Sqlite\SQLiteDisplayPreferencesRepository.cs" />
     <Compile Include="Sqlite\SQLiteExtensions.cs" />
     <Compile Include="Sqlite\SQLiteExtensions.cs" />
     <Compile Include="Sqlite\SQLiteItemRepository.cs" />
     <Compile Include="Sqlite\SQLiteItemRepository.cs" />

+ 46 - 0
MediaBrowser.Server.Implementations/Sorting/AlbumArtistComparer.cs

@@ -0,0 +1,46 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Sorting;
+using MediaBrowser.Model.Dto;
+using System;
+
+namespace MediaBrowser.Server.Implementations.Sorting
+{
+    /// <summary>
+    /// Class AlbumArtistComparer
+    /// </summary>
+    public class AlbumArtistComparer : IBaseItemComparer
+    {
+        /// <summary>
+        /// Compares the specified x.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <param name="y">The y.</param>
+        /// <returns>System.Int32.</returns>
+        public int Compare(BaseItem x, BaseItem y)
+        {
+            return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase);
+        }
+
+        /// <summary>
+        /// Gets the value.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <returns>System.String.</returns>
+        private string GetValue(BaseItem x)
+        {
+            var audio = x as Audio;
+
+            return audio == null ? string.Empty : audio.AlbumArtist;
+        }
+
+        /// <summary>
+        /// Gets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name
+        {
+            get { return ItemSortBy.AlbumArtist; }
+        }
+    }
+}

+ 46 - 0
MediaBrowser.Server.Implementations/Sorting/AlbumComparer.cs

@@ -0,0 +1,46 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Sorting;
+using MediaBrowser.Model.Dto;
+using System;
+
+namespace MediaBrowser.Server.Implementations.Sorting
+{
+    /// <summary>
+    /// Class AlbumComparer
+    /// </summary>
+    public class AlbumComparer : IBaseItemComparer
+    {
+        /// <summary>
+        /// Compares the specified x.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <param name="y">The y.</param>
+        /// <returns>System.Int32.</returns>
+        public int Compare(BaseItem x, BaseItem y)
+        {
+            return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase);
+        }
+
+        /// <summary>
+        /// Gets the value.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <returns>System.String.</returns>
+        private string GetValue(BaseItem x)
+        {
+            var audio = x as Audio;
+
+            return audio == null ? string.Empty : audio.Album;
+        }
+
+        /// <summary>
+        /// Gets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name
+        {
+            get { return ItemSortBy.Album; }
+        }
+    }
+}

+ 46 - 0
MediaBrowser.Server.Implementations/Sorting/ArtistComparer.cs

@@ -0,0 +1,46 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Sorting;
+using MediaBrowser.Model.Dto;
+using System;
+
+namespace MediaBrowser.Server.Implementations.Sorting
+{
+    /// <summary>
+    /// Class ArtistComparer
+    /// </summary>
+    public class ArtistComparer : IBaseItemComparer
+    {
+        /// <summary>
+        /// Compares the specified x.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <param name="y">The y.</param>
+        /// <returns>System.Int32.</returns>
+        public int Compare(BaseItem x, BaseItem y)
+        {
+            return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase);
+        }
+
+        /// <summary>
+        /// Gets the value.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <returns>System.String.</returns>
+        private string GetValue(BaseItem x)
+        {
+            var audio = x as Audio;
+
+            return audio == null ? string.Empty : audio.Artist;
+        }
+
+        /// <summary>
+        /// Gets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name
+        {
+            get { return ItemSortBy.Artist; }
+        }
+    }
+}

+ 29 - 0
MediaBrowser.Server.Implementations/Sorting/CommunityRatingComparer.cs

@@ -0,0 +1,29 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Sorting;
+using MediaBrowser.Model.Dto;
+
+namespace MediaBrowser.Server.Implementations.Sorting
+{
+    public class CommunityRatingComparer : IBaseItemComparer
+    {
+        /// <summary>
+        /// Compares the specified x.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <param name="y">The y.</param>
+        /// <returns>System.Int32.</returns>
+        public int Compare(BaseItem x, BaseItem y)
+        {
+            return (x.CommunityRating ?? 0).CompareTo(y.CommunityRating ?? 0);
+        }
+
+        /// <summary>
+        /// Gets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name
+        {
+            get { return ItemSortBy.CommunityRating; }
+        }
+    }
+}

+ 33 - 0
MediaBrowser.Server.Implementations/Sorting/DateCreatedComparer.cs

@@ -0,0 +1,33 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Sorting;
+using MediaBrowser.Model.Dto;
+using System;
+
+namespace MediaBrowser.Server.Implementations.Sorting
+{
+    /// <summary>
+    /// Class DateCreatedComparer
+    /// </summary>
+    public class DateCreatedComparer : IBaseItemComparer
+    {
+        /// <summary>
+        /// Compares the specified x.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <param name="y">The y.</param>
+        /// <returns>System.Int32.</returns>
+        public int Compare(BaseItem x, BaseItem y)
+        {
+            return DateTime.Compare(x.DateCreated, y.DateCreated);
+        }
+
+        /// <summary>
+        /// Gets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name
+        {
+            get { return ItemSortBy.DateCreated; }
+        }
+    }
+}

+ 56 - 0
MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs

@@ -0,0 +1,56 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Sorting;
+using MediaBrowser.Model.Dto;
+using System;
+
+namespace MediaBrowser.Server.Implementations.Sorting
+{
+    /// <summary>
+    /// Class DatePlayedComparer
+    /// </summary>
+    public class DatePlayedComparer : IUserBaseItemComparer
+    {
+        /// <summary>
+        /// Gets or sets the user.
+        /// </summary>
+        /// <value>The user.</value>
+        public User User { get; set; }
+
+        /// <summary>
+        /// Compares the specified x.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <param name="y">The y.</param>
+        /// <returns>System.Int32.</returns>
+        public int Compare(BaseItem x, BaseItem y)
+        {
+            return GetDate(x).CompareTo(GetDate(y));
+        }
+
+        /// <summary>
+        /// Gets the date.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <returns>DateTime.</returns>
+        private DateTime GetDate(BaseItem x)
+        {
+            var userdata = x.GetUserData(User, false);
+
+            if (userdata != null && userdata.LastPlayedDate.HasValue)
+            {
+                return userdata.LastPlayedDate.Value;
+            }
+
+            return DateTime.MaxValue;
+        }
+
+        /// <summary>
+        /// Gets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name
+        {
+            get { return ItemSortBy.DatePlayed; }
+        }
+    }
+}

+ 52 - 0
MediaBrowser.Server.Implementations/Sorting/PremiereDateComparer.cs

@@ -0,0 +1,52 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Sorting;
+using MediaBrowser.Model.Dto;
+using System;
+
+namespace MediaBrowser.Server.Implementations.Sorting
+{
+    /// <summary>
+    /// Class PremiereDateComparer
+    /// </summary>
+    public class PremiereDateComparer : IBaseItemComparer
+    {
+        /// <summary>
+        /// Compares the specified x.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <param name="y">The y.</param>
+        /// <returns>System.Int32.</returns>
+        public int Compare(BaseItem x, BaseItem y)
+        {
+            return GetDate(x).CompareTo(GetDate(y));
+        }
+
+        /// <summary>
+        /// Gets the date.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <returns>DateTime.</returns>
+        private DateTime GetDate(BaseItem x)
+        {
+            if (x.PremiereDate.HasValue)
+            {
+                return x.PremiereDate.Value;
+            }
+            
+            if (x.ProductionYear.HasValue)
+            {
+                return new DateTime(x.ProductionYear.Value, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+            }
+            return DateTime.MaxValue;
+        }
+
+        /// <summary>
+        /// Gets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name
+        {
+            get { return ItemSortBy.PremiereDate; }
+        }
+    }
+}

+ 52 - 0
MediaBrowser.Server.Implementations/Sorting/ProductionYearComparer.cs

@@ -0,0 +1,52 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Sorting;
+using MediaBrowser.Model.Dto;
+
+namespace MediaBrowser.Server.Implementations.Sorting
+{
+    /// <summary>
+    /// Class ProductionYearComparer
+    /// </summary>
+    public class ProductionYearComparer : IBaseItemComparer
+    {
+        /// <summary>
+        /// Compares the specified x.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <param name="y">The y.</param>
+        /// <returns>System.Int32.</returns>
+        public int Compare(BaseItem x, BaseItem y)
+        {
+            return GetValue(x).CompareTo(GetValue(y));
+        }
+
+        /// <summary>
+        /// Gets the date.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <returns>DateTime.</returns>
+        private int GetValue(BaseItem x)
+        {
+            if (x.ProductionYear.HasValue)
+            {
+                return x.ProductionYear.Value;
+            }
+
+            if (x.PremiereDate.HasValue)
+            {
+                return x.PremiereDate.Value.Year;
+            }
+
+            return 0;
+        }
+
+        /// <summary>
+        /// Gets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name
+        {
+            get { return ItemSortBy.ProductionYear; }
+        }
+    }
+}

+ 33 - 0
MediaBrowser.Server.Implementations/Sorting/RandomComparer.cs

@@ -0,0 +1,33 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Sorting;
+using MediaBrowser.Model.Dto;
+using System;
+
+namespace MediaBrowser.Server.Implementations.Sorting
+{
+    /// <summary>
+    /// Class RandomComparer
+    /// </summary>
+    public class RandomComparer : IBaseItemComparer
+    {
+        /// <summary>
+        /// Compares the specified x.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <param name="y">The y.</param>
+        /// <returns>System.Int32.</returns>
+        public int Compare(BaseItem x, BaseItem y)
+        {
+            return Guid.NewGuid().CompareTo(Guid.NewGuid());
+        }
+
+        /// <summary>
+        /// Gets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name
+        {
+            get { return ItemSortBy.Random; }
+        }
+    }
+}

+ 32 - 0
MediaBrowser.Server.Implementations/Sorting/RuntimeComparer.cs

@@ -0,0 +1,32 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Sorting;
+using MediaBrowser.Model.Dto;
+
+namespace MediaBrowser.Server.Implementations.Sorting
+{
+    /// <summary>
+    /// Class RuntimeComparer
+    /// </summary>
+    public class RuntimeComparer : IBaseItemComparer
+    {
+        /// <summary>
+        /// Compares the specified x.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <param name="y">The y.</param>
+        /// <returns>System.Int32.</returns>
+        public int Compare(BaseItem x, BaseItem y)
+        {
+            return (x.RunTimeTicks ?? 0).CompareTo(y.RunTimeTicks ?? 0);
+        }
+
+        /// <summary>
+        /// Gets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name
+        {
+            get { return ItemSortBy.Runtime; }
+        }
+    }
+}

+ 33 - 0
MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs

@@ -0,0 +1,33 @@
+using MediaBrowser.Controller.Entities;
+using System;
+using MediaBrowser.Controller.Sorting;
+using MediaBrowser.Model.Dto;
+
+namespace MediaBrowser.Server.Implementations.Sorting
+{
+    /// <summary>
+    /// Class SortNameComparer
+    /// </summary>
+    public class SortNameComparer : IBaseItemComparer
+    {
+        /// <summary>
+        /// Compares the specified x.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <param name="y">The y.</param>
+        /// <returns>System.Int32.</returns>
+        public int Compare(BaseItem x, BaseItem y)
+        {
+            return string.Compare(x.SortName, y.SortName, StringComparison.CurrentCultureIgnoreCase);
+        }
+
+        /// <summary>
+        /// Gets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name
+        {
+            get { return ItemSortBy.SortName; }
+        }
+    }
+}

+ 2 - 1
MediaBrowser.ServerApplication/ApplicationHost.cs

@@ -18,6 +18,7 @@ using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Plugins;
 using MediaBrowser.Controller.Plugins;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Resolvers;
 using MediaBrowser.Controller.Resolvers;
+using MediaBrowser.Controller.Sorting;
 using MediaBrowser.Controller.Updates;
 using MediaBrowser.Controller.Updates;
 using MediaBrowser.Controller.Weather;
 using MediaBrowser.Controller.Weather;
 using MediaBrowser.IsoMounter;
 using MediaBrowser.IsoMounter;
@@ -242,7 +243,7 @@ namespace MediaBrowser.ServerApplication
             ServerManager.AddWebSocketListeners(GetExports<IWebSocketListener>(false));
             ServerManager.AddWebSocketListeners(GetExports<IWebSocketListener>(false));
             ServerManager.Start();
             ServerManager.Start();
 
 
-            LibraryManager.AddParts(GetExports<IResolverIgnoreRule>(), GetExports<IVirtualFolderCreator>(), GetExports<IItemResolver>(), GetExports<IIntroProvider>());
+            LibraryManager.AddParts(GetExports<IResolverIgnoreRule>(), GetExports<IVirtualFolderCreator>(), GetExports<IItemResolver>(), GetExports<IIntroProvider>(), GetExports<IBaseItemComparer>());
 
 
             ProviderManager.AddMetadataProviders(GetExports<BaseMetadataProvider>().OrderBy(e => e.Priority).ToArray());
             ProviderManager.AddMetadataProviders(GetExports<BaseMetadataProvider>().OrderBy(e => e.Priority).ToArray());
         }
         }

+ 52 - 10
MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs

@@ -4,6 +4,7 @@ using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Localization;
 using MediaBrowser.Controller.Localization;
+using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Serialization;
@@ -78,7 +79,8 @@ namespace MediaBrowser.ServerApplication
             Cursor = Cursors.Wait;
             Cursor = Cursors.Wait;
             await Task.Run(() =>
             await Task.Run(() =>
                 {
                 {
-                    IEnumerable<BaseItem> children = CurrentUser.Name == "Physical" ? _libraryManager.RootFolder.Children.OrderBy(i => i.SortName) : _libraryManager.RootFolder.GetChildren(CurrentUser, sortBy: LocalizedStrings.Instance.GetString("NameDispPref"));
+                    IEnumerable<BaseItem> children = CurrentUser.Name == "Physical" ? _libraryManager.RootFolder.Children : _libraryManager.RootFolder.GetChildren(CurrentUser);
+                    children = OrderByName(children, CurrentUser);
 
 
                     foreach (Folder folder in children)
                     foreach (Folder folder in children)
                                    {
                                    {
@@ -86,9 +88,12 @@ namespace MediaBrowser.ServerApplication
                                         var currentFolder = folder;
                                         var currentFolder = folder;
                                        Task.Factory.StartNew(() =>
                                        Task.Factory.StartNew(() =>
                                         {
                                         {
-                                            var prefs = ddlProfile.SelectedItem != null ? currentFolder.GetDisplayPrefs(ddlProfile.SelectedItem as User, false) ?? new DisplayPreferences {SortBy = LocalizedStrings.Instance.GetString("NameDispPref")} : new DisplayPreferences {SortBy = LocalizedStrings.Instance.GetString("NameDispPref")};
+                                            var prefs = ddlProfile.SelectedItem != null ? currentFolder.GetDisplayPrefs(ddlProfile.SelectedItem as User, false) ?? new DisplayPreferences {SortBy = ItemSortBy.SortName} : new DisplayPreferences {SortBy = ItemSortBy.SortName};
                                             var node = new TreeViewItem { Tag = currentFolder };
                                             var node = new TreeViewItem { Tag = currentFolder };
-                                            AddChildren(node, currentFolder.GetChildren(CurrentUser, prefs.IndexBy, prefs.SortBy ?? LocalizedStrings.Instance.GetString("NameDispPref")), CurrentUser);
+
+                                            var subChildren = currentFolder.GetChildren(CurrentUser, prefs.IndexBy);
+                                            subChildren = OrderByName(subChildren, CurrentUser);
+                                            AddChildren(node, subChildren, CurrentUser);
                                             node.Header = currentFolder.Name + " (" +
                                             node.Header = currentFolder.Name + " (" +
                                                         node.Items.Count + ")";
                                                         node.Items.Count + ")";
                                             tvwLibrary.Items.Add(node);
                                             tvwLibrary.Items.Add(node);
@@ -100,6 +105,28 @@ namespace MediaBrowser.ServerApplication
 
 
         }
         }
 
 
+        /// <summary>
+        /// Orders the name of the by.
+        /// </summary>
+        /// <param name="items">The items.</param>
+        /// <param name="user">The user.</param>
+        /// <returns>IEnumerable{BaseItem}.</returns>
+        private IEnumerable<BaseItem> OrderByName(IEnumerable<BaseItem> items, User user)
+        {
+            return OrderBy(items, user, ItemSortBy.SortName);
+        }
+
+        /// <summary>
+        /// Orders the name of the by.
+        /// </summary>
+        /// <param name="items">The items.</param>
+        /// <param name="user">The user.</param>
+        /// <returns>IEnumerable{BaseItem}.</returns>
+        private IEnumerable<BaseItem> OrderBy(IEnumerable<BaseItem> items, User user, string order)
+        {
+            return _libraryManager.Sort(items, user, new[] { order }, SortOrder.Ascending);
+        }
+
         /// <summary>
         /// <summary>
         /// Adds the children.
         /// Adds the children.
         /// </summary>
         /// </summary>
@@ -115,7 +142,7 @@ namespace MediaBrowser.ServerApplication
                 if (subFolder != null)
                 if (subFolder != null)
                 {
                 {
                     var prefs = subFolder.GetDisplayPrefs(user, false) ?? new DisplayPreferences {SortBy = LocalizedStrings.Instance.GetString("NameDispPref")};
                     var prefs = subFolder.GetDisplayPrefs(user, false) ?? new DisplayPreferences {SortBy = LocalizedStrings.Instance.GetString("NameDispPref")};
-                    AddChildren(node, subFolder.GetChildren(user, sortBy: prefs.SortBy), user);
+                    AddChildren(node, OrderBy(subFolder.GetChildren(user), user, prefs.SortBy), user);
                     node.Header = item.Name + " (" + node.Items.Count + ")";
                     node.Header = item.Name + " (" + node.Items.Count + ")";
                 }
                 }
                 else
                 else
@@ -152,14 +179,29 @@ namespace MediaBrowser.ServerApplication
                 {
                 {
                     lblIndexBy.Visibility = ddlIndexBy.Visibility = ddlSortBy.Visibility = lblSortBy.Visibility = Visibility.Visible;
                     lblIndexBy.Visibility = ddlIndexBy.Visibility = ddlSortBy.Visibility = lblSortBy.Visibility = Visibility.Visible;
                     ddlIndexBy.ItemsSource = folder.IndexByOptionStrings;
                     ddlIndexBy.ItemsSource = folder.IndexByOptionStrings;
-                    ddlSortBy.ItemsSource = folder.SortByOptionStrings;
+
+                    ddlSortBy.ItemsSource = new []
+                        {
+                            ItemSortBy.SortName, 
+                            ItemSortBy.Album, 
+                            ItemSortBy.AlbumArtist, 
+                            ItemSortBy.Artist, 
+                            ItemSortBy.CommunityRating, 
+                            ItemSortBy.DateCreated, 
+                            ItemSortBy.DatePlayed, 
+                            ItemSortBy.PremiereDate, 
+                            ItemSortBy.ProductionYear, 
+                            ItemSortBy.Random, 
+                            ItemSortBy.Runtime
+                        };
+
                     var prefs = folder.GetDisplayPrefs(ddlProfile.SelectedItem as User, false);
                     var prefs = folder.GetDisplayPrefs(ddlProfile.SelectedItem as User, false);
                     ddlIndexBy.SelectedItem = prefs != null
                     ddlIndexBy.SelectedItem = prefs != null
                                                   ? prefs.IndexBy ?? LocalizedStrings.Instance.GetString("NoneDispPref")
                                                   ? prefs.IndexBy ?? LocalizedStrings.Instance.GetString("NoneDispPref")
                                                   : LocalizedStrings.Instance.GetString("NoneDispPref");
                                                   : LocalizedStrings.Instance.GetString("NoneDispPref");
                     ddlSortBy.SelectedItem = prefs != null
                     ddlSortBy.SelectedItem = prefs != null
-                                                  ? prefs.SortBy ?? LocalizedStrings.Instance.GetString("NameDispPref")
-                                                  : LocalizedStrings.Instance.GetString("NameDispPref");
+                                                  ? prefs.SortBy ?? ItemSortBy.SortName
+                                                  : ItemSortBy.SortName;
                 }
                 }
                 else
                 else
                 {
                 {
@@ -311,7 +353,7 @@ namespace MediaBrowser.ServerApplication
                 var folder = treeItem != null
                 var folder = treeItem != null
                                  ? treeItem.Tag as Folder
                                  ? treeItem.Tag as Folder
                                  : null;
                                  : null;
-                var prefs = folder != null ? folder.GetDisplayPrefs(CurrentUser, true) : new DisplayPreferences {SortBy = LocalizedStrings.Instance.GetString("NameDispPref")};
+                var prefs = folder != null ? folder.GetDisplayPrefs(CurrentUser, true) : new DisplayPreferences {SortBy = ItemSortBy.SortName};
                 if (folder != null && prefs.IndexBy != ddlIndexBy.SelectedItem as string)
                 if (folder != null && prefs.IndexBy != ddlIndexBy.SelectedItem as string)
                 {
                 {
                     //grab UI context so we can update within the below task
                     //grab UI context so we can update within the below task
@@ -326,7 +368,7 @@ namespace MediaBrowser.ServerApplication
                                                             //re-build the current item's children as an index
                                                             //re-build the current item's children as an index
                                                             prefs.IndexBy = ddlIndexBy.SelectedItem as string;
                                                             prefs.IndexBy = ddlIndexBy.SelectedItem as string;
                                                             treeItem.Items.Clear();
                                                             treeItem.Items.Clear();
-                                                            AddChildren(treeItem,folder.GetChildren(CurrentUser, prefs.IndexBy, prefs.SortBy), CurrentUser);
+                                                            AddChildren(treeItem, OrderBy(folder.GetChildren(CurrentUser, prefs.IndexBy), CurrentUser, prefs.SortBy), CurrentUser);
                                                             treeItem.Header = folder.Name + "(" +
                                                             treeItem.Header = folder.Name + "(" +
                                                                               treeItem.Items.Count + ")";
                                                                               treeItem.Items.Count + ")";
                                                             Cursor = Cursors.Arrow;
                                                             Cursor = Cursors.Arrow;
@@ -367,7 +409,7 @@ namespace MediaBrowser.ServerApplication
                                                             //re-sort
                                                             //re-sort
                                                             prefs.SortBy = ddlSortBy.SelectedItem as string;
                                                             prefs.SortBy = ddlSortBy.SelectedItem as string;
                                                             treeItem.Items.Clear();
                                                             treeItem.Items.Clear();
-                                                            AddChildren(treeItem,folder.GetChildren(CurrentUser,prefs.IndexBy, prefs.SortBy ?? LocalizedStrings.Instance.GetString("NameDispPref")), CurrentUser);
+                                                            AddChildren(treeItem, OrderBy(folder.GetChildren(CurrentUser, prefs.IndexBy), CurrentUser, prefs.SortBy ?? ItemSortBy.SortName), CurrentUser);
                                                             treeItem.Header = folder.Name + "(" +
                                                             treeItem.Header = folder.Name + "(" +
                                                                               treeItem.Items.Count + ")";
                                                                               treeItem.Items.Count + ")";
                                                             Cursor = Cursors.Arrow;
                                                             Cursor = Cursors.Arrow;

+ 4 - 1
MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj

@@ -76,7 +76,7 @@
     </ManifestKeyFile>
     </ManifestKeyFile>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup>
   <PropertyGroup>
-    <GenerateManifests>true</GenerateManifests>
+    <GenerateManifests>false</GenerateManifests>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup>
   <PropertyGroup>
     <SignManifests>false</SignManifests>
     <SignManifests>false</SignManifests>
@@ -112,6 +112,9 @@
     <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
     <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
     <Prefer32Bit>true</Prefer32Bit>
     <Prefer32Bit>true</Prefer32Bit>
   </PropertyGroup>
   </PropertyGroup>
+  <PropertyGroup>
+    <TargetZone>LocalIntranet</TargetZone>
+  </PropertyGroup>
   <ItemGroup>
   <ItemGroup>
     <Reference Include="Hardcodet.Wpf.TaskbarNotification">
     <Reference Include="Hardcodet.Wpf.TaskbarNotification">
       <HintPath>..\packages\Hardcodet.Wpf.TaskbarNotification.1.0.4.0\lib\net40\Hardcodet.Wpf.TaskbarNotification.dll</HintPath>
       <HintPath>..\packages\Hardcodet.Wpf.TaskbarNotification.1.0.4.0\lib\net40\Hardcodet.Wpf.TaskbarNotification.dll</HintPath>

BIN
MediaBrowser.ServerApplication/MediaBrowser.ServerApplication_TemporaryKey.pfx