Bladeren bron

localize library changed messages per user

Luke Pulverenti 12 jaren geleden
bovenliggende
commit
a3ecf6c2b7

+ 11 - 11
MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs

@@ -162,17 +162,17 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
 
             using (var message = GetHttpRequestMessage(options))
             {
-                if (options.EnableResponseCache && cachedInfo != null)
-                {
-                    if (!string.IsNullOrEmpty(cachedInfo.Etag))
-                    {
-                        message.Headers.Add("If-None-Match", cachedInfo.Etag);
-                    }
-                    else if (cachedInfo.LastModified.HasValue)
-                    {
-                        message.Headers.IfModifiedSince = new DateTimeOffset(cachedInfo.LastModified.Value);
-                    }
-                }
+                //if (options.EnableResponseCache && cachedInfo != null)
+                //{
+                //    if (!string.IsNullOrEmpty(cachedInfo.Etag))
+                //    {
+                //        message.Headers.Add("If-None-Match", cachedInfo.Etag);
+                //    }
+                //    else if (cachedInfo.LastModified.HasValue)
+                //    {
+                //        message.Headers.IfModifiedSince = new DateTimeOffset(cachedInfo.LastModified.Value);
+                //    }
+                //}
 
                 if (options.ResourcePool != null)
                 {

+ 17 - 0
MediaBrowser.Common/Net/IServerManager.cs

@@ -52,10 +52,27 @@ namespace MediaBrowser.Common.Net
         /// <exception cref="System.ArgumentNullException">messageType</exception>
         Task SendWebSocketMessageAsync<T>(string messageType, Func<T> dataFunction, CancellationToken cancellationToken);
 
+        /// <summary>
+        /// Sends the web socket message async.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="messageType">Type of the message.</param>
+        /// <param name="dataFunction">The data function.</param>
+        /// <param name="connections">The connections.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task.</returns>
+        Task SendWebSocketMessageAsync<T>(string messageType, Func<T> dataFunction, IEnumerable<IWebSocketConnection> connections, CancellationToken cancellationToken);
+        
         /// <summary>
         /// Adds the web socket listeners.
         /// </summary>
         /// <param name="listeners">The listeners.</param>
         void AddWebSocketListeners(IEnumerable<IWebSocketListener> listeners);
+
+        /// <summary>
+        /// Gets the web socket connections.
+        /// </summary>
+        /// <value>The web socket connections.</value>
+        IEnumerable<IWebSocketConnection> WebSocketConnections { get; }
     }
 }

+ 1 - 1
MediaBrowser.Controller/Providers/Music/LastfmArtistProvider.cs

@@ -83,7 +83,7 @@ namespace MediaBrowser.Controller.Providers.Music
         private string FindIdFromMusicArtistEntity(BaseItem item)
         {
             var artist = _libraryManager.RootFolder.RecursiveChildren.OfType<MusicArtist>()
-                .FirstOrDefault(i => string.Equals(i.Name, item.Name, StringComparison.OrdinalIgnoreCase));
+                .FirstOrDefault(i => string.Compare(i.Name, item.Name, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols) == 0);
 
             return artist != null ? artist.GetProviderId(MetadataProviders.Musicbrainz) : null;
         }

