2
0
Эх сурвалжийг харах

fixes #223 - New Content Localhost Popups Repeat 'Old' 'New Content' on Media Changes

Luke Pulverenti 12 жил өмнө
parent
commit
6481688d2a
20 өөрчлөгдсөн 287 нэмэгдсэн , 811 устгасан
  1. 1 4
      MediaBrowser.Api/Playback/Progressive/VideoService.cs
  2. 1 1
      MediaBrowser.Controller/Entities/BaseItem.cs
  3. 13 23
      MediaBrowser.Controller/Entities/Folder.cs
  4. 4 12
      MediaBrowser.Controller/Entities/IndexFolder.cs
  5. 0 137
      MediaBrowser.Controller/Library/ChildrenChangedEventArgs.cs
  6. 32 17
      MediaBrowser.Controller/Library/ILibraryManager.cs
  7. 16 0
      MediaBrowser.Controller/Library/ItemChangeEventArgs.cs
  8. 1 1
      MediaBrowser.Controller/MediaBrowser.Controller.csproj
  9. 25 24
      MediaBrowser.Controller/MediaInfo/FFMpegManager.cs
  10. 7 3
      MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs
  11. 30 28
      MediaBrowser.Server.Implementations/IO/DirectoryWatchers.cs
  12. 57 32
      MediaBrowser.Server.Implementations/Library/LibraryManager.cs
  13. 15 15
      MediaBrowser.Server.Implementations/Library/LuceneSearchEngine.cs
  14. 1 1
      MediaBrowser.Server.Implementations/ScheduledTasks/AudioImagesTask.cs
  15. 1 1
      MediaBrowser.Server.Implementations/ScheduledTasks/VideoImagesTask.cs
  16. 0 63
      MediaBrowser.ServerApplication/Controls/ItemUpdateNotification.xaml
  17. 0 294
      MediaBrowser.ServerApplication/Controls/ItemUpdateNotification.xaml.cs
  18. 0 135
      MediaBrowser.ServerApplication/EntryPoints/NewItemNotifier.cs
  19. 83 12
      MediaBrowser.ServerApplication/EntryPoints/WebSocketEvents.cs
  20. 0 8
      MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj

+ 1 - 4
MediaBrowser.Api/Playback/Progressive/VideoService.cs

@@ -108,9 +108,7 @@ namespace MediaBrowser.Api.Playback.Progressive
                 format = " -f mp4 -movflags frag_keyframe+empty_moov";
             }
 
-            var threads = 0;
-
-            return string.Format("{0} {1} {2} -i {3}{4}{5} {6} {7} -threads {8} {9}{10} \"{11}\"",
+            return string.Format("{0} {1} {2} -i {3}{4}{5} {6} {7} -threads 0 {8}{9} \"{10}\"",
                 probeSize,
                 GetUserAgentParam(state.Item),
                 GetFastSeekCommandLineParameter(state.Request),
@@ -119,7 +117,6 @@ namespace MediaBrowser.Api.Playback.Progressive
                 keyFrame,
                 GetMapArgs(state),
                 GetVideoArguments(state, videoCodec, performSubtitleConversions),
-                threads,
                 GetAudioArguments(state),
                 format,
                 outputPath

+ 1 - 1
MediaBrowser.Controller/Entities/BaseItem.cs

@@ -968,7 +968,7 @@ namespace MediaBrowser.Controller.Entities
             {
                 cancellationToken.ThrowIfCancellationRequested();
 
-                await LibraryManager.SaveItem(this, cancellationToken).ConfigureAwait(false);
+                await LibraryManager.UpdateItem(this, cancellationToken).ConfigureAwait(false);
             }
 
             return changed;

+ 13 - 23
MediaBrowser.Controller/Entities/Folder.cs

@@ -436,7 +436,7 @@ namespace MediaBrowser.Controller.Entities
         /// </summary>
         /// <value>The children.</value>
         [IgnoreDataMember]
-        public ConcurrentBag<BaseItem> Children
+        public IEnumerable<BaseItem> Children
         {
             get
             {
@@ -557,8 +557,6 @@ namespace MediaBrowser.Controller.Entities
 
             cancellationToken.ThrowIfCancellationRequested();
 
-            var changedArgs = new ChildrenChangedEventArgs(this);
-
             //get the current valid children from filesystem (or wherever)
             var nonCachedChildren = GetNonCachedChildren();
 
@@ -571,6 +569,7 @@ namespace MediaBrowser.Controller.Entities
 
             //create a list for our validated children
             var validChildren = new ConcurrentBag<Tuple<BaseItem, bool>>();
+            var newItems = new ConcurrentBag<BaseItem>();
 
             cancellationToken.ThrowIfCancellationRequested();
 
@@ -592,7 +591,6 @@ namespace MediaBrowser.Controller.Entities
                     {
                         EntityResolutionHelper.EnsureDates(currentChild, child.ResolveArgs);
 
-                        changedArgs.AddUpdatedItem(currentChild);
                         validChildren.Add(new Tuple<BaseItem, bool>(currentChild, true));
                     }
                     else
@@ -603,36 +601,36 @@ namespace MediaBrowser.Controller.Entities
                 else
                 {
                     //brand new item - needs to be added
-                    changedArgs.AddNewItem(child);
+                    newItems.Add(child);
 
                     validChildren.Add(new Tuple<BaseItem, bool>(child, true));
                 }
             });
 
             // If any items were added or removed....
-            if (!changedArgs.ItemsAdded.IsEmpty || currentChildren.Count != validChildren.Count)
+            if (!newItems.IsEmpty || currentChildren.Count != validChildren.Count)
             {
                 var newChildren = validChildren.Select(c => c.Item1).ToList();
 
                 //that's all the new and changed ones - now see if there are any that are missing
-                changedArgs.ItemsRemoved = currentChildren.Values.Except(newChildren).ToList();
-
-                foreach (var item in changedArgs.ItemsRemoved)
-                {
-                    Logger.Debug("** " + item.Name + " Removed from library.");
-                }
+                var itemsRemoved = currentChildren.Values.Except(newChildren).ToList();
 
                 var childrenReplaced = false;
 
-                if (changedArgs.ItemsRemoved.Count > 0)
+                if (itemsRemoved.Count > 0)
                 {
                     ActualChildren = new ConcurrentBag<BaseItem>(newChildren);
                     childrenReplaced = true;
+
+                    foreach (var item in itemsRemoved)
+                    {
+                        LibraryManager.ReportItemRemoved(item);
+                    }
                 }
 
                 var saveTasks = new List<Task>();
 
-                foreach (var item in changedArgs.ItemsAdded)
+                foreach (var item in newItems)
                 {
                     Logger.Debug("** " + item.Name + " Added to library.");
 
@@ -647,23 +645,15 @@ namespace MediaBrowser.Controller.Entities
                         saveTasks.Clear();
                     }
 
-                    saveTasks.Add(LibraryManager.SaveItem(item, CancellationToken.None));
+                    saveTasks.Add(LibraryManager.CreateItem(item, CancellationToken.None));
                 }
 
                 await Task.WhenAll(saveTasks).ConfigureAwait(false);
 
-                //and save children in repo...
-                Logger.Debug("*** Saving " + newChildren.Count + " children for " + Name);
                 await LibraryManager.SaveChildren(Id, newChildren, CancellationToken.None).ConfigureAwait(false);
-            }
 
-            if (changedArgs.HasChange)
-            {
                 //force the indexes to rebuild next time
                 IndexCache.Clear();
-
-                //and fire event
-                LibraryManager.ReportLibraryChanged(changedArgs);
             }
 
             progress.Report(10);

+ 4 - 12
MediaBrowser.Controller/Entities/IndexFolder.cs

@@ -1,11 +1,11 @@
 using MediaBrowser.Common.Extensions;
+using MediaBrowser.Model.Entities;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Linq;
 using System.Runtime.Serialization;
 using System.Threading;
 using System.Threading.Tasks;
-using MediaBrowser.Model.Entities;
 
 namespace MediaBrowser.Controller.Entities
 {
@@ -196,18 +196,10 @@ namespace MediaBrowser.Controller.Entities
         /// <param name="allowSlowProviders">if set to <c>true</c> [allow slow providers].</param>
         /// <param name="resetResolveArgs">if set to <c>true</c> [reset resolve args].</param>
         /// <returns>Task{System.Boolean}.</returns>
-        public override async Task<bool> RefreshMetadata(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false, bool allowSlowProviders = true, bool resetResolveArgs = true)
+        public override Task<bool> RefreshMetadata(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false, bool allowSlowProviders = true, bool resetResolveArgs = true)
         {
-            if (ShadowItem != null)
-            {
-                var changed = await ShadowItem.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders, resetResolveArgs).ConfigureAwait(false);
-
-                cancellationToken.ThrowIfCancellationRequested();
-
-                SetShadowValues();
-                return changed;
-            }
-            return false;
+            // We should never get in here since these are not part of the library
+            return Task.FromResult(false);
         }
     }
 }

