aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Server.Implementations
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Server.Implementations')
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs339
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/LoadRegistrations.cs57
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/RefreshUsersMetadata.cs41
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/WebSocketEvents.cs207
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj10
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteChapterRepository.cs63
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs31
-rw-r--r--MediaBrowser.Server.Implementations/packages.config1
8 files changed, 707 insertions, 42 deletions
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/MediaBrowser.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
new file mode 100644
index 000000000..71d014468
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
@@ -0,0 +1,339 @@
+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 MediaBrowser.Model.Logging;
+using MoreLinq;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+
+namespace MediaBrowser.Server.Implementations.EntryPoints
+{
+ public class LibraryChangedNotifier : IServerEntryPoint
+ {
+ /// <summary>
+ /// The _library manager
+ /// </summary>
+ private readonly ILibraryManager _libraryManager;
+
+ private readonly ISessionManager _sessionManager;
+ private readonly IServerManager _serverManager;
+ private readonly IUserManager _userManager;
+ private readonly ILogger _logger;
+
+ /// <summary>
+ /// The _library changed sync lock
+ /// </summary>
+ private readonly object _libraryChangedSyncLock = new object();
+
+ 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.
+ /// </summary>
+ /// <value>The library update timer.</value>
+ private Timer LibraryUpdateTimer { get; set; }
+
+ /// <summary>
+ /// The library update duration
+ /// </summary>
+ private const int LibraryUpdateDuration = 60000;
+
+ public LibraryChangedNotifier(ILibraryManager libraryManager, ISessionManager sessionManager, IServerManager serverManager, IUserManager userManager, ILogger logger)
+ {
+ _libraryManager = libraryManager;
+ _sessionManager = sessionManager;
+ _serverManager = serverManager;
+ _userManager = userManager;
+ _logger = logger;
+ }
+
+ public void Run()
+ {
+ _libraryManager.ItemAdded += libraryManager_ItemAdded;
+ _libraryManager.ItemUpdated += libraryManager_ItemUpdated;
+ _libraryManager.ItemRemoved += libraryManager_ItemRemoved;
+
+ }
+
+ /// <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)
+ {
+ lock (_libraryChangedSyncLock)
+ {
+ if (LibraryUpdateTimer == null)
+ {
+ LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration,
+ Timeout.Infinite);
+ }
+ else
+ {
+ LibraryUpdateTimer.Change(LibraryUpdateDuration, Timeout.Infinite);
+ }
+
+ if (e.Item.Parent != null)
+ {
+ _foldersAddedTo.Add(e.Item.Parent);
+ }
+
+ _itemsAdded.Add(e.Item);
+ }
+ }
+
+ /// <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 (LibraryUpdateTimer == null)
+ {
+ LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration,
+ Timeout.Infinite);
+ }
+ else
+ {
+ LibraryUpdateTimer.Change(LibraryUpdateDuration, Timeout.Infinite);
+ }
+
+ _itemsUpdated.Add(e.Item);
+ }
+ }
+
+ /// <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)
+ {
+ lock (_libraryChangedSyncLock)
+ {
+ if (LibraryUpdateTimer == null)
+ {
+ LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration,
+ Timeout.Infinite);
+ }
+ else
+ {
+ LibraryUpdateTimer.Change(LibraryUpdateDuration, Timeout.Infinite);
+ }
+
+ if (e.Item.Parent != null)
+ {
+ _foldersRemovedFrom.Add(e.Item.Parent);
+ }
+
+ _itemsRemoved.Add(e.Item);
+ }
+ }
+
+ /// <summary>
+ /// Libraries the update timer callback.
+ /// </summary>
+ /// <param name="state">The state.</param>
+ private void LibraryUpdateTimerCallback(object state)
+ {
+ lock (_libraryChangedSyncLock)
+ {
+ // Remove dupes in case some were saved multiple times
+ var foldersAddedTo = _foldersAddedTo.DistinctBy(i => i.Id).ToList();
+
+ var foldersRemovedFrom = _foldersRemovedFrom.DistinctBy(i => i.Id).ToList();
+
+ var itemsUpdated = _itemsUpdated
+ .Where(i => !_itemsAdded.Contains(i))
+ .DistinctBy(i => i.Id)
+ .ToList();
+
+ SendChangeNotifications(_itemsAdded.ToList(), itemsUpdated, _itemsRemoved.ToList(), foldersAddedTo, foldersRemovedFrom, CancellationToken.None);
+
+ if (LibraryUpdateTimer != null)
+ {
+ LibraryUpdateTimer.Dispose();
+ LibraryUpdateTimer = 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.User)
+ .Where(i => i != null)
+ .Select(i => i.Id)
+ .Distinct()
+ .ToList();
+
+ foreach (var userId in users)
+ {
+ var id = userId;
+ var webSockets = currentSessions.Where(u => u.User != null && u.User.Id == id)
+ .SelectMany(i => i.WebSockets)
+ .ToList();
+
+ try
+ {
+ await _serverManager.SendWebSocketMessageAsync("LibraryChanged", () => GetLibraryUpdateInfo(itemsAdded, itemsUpdated, itemsRemoved, foldersAddedTo, foldersRemovedFrom, id), webSockets, cancellationToken).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error sending LibraryChanged message", ex);
+ }
+ }
+ }
+
+ /// <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, IEnumerable<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)
+ {
+ if (item.LocationType == LocationType.FileSystem)
+ {
+ return collections.Where(i =>
+ {
+
+ try
+ {
+ return i.LocationType == LocationType.FileSystem &&
+ i.ResolveArgs.PhysicalLocations.Contains(item.Path);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error getting ResolveArgs for {0}", ex, i.Path);
+ return false;
+ }
+
+ }).Cast<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>
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ /// </summary>
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ /// <summary>
+ /// Releases unmanaged and - optionally - managed resources.
+ /// </summary>
+ /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
+ protected virtual void Dispose(bool dispose)
+ {
+ if (dispose)
+ {
+ if (LibraryUpdateTimer != null)
+ {
+ LibraryUpdateTimer.Dispose();
+ LibraryUpdateTimer = null;
+ }
+
+ _libraryManager.ItemAdded -= libraryManager_ItemAdded;
+ _libraryManager.ItemUpdated -= libraryManager_ItemUpdated;
+ _libraryManager.ItemRemoved -= libraryManager_ItemRemoved;
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/LoadRegistrations.cs b/MediaBrowser.Server.Implementations/EntryPoints/LoadRegistrations.cs
new file mode 100644
index 000000000..c2c4056f5
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/EntryPoints/LoadRegistrations.cs
@@ -0,0 +1,57 @@
+using MediaBrowser.Common.Security;
+using MediaBrowser.Controller.Plugins;
+using MediaBrowser.Model.Logging;
+using System;
+
+namespace MediaBrowser.Server.Implementations.EntryPoints
+{
+ /// <summary>
+ /// Class LoadRegistrations
+ /// </summary>
+ public class LoadRegistrations : IServerEntryPoint
+ {
+ /// <summary>
+ /// The _security manager
+ /// </summary>
+ private readonly ISecurityManager _securityManager;
+
+ /// <summary>
+ /// The _logger
+ /// </summary>
+ private readonly ILogger _logger;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="LoadRegistrations" /> class.
+ /// </summary>
+ /// <param name="securityManager">The security manager.</param>
+ /// <param name="logManager">The log manager.</param>
+ public LoadRegistrations(ISecurityManager securityManager, ILogManager logManager)
+ {
+ _securityManager = securityManager;
+
+ _logger = logManager.GetLogger("Registration Loader");
+ }
+
+ /// <summary>
+ /// Runs this instance.
+ /// </summary>
+ public async void Run()
+ {
+ try
+ {
+ await _securityManager.LoadAllRegistrationInfo().ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error loading registration info", ex);
+ }
+ }
+
+ /// <summary>
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ /// </summary>
+ public void Dispose()
+ {
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/RefreshUsersMetadata.cs b/MediaBrowser.Server.Implementations/EntryPoints/RefreshUsersMetadata.cs
new file mode 100644
index 000000000..a0b7ff515
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/EntryPoints/RefreshUsersMetadata.cs
@@ -0,0 +1,41 @@
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Plugins;
+using System.Threading;
+
+namespace MediaBrowser.Server.Implementations.EntryPoints
+{
+ /// <summary>
+ /// Class RefreshUsersMetadata
+ /// </summary>
+ public class RefreshUsersMetadata : IServerEntryPoint
+ {
+ /// <summary>
+ /// The _user manager
+ /// </summary>
+ private readonly IUserManager _userManager;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="RefreshUsersMetadata" /> class.
+ /// </summary>
+ /// <param name="userManager">The user manager.</param>
+ public RefreshUsersMetadata(IUserManager userManager)
+ {
+ _userManager = userManager;
+ }
+
+ /// <summary>
+ /// Runs this instance.
+ /// </summary>
+ public async void Run()
+ {
+ await _userManager.RefreshUsersMetadata(CancellationToken.None).ConfigureAwait(false);
+ }
+
+ /// <summary>
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ /// </summary>
+ public void Dispose()
+ {
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/WebSocketEvents.cs b/MediaBrowser.Server.Implementations/EntryPoints/WebSocketEvents.cs
new file mode 100644
index 000000000..b4bffc077
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/EntryPoints/WebSocketEvents.cs
@@ -0,0 +1,207 @@
+using MediaBrowser.Common.Events;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Plugins;
+using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Common.Updates;
+using MediaBrowser.Controller;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Plugins;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Tasks;
+using MediaBrowser.Model.Updates;
+using System;
+
+namespace MediaBrowser.Server.Implementations.EntryPoints
+{
+ /// <summary>
+ /// Class WebSocketEvents
+ /// </summary>
+ public class WebSocketEvents : IServerEntryPoint
+ {
+ /// <summary>
+ /// The _server manager
+ /// </summary>
+ private readonly IServerManager _serverManager;
+ /// <summary>
+ /// The _logger
+ /// </summary>
+ private readonly ILogger _logger;
+
+ /// <summary>
+ /// The _user manager
+ /// </summary>
+ private readonly IUserManager _userManager;
+
+ /// <summary>
+ /// The _installation manager
+ /// </summary>
+ private readonly IInstallationManager _installationManager;
+
+ /// <summary>
+ /// The _kernel
+ /// </summary>
+ private readonly IServerApplicationHost _appHost;
+
+ /// <summary>
+ /// The _task manager
+ /// </summary>
+ private readonly ITaskManager _taskManager;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="WebSocketEvents" /> class.
+ /// </summary>
+ /// <param name="serverManager">The server manager.</param>
+ /// <param name="logger">The logger.</param>
+ /// <param name="userManager">The user manager.</param>
+ public WebSocketEvents(IServerManager serverManager, IServerApplicationHost appHost, ILogger logger, IUserManager userManager, IInstallationManager installationManager, ITaskManager taskManager)
+ {
+ _serverManager = serverManager;
+ _logger = logger;
+ _userManager = userManager;
+ _installationManager = installationManager;
+ _appHost = appHost;
+ _taskManager = taskManager;
+ }
+
+ public void Run()
+ {
+ _userManager.UserDeleted += userManager_UserDeleted;
+ _userManager.UserUpdated += userManager_UserUpdated;
+
+ _appHost.HasPendingRestartChanged += kernel_HasPendingRestartChanged;
+
+ _installationManager.PluginUninstalled += InstallationManager_PluginUninstalled;
+ _installationManager.PackageInstalling += installationManager_PackageInstalling;
+ _installationManager.PackageInstallationCancelled += installationManager_PackageInstallationCancelled;
+ _installationManager.PackageInstallationCompleted += installationManager_PackageInstallationCompleted;
+ _installationManager.PackageInstallationFailed += installationManager_PackageInstallationFailed;
+
+ _taskManager.TaskExecuting += _taskManager_TaskExecuting;
+ _taskManager.TaskCompleted += _taskManager_TaskCompleted;
+ }
+
+ void _taskManager_TaskCompleted(object sender, GenericEventArgs<TaskResult> e)
+ {
+ _serverManager.SendWebSocketMessage("ScheduledTaskEnded", e.Argument);
+ }
+
+ void _taskManager_TaskExecuting(object sender, EventArgs e)
+ {
+ var task = (IScheduledTask)sender;
+ _serverManager.SendWebSocketMessage("ScheduledTaskStarted", task.Name);
+ }
+
+ /// <summary>
+ /// Installations the manager_ package installation failed.
+ /// </summary>
+ /// <param name="sender">The sender.</param>
+ /// <param name="e">The e.</param>
+ void installationManager_PackageInstallationFailed(object sender, GenericEventArgs<InstallationInfo> e)
+ {
+ _serverManager.SendWebSocketMessage("PackageInstallationFailed", e.Argument);
+ }
+
+ /// <summary>
+ /// Installations the manager_ package installation completed.
+ /// </summary>
+ /// <param name="sender">The sender.</param>
+ /// <param name="e">The e.</param>
+ void installationManager_PackageInstallationCompleted(object sender, GenericEventArgs<InstallationInfo> e)
+ {
+ _serverManager.SendWebSocketMessage("PackageInstallationCompleted", e.Argument);
+ }
+
+ /// <summary>
+ /// Installations the manager_ package installation cancelled.
+ /// </summary>
+ /// <param name="sender">The sender.</param>
+ /// <param name="e">The e.</param>
+ void installationManager_PackageInstallationCancelled(object sender, GenericEventArgs<InstallationInfo> e)
+ {
+ _serverManager.SendWebSocketMessage("PackageInstallationCancelled", e.Argument);
+ }
+
+ /// <summary>
+ /// Installations the manager_ package installing.
+ /// </summary>
+ /// <param name="sender">The sender.</param>
+ /// <param name="e">The e.</param>
+ void installationManager_PackageInstalling(object sender, GenericEventArgs<InstallationInfo> e)
+ {
+ _serverManager.SendWebSocketMessage("PackageInstalling", e.Argument);
+ }
+
+ /// <summary>
+ /// Installations the manager_ plugin uninstalled.
+ /// </summary>
+ /// <param name="sender">The sender.</param>
+ /// <param name="e">The e.</param>
+ void InstallationManager_PluginUninstalled(object sender, GenericEventArgs<IPlugin> e)
+ {
+ _serverManager.SendWebSocketMessage("PluginUninstalled", e.Argument.GetPluginInfo());
+ }
+
+ /// <summary>
+ /// Handles the HasPendingRestartChanged event of the kernel control.
+ /// </summary>
+ /// <param name="sender">The source of the event.</param>
+ /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
+ void kernel_HasPendingRestartChanged(object sender, EventArgs e)
+ {
+ _serverManager.SendWebSocketMessage("RestartRequired", _appHost.GetSystemInfo());
+ }
+
+ /// <summary>
+ /// Users the manager_ user updated.
+ /// </summary>
+ /// <param name="sender">The sender.</param>
+ /// <param name="e">The e.</param>
+ async void userManager_UserUpdated(object sender, GenericEventArgs<User> e)
+ {
+ var dto = await new UserDtoBuilder(_logger).GetUserDto(e.Argument).ConfigureAwait(false);
+
+ _serverManager.SendWebSocketMessage("UserUpdated", dto);
+ }
+
+ /// <summary>
+ /// Users the manager_ user deleted.
+ /// </summary>
+ /// <param name="sender">The sender.</param>
+ /// <param name="e">The e.</param>
+ void userManager_UserDeleted(object sender, GenericEventArgs<User> e)
+ {
+ _serverManager.SendWebSocketMessage("UserDeleted", e.Argument.Id.ToString("N"));
+ }
+
+ /// <summary>
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ /// </summary>
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ /// <summary>
+ /// Releases unmanaged and - optionally - managed resources.
+ /// </summary>
+ /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
+ protected virtual void Dispose(bool dispose)
+ {
+ if (dispose)
+ {
+ _userManager.UserDeleted -= userManager_UserDeleted;
+ _userManager.UserUpdated -= userManager_UserUpdated;
+
+ _installationManager.PluginUninstalled -= InstallationManager_PluginUninstalled;
+ _installationManager.PackageInstalling -= installationManager_PackageInstalling;
+ _installationManager.PackageInstallationCancelled -= installationManager_PackageInstallationCancelled;
+ _installationManager.PackageInstallationCompleted -= installationManager_PackageInstallationCompleted;
+ _installationManager.PackageInstallationFailed -= installationManager_PackageInstallationFailed;
+
+ _appHost.HasPendingRestartChanged -= kernel_HasPendingRestartChanged;
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index b2e60a401..34dc8ff52 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -64,12 +64,6 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\ServiceStack.Common.3.9.54\lib\net35\ServiceStack.Interfaces.dll</HintPath>
</Reference>
- <Reference Include="ServiceStack.OrmLite">
- <HintPath>..\packages\ServiceStack.OrmLite.Sqlite32.3.9.54\lib\net40\ServiceStack.OrmLite.dll</HintPath>
- </Reference>
- <Reference Include="ServiceStack.OrmLite.SqliteNET">
- <HintPath>..\packages\ServiceStack.OrmLite.Sqlite32.3.9.54\lib\net40\ServiceStack.OrmLite.SqliteNET.dll</HintPath>
- </Reference>
<Reference Include="ServiceStack.OrmLite.SqlServer, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\ServiceStack.OrmLite.SqlServer.3.9.43\lib\ServiceStack.OrmLite.SqlServer.dll</HintPath>
@@ -115,6 +109,10 @@
</Compile>
<Compile Include="BdInfo\BdInfoExaminer.cs" />
<Compile Include="Configuration\ServerConfigurationManager.cs" />
+ <Compile Include="EntryPoints\LibraryChangedNotifier.cs" />
+ <Compile Include="EntryPoints\LoadRegistrations.cs" />
+ <Compile Include="EntryPoints\RefreshUsersMetadata.cs" />
+ <Compile Include="EntryPoints\WebSocketEvents.cs" />
<Compile Include="HttpServer\HttpResultFactory.cs" />
<Compile Include="HttpServer\HttpServer.cs" />
<Compile Include="HttpServer\NativeWebSocket.cs" />
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteChapterRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteChapterRepository.cs
index cac612fc8..c472241e3 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteChapterRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteChapterRepository.cs
@@ -1,11 +1,9 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
using System;
using System.Collections.Generic;
using System.Data;
-using System.Data.SQLite;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
@@ -14,7 +12,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
public class SqliteChapterRepository
{
- private SQLiteConnection _connection;
+ private IDbConnection _connection;
private readonly ILogger _logger;
@@ -23,8 +21,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// </summary>
private readonly IApplicationPaths _appPaths;
- private SQLiteCommand _deleteChaptersCommand;
- private SQLiteCommand _saveChapterCommand;
+ private IDbCommand _deleteChaptersCommand;
+ private IDbCommand _saveChapterCommand;
/// <summary>
/// Initializes a new instance of the <see cref="SqliteItemRepository" /> class.
@@ -80,23 +78,18 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// </summary>
private void PrepareStatements()
{
- _deleteChaptersCommand = new SQLiteCommand
- {
- CommandText = "delete from chapters where ItemId=@ItemId"
- };
-
- _deleteChaptersCommand.Parameters.Add(new SQLiteParameter("@ItemId"));
-
- _saveChapterCommand = new SQLiteCommand
- {
- CommandText = "replace into chapters (ItemId, ChapterIndex, StartPositionTicks, Name, ImagePath) values (@ItemId, @ChapterIndex, @StartPositionTicks, @Name, @ImagePath)"
- };
-
- _saveChapterCommand.Parameters.Add(new SQLiteParameter("@ItemId"));
- _saveChapterCommand.Parameters.Add(new SQLiteParameter("@ChapterIndex"));
- _saveChapterCommand.Parameters.Add(new SQLiteParameter("@StartPositionTicks"));
- _saveChapterCommand.Parameters.Add(new SQLiteParameter("@Name"));
- _saveChapterCommand.Parameters.Add(new SQLiteParameter("@ImagePath"));
+ _deleteChaptersCommand = _connection.CreateCommand();
+ _deleteChaptersCommand.CommandText = "delete from chapters where ItemId=@ItemId";
+ _deleteChaptersCommand.Parameters.Add(_deleteChaptersCommand, "@ItemId");
+
+ _saveChapterCommand = _connection.CreateCommand();
+ _saveChapterCommand.CommandText = "replace into chapters (ItemId, ChapterIndex, StartPositionTicks, Name, ImagePath) values (@ItemId, @ChapterIndex, @StartPositionTicks, @Name, @ImagePath)";
+
+ _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@ItemId");
+ _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@ChapterIndex");
+ _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@StartPositionTicks");
+ _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@Name");
+ _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@ImagePath");
}
/// <summary>
@@ -116,7 +109,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
cmd.CommandText = "select StartPositionTicks,Name,ImagePath from Chapters where ItemId = @ItemId order by ChapterIndex asc";
- cmd.Parameters.Add("@ItemId", DbType.Guid).Value = id;
+ cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = id;
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
{
@@ -161,8 +154,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
cmd.CommandText = "select StartPositionTicks,Name,ImagePath from Chapters where ItemId = @ItemId and ChapterIndex=@ChapterIndex";
- cmd.Parameters.Add("@ItemId", DbType.Guid).Value = id;
- cmd.Parameters.Add("@ChapterIndex", DbType.Int32).Value = index;
+ cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = id;
+ cmd.Parameters.Add(cmd, "@ChapterIndex", DbType.Int32).Value = index;
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
{
@@ -215,16 +208,18 @@ namespace MediaBrowser.Server.Implementations.Persistence
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
- SQLiteTransaction transaction = null;
+ IDbTransaction transaction = null;
try
{
transaction = _connection.BeginTransaction();
// First delete chapters
- _deleteChaptersCommand.Parameters[0].Value = id;
+ _deleteChaptersCommand.GetParameter(0).Value = id;
+
_deleteChaptersCommand.Transaction = transaction;
- await _deleteChaptersCommand.ExecuteNonQueryAsync(cancellationToken);
+
+ _deleteChaptersCommand.ExecuteNonQuery();
var index = 0;
@@ -232,15 +227,15 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
cancellationToken.ThrowIfCancellationRequested();
- _saveChapterCommand.Parameters[0].Value = id;
- _saveChapterCommand.Parameters[1].Value = index;
- _saveChapterCommand.Parameters[2].Value = chapter.StartPositionTicks;
- _saveChapterCommand.Parameters[3].Value = chapter.Name;
- _saveChapterCommand.Parameters[4].Value = chapter.ImagePath;
+ _saveChapterCommand.GetParameter(0).Value = id;
+ _saveChapterCommand.GetParameter(1).Value = index;
+ _saveChapterCommand.GetParameter(2).Value = chapter.StartPositionTicks;
+ _saveChapterCommand.GetParameter(3).Value = chapter.Name;
+ _saveChapterCommand.GetParameter(4).Value = chapter.ImagePath;
_saveChapterCommand.Transaction = transaction;
- await _saveChapterCommand.ExecuteNonQueryAsync(cancellationToken);
+ _saveChapterCommand.ExecuteNonQuery();
index++;
}
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs
index 2b14e9b24..ead409598 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs
@@ -56,11 +56,40 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// </summary>
/// <param name="conn">The conn.</param>
/// <returns><c>true</c> if the specified conn is open; otherwise, <c>false</c>.</returns>
- public static bool IsOpen(this SQLiteConnection conn)
+ public static bool IsOpen(this IDbConnection conn)
{
return conn.State == ConnectionState.Open;
}
+ public static IDataParameter GetParameter(this IDbCommand cmd, int index)
+ {
+ return (IDataParameter)cmd.Parameters[index];
+ }
+
+ public static IDataParameter Add(this IDataParameterCollection paramCollection, IDbCommand cmd, string name, DbType type)
+ {
+ var param = cmd.CreateParameter();
+
+ param.ParameterName = name;
+ param.DbType = type;
+
+ paramCollection.Add(param);
+
+ return param;
+ }
+
+ public static IDataParameter Add(this IDataParameterCollection paramCollection, IDbCommand cmd, string name)
+ {
+ var param = cmd.CreateParameter();
+
+ param.ParameterName = name;
+
+ paramCollection.Add(param);
+
+ return param;
+ }
+
+
/// <summary>
/// Gets a stream from a DataReader at a given ordinal
/// </summary>
diff --git a/MediaBrowser.Server.Implementations/packages.config b/MediaBrowser.Server.Implementations/packages.config
index e13d18747..b3294492f 100644
--- a/MediaBrowser.Server.Implementations/packages.config
+++ b/MediaBrowser.Server.Implementations/packages.config
@@ -10,7 +10,6 @@
<package id="ServiceStack" version="3.9.54" targetFramework="net45" />
<package id="ServiceStack.Api.Swagger" version="3.9.54" targetFramework="net45" />
<package id="ServiceStack.Common" version="3.9.54" targetFramework="net45" />
- <package id="ServiceStack.OrmLite.Sqlite32" version="3.9.54" targetFramework="net45" />
<package id="ServiceStack.OrmLite.SqlServer" version="3.9.43" targetFramework="net45" />
<package id="ServiceStack.Redis" version="3.9.43" targetFramework="net45" />
<package id="ServiceStack.Text" version="3.9.54" targetFramework="net45" />