+ 16 - 3
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -32,7 +32,7 @@ namespace MediaBrowser.Server.Implementations.Library
     public class LibraryManager : ILibraryManager
     {
         private IEnumerable<ILibraryPrescanTask> PrescanTasks { get; set; }
-        
+
         /// <summary>
         /// Gets the intro providers.
         /// </summary>
@@ -306,7 +306,20 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <returns>BaseItem.</returns>
         public BaseItem ResolveItem(ItemResolveArgs args)
         {
-            var item = EntityResolvers.Select(r => r.ResolvePath(args)).FirstOrDefault(i => i != null);
+            var item = EntityResolvers.Select(r =>
+            {
+                try
+                {
+                    return r.ResolvePath(args);
+                }
+                catch (Exception ex)
+                {
+                    _logger.ErrorException("Error in {0} resolving {1}", ex, r.GetType().Name, args.Path);
+
+                    return null;
+                }
+
+            }).FirstOrDefault(i => i != null);
 
             if (item != null)
             {
@@ -1028,7 +1041,7 @@ namespace MediaBrowser.Server.Implementations.Library
             await SaveItem(item, cancellationToken).ConfigureAwait(false);
 
             UpdateItemInLibraryCache(item);
-            
+
             if (ItemAdded != null)
             {
                 try

+ 34 - 4
MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs

@@ -36,6 +36,14 @@ namespace MediaBrowser.Server.Implementations.ServerManager
         /// The web socket connections
         /// </summary>
         private readonly List<IWebSocketConnection> _webSocketConnections = new List<IWebSocketConnection>();
+        /// <summary>
+        /// Gets the web socket connections.
+        /// </summary>
+        /// <value>The web socket connections.</value>
+        public IEnumerable<IWebSocketConnection> WebSocketConnections
+        {
+            get { return _webSocketConnections; }
+        }
 
         /// <summary>
         /// Gets or sets the external web socket server.
@@ -83,6 +91,9 @@ namespace MediaBrowser.Server.Implementations.ServerManager
         /// <value>The web socket listeners.</value>
         private readonly List<IWebSocketListener> _webSocketListeners = new List<IWebSocketListener>();
 
+        /// <summary>
+        /// The _kernel
+        /// </summary>
         private readonly Kernel _kernel;
 
         /// <summary>
@@ -240,7 +251,26 @@ namespace MediaBrowser.Server.Implementations.ServerManager
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
         /// <exception cref="System.ArgumentNullException">messageType</exception>
-        public async Task SendWebSocketMessageAsync<T>(string messageType, Func<T> dataFunction, CancellationToken cancellationToken)
+        public Task SendWebSocketMessageAsync<T>(string messageType, Func<T> dataFunction, CancellationToken cancellationToken)
+        {
+            return SendWebSocketMessageAsync(messageType, dataFunction, _webSocketConnections, cancellationToken);
+        }
+
+        /// <summary>
+        /// Sends the web socket message async.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="messageType">Type of the message.</param>
+        /// <param name="dataFunction">The data function.</param>
+        /// <param name="connections">The connections.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task.</returns>
+        /// <exception cref="System.ArgumentNullException">messageType
+        /// or
+        /// dataFunction
+        /// or
+        /// cancellationToken</exception>
+        public async Task SendWebSocketMessageAsync<T>(string messageType, Func<T> dataFunction, IEnumerable<IWebSocketConnection> connections, CancellationToken cancellationToken)
         {
             if (string.IsNullOrEmpty(messageType))
             {
@@ -259,16 +289,16 @@ namespace MediaBrowser.Server.Implementations.ServerManager
 
             cancellationToken.ThrowIfCancellationRequested();
 
-            var connections = _webSocketConnections.Where(s => s.State == WebSocketState.Open).ToList();
+            var connectionsList = connections.Where(s => s.State == WebSocketState.Open).ToList();
 
-            if (connections.Count > 0)
+            if (connectionsList.Count > 0)
             {
                 _logger.Info("Sending web socket message {0}", messageType);
 
                 var message = new WebSocketMessage<T> { MessageType = messageType, Data = dataFunction() };
                 var bytes = _jsonSerializer.SerializeToBytes(message);
 
-                var tasks = connections.Select(s => Task.Run(() =>
+                var tasks = connectionsList.Select(s => Task.Run(() =>
                 {
                     try
                     {

+ 130 - 34
MediaBrowser.ServerApplication/EntryPoints/LibraryChangedNotifier.cs

@@ -1,8 +1,12 @@
 using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Plugins;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.Entities;
+using MoreLinq;
+using System;
+using System.Collections.Generic;
 using System.Linq;
 using System.Threading;
 
@@ -17,17 +21,19 @@ namespace MediaBrowser.ServerApplication.EntryPoints
 
         private readonly ISessionManager _sessionManager;
         private readonly IServerManager _serverManager;
-   
+        private readonly IUserManager _userManager;
+
         /// <summary>
         /// The _library changed sync lock
         /// </summary>
         private readonly object _libraryChangedSyncLock = new object();
 
-        /// <summary>
-        /// Gets or sets the library update info.
-        /// </summary>
-        /// <value>The library update info.</value>
-        private LibraryUpdateInfo LibraryUpdateInfo { get; set; }
+        private readonly List<Folder> _foldersAddedTo = new List<Folder>();
+        private readonly List<Folder> _foldersRemovedFrom = new List<Folder>();
+
+        private readonly List<BaseItem> _itemsAdded = new List<BaseItem>();
+        private readonly List<BaseItem> _itemsRemoved = new List<BaseItem>();
+        private readonly List<BaseItem> _itemsUpdated = new List<BaseItem>();
 
         /// <summary>
         /// Gets or sets the library update timer.
@@ -40,11 +46,12 @@ namespace MediaBrowser.ServerApplication.EntryPoints
         /// </summary>
         private const int LibraryUpdateDuration = 60000;
 
-        public LibraryChangedNotifier(ILibraryManager libraryManager, ISessionManager sessionManager, IServerManager serverManager)
+        public LibraryChangedNotifier(ILibraryManager libraryManager, ISessionManager sessionManager, IServerManager serverManager, IUserManager userManager)
         {
             _libraryManager = libraryManager;
             _sessionManager = sessionManager;
             _serverManager = serverManager;
+            _userManager = userManager;
         }
 
         public void Run()
@@ -64,11 +71,6 @@ namespace MediaBrowser.ServerApplication.EntryPoints
         {
             lock (_libraryChangedSyncLock)
             {
-                if (LibraryUpdateInfo == null)
-                {
-                    LibraryUpdateInfo = new LibraryUpdateInfo();
-                }
-
                 if (LibraryUpdateTimer == null)
                 {
                     LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration,
@@ -81,10 +83,10 @@ namespace MediaBrowser.ServerApplication.EntryPoints
 
                 if (e.Item.Parent != null)
                 {
-                    LibraryUpdateInfo.FoldersAddedTo.Add(e.Item.Parent.Id);
+                    _foldersAddedTo.Add(e.Item.Parent);
                 }
 
-                LibraryUpdateInfo.ItemsAdded.Add(e.Item.Id);
+                _itemsAdded.Add(e.Item);
             }
         }
 
@@ -97,11 +99,6 @@ namespace MediaBrowser.ServerApplication.EntryPoints
         {
             lock (_libraryChangedSyncLock)
             {
-                if (LibraryUpdateInfo == null)
-                {
-                    LibraryUpdateInfo = new LibraryUpdateInfo();
-                }
-
                 if (LibraryUpdateTimer == null)
                 {
                     LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration,
@@ -112,7 +109,7 @@ namespace MediaBrowser.ServerApplication.EntryPoints
                     LibraryUpdateTimer.Change(LibraryUpdateDuration, Timeout.Infinite);
                 }
 
-                LibraryUpdateInfo.ItemsUpdated.Add(e.Item.Id);
+                _itemsUpdated.Add(e.Item);
             }
         }
 
@@ -125,11 +122,6 @@ namespace MediaBrowser.ServerApplication.EntryPoints
         {
             lock (_libraryChangedSyncLock)
             {
-                if (LibraryUpdateInfo == null)
-                {
-                    LibraryUpdateInfo = new LibraryUpdateInfo();
-                }
-
                 if (LibraryUpdateTimer == null)
                 {
                     LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration,
@@ -142,10 +134,10 @@ namespace MediaBrowser.ServerApplication.EntryPoints
 
                 if (e.Item.Parent != null)
                 {
-                    LibraryUpdateInfo.FoldersRemovedFrom.Add(e.Item.Parent.Id);
+                    _foldersRemovedFrom.Add(e.Item.Parent);
                 }
 
-                LibraryUpdateInfo.ItemsRemoved.Add(e.Item.Id);
+                _itemsRemoved.Add(e.Item);
             }
         }
 
@@ -158,16 +150,16 @@ namespace MediaBrowser.ServerApplication.EntryPoints
             lock (_libraryChangedSyncLock)
             {
                 // Remove dupes in case some were saved multiple times
-                LibraryUpdateInfo.FoldersAddedTo = LibraryUpdateInfo.FoldersAddedTo.Distinct().ToList();
+                var foldersAddedTo = _foldersAddedTo.DistinctBy(i => i.Id).ToList();
 
-                LibraryUpdateInfo.FoldersRemovedFrom = LibraryUpdateInfo.FoldersRemovedFrom.Distinct().ToList();
+                var foldersRemovedFrom = _foldersRemovedFrom.DistinctBy(i => i.Id).ToList();
 
-                LibraryUpdateInfo.ItemsUpdated = LibraryUpdateInfo.ItemsUpdated
-                    .Where(i => !LibraryUpdateInfo.ItemsAdded.Contains(i))
-                    .Distinct()
+                var itemsUpdated = _itemsUpdated
+                    .Where(i => !_itemsAdded.Contains(i))
+                    .DistinctBy(i => i.Id)
                     .ToList();
 
-                _serverManager.SendWebSocketMessage("LibraryChanged", LibraryUpdateInfo);
+                SendChangeNotifications(_itemsAdded.ToList(), itemsUpdated, _itemsRemoved.ToList(), foldersAddedTo, foldersRemovedFrom, CancellationToken.None);
 
                 if (LibraryUpdateTimer != null)
                 {
@@ -175,8 +167,112 @@ namespace MediaBrowser.ServerApplication.EntryPoints
                     LibraryUpdateTimer = null;
                 }
 
-                LibraryUpdateInfo = null;
+                _itemsAdded.Clear();
+                _itemsRemoved.Clear();
+                _itemsUpdated.Clear();
+                _foldersAddedTo.Clear();
+                _foldersRemovedFrom.Clear();
+            }
+        }
+
+        /// <summary>
+        /// Sends the change notifications.
+        /// </summary>
+        /// <param name="itemsAdded">The items added.</param>
+        /// <param name="itemsUpdated">The items updated.</param>
+        /// <param name="itemsRemoved">The items removed.</param>
+        /// <param name="foldersAddedTo">The folders added to.</param>
+        /// <param name="foldersRemovedFrom">The folders removed from.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        private async void SendChangeNotifications(IEnumerable<BaseItem> itemsAdded, IEnumerable<BaseItem> itemsUpdated, IEnumerable<BaseItem> itemsRemoved, IEnumerable<Folder> foldersAddedTo, IEnumerable<Folder> foldersRemovedFrom, CancellationToken cancellationToken)
+        {
+            var currentSessions = _sessionManager.Sessions.ToList();
+
+            var users = currentSessions.Select(i => i.UserId ?? Guid.Empty).Where(i => i != Guid.Empty).Distinct().ToList();
+
+            foreach (var userId in users)
+            {
+                var id = userId;
+                var webSockets = currentSessions.Where(u => u.UserId.HasValue && u.UserId.Value == id).SelectMany(i => i.WebSockets).ToList();
+
+                await _serverManager.SendWebSocketMessageAsync("LibraryChanged", () => GetLibraryUpdateInfo(itemsAdded, itemsUpdated, itemsRemoved, foldersAddedTo, foldersRemovedFrom, id), webSockets, cancellationToken).ConfigureAwait(false);
+            }
+        }
+
+        /// <summary>
+        /// Gets the library update info.
+        /// </summary>
+        /// <param name="itemsAdded">The items added.</param>
+        /// <param name="itemsUpdated">The items updated.</param>
+        /// <param name="itemsRemoved">The items removed.</param>
+        /// <param name="foldersAddedTo">The folders added to.</param>
+        /// <param name="foldersRemovedFrom">The folders removed from.</param>
+        /// <param name="userId">The user id.</param>
+        /// <returns>LibraryUpdateInfo.</returns>
+        private LibraryUpdateInfo GetLibraryUpdateInfo(IEnumerable<BaseItem> itemsAdded, IEnumerable<BaseItem> itemsUpdated, IEnumerable<BaseItem> itemsRemoved, IEnumerable<Folder> foldersAddedTo, IEnumerable<Folder> foldersRemovedFrom, Guid userId)
+        {
+            var user = _userManager.GetUserById(userId);
+
+            var collections = user.RootFolder.GetChildren(user).ToList();
+
+            var allRecursiveChildren = user.RootFolder.GetRecursiveChildren(user).ToDictionary(i => i.Id);
+
+            return new LibraryUpdateInfo
+            {
+                ItemsAdded = itemsAdded.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user, collections, allRecursiveChildren)).Select(i => i.Id).Distinct().ToList(),
+
+                ItemsUpdated = itemsUpdated.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user, collections, allRecursiveChildren)).Select(i => i.Id).Distinct().ToList(),
+
+                ItemsRemoved = itemsRemoved.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user, collections, allRecursiveChildren)).Select(i => i.Id).Distinct().ToList(),
+
+                FoldersAddedTo = foldersAddedTo.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user, collections, allRecursiveChildren)).Select(i => i.Id).Distinct().ToList(),
+
+                FoldersRemovedFrom = foldersRemovedFrom.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user, collections, allRecursiveChildren)).Select(i => i.Id).Distinct().ToList()
+            };
+        }
+
+        /// <summary>
+        /// Translates the physical item to user library.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="item">The item.</param>
+        /// <param name="user">The user.</param>
+        /// <param name="collections">The collections.</param>
+        /// <param name="allRecursiveChildren">All recursive children.</param>
+        /// <returns>IEnumerable{``0}.</returns>
+        private IEnumerable<T> TranslatePhysicalItemToUserLibrary<T>(T item, User user, List<BaseItem> collections, Dictionary<Guid, BaseItem> allRecursiveChildren)
+            where T : BaseItem
+        {
+            // If the physical root changed, return the user root
+            if (item is AggregateFolder)
+            {
+                return new T[] { user.RootFolder as T };
+            }
+
+            // Need to find what user collection folder this belongs to
+            if (item.Parent is AggregateFolder)
+            {
+                return new T[] { user.RootFolder as T };
+            }
+
+            // If it's a user root, return it only if it's the right one
+            if (item is UserRootFolder)
+            {
+                if (item.Id == user.RootFolder.Id)
+                {
+                    return new T[] { item };
+                }
+
+                return new T[] { };
             }
+
+            // Return it only if it's in the user's library
+            if (allRecursiveChildren.ContainsKey(item.Id))
+            {
+                return new T[] { item };
+            }
+
+            return new T[] { };
         }
 
         /// <summary>

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

@@ -130,6 +130,10 @@
       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\packages\MediaBrowser.IsoMounting.3.0.51\lib\net45\MediaBrowser.IsoMounter.dll</HintPath>
     </Reference>
+    <Reference Include="MoreLinq, Version=1.0.15631.0, Culture=neutral, PublicKeyToken=384d532d7e88985d, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\packages\morelinq.1.0.15631-beta\lib\net35\MoreLinq.dll</HintPath>
+    </Reference>
     <Reference Include="NLog, Version=2.0.1.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\packages\NLog.2.0.1.2\lib\net45\NLog.dll</HintPath>

+ 1 - 0
MediaBrowser.ServerApplication/packages.config

@@ -4,6 +4,7 @@
   <package id="Hardcodet.Wpf.TaskbarNotification" version="1.0.4.0" targetFramework="net45" />
   <package id="MahApps.Metro" version="0.11.0.17-ALPHA" targetFramework="net45" />
   <package id="MediaBrowser.IsoMounting" version="3.0.51" targetFramework="net45" />
+  <package id="morelinq" version="1.0.15631-beta" targetFramework="net45" />
   <package id="NLog" version="2.0.1.2" targetFramework="net45" />
   <package id="ServiceStack" version="3.9.46" targetFramework="net45" />
   <package id="ServiceStack.Common" version="3.9.46" targetFramework="net45" />