+ 0 - 137
MediaBrowser.Controller/Library/ChildrenChangedEventArgs.cs

@@ -1,137 +0,0 @@
-using System.Collections.Concurrent;
-using MediaBrowser.Controller.Entities;
-using System;
-using System.Collections.Generic;
-
-namespace MediaBrowser.Controller.Library
-{
-    /// <summary>
-    /// Class ChildrenChangedEventArgs
-    /// </summary>
-    public class ChildrenChangedEventArgs : EventArgs
-    {
-        /// <summary>
-        /// Gets or sets the folder.
-        /// </summary>
-        /// <value>The folder.</value>
-        public Folder Folder { get; set; }
-        /// <summary>
-        /// Gets or sets the items added.
-        /// </summary>
-        /// <value>The items added.</value>
-        public ConcurrentBag<BaseItem> ItemsAdded { get; set; }
-        /// <summary>
-        /// Gets or sets the items removed.
-        /// </summary>
-        /// <value>The items removed.</value>
-        public List<BaseItem> ItemsRemoved { get; set; }
-        /// <summary>
-        /// Gets or sets the items updated.
-        /// </summary>
-        /// <value>The items updated.</value>
-        public ConcurrentBag<BaseItem> ItemsUpdated { get; set; }
-
-        /// <summary>
-        /// Create the args and set the folder property
-        /// </summary>
-        /// <param name="folder">The folder.</param>
-        /// <exception cref="System.ArgumentNullException"></exception>
-        public ChildrenChangedEventArgs(Folder folder)
-        {
-            if (folder == null)
-            {
-                throw new ArgumentNullException();
-            }
-
-            //init the folder property
-            Folder = folder;
-            //init the list
-            ItemsAdded = new ConcurrentBag<BaseItem>();
-            ItemsRemoved = new List<BaseItem>();
-            ItemsUpdated = new ConcurrentBag<BaseItem>();
-        }
-
-        /// <summary>
-        /// Adds the new item.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <exception cref="System.ArgumentNullException"></exception>
-        public void AddNewItem(BaseItem item)
-        {
-            if (item == null)
-            {
-                throw new ArgumentNullException();
-            }
-            
-            ItemsAdded.Add(item);
-        }
-
-        /// <summary>
-        /// Adds the updated item.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <exception cref="System.ArgumentNullException"></exception>
-        public void AddUpdatedItem(BaseItem item)
-        {
-            if (item == null)
-            {
-                throw new ArgumentNullException();
-            }
-            
-            ItemsUpdated.Add(item);
-        }
-
-        /// <summary>
-        /// Adds the removed item.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <exception cref="System.ArgumentNullException"></exception>
-        public void AddRemovedItem(BaseItem item)
-        {
-            if (item == null)
-            {
-                throw new ArgumentNullException();
-            }
-
-            ItemsRemoved.Add(item);
-        }
-
-        /// <summary>
-        /// Lists the has change.
-        /// </summary>
-        /// <param name="list">The list.</param>
-        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
-        private bool ListHasChange(List<BaseItem> list)
-        {
-            return list != null && list.Count > 0;
-        }
-
-        /// <summary>
-        /// Lists the has change.
-        /// </summary>
-        /// <param name="list">The list.</param>
-        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
-        private bool ListHasChange(ConcurrentBag<BaseItem> list)
-        {
-            return list != null && !list.IsEmpty;
-        }
-        
-        /// <summary>
-        /// Gets a value indicating whether this instance has change.
-        /// </summary>
-        /// <value><c>true</c> if this instance has change; otherwise, <c>false</c>.</value>
-        public bool HasChange
-        {
-            get { return HasAddOrRemoveChange || ListHasChange(ItemsUpdated); }
-        }
-
-        /// <summary>
-        /// Gets a value indicating whether this instance has add or remove change.
-        /// </summary>
-        /// <value><c>true</c> if this instance has add or remove change; otherwise, <c>false</c>.</value>
-        public bool HasAddOrRemoveChange
-        {
-            get { return ListHasChange(ItemsAdded) || ListHasChange(ItemsRemoved); }
-        }
-    }
-}

+ 32 - 17
MediaBrowser.Controller/Library/ILibraryManager.cs

@@ -1,12 +1,11 @@
-using System.IO;
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Resolvers;
 using MediaBrowser.Controller.Sorting;
 using MediaBrowser.Model.Entities;
 using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Threading;
 using System.Threading.Tasks;
 
