aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MediaBrowser.Controller/Dto/DtoBuilder.cs16
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs2
-rw-r--r--MediaBrowser.Controller/Providers/BaseItemXmlParser.cs13
-rw-r--r--MediaBrowser.Controller/Providers/BaseMetadataProvider.cs2
-rw-r--r--MediaBrowser.Controller/Providers/FolderProviderFromXml.cs17
-rw-r--r--MediaBrowser.Controller/Providers/Movies/MovieProviderFromXml.cs23
-rw-r--r--MediaBrowser.Controller/Providers/TV/EpisodeProviderFromXml.cs40
-rw-r--r--MediaBrowser.Controller/Providers/TV/SeriesProviderFromXml.cs16
-rw-r--r--MediaBrowser.Model/Entities/LibraryUpdateInfo.cs20
-rw-r--r--MediaBrowser.Model/Weather/WeatherInfo.cs8
-rw-r--r--MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs2
-rw-r--r--MediaBrowser.Server.Implementations/ScheduledTasks/AudioImagesTask.cs2
-rw-r--r--MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs42
-rw-r--r--MediaBrowser.Server.Implementations/ScheduledTasks/VideoImagesTask.cs2
-rw-r--r--MediaBrowser.ServerApplication/EntryPoints/WebSocketEvents.cs80
-rw-r--r--MediaBrowser.sln3
16 files changed, 195 insertions, 93 deletions
diff --git a/MediaBrowser.Controller/Dto/DtoBuilder.cs b/MediaBrowser.Controller/Dto/DtoBuilder.cs
index 84f9f8827..6e33f52e6 100644
--- a/MediaBrowser.Controller/Dto/DtoBuilder.cs
+++ b/MediaBrowser.Controller/Dto/DtoBuilder.cs
@@ -665,22 +665,6 @@ namespace MediaBrowser.Controller.Dto
}
/// <summary>
- /// Gets the library update info.
- /// </summary>
- /// <param name="changeEvent">The <see cref="ChildrenChangedEventArgs" /> instance containing the event data.</param>
- /// <returns>LibraryUpdateInfo.</returns>
- public static LibraryUpdateInfo GetLibraryUpdateInfo(ChildrenChangedEventArgs changeEvent)
- {
- return new LibraryUpdateInfo
- {
- Folder = GetBaseItemInfo(changeEvent.Folder),
- ItemsAdded = changeEvent.ItemsAdded.Select(GetBaseItemInfo),
- ItemsRemoved = changeEvent.ItemsRemoved.Select(i => i.Id),
- ItemsUpdated = changeEvent.ItemsUpdated.Select(i => i.Id)
- };
- }
-
- /// <summary>
/// Converts a UserItemData to a DTOUserItemData
/// </summary>
/// <param name="data">The data.</param>
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index b7508a641..f8db07fe3 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -659,7 +659,7 @@ namespace MediaBrowser.Controller.Entities
foreach (var tuple in list)
{
- if (tasks.Count > 50)
+ if (tasks.Count > 5)
{
await Task.WhenAll(tasks).ConfigureAwait(false);
}
diff --git a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs
index e0091cd80..d5df769a9 100644
--- a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs
+++ b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs
@@ -49,8 +49,17 @@ namespace MediaBrowser.Controller.Providers
throw new ArgumentNullException();
}
+ var settings = new XmlReaderSettings
+ {
+ CheckCharacters = false,
+ IgnoreProcessingInstructions = true,
+ IgnoreComments = true,
+ IgnoreWhitespace = true,
+ ValidationType = ValidationType.None
+ };
+
// Use XmlReader for best performance
- using (var reader = XmlReader.Create(metadataFile))
+ using (var reader = XmlReader.Create(metadataFile, settings))
{
reader.MoveToContent();
@@ -93,7 +102,7 @@ namespace MediaBrowser.Controller.Providers
{
var type = reader.ReadElementContentAsString();
- if (!string.IsNullOrWhiteSpace(type) && !type.Equals("none",StringComparison.OrdinalIgnoreCase))
+ if (!string.IsNullOrWhiteSpace(type) && !type.Equals("none", StringComparison.OrdinalIgnoreCase))
{
item.DisplayMediaType = type;
}
diff --git a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs
index 3f71e398a..b69ece418 100644
--- a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs
+++ b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs
@@ -31,6 +31,8 @@ namespace MediaBrowser.Controller.Providers
/// </summary>
protected readonly Guid Id;
+ protected static readonly SemaphoreSlim XmlParsingResourcePool = new SemaphoreSlim(5, 5);
+
/// <summary>
/// Supportses the specified item.
/// </summary>
diff --git a/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs b/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs
index d2c2d5b15..99744390a 100644
--- a/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs
+++ b/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs
@@ -58,7 +58,7 @@ namespace MediaBrowser.Controller.Providers
/// <returns>Task{System.Boolean}.</returns>
public override Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
{
- return Task.Run(() => Fetch(item, cancellationToken));
+ return Fetch(item, cancellationToken);
}
/// <summary>
@@ -67,7 +67,7 @@ namespace MediaBrowser.Controller.Providers
/// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- private bool Fetch(BaseItem item, CancellationToken cancellationToken)
+ private async Task<bool> Fetch(BaseItem item, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -76,7 +76,18 @@ namespace MediaBrowser.Controller.Providers
if (metadataFile.HasValue)
{
var path = metadataFile.Value.Path;
- new BaseItemXmlParser<Folder>(Logger).Fetch((Folder)item, path, cancellationToken);
+
+ await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
+
+ try
+ {
+ new BaseItemXmlParser<Folder>(Logger).Fetch((Folder)item, path, cancellationToken);
+ }
+ finally
+ {
+ XmlParsingResourcePool.Release();
+ }
+
SetLastRefreshed(item, DateTime.UtcNow);
return true;
}
diff --git a/MediaBrowser.Controller/Providers/Movies/MovieProviderFromXml.cs b/MediaBrowser.Controller/Providers/Movies/MovieProviderFromXml.cs
index 279533636..1ed003e87 100644
--- a/MediaBrowser.Controller/Providers/Movies/MovieProviderFromXml.cs
+++ b/MediaBrowser.Controller/Providers/Movies/MovieProviderFromXml.cs
@@ -58,7 +58,7 @@ namespace MediaBrowser.Controller.Providers.Movies
/// <returns>Task{System.Boolean}.</returns>
public override Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
{
- return Task.Run(() => Fetch(item, cancellationToken));
+ return Fetch(item, cancellationToken);
}
/// <summary>
@@ -67,7 +67,7 @@ namespace MediaBrowser.Controller.Providers.Movies
/// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- private bool Fetch(BaseItem item, CancellationToken cancellationToken)
+ private async Task<bool> Fetch(BaseItem item, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -77,14 +77,25 @@ namespace MediaBrowser.Controller.Providers.Movies
{
var path = metadataFile.Value.Path;
var boxset = item as BoxSet;
- if (boxset != null)
+
+ await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
+
+ try
{
- new BaseItemXmlParser<BoxSet>(Logger).Fetch(boxset, path, cancellationToken);
+ if (boxset != null)
+ {
+ new BaseItemXmlParser<BoxSet>(Logger).Fetch(boxset, path, cancellationToken);
+ }
+ else
+ {
+ new BaseItemXmlParser<Movie>(Logger).Fetch((Movie)item, path, cancellationToken);
+ }
}
- else
+ finally
{
- new BaseItemXmlParser<Movie>(Logger).Fetch((Movie)item, path, cancellationToken);
+ XmlParsingResourcePool.Release();
}
+
SetLastRefreshed(item, DateTime.UtcNow);
return true;
}
diff --git a/MediaBrowser.Controller/Providers/TV/EpisodeProviderFromXml.cs b/MediaBrowser.Controller/Providers/TV/EpisodeProviderFromXml.cs
index 483d1ddce..e6fb2eb4f 100644
--- a/MediaBrowser.Controller/Providers/TV/EpisodeProviderFromXml.cs
+++ b/MediaBrowser.Controller/Providers/TV/EpisodeProviderFromXml.cs
@@ -15,7 +15,8 @@ namespace MediaBrowser.Controller.Providers.TV
/// </summary>
public class EpisodeProviderFromXml : BaseMetadataProvider
{
- public EpisodeProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager) : base(logManager, configurationManager)
+ public EpisodeProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager)
+ : base(logManager, configurationManager)
{
}
@@ -55,7 +56,7 @@ namespace MediaBrowser.Controller.Providers.TV
/// <returns>Task{System.Boolean}.</returns>
public override Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
{
- return Task.Run(() => Fetch(item, cancellationToken));
+ return Fetch(item, cancellationToken);
}
/// <summary>
@@ -84,42 +85,31 @@ namespace MediaBrowser.Controller.Providers.TV
/// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- private bool Fetch(BaseItem item, CancellationToken cancellationToken)
+ private async Task<bool> Fetch(BaseItem item, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
-
+
var metadataFile = Path.Combine(item.MetaLocation, Path.ChangeExtension(Path.GetFileName(item.Path), ".xml"));
- var episode = (Episode)item;
+ var file = item.ResolveArgs.Parent.ResolveArgs.GetMetaFileByPath(metadataFile);
- if (!FetchMetadata(episode, item.ResolveArgs.Parent, metadataFile, cancellationToken))
+ if (!file.HasValue)
{
- // Don't set last refreshed if we didn't do anything
return false;
}
- SetLastRefreshed(item, DateTime.UtcNow);
- return true;
- }
-
- /// <summary>
- /// Fetches the metadata.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="parent">The parent.</param>
- /// <param name="metadataFile">The metadata file.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- private bool FetchMetadata(Episode item, Folder parent, string metadataFile, CancellationToken cancellationToken)
- {
- var file = parent.ResolveArgs.GetMetaFileByPath(metadataFile);
+ await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
- if (!file.HasValue)
+ try
{
- return false;
+ new EpisodeXmlParser(Logger).Fetch((Episode)item, metadataFile, cancellationToken);
+ }
+ finally
+ {
+ XmlParsingResourcePool.Release();
}
- new EpisodeXmlParser(Logger).Fetch(item, metadataFile, cancellationToken);
+ SetLastRefreshed(item, DateTime.UtcNow);
return true;
}
}
diff --git a/MediaBrowser.Controller/Providers/TV/SeriesProviderFromXml.cs b/MediaBrowser.Controller/Providers/TV/SeriesProviderFromXml.cs
index 8e42e9d55..556ef24c9 100644
--- a/MediaBrowser.Controller/Providers/TV/SeriesProviderFromXml.cs
+++ b/MediaBrowser.Controller/Providers/TV/SeriesProviderFromXml.cs
@@ -59,7 +59,7 @@ namespace MediaBrowser.Controller.Providers.TV
/// <returns>Task{System.Boolean}.</returns>
public override Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
{
- return Task.Run(() => Fetch(item, cancellationToken));
+ return Fetch(item, cancellationToken);
}
/// <summary>
@@ -68,7 +68,7 @@ namespace MediaBrowser.Controller.Providers.TV
/// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- private bool Fetch(BaseItem item, CancellationToken cancellationToken)
+ private async Task<bool> Fetch(BaseItem item, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -78,7 +78,17 @@ namespace MediaBrowser.Controller.Providers.TV
{
var path = metadataFile.Value.Path;
- new SeriesXmlParser(Logger).Fetch((Series)item, path, cancellationToken);
+ await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
+
+ try
+ {
+ new SeriesXmlParser(Logger).Fetch((Series)item, path, cancellationToken);
+ }
+ finally
+ {
+ XmlParsingResourcePool.Release();
+ }
+
SetLastRefreshed(item, DateTime.UtcNow);
return true;
diff --git a/MediaBrowser.Model/Entities/LibraryUpdateInfo.cs b/MediaBrowser.Model/Entities/LibraryUpdateInfo.cs
index 1ad117009..e98b7ae2c 100644
--- a/MediaBrowser.Model/Entities/LibraryUpdateInfo.cs
+++ b/MediaBrowser.Model/Entities/LibraryUpdateInfo.cs
@@ -9,27 +9,35 @@ namespace MediaBrowser.Model.Entities
public class LibraryUpdateInfo
{
/// <summary>
- /// Gets or sets the folder.
+ /// Gets or sets the folders.
/// </summary>
- /// <value>The folder.</value>
- public BaseItemInfo Folder { get; set; }
+ /// <value>The folders.</value>
+ public List<Guid> Folders { get; set; }
/// <summary>
/// Gets or sets the items added.
/// </summary>
/// <value>The items added.</value>
- public IEnumerable<BaseItemInfo> ItemsAdded { get; set; }
+ public List<Guid> ItemsAdded { get; set; }
/// <summary>
/// Gets or sets the items removed.
/// </summary>
/// <value>The items removed.</value>
- public IEnumerable<Guid> ItemsRemoved { get; set; }
+ public List<Guid> ItemsRemoved { get; set; }
/// <summary>
/// Gets or sets the items updated.
/// </summary>
/// <value>The items updated.</value>
- public IEnumerable<Guid> ItemsUpdated { get; set; }
+ public List<Guid> ItemsUpdated { get; set; }
+
+ public LibraryUpdateInfo()
+ {
+ Folders = new List<Guid>();
+ ItemsAdded = new List<Guid>();
+ ItemsRemoved = new List<Guid>();
+ ItemsUpdated = new List<Guid>();
+ }
}
}
diff --git a/MediaBrowser.Model/Weather/WeatherInfo.cs b/MediaBrowser.Model/Weather/WeatherInfo.cs
index b423380f5..57a9432f6 100644
--- a/MediaBrowser.Model/Weather/WeatherInfo.cs
+++ b/MediaBrowser.Model/Weather/WeatherInfo.cs
@@ -21,5 +21,13 @@ namespace MediaBrowser.Model.Weather
/// <value>The forecasts.</value>
[ProtoMember(2)]
public WeatherForecast[] Forecasts { get; set; }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="WeatherInfo"/> class.
+ /// </summary>
+ public WeatherInfo()
+ {
+ Forecasts = new WeatherForecast[] {};
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs b/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs
index 08e2eb774..709c21f50 100644
--- a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs
+++ b/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs
@@ -55,7 +55,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
/// <summary>
/// The audio image resource pool
/// </summary>
- private readonly SemaphoreSlim _audioImageResourcePool = new SemaphoreSlim(2, 2);
+ private readonly SemaphoreSlim _audioImageResourcePool = new SemaphoreSlim(1, 1);
/// <summary>
/// The _subtitle extraction resource pool
diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/AudioImagesTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/AudioImagesTask.cs
index db809a47b..66ca9db9a 100644
--- a/MediaBrowser.Server.Implementations/ScheduledTasks/AudioImagesTask.cs
+++ b/MediaBrowser.Server.Implementations/ScheduledTasks/AudioImagesTask.cs
@@ -147,6 +147,8 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
{
// Image is already in the cache
item.PrimaryImagePath = path;
+
+ await _libraryManager.SaveItem(item, cancellationToken).ConfigureAwait(false);
}
}
diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
index d46d4ec8a..7f158f1f2 100644
--- a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
+++ b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
@@ -2,6 +2,7 @@
using MediaBrowser.Controller;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
@@ -60,40 +61,27 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns>Task.</returns>
- public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
+ public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
{
- var videos = _libraryManager.RootFolder.RecursiveChildren.OfType<Video>().Where(v => v.Chapters != null).ToList();
+ var videos = _libraryManager.RootFolder.RecursiveChildren
+ .OfType<Video>()
+ .Where(v => v.Chapters != null && v.Chapters.Count != 0)
+ .ToList();
var numComplete = 0;
- var tasks = videos.Select(v => Task.Run(async () =>
+ foreach (var video in videos)
{
- try
- {
- await _kernel.FFMpegManager.PopulateChapterImages(v, cancellationToken, true, true);
- }
- catch (OperationCanceledException)
- {
- throw;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error creating chapter images for {0}", ex, v.Name);
- }
- finally
- {
- lock (progress)
- {
- numComplete++;
- double percent = numComplete;
- percent /= videos.Count;
+ cancellationToken.ThrowIfCancellationRequested();
+
+ await _kernel.FFMpegManager.PopulateChapterImages(video, cancellationToken, true, true);
- progress.Report(100 * percent);
- }
- }
- }));
+ numComplete++;
+ double percent = numComplete;
+ percent /= videos.Count;
- return Task.WhenAll(tasks);
+ progress.Report(100 * percent);
+ }
}
/// <summary>
diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/VideoImagesTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/VideoImagesTask.cs
index a82c22fe9..a995f1a47 100644
--- a/MediaBrowser.Server.Implementations/ScheduledTasks/VideoImagesTask.cs
+++ b/MediaBrowser.Server.Implementations/ScheduledTasks/VideoImagesTask.cs
@@ -176,6 +176,8 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
{
// Image is already in the cache
item.PrimaryImagePath = path;
+
+ await _libraryManager.SaveItem(item, cancellationToken).ConfigureAwait(false);
}
}
diff --git a/MediaBrowser.ServerApplication/EntryPoints/WebSocketEvents.cs b/MediaBrowser.ServerApplication/EntryPoints/WebSocketEvents.cs
index 19c42e8d8..a8eb8f4c0 100644
--- a/MediaBrowser.ServerApplication/EntryPoints/WebSocketEvents.cs
+++ b/MediaBrowser.ServerApplication/EntryPoints/WebSocketEvents.cs
@@ -1,4 +1,6 @@
-using MediaBrowser.Common.Events;
+using System.Linq;
+using System.Threading;
+using MediaBrowser.Common.Events;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.ScheduledTasks;
@@ -8,6 +10,7 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Updates;
+using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Tasks;
using MediaBrowser.Model.Updates;
@@ -49,8 +52,33 @@ namespace MediaBrowser.ServerApplication.EntryPoints
/// </summary>
private readonly IServerApplicationHost _appHost;
+ /// <summary>
+ /// The _task manager
+ /// </summary>
private readonly ITaskManager _taskManager;
-
+
+ /// <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; }
+
+ /// <summary>
+ /// Gets or sets the library update timer.
+ /// </summary>
+ /// <value>The library update timer.</value>
+ private Timer LibraryUpdateTimer { get; set; }
+
+ /// <summary>
+ /// The library update duration
+ /// </summary>
+ private const int LibraryUpdateDuration = 60000;
+
/// <summary>
/// Initializes a new instance of the <see cref="WebSocketEvents" /> class.
/// </summary>
@@ -145,7 +173,47 @@ namespace MediaBrowser.ServerApplication.EntryPoints
/// <param name="e">The <see cref="ChildrenChangedEventArgs" /> instance containing the event data.</param>
void libraryManager_LibraryChanged(object sender, ChildrenChangedEventArgs e)
{
- _serverManager.SendWebSocketMessage("LibraryChanged", () => DtoBuilder.GetLibraryUpdateInfo(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);
+ }
+
+ LibraryUpdateInfo.Folders.Add(e.Folder.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));
+ }
+ }
+
+ /// <summary>
+ /// Libraries the update timer callback.
+ /// </summary>
+ /// <param name="state">The state.</param>
+ private void LibraryUpdateTimerCallback(object state)
+ {
+ lock (_libraryChangedSyncLock)
+ {
+ _serverManager.SendWebSocketMessage("LibraryChanged", LibraryUpdateInfo);
+
+ if (LibraryUpdateTimer != null)
+ {
+ LibraryUpdateTimer.Dispose();
+ LibraryUpdateTimer = null;
+ }
+ }
}
/// <summary>
@@ -206,6 +274,12 @@ namespace MediaBrowser.ServerApplication.EntryPoints
{
if (dispose)
{
+ if (LibraryUpdateTimer != null)
+ {
+ LibraryUpdateTimer.Dispose();
+ LibraryUpdateTimer = null;
+ }
+
_userManager.UserDeleted -= userManager_UserDeleted;
_userManager.UserUpdated -= userManager_UserUpdated;
diff --git a/MediaBrowser.sln b/MediaBrowser.sln
index 830fbe16d..d43ba947a 100644
--- a/MediaBrowser.sln
+++ b/MediaBrowser.sln
@@ -205,4 +205,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(Performance) = preSolution
+ HasPerformanceSessions = true
+ EndGlobalSection
EndGlobal