@@ -14,18 +13,6 @@ namespace MediaBrowser.Controller.Library
 {
     public interface ILibraryManager
     {
-        /// <summary>
-        /// Fires whenever any validation routine adds or removes items.  The added and removed items are properties of the args.
-        /// *** Will fire asynchronously. ***
-        /// </summary>
-        event EventHandler<ChildrenChangedEventArgs> LibraryChanged;
-
-        /// <summary>
-        /// Reports the library changed.
-        /// </summary>
-        /// <param name="args">The <see cref="ChildrenChangedEventArgs"/> instance containing the event data.</param>
-        void ReportLibraryChanged(ChildrenChangedEventArgs args);
-
         /// <summary>
         /// Resolves the item.
         /// </summary>
@@ -185,13 +172,21 @@ namespace MediaBrowser.Controller.Library
         UserRootFolder GetUserRootFolder(string userRootPath);
 
         /// <summary>
-        /// Saves the item.
+        /// Creates the item.
         /// </summary>
         /// <param name="item">The item.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
-        Task SaveItem(BaseItem item, CancellationToken cancellationToken);
+        Task CreateItem(BaseItem item, CancellationToken cancellationToken);
 
+        /// <summary>
+        /// Updates the item.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task.</returns>
+        Task UpdateItem(BaseItem item, CancellationToken cancellationToken);
+        
         /// <summary>
         /// Retrieves the item.
         /// </summary>
@@ -222,5 +217,25 @@ namespace MediaBrowser.Controller.Library
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
         Task ValidateArtists(CancellationToken cancellationToken, IProgress<double> progress);
+
+        /// <summary>
+        /// Occurs when [item added].
+        /// </summary>
+        event EventHandler<ItemChangeEventArgs> ItemAdded;
+
+        /// <summary>
+        /// Occurs when [item updated].
+        /// </summary>
+        event EventHandler<ItemChangeEventArgs> ItemUpdated;
+        /// <summary>
+        /// Occurs when [item removed].
+        /// </summary>
+        event EventHandler<ItemChangeEventArgs> ItemRemoved;
+
+        /// <summary>
+        /// Reports the item removed.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        void ReportItemRemoved(BaseItem item);
     }
 }

+ 16 - 0
MediaBrowser.Controller/Library/ItemChangeEventArgs.cs

@@ -0,0 +1,16 @@
+using MediaBrowser.Controller.Entities;
+
+namespace MediaBrowser.Controller.Library
+{
+    /// <summary>
+    /// Class ItemChangeEventArgs
+    /// </summary>
+    public class ItemChangeEventArgs
+    {
+        /// <summary>
+        /// Gets or sets the item.
+        /// </summary>
+        /// <value>The item.</value>
+        public BaseItem Item { get; set; }
+    }
+}

+ 1 - 1
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -92,6 +92,7 @@
     <Compile Include="Entities\Person.cs" />
     <Compile Include="Library\IDisplayPreferencesManager.cs" />
     <Compile Include="Library\ILibrarySearchEngine.cs" />
+    <Compile Include="Library\ItemChangeEventArgs.cs" />
     <Compile Include="Library\PlaybackProgressEventArgs.cs" />
     <Compile Include="Entities\Studio.cs" />
     <Compile Include="Entities\Trailer.cs" />
@@ -110,7 +111,6 @@
     <Compile Include="IO\NativeMethods.cs" />
     <Compile Include="IServerApplicationHost.cs" />
     <Compile Include="IServerApplicationPaths.cs" />
-    <Compile Include="Library\ChildrenChangedEventArgs.cs" />
     <Compile Include="Dto\DtoBuilder.cs" />
     <Compile Include="Library\SearchHintInfo.cs" />
     <Compile Include="Providers\IProviderManager.cs" />

+ 25 - 24
MediaBrowser.Controller/MediaInfo/FFMpegManager.cs

@@ -1,16 +1,17 @@
-using System.Collections.Generic;
-using MediaBrowser.Common.IO;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Common.MediaInfo;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Providers.MediaInfo;
 using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Logging;
+using MoreLinq;
 using System;
+using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
-using MediaBrowser.Model.Logging;
 
 namespace MediaBrowser.Controller.MediaInfo
 {
@@ -71,35 +72,35 @@ namespace MediaBrowser.Controller.MediaInfo
             VideoImageCache = new FileSystemRepository(VideoImagesDataPath);
             SubtitleCache = new FileSystemRepository(SubtitleCachePath);
 
-            libraryManager.LibraryChanged += libraryManager_LibraryChanged;
+            libraryManager.ItemAdded += libraryManager_ItemAdded;
+            libraryManager.ItemUpdated += libraryManager_ItemAdded;
         }
 
         /// <summary>
-        /// Handles the LibraryChanged event of the libraryManager control.
+        /// Handles the ItemAdded event of the libraryManager control.
         /// </summary>
         /// <param name="sender">The source of the event.</param>
-        /// <param name="e">The <see cref="ChildrenChangedEventArgs"/> instance containing the event data.</param>
-        void libraryManager_LibraryChanged(object sender, ChildrenChangedEventArgs e)
+        /// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
+        void libraryManager_ItemAdded(object sender, ItemChangeEventArgs e)
         {
-            var videos = e.ItemsAdded.OfType<Video>().ToList();
+            var video = e.Item as Video;
 
-            videos.AddRange(e.ItemsUpdated.OfType<Video>());
+            if (video == null)
+            {
+                return;
+            }
 
-            // Use a timer to prevent lots of these notifications from showing in a short period of time
-            if (videos.Count > 0)
+            lock (_newlyAddedItems)
             {
-                lock (_newlyAddedItems)
-                {
-                    _newlyAddedItems.AddRange(videos);
+                _newlyAddedItems.Add(video);
 
-                    if (NewItemTimer == null)
-                    {
-                        NewItemTimer = new Timer(NewItemTimerCallback, null, NewItemDelay, Timeout.Infinite);
-                    }
-                    else
-                    {
-                        NewItemTimer.Change(NewItemDelay, Timeout.Infinite);
-                    }
+                if (NewItemTimer == null)
+                {
+                    NewItemTimer = new Timer(NewItemTimerCallback, null, NewItemDelay, Timeout.Infinite);
+                }
+                else
+                {
+                    NewItemTimer.Change(NewItemDelay, Timeout.Infinite);
                 }
             }
         }
@@ -193,7 +194,7 @@ namespace MediaBrowser.Controller.MediaInfo
             // Lock the list and release all resources
             lock (_newlyAddedItems)
             {
-                newItems = _newlyAddedItems.ToList();
+                newItems = _newlyAddedItems.DistinctBy(i => i.Id).ToList();
                 _newlyAddedItems.Clear();
 
                 NewItemTimer.Dispose();
@@ -297,7 +298,7 @@ namespace MediaBrowser.Controller.MediaInfo
 
             if (saveItem && changesMade)
             {
-                await _libraryManager.SaveItem(video, CancellationToken.None).ConfigureAwait(false);
+                await _libraryManager.UpdateItem(video, CancellationToken.None).ConfigureAwait(false);
             }
         }
 

+ 7 - 3
MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs

@@ -438,9 +438,10 @@ namespace MediaBrowser.Controller.Providers.Movies
             var boxset = item as BoxSet;
             if (boxset != null)
             {
-                if (!boxset.Children.IsEmpty)
+                var firstChild = boxset.Children.FirstOrDefault();
+
+                if (firstChild != null)
                 {
-                    var firstChild = boxset.Children.First();
                     Logger.Debug("MovieDbProvider - Attempting to find boxset ID from: " + firstChild.Name);
                     string childName;
                     int? childYear;
@@ -953,7 +954,10 @@ namespace MediaBrowser.Controller.Providers.Movies
                 {
                     var boxset = movie as BoxSet;
                     Logger.Info("MovieDbProvider - Using rating of first child of boxset...");
-                    boxset.OfficialRating = !boxset.Children.IsEmpty ? boxset.Children.First().OfficialRating : null;
+
+                    var firstChild = boxset.Children.FirstOrDefault();
+
+                    boxset.OfficialRating = firstChild != null ? firstChild.OfficialRating : null;
                 }
 
                 if (movie.RunTimeTicks == null && movieData.runtime > 0)

+ 30 - 28
MediaBrowser.Server.Implementations/IO/DirectoryWatchers.cs

@@ -103,7 +103,8 @@ namespace MediaBrowser.Server.Implementations.IO
         /// </summary>
         public void Start()
         {
-            LibraryManager.LibraryChanged += Instance_LibraryChanged;
+            LibraryManager.ItemAdded += LibraryManager_ItemAdded;
+            LibraryManager.ItemRemoved += LibraryManager_ItemRemoved;
 
             var pathsToWatch = new List<string> { LibraryManager.RootFolder.Path };
 
@@ -137,6 +138,32 @@ namespace MediaBrowser.Server.Implementations.IO
             }
         }
 
+        /// <summary>
+        /// Handles the ItemRemoved event of the LibraryManager control.
+        /// </summary>
+        /// <param name="sender">The source of the event.</param>
+        /// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
+        void LibraryManager_ItemRemoved(object sender, ItemChangeEventArgs e)
+        {
+            if (e.Item.Parent is AggregateFolder)
+            {
+                StopWatchingPath(e.Item.Path);
+            }
+        }
+
+        /// <summary>
+        /// Handles the ItemAdded event of the LibraryManager control.
+        /// </summary>
+        /// <param name="sender">The source of the event.</param>
+        /// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
+        void LibraryManager_ItemAdded(object sender, ItemChangeEventArgs e)
+        {
+            if (e.Item.Parent is AggregateFolder)
+            {
+                StartWatchingPath(e.Item.Path);
+            }
+        }
+
         /// <summary>
         /// Examine a list of strings assumed to be file paths to see if it contains a parent of
         /// the provided path.
@@ -231,32 +258,6 @@ namespace MediaBrowser.Server.Implementations.IO
             _fileSystemWatchers = new ConcurrentBag<FileSystemWatcher>(watchers);
         }
 
-        /// <summary>
-        /// Handles the LibraryChanged event of the Kernel
-        /// </summary>
-        /// <param name="sender">The source of the event.</param>
-        /// <param name="e">The <see cref="MediaBrowser.Controller.Library.ChildrenChangedEventArgs" /> instance containing the event data.</param>
-        void Instance_LibraryChanged(object sender, ChildrenChangedEventArgs e)
-        {
-            if (e.Folder is AggregateFolder && e.HasAddOrRemoveChange)
-            {
-                if (e.ItemsRemoved != null)
-                {
-                    foreach (var item in e.ItemsRemoved.OfType<Folder>())
-                    {
-                        StopWatchingPath(item.Path);
-                    }
-                }
-                if (e.ItemsAdded != null)
-                {
-                    foreach (var item in e.ItemsAdded.OfType<Folder>())
-                    {
-                        StartWatchingPath(item.Path);
-                    }
-                }
-            }
-        }
-
         /// <summary>
         /// Handles the Error event of the watcher control.
         /// </summary>
@@ -497,7 +498,8 @@ namespace MediaBrowser.Server.Implementations.IO
         /// </summary>
         public void Stop()
         {
-            LibraryManager.LibraryChanged -= Instance_LibraryChanged;
+            LibraryManager.ItemAdded -= LibraryManager_ItemAdded;
+            LibraryManager.ItemRemoved -= LibraryManager_ItemRemoved;
 
             FileSystemWatcher watcher;
 

+ 57 - 32
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -69,24 +69,20 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <value>The item repository.</value>
         public IItemRepository ItemRepository { get; set; }
 
-        #region LibraryChanged Event
         /// <summary>
-        /// Fires whenever any validation routine adds or removes items.  The added and removed items are properties of the args.
-        /// *** Will fire asynchronously. ***
+        /// Occurs when [item added].
         /// </summary>
-        public event EventHandler<ChildrenChangedEventArgs> LibraryChanged;
+        public event EventHandler<ItemChangeEventArgs> ItemAdded;
 
         /// <summary>
-        /// Reports the library changed.
+        /// Occurs when [item updated].
         /// </summary>
-        /// <param name="args">The <see cref="ChildrenChangedEventArgs" /> instance containing the event data.</param>
-        public void ReportLibraryChanged(ChildrenChangedEventArgs args)
-        {
-            UpdateLibraryCache(args);
+        public event EventHandler<ItemChangeEventArgs> ItemUpdated;
 
-            EventHelper.FireEventIfNotNull(LibraryChanged, this, args, _logger);
-        }
-        #endregion
+        /// <summary>
+        /// Occurs when [item removed].
+        /// </summary>
+        public event EventHandler<ItemChangeEventArgs> ItemRemoved;
 
         /// <summary>
         /// The _logger
@@ -302,25 +298,6 @@ namespace MediaBrowser.Server.Implementations.Library
             return new ConcurrentDictionary<Guid, BaseItem>(items.ToDictionary(i => i.Id));
         }
 
-        /// <summary>
-        /// Updates the library cache.
-        /// </summary>
-        /// <param name="args">The <see cref="ChildrenChangedEventArgs"/> instance containing the event data.</param>
-        private void UpdateLibraryCache(ChildrenChangedEventArgs args)
-        {
-            UpdateItemInLibraryCache(args.Folder);
-
-            foreach (var item in args.ItemsAdded)
-            {
-                UpdateItemInLibraryCache(item);
-            }
-
-            foreach (var item in args.ItemsUpdated)
-            {
-                UpdateItemInLibraryCache(item);
-            }
-        }
-
         /// <summary>
         /// Updates the item in library cache.
         /// </summary>
@@ -1069,13 +1046,61 @@ namespace MediaBrowser.Server.Implementations.Library
             return comparer;
         }
 
+        /// <summary>
+        /// Creates the item.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task.</returns>
+        public async Task CreateItem(BaseItem item, CancellationToken cancellationToken)
+        {
+            await SaveItem(item, cancellationToken).ConfigureAwait(false);
+
+            UpdateItemInLibraryCache(item);
+            
+            if (ItemAdded != null)
+            {
+                ItemAdded(this, new ItemChangeEventArgs { Item = item });
+            }
+        }
+
+        /// <summary>
+        /// Updates the item.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task.</returns>
+        public async Task UpdateItem(BaseItem item, CancellationToken cancellationToken)
+        {
+            await SaveItem(item, cancellationToken).ConfigureAwait(false);
+
+            UpdateItemInLibraryCache(item);
+
+            if (ItemUpdated != null)
+            {
+                ItemUpdated(this, new ItemChangeEventArgs { Item = item });
+            }
+        }
+
+        /// <summary>
+        /// Reports the item removed.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        public void ReportItemRemoved(BaseItem item)
+        {
+            if (ItemRemoved != null)
+            {
+                ItemRemoved(this, new ItemChangeEventArgs { Item = item });
+            }
+        }
+
         /// <summary>
         /// Saves the item.
         /// </summary>
         /// <param name="item">The item.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
-        public Task SaveItem(BaseItem item, CancellationToken cancellationToken)
+        private Task SaveItem(BaseItem item, CancellationToken cancellationToken)
         {
             return ItemRepository.SaveItem(item, cancellationToken);
         }

+ 15 - 15
MediaBrowser.Server.Implementations/Library/LuceneSearchEngine.cs

@@ -43,21 +43,21 @@ namespace MediaBrowser.Server.Implementations.Library
             //BaseItem.LibraryManager.LibraryChanged += LibraryChanged;
         }
 
-        public void LibraryChanged(object source, ChildrenChangedEventArgs changeInformation)
-        {
-            Task.Run(() =>
-            {
-                if (changeInformation.ItemsAdded.Count + changeInformation.ItemsUpdated.Count > 0)
-                {
-                    LuceneSearch.AddUpdateLuceneIndex(changeInformation.ItemsAdded.Concat(changeInformation.ItemsUpdated));
-                }
-
-                if (changeInformation.ItemsRemoved.Count > 0)
-                {
-                    LuceneSearch.RemoveFromLuceneIndex(changeInformation.ItemsRemoved);
-                }
-            });
-        }
+        //public void LibraryChanged(object source, ChildrenChangedEventArgs changeInformation)
+        //{
+        //    Task.Run(() =>
+        //    {
+        //        if (changeInformation.ItemsAdded.Count + changeInformation.ItemsUpdated.Count > 0)
+        //        {
+        //            LuceneSearch.AddUpdateLuceneIndex(changeInformation.ItemsAdded.Concat(changeInformation.ItemsUpdated));
+        //        }
+
+        //        if (changeInformation.ItemsRemoved.Count > 0)
+        //        {
+        //            LuceneSearch.RemoveFromLuceneIndex(changeInformation.ItemsRemoved);
+        //        }
+        //    });
+        //}
 
         public void AddItemsToIndex(IEnumerable<BaseItem> items)
         {

+ 1 - 1
MediaBrowser.Server.Implementations/ScheduledTasks/AudioImagesTask.cs

@@ -150,7 +150,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
                     // Image is already in the cache
                     item.PrimaryImagePath = path;
 
-                    await _libraryManager.SaveItem(item, cancellationToken).ConfigureAwait(false);
+                    await _libraryManager.UpdateItem(item, cancellationToken).ConfigureAwait(false);
                 }
             }
 

+ 1 - 1
MediaBrowser.Server.Implementations/ScheduledTasks/VideoImagesTask.cs

@@ -187,7 +187,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
                     // Image is already in the cache
                     item.PrimaryImagePath = path;
 
-                    await _libraryManager.SaveItem(item, cancellationToken).ConfigureAwait(false);
+                    await _libraryManager.UpdateItem(item, cancellationToken).ConfigureAwait(false);
                 }
             }
 

+ 0 - 63
MediaBrowser.ServerApplication/Controls/ItemUpdateNotification.xaml

@@ -1,63 +0,0 @@
-<UserControl x:Class="MediaBrowser.ServerApplication.Controls.ItemUpdateNotification"
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
-             mc:Ignorable="d" 
-             d:DesignHeight="300" d:DesignWidth="300">
-
-    <Grid MaxHeight="280" MaxWidth="600" Margin="20">
-        <Border BorderThickness="0" Background="#333333">
-            <Border.Effect>
-                <DropShadowEffect BlurRadius="25" ShadowDepth="0">
-
-                </DropShadowEffect>
-            </Border.Effect>
-        </Border>
-        <Grid>
-            <Grid.Background>
-                <LinearGradientBrush SpreadMethod="Reflect" ColorInterpolationMode="SRgbLinearInterpolation" StartPoint="0,0" EndPoint="0,1" >
-                    <GradientStop Color="#ff222222" Offset="0" />
-                    <GradientStop Color="#ffbbbbbb" Offset="1.0" />
-                </LinearGradientBrush>
-            </Grid.Background>
-
-            <Grid Margin="20">
-                <Grid.RowDefinitions>
-                    <RowDefinition Height="auto"></RowDefinition>
-                    <RowDefinition Height="*"></RowDefinition>
-                </Grid.RowDefinitions>
-
-                <StackPanel Orientation="Vertical" Grid.Row="0">
-                    <Image x:Name="imgParentLogo" Stretch="Uniform" Height="40" RenderOptions.BitmapScalingMode="Fant" HorizontalAlignment="Left"></Image>
-                    <TextBlock x:Name="txtParentName" FontSize="26" Foreground="White"></TextBlock>
-                    <TextBlock x:Name="txtName" FontSize="26" Foreground="White"></TextBlock>
-                </StackPanel>
-
-                <Grid Grid.Row="1" Margin="0 20 0 0">
-
-                    <Grid.ColumnDefinitions>
-                        <ColumnDefinition Width="auto"></ColumnDefinition>
-                        <ColumnDefinition Width="*"></ColumnDefinition>
-                    </Grid.ColumnDefinitions>
-
-                    <Grid.RowDefinitions>
-                        <RowDefinition Height="auto"></RowDefinition>
-                        <RowDefinition Height="auto"></RowDefinition>
-                        <RowDefinition Height="*"></RowDefinition>
-                        <RowDefinition Height="auto"></RowDefinition>
-                    </Grid.RowDefinitions>
-
-                    <StackPanel Orientation="Vertical" Grid.Column="0" Grid.RowSpan="4" Margin="0 0 20 0" VerticalAlignment="Top">
-                        <Image x:Name="img" Stretch="Uniform" RenderOptions.BitmapScalingMode="Fant" Height="150"></Image>
-                    </StackPanel>
-
-                    <TextBlock x:Name="txtTagline" Foreground="White" Grid.Column="1" Grid.Row="0" Margin="0 0 0 20" TextWrapping="Wrap" FontStyle="Italic"></TextBlock>
-                    <StackPanel x:Name="pnlRating" Orientation="Horizontal" Margin="0 2 0 20" Grid.Column="1" Grid.Row="1"></StackPanel>
-                    <TextBlock x:Name="txtOverview" Foreground="White" Grid.Column="1" Grid.Row="2" TextWrapping="Wrap" Margin="0 0 0 20"></TextBlock>
-                    <TextBlock x:Name="txtPremeireDate" Foreground="White" Grid.Column="1" Grid.Row="3"></TextBlock>
-                </Grid>
-            </Grid>
-        </Grid>
-    </Grid>
-</UserControl>

+ 0 - 294
MediaBrowser.ServerApplication/Controls/ItemUpdateNotification.xaml.cs

@@ -1,294 +0,0 @@
-using System.Linq;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Media;
-
-namespace MediaBrowser.ServerApplication.Controls
-{
-    /// <summary>
-    /// Interaction logic for ItemUpdateNotification.xaml
-    /// </summary>
-    public partial class ItemUpdateNotification : UserControl
-    {
-        /// <summary>
-        /// The logger
-        /// </summary>
-        private readonly ILogger Logger;
-
-        /// <summary>
-        /// Gets the children changed event args.
-        /// </summary>
-        /// <value>The children changed event args.</value>
-        private BaseItem Item
-        {
-            get { return DataContext as BaseItem; }
-        }
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="ItemUpdateNotification" /> class.
-        /// </summary>
-        public ItemUpdateNotification(ILogger logger)
-        {
-            if (logger == null)
-            {
-                throw new ArgumentNullException("logger");
-            }
-
-            Logger = logger;
-            
-            InitializeComponent();
-
-            Loaded += ItemUpdateNotification_Loaded;
-        }
-
-        /// <summary>
-        /// Handles the Loaded event of the ItemUpdateNotification control.
-        /// </summary>
-        /// <param name="sender">The source of the event.</param>
-        /// <param name="e">The <see cref="RoutedEventArgs" /> instance containing the event data.</param>
-        void ItemUpdateNotification_Loaded(object sender, RoutedEventArgs e)
-        {
-            DisplayItem(Item);
-        }
-
-        /// <summary>
-        /// Gets the display name.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <param name="includeParentName">if set to <c>true</c> [include parent name].</param>
-        /// <returns>System.String.</returns>
-        internal static string GetDisplayName(BaseItem item, bool includeParentName)
-        {
-            var name = item.Name;
-
-            if (item.ProductionYear.HasValue && !(item is Episode))
-            {
-                name += string.Format(" ({0})", item.ProductionYear);
-            }
-
-            var episode = item as Episode;
-            if (episode != null)
-            {
-                var indexNumbers = new List<int>();
-
-                if (episode.Season.IndexNumber.HasValue)
-                {
-                    indexNumbers.Add(episode.Season.IndexNumber.Value);
-                }
-                if (episode.IndexNumber.HasValue)
-                {
-                    indexNumbers.Add(episode.IndexNumber.Value);
-                }
-                var indexNumber = string.Join(".", indexNumbers.ToArray());
-
-                name = string.Format("{0} - {1}", indexNumber, name);
-
-                if (includeParentName)
-                {
-                    name = episode.Series.Name + " - " + name;
-                }
-            }
-
-            if (includeParentName)
-            {
-                var season = item as Season;
-
-                if (season != null)
-                {
-                    name = season.Series.Name + " - " + name;
-                }
-            }
-
-            return name;
-        }
-
-        /// <summary>
-        /// Displays the parent title.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        private void DisplayParentTitle(BaseItem item)
-        {
-            if (!(item is Episode || item is Season))
-            {
-                txtParentName.Visibility = Visibility.Collapsed;
-                imgParentLogo.Visibility = Visibility.Collapsed;
-                return;
-            }
-
-            var series = item is Episode ? (item as Episode).Series : (item as Season).Series;
-
-            var logo = series.GetImage(ImageType.Logo);
-
-            if (string.IsNullOrEmpty(logo))
-            {
-                imgParentLogo.Visibility = Visibility.Collapsed;
-                txtParentName.Visibility = Visibility.Visible;
-            }
-            else
-            {
-                imgParentLogo.Visibility = Visibility.Visible;
-                txtParentName.Visibility = Visibility.Collapsed;
-                imgParentLogo.Source = App.Instance.GetBitmapImage(logo);
-            }
-
-            txtParentName.Text = series.Name;
-        }
-
-        /// <summary>
-        /// Displays the title.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        private void DisplayTitle(BaseItem item)
-        {
-            txtName.Text = GetDisplayName(item, false);
-        }
-
-        /// <summary>
-        /// Displays the item.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        private void DisplayItem(BaseItem item)
-        {
-            DisplayParentTitle(item);
-            DisplayTitle(item);
-            DisplayRating(item);
-
-            var path = GetImagePath(item);
-
-            if (string.IsNullOrEmpty(path))
-            {
-                img.Visibility = Visibility.Collapsed;
-            }
-            else
-            {
-                img.Visibility = Visibility.Visible;
-
-                try
-                {
-                    img.Source = App.Instance.GetBitmapImage(path);
-                }
-                catch (FileNotFoundException)
-                {
-                    Logger.Error("Image file not found {0}", path);
-                }
-            }
-
-            if (string.IsNullOrEmpty(item.Overview))
-            {
-                txtOverview.Visibility = Visibility.Collapsed;
-            }
-            else
-            {
-                txtOverview.Visibility = Visibility.Visible;
-                txtOverview.Text = item.Overview;
-            }
-
-            if (item.Taglines == null || item.Taglines.Count == 0)
-            {
-                txtTagline.Visibility = Visibility.Collapsed;
-            }
-            else
-            {
-                txtTagline.Visibility = Visibility.Visible;
-                txtTagline.Text = item.Taglines[0];
-            }
-
-            if (!item.PremiereDate.HasValue)
-            {
-                txtPremeireDate.Visibility = Visibility.Collapsed;
-            }
-            else
-            {
-                txtPremeireDate.Visibility = Visibility.Visible;
-                txtPremeireDate.Text = "Premiered " + item.PremiereDate.Value.ToLocalTime().ToShortDateString();
-            }
-        }
-
-        /// <summary>
-        /// Gets the image path.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <returns>System.String.</returns>
-        internal static string GetImagePath(BaseItem item)
-        {
-            // Try our best to find an image
-            var path = item.PrimaryImagePath;
-
-            if (string.IsNullOrEmpty(path) && item.BackdropImagePaths != null)
-            {
-                path = item.BackdropImagePaths.FirstOrDefault();
-            }
-
-            if (string.IsNullOrEmpty(path))
-            {
-                path = item.GetImage(ImageType.Thumb);
-            }
-
-            if (string.IsNullOrEmpty(path))
-            {
-                path = item.GetImage(ImageType.Art);
-            }
-
-            if (string.IsNullOrEmpty(path))
-            {
-                path = item.GetImage(ImageType.Logo);
-            }
-
-            if (string.IsNullOrEmpty(path))
-            {
-                path = item.GetImage(ImageType.Disc);
-            }
-
-            return path;
-        }
-
-        /// <summary>
-        /// Displays the rating.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        private void DisplayRating(BaseItem item)
-        {
-            if (!item.CommunityRating.HasValue)
-            {
-                pnlRating.Visibility = Visibility.Collapsed;
-                return;
-            }
-
-            pnlRating.Children.Clear();
-            pnlRating.Visibility = Visibility.Visible;
-
-            var rating = item.CommunityRating.Value;
-
-            for (var i = 0; i < 10; i++)
-            {
-                Image image;
-                if (rating < i - 1)
-                {
-                    image = App.Instance.GetImage(new Uri("../Resources/Images/starEmpty.png", UriKind.Relative));
-                }
-                else if (rating < i)
-                {
-                    image = App.Instance.GetImage(new Uri("../Resources/Images/starHalf.png", UriKind.Relative));
-                }
-                else
-                {
-                    image = App.Instance.GetImage(new Uri("../Resources/Images/starFull.png", UriKind.Relative));
-                }
-
-                RenderOptions.SetBitmapScalingMode(image, BitmapScalingMode.Fant);
-
-                image.Stretch = Stretch.Uniform;
-                image.Height = 16;
-
-                pnlRating.Children.Add(image);
-            }
-        }
-    }
-}

+ 0 - 135
MediaBrowser.ServerApplication/EntryPoints/NewItemNotifier.cs

@@ -1,135 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Plugins;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.ServerApplication.Controls;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Windows;
-using System.Windows.Controls.Primitives;
-
-namespace MediaBrowser.ServerApplication.EntryPoints
-{
-    /// <summary>
-    /// Class NewItemNotifier
-    /// </summary>
-    public class NewItemNotifier
-    {
-        /// <summary>
-        /// Holds the list of new items to display when the NewItemTimer expires
-        /// </summary>
-        private readonly List<BaseItem> _newlyAddedItems = new List<BaseItem>();
-
-        /// <summary>
-        /// The amount of time to wait before showing a new item notification
-        /// This allows us to group items together into one notification
-        /// </summary>
-        private const int NewItemDelay = 60000;
-
-        /// <summary>
-        /// The current new item timer
-        /// </summary>
-        /// <value>The new item timer.</value>
-        private Timer NewItemTimer { get; set; }
-
-        /// <summary>
-        /// The _library manager
-        /// </summary>
-        private readonly ILibraryManager _libraryManager;
-
-        /// <summary>
-        /// The _logger
-        /// </summary>
-        private readonly ILogger _logger;
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="NewItemNotifier" /> class.
-        /// </summary>
-        /// <param name="libraryManager">The library manager.</param>
-        /// <param name="logManager">The log manager.</param>
-        public NewItemNotifier(ILibraryManager libraryManager, ILogManager logManager)
-        {
-            _logger = logManager.GetLogger("NewItemNotifier");
-            _libraryManager = libraryManager;
-        }
-
-        /// <summary>
-        /// Runs this instance.
-        /// </summary>
-        public void Run()
-        {
-            _libraryManager.LibraryChanged += libraryManager_LibraryChanged;
-        }
-
-        /// <summary>
-        /// Handles the LibraryChanged event of the libraryManager control.
-        /// </summary>
-        /// <param name="sender">The source of the event.</param>
-        /// <param name="e">The <see cref="ChildrenChangedEventArgs" /> instance containing the event data.</param>
-        void libraryManager_LibraryChanged(object sender, ChildrenChangedEventArgs e)
-        {
-            var newItems = e.ItemsAdded.Where(i => !i.IsFolder).ToList();
-
-            // Use a timer to prevent lots of these notifications from showing in a short period of time
-            if (newItems.Count > 0)
-            {
-                lock (_newlyAddedItems)
-                {
-                    _newlyAddedItems.AddRange(newItems);
-
-                    if (NewItemTimer == null)
-                    {
-                        NewItemTimer = new Timer(NewItemTimerCallback, null, NewItemDelay, Timeout.Infinite);
-                    }
-                    else
-                    {
-                        NewItemTimer.Change(NewItemDelay, Timeout.Infinite);
-                    }
-                }
-            }
-        }
-
-        /// <summary>
-        /// Called when the new item timer expires
-        /// </summary>
-        /// <param name="state">The state.</param>
-        private void NewItemTimerCallback(object state)
-        {
-            List<BaseItem> newItems;
-
-            // Lock the list and release all resources
-            lock (_newlyAddedItems)
-            {
-                newItems = _newlyAddedItems.ToList();
-                _newlyAddedItems.Clear();
-
-                NewItemTimer.Dispose();
-                NewItemTimer = null;
-            }
-
-            // Show the notification
-            if (newItems.Count > 0)
-            {
-                Application.Current.Dispatcher.InvokeAsync(() =>
-                {
-                    var window = Application.Current.Windows.OfType<MainWindow>().First();
-
-                    window.Dispatcher.InvokeAsync(() => window.MbTaskbarIcon.ShowCustomBalloon(new ItemUpdateNotification(_logger)
-                    {
-                        DataContext = newItems[0]
-
-                    }, PopupAnimation.Slide, 6000));
-                });
-            }
-        }
-
-        /// <summary>
-        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
-        /// </summary>
-        public void Dispose()
-        {
-            _libraryManager.LibraryChanged -= libraryManager_LibraryChanged;
-        }
-    }
-}

+ 83 - 12
MediaBrowser.ServerApplication/EntryPoints/WebSocketEvents.cs

@@ -101,10 +101,12 @@ namespace MediaBrowser.ServerApplication.EntryPoints
             _userManager.UserDeleted += userManager_UserDeleted;
             _userManager.UserUpdated += userManager_UserUpdated;
 
-            _libraryManager.LibraryChanged += libraryManager_LibraryChanged;
-
             _appHost.HasPendingRestartChanged += kernel_HasPendingRestartChanged;
 
+            _libraryManager.ItemAdded += libraryManager_ItemAdded;
+            _libraryManager.ItemUpdated += libraryManager_ItemUpdated;
+            _libraryManager.ItemRemoved += libraryManager_ItemRemoved;
+
             _installationManager.PluginUninstalled += InstallationManager_PluginUninstalled;
             _installationManager.PackageInstalling += installationManager_PackageInstalling;
             _installationManager.PackageInstallationCancelled += installationManager_PackageInstallationCancelled;
@@ -122,7 +124,7 @@ namespace MediaBrowser.ServerApplication.EntryPoints
 
         void _taskManager_TaskExecuting(object sender, EventArgs e)
         {
-            var task = (IScheduledTask) sender;
+            var task = (IScheduledTask)sender;
             _serverManager.SendWebSocketMessage("ScheduledTaskStarted", task.Name);
         }
 
@@ -167,11 +169,77 @@ namespace MediaBrowser.ServerApplication.EntryPoints
         }
 
         /// <summary>
-        /// Handles the LibraryChanged event of the libraryManager control.
+        /// Handles the ItemAdded event of the libraryManager control.
+        /// </summary>
+        /// <param name="sender">The source of the event.</param>
+        /// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
+        void libraryManager_ItemAdded(object sender, ItemChangeEventArgs e)
+        {
+            lock (_libraryChangedSyncLock)
+            {
+                if (LibraryUpdateInfo == null)
+                {
+                    LibraryUpdateInfo = new LibraryUpdateInfo();
+                }
+
+                if (LibraryUpdateTimer == null)
+                {
+                    LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration,
+                                                   Timeout.Infinite);
+                }
+                else
+                {
+                    LibraryUpdateTimer.Change(LibraryUpdateDuration, Timeout.Infinite);
+                }
+
+                if (e.Item.Parent != null)
+                {
+                    LibraryUpdateInfo.Folders.Add(e.Item.Parent.Id);
+                }
+
+                LibraryUpdateInfo.ItemsAdded.Add(e.Item.Id);
+            }
+        }
+
+        /// <summary>
+        /// Handles the ItemUpdated event of the libraryManager control.
+        /// </summary>
+        /// <param name="sender">The source of the event.</param>
+        /// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
+        void libraryManager_ItemUpdated(object sender, ItemChangeEventArgs e)
+        {
+            lock (_libraryChangedSyncLock)
+            {
+                if (LibraryUpdateInfo == null)
+                {
+                    LibraryUpdateInfo = new LibraryUpdateInfo();
+                }
+
+                if (LibraryUpdateTimer == null)
+                {
+                    LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration,
+                                                   Timeout.Infinite);
+                }
+                else
+                {
+                    LibraryUpdateTimer.Change(LibraryUpdateDuration, Timeout.Infinite);
+                }
+
+                if (e.Item.Parent != null)
+                {
+                    LibraryUpdateInfo.Folders.Add(e.Item.Parent.Id);
+                }
+
+                LibraryUpdateInfo.ItemsUpdated.Add(e.Item.Id);
+            }
+        }
+
+        /// <summary>
+        /// Handles the ItemRemoved event of the libraryManager control.
         /// </summary>
         /// <param name="sender">The source of the event.</param>
-        /// <param name="e">The <see cref="ChildrenChangedEventArgs" /> instance containing the event data.</param>
-        void libraryManager_LibraryChanged(object sender, ChildrenChangedEventArgs e)
+        /// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
+        void libraryManager_ItemRemoved(object sender, ItemChangeEventArgs e)
         {
             lock (_libraryChangedSyncLock)
             {
@@ -190,11 +258,12 @@ namespace MediaBrowser.ServerApplication.EntryPoints
                     LibraryUpdateTimer.Change(LibraryUpdateDuration, Timeout.Infinite);
                 }
 
-                LibraryUpdateInfo.Folders.Add(e.Folder.Id);
+                if (e.Item.Parent != null)
+                {
+                    LibraryUpdateInfo.Folders.Add(e.Item.Parent.Id);
+                }
 
-                LibraryUpdateInfo.ItemsAdded.AddRange(e.ItemsAdded.Select(i => i.Id));
-                LibraryUpdateInfo.ItemsUpdated.AddRange(e.ItemsUpdated.Select(i => i.Id));
-                LibraryUpdateInfo.ItemsRemoved.AddRange(e.ItemsRemoved.Select(i => i.Id));
+                LibraryUpdateInfo.ItemsRemoved.Add(e.Item.Id);
             }
         }
 
@@ -281,12 +350,14 @@ namespace MediaBrowser.ServerApplication.EntryPoints
                     LibraryUpdateTimer.Dispose();
                     LibraryUpdateTimer = null;
                 }
+
+                _libraryManager.ItemAdded -= libraryManager_ItemAdded;
+                _libraryManager.ItemUpdated -= libraryManager_ItemUpdated;
+                _libraryManager.ItemRemoved -= libraryManager_ItemRemoved;
                 
                 _userManager.UserDeleted -= userManager_UserDeleted;
                 _userManager.UserUpdated -= userManager_UserUpdated;
 
-                _libraryManager.LibraryChanged -= libraryManager_LibraryChanged;
-
                 _installationManager.PluginUninstalled -= InstallationManager_PluginUninstalled;
                 _installationManager.PackageInstalling -= installationManager_PackageInstalling;
                 _installationManager.PackageInstallationCancelled -= installationManager_PackageInstallationCancelled;

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

@@ -170,7 +170,6 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="EntryPoints\LoadRegistrations.cs" />
-    <Compile Include="EntryPoints\NewItemNotifier.cs" />
     <Compile Include="EntryPoints\RefreshUsersMetadata.cs" />
     <Compile Include="EntryPoints\StartupWizard.cs" />
     <Compile Include="EntryPoints\WebSocketEvents.cs" />
@@ -181,10 +180,6 @@
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>
     </Page>
-    <Page Include="Controls\ItemUpdateNotification.xaml">
-      <SubType>Designer</SubType>
-      <Generator>MSBuild:Compile</Generator>
-    </Page>
     <Page Include="LibraryExplorer.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
@@ -205,9 +200,6 @@
       <SubType>Code</SubType>
     </Compile>
     <Compile Include="ApplicationHost.cs" />
-    <Compile Include="Controls\ItemUpdateNotification.xaml.cs">
-      <DependentUpon>ItemUpdateNotification.xaml</DependentUpon>
-    </Compile>
     <Compile Include="Implementations\DotNetZipClient.cs" />
     <Compile Include="LibraryExplorer.xaml.cs">
       <DependentUpon>LibraryExplorer.xaml</DependentUpon>