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

make channel access opt-in rather than opt out

Luke Pulverenti 10 жил өмнө
parent
commit
d8d5dd4873
72 өөрчлөгдсөн 399 нэмэгдсэн , 241 устгасан
  1. 8 5
      MediaBrowser.Api/ApiEntryPoint.cs
  2. 4 4
      MediaBrowser.Api/ConnectService.cs
  3. 1 1
      MediaBrowser.Api/Library/LibraryHelpers.cs
  4. 1 1
      MediaBrowser.Api/Library/LibraryStructureService.cs
  5. 2 2
      MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
  6. 1 1
      MediaBrowser.Api/Playback/Hls/MpegDashService.cs
  7. 5 0
      MediaBrowser.Api/Session/SessionsService.cs
  8. 2 0
      MediaBrowser.Api/StartupWizardService.cs
  9. 1 1
      MediaBrowser.Common.Implementations/BaseApplicationHost.cs
  10. 1 1
      MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs
  11. 22 2
      MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs
  12. 1 1
      MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
  13. 1 1
      MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
  14. 6 3
      MediaBrowser.Common.Implementations/Updates/InstallationManager.cs
  15. 28 0
      MediaBrowser.Common/IO/IFileSystem.cs
  16. 1 1
      MediaBrowser.Controller/Channels/Channel.cs
  17. 9 2
      MediaBrowser.Controller/Entities/BaseItem.cs
  18. 1 1
      MediaBrowser.Controller/Entities/User.cs
  19. 0 6
      MediaBrowser.Controller/IServerApplicationPaths.cs
  20. 6 1
      MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs
  21. 5 0
      MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
  22. 5 0
      MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
  23. 5 0
      MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs
  24. 5 7
      MediaBrowser.Controller/MediaEncoding/MediaStreamSelector.cs
  25. 10 0
      MediaBrowser.Controller/Session/ISessionController.cs
  26. 11 0
      MediaBrowser.Controller/Session/ISessionManager.cs
  27. 5 0
      MediaBrowser.Controller/Session/SessionInfo.cs
  28. 3 3
      MediaBrowser.Dlna/DlnaManager.cs
  29. 6 0
      MediaBrowser.Dlna/PlayTo/PlayToController.cs
  30. 1 1
      MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
  31. 2 2
      MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
  32. 8 0
      MediaBrowser.Model/Configuration/ServerConfiguration.cs
  33. 0 35
      MediaBrowser.Model/Configuration/UserConfiguration.cs
  34. 2 2
      MediaBrowser.Model/Connect/ConnectAuthorization.cs
  35. 2 2
      MediaBrowser.Model/Connect/ConnectAuthorizationRequest.cs
  36. 3 1
      MediaBrowser.Model/Users/UserPolicy.cs
  37. 1 1
      MediaBrowser.Providers/Manager/ImageSaver.cs
  38. 1 1
      MediaBrowser.Providers/Manager/ItemImageProvider.cs
  39. 1 1
      MediaBrowser.Providers/Subtitles/SubtitleManager.cs
  40. 1 1
      MediaBrowser.Providers/TV/TvdbSeriesProvider.cs
  41. 2 2
      MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs
  42. 2 2
      MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
  43. 1 1
      MediaBrowser.Server.Implementations/Collections/CollectionManager.cs
  44. 4 3
      MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
  45. 6 3
      MediaBrowser.Server.Implementations/Devices/DeviceRepository.cs
  46. 16 25
      MediaBrowser.Server.Implementations/EntryPoints/ServerEventNotifier.cs
  47. 1 1
      MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
  48. 2 2
      MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
  49. 1 1
      MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs
  50. 1 1
      MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs
  51. 0 25
      MediaBrowser.Server.Implementations/HttpServer/SocketSharp/RequestMono.cs
  52. 23 6
      MediaBrowser.Server.Implementations/Library/LibraryManager.cs
  53. 54 18
      MediaBrowser.Server.Implementations/Library/UserManager.cs
  54. 1 0
      MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json
  55. 1 0
      MediaBrowser.Server.Implementations/Localization/Server/server.json
  56. 1 1
      MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs
  57. 0 13
      MediaBrowser.Server.Implementations/ServerApplicationPaths.cs
  58. 6 0
      MediaBrowser.Server.Implementations/Session/HttpSessionController.cs
  59. 21 0
      MediaBrowser.Server.Implementations/Session/SessionManager.cs
  60. 23 13
      MediaBrowser.Server.Implementations/Session/WebSocketController.cs
  61. 5 2
      MediaBrowser.Server.Implementations/Sync/SyncManager.cs
  62. 1 1
      MediaBrowser.Server.Implementations/Sync/SyncScheduledTask.cs
  63. 6 6
      MediaBrowser.Server.Startup.Common/ApplicationHost.cs
  64. 4 4
      MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloader.cs
  65. 7 4
      MediaBrowser.Server.Startup.Common/Migrations/DeleteDlnaProfiles.cs
  66. 6 3
      MediaBrowser.Server.Startup.Common/Migrations/DeprecatePlugins.cs
  67. 6 3
      MediaBrowser.Server.Startup.Common/Migrations/MigrateUserFolders.cs
  68. 1 1
      MediaBrowser.ServerApplication/MainStartup.cs
  69. 5 3
      MediaBrowser.ServerApplication/Native/Autorun.cs
  70. 10 2
      MediaBrowser.ServerApplication/Native/WindowsApp.cs
  71. 2 2
      MediaBrowser.WebDashboard/Api/DashboardService.cs
  72. 2 2
      SharedVersion.cs

+ 8 - 5
MediaBrowser.Api/ApiEntryPoint.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Api.Playback;
 using MediaBrowser.Api.Playback;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Plugins;
 using MediaBrowser.Controller.Plugins;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Controller.Session;
@@ -39,6 +40,7 @@ namespace MediaBrowser.Api
         private readonly IServerConfigurationManager _config;
         private readonly IServerConfigurationManager _config;
 
 
         private readonly ISessionManager _sessionManager;
         private readonly ISessionManager _sessionManager;
+        private readonly IFileSystem _fileSystem;
 
 
         public readonly SemaphoreSlim TranscodingStartLock = new SemaphoreSlim(1, 1);
         public readonly SemaphoreSlim TranscodingStartLock = new SemaphoreSlim(1, 1);
 
 
@@ -48,11 +50,12 @@ namespace MediaBrowser.Api
         /// <param name="logger">The logger.</param>
         /// <param name="logger">The logger.</param>
         /// <param name="sessionManager">The session manager.</param>
         /// <param name="sessionManager">The session manager.</param>
         /// <param name="config">The configuration.</param>
         /// <param name="config">The configuration.</param>
-        public ApiEntryPoint(ILogger logger, ISessionManager sessionManager, IServerConfigurationManager config)
+        public ApiEntryPoint(ILogger logger, ISessionManager sessionManager, IServerConfigurationManager config, IFileSystem fileSystem)
         {
         {
             Logger = logger;
             Logger = logger;
             _sessionManager = sessionManager;
             _sessionManager = sessionManager;
             _config = config;
             _config = config;
+            _fileSystem = fileSystem;
 
 
             Instance = this;
             Instance = this;
         }
         }
@@ -91,7 +94,7 @@ namespace MediaBrowser.Api
             foreach (var file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)
             foreach (var file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)
                 .ToList())
                 .ToList())
             {
             {
-                File.Delete(file);
+                _fileSystem.DeleteFile(file);
             }
             }
         }
         }
 
 
@@ -462,7 +465,7 @@ namespace MediaBrowser.Api
         /// <param name="outputFilePath">The output file path.</param>
         /// <param name="outputFilePath">The output file path.</param>
         private void DeleteProgressivePartialStreamFiles(string outputFilePath)
         private void DeleteProgressivePartialStreamFiles(string outputFilePath)
         {
         {
-            File.Delete(outputFilePath);
+            _fileSystem.DeleteFile(outputFilePath);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -479,13 +482,13 @@ namespace MediaBrowser.Api
                 .ToList();
                 .ToList();
 
 
             Exception e = null;
             Exception e = null;
-
+            
             foreach (var file in filesToDelete)
             foreach (var file in filesToDelete)
             {
             {
                 try
                 try
                 {
                 {
                     Logger.Info("Deleting HLS file {0}", file);
                     Logger.Info("Deleting HLS file {0}", file);
-                    File.Delete(file);
+                    _fileSystem.DeleteFile(file);
                 }
                 }
                 catch (DirectoryNotFoundException)
                 catch (DirectoryNotFoundException)
                 {
                 {

+ 4 - 4
MediaBrowser.Api/ConnectService.cs

@@ -42,8 +42,8 @@ namespace MediaBrowser.Api
         [ApiMember(Name = "ExcludeLibraries", Description = "ExcludeLibraries", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
         [ApiMember(Name = "ExcludeLibraries", Description = "ExcludeLibraries", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
         public string ExcludedLibraries { get; set; }
         public string ExcludedLibraries { get; set; }
 
 
-        [ApiMember(Name = "ExcludedChannels", Description = "ExcludedChannels", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
-        public string ExcludedChannels { get; set; }
+        [ApiMember(Name = "EnabledChannels", Description = "EnabledChannels", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
+        public string EnabledChannels { get; set; }
 
 
         [ApiMember(Name = "EnableLiveTv", Description = "EnableLiveTv", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
         [ApiMember(Name = "EnableLiveTv", Description = "EnableLiveTv", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
         public bool EnableLiveTv { get; set; }
         public bool EnableLiveTv { get; set; }
@@ -96,7 +96,7 @@ namespace MediaBrowser.Api
                 .Where(i => !string.IsNullOrWhiteSpace(i))
                 .Where(i => !string.IsNullOrWhiteSpace(i))
                 .ToArray();
                 .ToArray();
 
 
-            var excludedChannels = (request.ExcludedChannels ?? string.Empty)
+            var enabledChannels = (request.EnabledChannels ?? string.Empty)
                 .Split(',')
                 .Split(',')
                 .Where(i => !string.IsNullOrWhiteSpace(i))
                 .Where(i => !string.IsNullOrWhiteSpace(i))
                 .ToArray();
                 .ToArray();
@@ -106,7 +106,7 @@ namespace MediaBrowser.Api
                 ConnectUserName = request.ConnectUsername,
                 ConnectUserName = request.ConnectUsername,
                 SendingUserId = request.SendingUserId,
                 SendingUserId = request.SendingUserId,
                 ExcludedLibraries = excludeLibraries,
                 ExcludedLibraries = excludeLibraries,
-                ExcludedChannels = excludedChannels,
+                EnabledChannels = enabledChannels,
                 EnableLiveTv = request.EnableLiveTv
                 EnableLiveTv = request.EnableLiveTv
             });
             });
         }
         }

+ 1 - 1
MediaBrowser.Api/Library/LibraryHelpers.cs

@@ -42,7 +42,7 @@ namespace MediaBrowser.Api.Library
 
 
             if (!string.IsNullOrEmpty(shortcut))
             if (!string.IsNullOrEmpty(shortcut))
             {
             {
-                File.Delete(shortcut);
+                fileSystem.DeleteFile(shortcut);
             }
             }
         }
         }
 
 

+ 1 - 1
MediaBrowser.Api/Library/LibraryStructureService.cs

@@ -348,7 +348,7 @@ namespace MediaBrowser.Api.Library
 
 
             try
             try
             {
             {
-                Directory.Delete(path, true);
+                _fileSystem.DeleteDirectory(path, true);
 
 
                 // Need to add a delay here or directory watchers may still pick up the changes
                 // Need to add a delay here or directory watchers may still pick up the changes
                 var delayTask = Task.Delay(1000);
                 var delayTask = Task.Delay(1000);

+ 2 - 2
MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs

@@ -210,10 +210,10 @@ namespace MediaBrowser.Api.Playback.Hls
             {
             {
                 return;
                 return;
             }
             }
-
+            
             try
             try
             {
             {
-                File.Delete(file.FullName);
+                FileSystem.DeleteFile(file.FullName);
             }
             }
             catch (IOException ex)
             catch (IOException ex)
             {
             {

+ 1 - 1
MediaBrowser.Api/Playback/Hls/MpegDashService.cs

@@ -489,7 +489,7 @@ namespace MediaBrowser.Api.Playback.Hls
             {
             {
                 try
                 try
                 {
                 {
-                    File.Delete(file.FullName);
+                    FileSystem.DeleteFile(file.FullName);
                 }
                 }
                 catch (IOException ex)
                 catch (IOException ex)
                 {
                 {

+ 5 - 0
MediaBrowser.Api/Session/SessionsService.cs

@@ -245,6 +245,11 @@ namespace MediaBrowser.Api.Session
 
 
         [ApiMember(Name = "SupportsUniqueIdentifier", Description = "Determines whether the device supports a unique identifier.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
         [ApiMember(Name = "SupportsUniqueIdentifier", Description = "Determines whether the device supports a unique identifier.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
         public bool SupportsUniqueIdentifier { get; set; }
         public bool SupportsUniqueIdentifier { get; set; }
+
+        public PostCapabilities()
+        {
+            SupportsUniqueIdentifier = true;
+        }
     }
     }
 
 
     [Route("/Sessions/Capabilities/Full", "POST", Summary = "Updates capabilities for a device")]
     [Route("/Sessions/Capabilities/Full", "POST", Summary = "Updates capabilities for a device")]

+ 2 - 0
MediaBrowser.Api/StartupWizardService.cs

@@ -62,6 +62,8 @@ namespace MediaBrowser.Api
         {
         {
             _config.Configuration.IsStartupWizardCompleted = true;
             _config.Configuration.IsStartupWizardCompleted = true;
             _config.Configuration.EnableLocalizedGuids = true;
             _config.Configuration.EnableLocalizedGuids = true;
+            _config.Configuration.StoreArtistsInMetadata = true;
+            _config.Configuration.EnableLibraryMetadataSubFolder = true;
             _config.SaveConfiguration();
             _config.SaveConfiguration();
         }
         }
 
 

+ 1 - 1
MediaBrowser.Common.Implementations/BaseApplicationHost.cs

@@ -475,7 +475,7 @@ namespace MediaBrowser.Common.Implementations
 			SecurityManager = new PluginSecurityManager(this, HttpClient, JsonSerializer, ApplicationPaths, LogManager);
 			SecurityManager = new PluginSecurityManager(this, HttpClient, JsonSerializer, ApplicationPaths, LogManager);
 			RegisterSingleInstance(SecurityManager);
 			RegisterSingleInstance(SecurityManager);
 
 
-			InstallationManager = new InstallationManager(Logger, this, ApplicationPaths, HttpClient, JsonSerializer, SecurityManager, ConfigurationManager);
+			InstallationManager = new InstallationManager(Logger, this, ApplicationPaths, HttpClient, JsonSerializer, SecurityManager, ConfigurationManager, FileSystemManager);
 			RegisterSingleInstance(InstallationManager);
 			RegisterSingleInstance(InstallationManager);
 
 
 			ZipClient = new ZipClient();
 			ZipClient = new ZipClient();

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

@@ -690,7 +690,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
         {
         {
             try
             try
             {
             {
-                File.Delete(file);
+                _fileSystem.DeleteFile(file);
             }
             }
             catch (IOException)
             catch (IOException)
             {
             {

+ 22 - 2
MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs

@@ -270,8 +270,8 @@ namespace MediaBrowser.Common.Implementations.IO
             File.Copy(temp1, file2, true);
             File.Copy(temp1, file2, true);
             File.Copy(temp2, file1, true);
             File.Copy(temp2, file1, true);
 
 
-            File.Delete(temp1);
-            File.Delete(temp2);
+            DeleteFile(temp1);
+            DeleteFile(temp2);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -409,5 +409,25 @@ namespace MediaBrowser.Common.Implementations.IO
 
 
             //return Path.IsPathRooted(path);
             //return Path.IsPathRooted(path);
         }
         }
+
+        public void DeleteFile(string path, bool sendToRecycleBin)
+        {
+            File.Delete(path);
+        }
+
+        public void DeleteDirectory(string path, bool recursive, bool sendToRecycleBin)
+        {
+            Directory.Delete(path, recursive);
+        }
+
+        public void DeleteFile(string path)
+        {
+            DeleteFile(path, false);
+        }
+
+        public void DeleteDirectory(string path, bool recursive)
+        {
+            DeleteDirectory(path, recursive, false);
+        }
     }
     }
 }
 }

+ 1 - 1
MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs

@@ -125,7 +125,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
         {
         {
             try
             try
             {
             {
-                File.Delete(path);
+                _fileSystem.DeleteFile(path);
             }
             }
             catch (IOException ex)
             catch (IOException ex)
             {
             {

+ 1 - 1
MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs

@@ -76,7 +76,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
 
 
                 cancellationToken.ThrowIfCancellationRequested();
                 cancellationToken.ThrowIfCancellationRequested();
 
 
-                File.Delete(file.FullName);
+                _fileSystem.DeleteFile(file.FullName);
 
 
                 index++;
                 index++;
             }
             }

+ 6 - 3
MediaBrowser.Common.Implementations/Updates/InstallationManager.cs

@@ -1,6 +1,7 @@
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Events;
 using MediaBrowser.Common.Events;
 using MediaBrowser.Common.Implementations.Security;
 using MediaBrowser.Common.Implementations.Security;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Plugins;
 using MediaBrowser.Common.Plugins;
 using MediaBrowser.Common.Progress;
 using MediaBrowser.Common.Progress;
@@ -106,6 +107,7 @@ namespace MediaBrowser.Common.Implementations.Updates
         private readonly IJsonSerializer _jsonSerializer;
         private readonly IJsonSerializer _jsonSerializer;
         private readonly ISecurityManager _securityManager;
         private readonly ISecurityManager _securityManager;
         private readonly IConfigurationManager _config;
         private readonly IConfigurationManager _config;
+        private readonly IFileSystem _fileSystem;
 
 
         /// <summary>
         /// <summary>
         /// Gets the application host.
         /// Gets the application host.
@@ -113,7 +115,7 @@ namespace MediaBrowser.Common.Implementations.Updates
         /// <value>The application host.</value>
         /// <value>The application host.</value>
         private readonly IApplicationHost _applicationHost;
         private readonly IApplicationHost _applicationHost;
 
 
-        public InstallationManager(ILogger logger, IApplicationHost appHost, IApplicationPaths appPaths, IHttpClient httpClient, IJsonSerializer jsonSerializer, ISecurityManager securityManager, IConfigurationManager config)
+        public InstallationManager(ILogger logger, IApplicationHost appHost, IApplicationPaths appPaths, IHttpClient httpClient, IJsonSerializer jsonSerializer, ISecurityManager securityManager, IConfigurationManager config, IFileSystem fileSystem)
         {
         {
             if (logger == null)
             if (logger == null)
             {
             {
@@ -129,6 +131,7 @@ namespace MediaBrowser.Common.Implementations.Updates
             _jsonSerializer = jsonSerializer;
             _jsonSerializer = jsonSerializer;
             _securityManager = securityManager;
             _securityManager = securityManager;
             _config = config;
             _config = config;
+            _fileSystem = fileSystem;
             _logger = logger;
             _logger = logger;
         }
         }
 
 
@@ -570,7 +573,7 @@ namespace MediaBrowser.Common.Implementations.Updates
 
 
             try
             try
             {
             {
-                File.Delete(tempFile);
+                _fileSystem.DeleteFile(tempFile);
             }
             }
             catch (IOException e)
             catch (IOException e)
             {
             {
@@ -591,7 +594,7 @@ namespace MediaBrowser.Common.Implementations.Updates
             // Remove it the quick way for now
             // Remove it the quick way for now
             _applicationHost.RemovePlugin(plugin);
             _applicationHost.RemovePlugin(plugin);
 
 
-            File.Delete(plugin.AssemblyFilePath);
+            _fileSystem.DeleteFile(plugin.AssemblyFilePath);
 
 
             OnPluginUninstalled(plugin);
             OnPluginUninstalled(plugin);
 
 

+ 28 - 0
MediaBrowser.Common/IO/IFileSystem.cs

@@ -133,5 +133,33 @@ namespace MediaBrowser.Common.IO
         /// <param name="path">The path.</param>
         /// <param name="path">The path.</param>
         /// <returns><c>true</c> if [is path file] [the specified path]; otherwise, <c>false</c>.</returns>
         /// <returns><c>true</c> if [is path file] [the specified path]; otherwise, <c>false</c>.</returns>
         bool IsPathFile(string path);
         bool IsPathFile(string path);
+
+        /// <summary>
+        /// Deletes the file.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="sendToRecycleBin">if set to <c>true</c> [send to recycle bin].</param>
+        void DeleteFile(string path, bool sendToRecycleBin);
+
+        /// <summary>
+        /// Deletes the directory.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="recursive">if set to <c>true</c> [recursive].</param>
+        /// <param name="sendToRecycleBin">if set to <c>true</c> [send to recycle bin].</param>
+        void DeleteDirectory(string path, bool recursive, bool sendToRecycleBin);
+
+        /// <summary>
+        /// Deletes the file.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        void DeleteFile(string path);
+
+        /// <summary>
+        /// Deletes the directory.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="recursive">if set to <c>true</c> [recursive].</param>
+        void DeleteDirectory(string path, bool recursive);
     }
     }
 }
 }

+ 1 - 1
MediaBrowser.Controller/Channels/Channel.cs

@@ -14,7 +14,7 @@ namespace MediaBrowser.Controller.Channels
 
 
         public override bool IsVisible(User user)
         public override bool IsVisible(User user)
         {
         {
-            if (user.Policy.BlockedChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
+            if (!user.Policy.EnableAllChannels && !user.Policy.EnabledChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
             {
             {
                 return false;
                 return false;
             }
             }

+ 9 - 2
MediaBrowser.Controller/Entities/BaseItem.cs

@@ -379,7 +379,14 @@ namespace MediaBrowser.Controller.Entities
 
 
         public string GetInternalMetadataPath()
         public string GetInternalMetadataPath()
         {
         {
-            return GetInternalMetadataPath(ConfigurationManager.ApplicationPaths.InternalMetadataPath);
+            var basePath = ConfigurationManager.ApplicationPaths.InternalMetadataPath;
+
+            if (ConfigurationManager.Configuration.EnableLibraryMetadataSubFolder)
+            {
+                basePath = System.IO.Path.Combine(basePath, "library");
+            }
+
+            return GetInternalMetadataPath(basePath);
         }
         }
 
 
         protected virtual string GetInternalMetadataPath(string basePath)
         protected virtual string GetInternalMetadataPath(string basePath)
@@ -1458,7 +1465,7 @@ namespace MediaBrowser.Controller.Entities
                     currentFile.Attributes &= ~FileAttributes.Hidden;
                     currentFile.Attributes &= ~FileAttributes.Hidden;
                 }
                 }
 
 
-                currentFile.Delete();
+                FileSystem.DeleteFile(currentFile.FullName);
             }
             }
 
 
             return UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None);
             return UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None);

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

@@ -177,7 +177,7 @@ namespace MediaBrowser.Controller.Entities
                 // Exceptions will be thrown if these paths already exist
                 // Exceptions will be thrown if these paths already exist
                 if (Directory.Exists(newConfigDirectory))
                 if (Directory.Exists(newConfigDirectory))
                 {
                 {
-                    Directory.Delete(newConfigDirectory, true);
+                    FileSystem.DeleteDirectory(newConfigDirectory, true);
                 }
                 }
 
 
                 if (Directory.Exists(oldConfigurationDirectory))
                 if (Directory.Exists(oldConfigurationDirectory))

+ 0 - 6
MediaBrowser.Controller/IServerApplicationPaths.cs

@@ -59,12 +59,6 @@ namespace MediaBrowser.Controller
         /// <value>The game genre path.</value>
         /// <value>The game genre path.</value>
         string GameGenrePath { get; }
         string GameGenrePath { get; }
 
 
-        /// <summary>
-        /// Gets the artists path.
-        /// </summary>
-        /// <value>The artists path.</value>
-        string ArtistsPath { get; }
-
         /// <summary>
         /// <summary>
         /// Gets the path to the Studio directory
         /// Gets the path to the Studio directory
         /// </summary>
         /// </summary>

+ 6 - 1
MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs

@@ -1,8 +1,8 @@
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
-using System.Linq;
 using MediaBrowser.Model.Users;
 using MediaBrowser.Model.Users;
+using System.Linq;
 
 
 namespace MediaBrowser.Controller.LiveTv
 namespace MediaBrowser.Controller.LiveTv
 {
 {
@@ -83,5 +83,10 @@ namespace MediaBrowser.Controller.LiveTv
         {
         {
             return config.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram);
             return config.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram);
         }
         }
+
+        protected override string GetInternalMetadataPath(string basePath)
+        {
+            return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N"));
+        }
     }
     }
 }
 }

+ 5 - 0
MediaBrowser.Controller/LiveTv/LiveTvChannel.cs

@@ -145,5 +145,10 @@ namespace MediaBrowser.Controller.LiveTv
 
 
             return list;
             return list;
         }
         }
+
+        protected override string GetInternalMetadataPath(string basePath)
+        {
+            return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N"), "metadata");
+        }
     }
     }
 }
 }

+ 5 - 0
MediaBrowser.Controller/LiveTv/LiveTvProgram.cs

@@ -204,5 +204,10 @@ namespace MediaBrowser.Controller.LiveTv
         {
         {
             return config.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram);
             return config.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram);
         }
         }
+
+        protected override string GetInternalMetadataPath(string basePath)
+        {
+            return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N"));
+        }
     }
     }
 }
 }

+ 5 - 0
MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs

@@ -83,5 +83,10 @@ namespace MediaBrowser.Controller.LiveTv
         {
         {
             return config.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram);
             return config.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram);
         }
         }
+
+        protected override string GetInternalMetadataPath(string basePath)
+        {
+            return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N"));
+        }
     }
     }
 }
 }

+ 5 - 7
MediaBrowser.Controller/MediaEncoding/MediaStreamSelector.cs

@@ -38,7 +38,8 @@ namespace MediaBrowser.Controller.MediaEncoding
             SubtitlePlaybackMode mode,
             SubtitlePlaybackMode mode,
             string audioTrackLanguage)
             string audioTrackLanguage)
         {
         {
-            streams = GetSortedStreams(streams, MediaStreamType.Subtitle, preferredLanguages).ToList();
+            streams = GetSortedStreams(streams, MediaStreamType.Subtitle, preferredLanguages)
+                .ToList();
 
 
             var full = streams.Where(s => !s.IsForced);
             var full = streams.Where(s => !s.IsForced);
 
 
@@ -81,11 +82,9 @@ namespace MediaBrowser.Controller.MediaEncoding
 
 
         private static IEnumerable<MediaStream> GetSortedStreams(IEnumerable<MediaStream> streams, MediaStreamType type, List<string> languagePreferences)
         private static IEnumerable<MediaStream> GetSortedStreams(IEnumerable<MediaStream> streams, MediaStreamType type, List<string> languagePreferences)
         {
         {
-            var orderStreams = streams
-                .Where(i => i.Type == type);
-
             // Give some preferance to external text subs for better performance
             // Give some preferance to external text subs for better performance
-            return orderStreams.OrderBy(i =>
+            return streams.Where(i => i.Type == type)
+                .OrderBy(i =>
             {
             {
                 var index = languagePreferences.FindIndex(l => string.Equals(i.Language, l, StringComparison.OrdinalIgnoreCase));
                 var index = languagePreferences.FindIndex(l => string.Equals(i.Language, l, StringComparison.OrdinalIgnoreCase));
 
 
@@ -94,8 +93,7 @@ namespace MediaBrowser.Controller.MediaEncoding
                  .ThenBy(i => i.IsDefault)
                  .ThenBy(i => i.IsDefault)
                  .ThenBy(i => i.IsTextSubtitleStream)
                  .ThenBy(i => i.IsTextSubtitleStream)
                  .ThenBy(i => i.IsExternal)
                  .ThenBy(i => i.IsExternal)
-                 .ThenBy(i => i.Index)
-                 .ToList();
+                 .ThenBy(i => i.Index);
         }
         }
     }
     }
 }
 }

+ 10 - 0
MediaBrowser.Controller/Session/ISessionController.cs

@@ -105,5 +105,15 @@ namespace MediaBrowser.Controller.Session
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         Task SendServerRestartNotification(CancellationToken cancellationToken);
         Task SendServerRestartNotification(CancellationToken cancellationToken);
+
+        /// <summary>
+        /// Sends the message.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="name">The name.</param>
+        /// <param name="data">The data.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task.</returns>
+        Task SendMessage<T>(string name, T data, CancellationToken cancellationToken);
     }
     }
 }
 }

+ 11 - 0
MediaBrowser.Controller/Session/ISessionManager.cs

@@ -170,6 +170,17 @@ namespace MediaBrowser.Controller.Session
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         Task SendPlaystateCommand(string controllingSessionId, string sessionId, PlaystateRequest command, CancellationToken cancellationToken);
         Task SendPlaystateCommand(string controllingSessionId, string sessionId, PlaystateRequest command, CancellationToken cancellationToken);
 
 
+        /// <summary>
+        /// Sends the message to user sessions.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="userId">The user identifier.</param>
+        /// <param name="name">The name.</param>
+        /// <param name="data">The data.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task.</returns>
+        Task SendMessageToUserSessions<T>(string userId, string name, T data, CancellationToken cancellationToken);
+        
         /// <summary>
         /// <summary>
         /// Sends the restart required message.
         /// Sends the restart required message.
         /// </summary>
         /// </summary>

+ 5 - 0
MediaBrowser.Controller/Session/SessionInfo.cs

@@ -160,6 +160,11 @@ namespace MediaBrowser.Controller.Session
             }
             }
         }
         }
 
 
+        public bool ContainsUser(string userId)
+        {
+            return ContainsUser(new Guid(userId));
+        }
+
         public bool ContainsUser(Guid userId)
         public bool ContainsUser(Guid userId)
         {
         {
             return (UserId ?? Guid.Empty) == userId || AdditionalUsers.Any(i => userId == new Guid(i.UserId));
             return (UserId ?? Guid.Empty) == userId || AdditionalUsers.Any(i => userId == new Guid(i.UserId));

+ 3 - 3
MediaBrowser.Dlna/DlnaManager.cs

@@ -393,7 +393,7 @@ namespace MediaBrowser.Dlna
                 throw new ArgumentException("System profiles cannot be deleted.");
                 throw new ArgumentException("System profiles cannot be deleted.");
             }
             }
 
 
-            File.Delete(info.Path);
+            _fileSystem.DeleteFile(info.Path);
         }
         }
 
 
         public void CreateProfile(DeviceProfile profile)
         public void CreateProfile(DeviceProfile profile)
@@ -432,9 +432,9 @@ namespace MediaBrowser.Dlna
             if (!string.Equals(path, current.Path, StringComparison.Ordinal) &&
             if (!string.Equals(path, current.Path, StringComparison.Ordinal) &&
                 current.Info.Type != DeviceProfileType.System)
                 current.Info.Type != DeviceProfileType.System)
             {
             {
-                File.Delete(current.Path);
+                _fileSystem.DeleteFile(current.Path);
             }
             }
-
+            
             _xmlSerializer.SerializeToFile(profile, path);
             _xmlSerializer.SerializeToFile(profile, path);
         }
         }
 
 

+ 6 - 0
MediaBrowser.Dlna/PlayTo/PlayToController.cs

@@ -899,5 +899,11 @@ namespace MediaBrowser.Dlna.PlayTo
                 return request;
                 return request;
             }
             }
         }
         }
+
+        public Task SendMessage<T>(string name, T data, CancellationToken cancellationToken)
+        {
+            // Not supported or needed right now
+            return Task.FromResult(true);
+        }
     }
     }
 }
 }

+ 1 - 1
MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs

@@ -248,7 +248,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
 
         protected virtual void DeleteFiles(EncodingJob job)
         protected virtual void DeleteFiles(EncodingJob job)
         {
         {
-            File.Delete(job.OutputFilePath);
+            FileSystem.DeleteFile(job.OutputFilePath);
         }
         }
 
 
         private void OnTranscodeBeginning(EncodingJob job)
         private void OnTranscodeBeginning(EncodingJob job)

+ 2 - 2
MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs

@@ -459,7 +459,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
                     try
                     try
                     {
                     {
                         _logger.Info("Deleting converted subtitle due to failure: ", outputPath);
                         _logger.Info("Deleting converted subtitle due to failure: ", outputPath);
-                        File.Delete(outputPath);
+                        _fileSystem.DeleteFile(outputPath);
                     }
                     }
                     catch (IOException ex)
                     catch (IOException ex)
                     {
                     {
@@ -608,7 +608,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
                 try
                 try
                 {
                 {
                     _logger.Info("Deleting extracted subtitle due to failure: {0}", outputPath);
                     _logger.Info("Deleting extracted subtitle due to failure: {0}", outputPath);
-                    File.Delete(outputPath);
+                    _fileSystem.DeleteFile(outputPath);
                 }
                 }
                 catch (FileNotFoundException)
                 catch (FileNotFoundException)
                 {
                 {

+ 8 - 0
MediaBrowser.Model/Configuration/ServerConfiguration.cs

@@ -73,6 +73,12 @@ namespace MediaBrowser.Model.Configuration
         /// </summary>
         /// </summary>
         /// <value><c>true</c> if [enable localized guids]; otherwise, <c>false</c>.</value>
         /// <value><c>true</c> if [enable localized guids]; otherwise, <c>false</c>.</value>
         public bool EnableLocalizedGuids { get; set; }
         public bool EnableLocalizedGuids { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether [enable library metadata sub folder].
+        /// </summary>
+        /// <value><c>true</c> if [enable library metadata sub folder]; otherwise, <c>false</c>.</value>
+        public bool EnableLibraryMetadataSubFolder { get; set; }
         
         
         /// <summary>
         /// <summary>
         /// Gets or sets the preferred metadata language.
         /// Gets or sets the preferred metadata language.
@@ -150,6 +156,8 @@ namespace MediaBrowser.Model.Configuration
         public bool EnableTvDbUpdates { get; set; }
         public bool EnableTvDbUpdates { get; set; }
         public bool EnableTmdbUpdates { get; set; }
         public bool EnableTmdbUpdates { get; set; }
 
 
+        public bool StoreArtistsInMetadata { get; set; }
+
         public bool EnableFanArtUpdates { get; set; }
         public bool EnableFanArtUpdates { get; set; }
         public string FanartApiKey { get; set; }
         public string FanartApiKey { get; set; }
 
 

+ 0 - 35
MediaBrowser.Model/Configuration/UserConfiguration.cs

@@ -6,12 +6,6 @@ namespace MediaBrowser.Model.Configuration
     /// </summary>
     /// </summary>
     public class UserConfiguration
     public class UserConfiguration
     {
     {
-        /// <summary>
-        /// Gets or sets the max parental rating.
-        /// </summary>
-        /// <value>The max parental rating.</value>
-        public int? MaxParentalRating { get; set; }
-
         /// <summary>
         /// <summary>
         /// Gets or sets a value indicating whether this instance is administrator.
         /// Gets or sets a value indicating whether this instance is administrator.
         /// </summary>
         /// </summary>
@@ -36,22 +30,8 @@ namespace MediaBrowser.Model.Configuration
         /// <value>The subtitle language preference.</value>
         /// <value>The subtitle language preference.</value>
         public string SubtitleLanguagePreference { get; set; }
         public string SubtitleLanguagePreference { get; set; }
 
 
-        /// <summary>
-        /// Gets or sets a value indicating whether this instance is hidden.
-        /// </summary>
-        /// <value><c>true</c> if this instance is hidden; otherwise, <c>false</c>.</value>
-        public bool IsHidden { get; set; }
-
-        /// <summary>
-        /// Gets or sets a value indicating whether this instance is disabled.
-        /// </summary>
-        /// <value><c>true</c> if this instance is disabled; otherwise, <c>false</c>.</value>
-        public bool IsDisabled { get; set; }
-
         public bool DisplayMissingEpisodes { get; set; }
         public bool DisplayMissingEpisodes { get; set; }
         public bool DisplayUnairedEpisodes { get; set; }
         public bool DisplayUnairedEpisodes { get; set; }
-        public bool EnableRemoteControlOfOtherUsers { get; set; }
-        public bool EnableSharedDeviceControl { get; set; }
 
 
         public bool EnableLiveTvManagement { get; set; }
         public bool EnableLiveTvManagement { get; set; }
         public bool EnableLiveTvAccess { get; set; }
         public bool EnableLiveTvAccess { get; set; }
@@ -61,9 +41,6 @@ namespace MediaBrowser.Model.Configuration
 
 
         public bool GroupMoviesIntoBoxSets { get; set; }
         public bool GroupMoviesIntoBoxSets { get; set; }
 
 
-        public string[] BlockedMediaFolders { get; set; }
-        public string[] BlockedChannels { get; set; }
-
         public string[] DisplayChannelsWithinViews { get; set; }
         public string[] DisplayChannelsWithinViews { get; set; }
 
 
         public string[] ExcludeFoldersFromGrouping { get; set; }
         public string[] ExcludeFoldersFromGrouping { get; set; }
@@ -82,12 +59,7 @@ namespace MediaBrowser.Model.Configuration
 
 
         public bool EnableCinemaMode { get; set; }
         public bool EnableCinemaMode { get; set; }
 
 
-        public AccessSchedule[] AccessSchedules { get; set; }
-
-        public bool EnableUserPreferenceAccess { get; set; }
-
         public string[] LatestItemsExcludes { get; set; }
         public string[] LatestItemsExcludes { get; set; }
-        public string[] BlockedTags { get; set; }
 
 
         public bool HasMigratedToPolicy { get; set; }
         public bool HasMigratedToPolicy { get; set; }
 
 
@@ -100,14 +72,10 @@ namespace MediaBrowser.Model.Configuration
             EnableLiveTvManagement = true;
             EnableLiveTvManagement = true;
             EnableMediaPlayback = true;
             EnableMediaPlayback = true;
             EnableLiveTvAccess = true;
             EnableLiveTvAccess = true;
-            EnableSharedDeviceControl = true;
 
 
             LatestItemsExcludes = new string[] { };
             LatestItemsExcludes = new string[] { };
             OrderedViews = new string[] { };
             OrderedViews = new string[] { };
-            BlockedMediaFolders = new string[] { };
             DisplayChannelsWithinViews = new string[] { };
             DisplayChannelsWithinViews = new string[] { };
-            BlockedTags = new string[] { };
-            BlockedChannels = new string[] { };
             BlockUnratedItems = new UnratedItem[] { };
             BlockUnratedItems = new UnratedItem[] { };
 
 
             ExcludeFoldersFromGrouping = new string[] { };
             ExcludeFoldersFromGrouping = new string[] { };
@@ -115,9 +83,6 @@ namespace MediaBrowser.Model.Configuration
 
 
             IncludeTrailersInSuggestions = true;
             IncludeTrailersInSuggestions = true;
             EnableCinemaMode = true;
             EnableCinemaMode = true;
-            EnableUserPreferenceAccess = true;
-
-            AccessSchedules = new AccessSchedule[] { };
         }
         }
     }
     }
 }
 }

+ 2 - 2
MediaBrowser.Model/Connect/ConnectAuthorization.cs

@@ -9,12 +9,12 @@ namespace MediaBrowser.Model.Connect
         public string Id { get; set; }
         public string Id { get; set; }
         public string[] ExcludedLibraries { get; set; }
         public string[] ExcludedLibraries { get; set; }
         public bool EnableLiveTv { get; set; }
         public bool EnableLiveTv { get; set; }
-        public string[] ExcludedChannels { get; set; }
+        public string[] EnabledChannels { get; set; }
 
 
         public ConnectAuthorization()
         public ConnectAuthorization()
         {
         {
             ExcludedLibraries = new string[] { };
             ExcludedLibraries = new string[] { };
-            ExcludedChannels = new string[] { };
+            EnabledChannels = new string[] { };
         }
         }
     }
     }
 }
 }

+ 2 - 2
MediaBrowser.Model/Connect/ConnectAuthorizationRequest.cs

@@ -7,12 +7,12 @@ namespace MediaBrowser.Model.Connect
         public string ConnectUserName { get; set; }
         public string ConnectUserName { get; set; }
         public string[] ExcludedLibraries { get; set; }
         public string[] ExcludedLibraries { get; set; }
         public bool EnableLiveTv { get; set; }
         public bool EnableLiveTv { get; set; }
-        public string[] ExcludedChannels { get; set; }
+        public string[] EnabledChannels { get; set; }
 
 
         public ConnectAuthorizationRequest()
         public ConnectAuthorizationRequest()
         {
         {
             ExcludedLibraries = new string[] { };
             ExcludedLibraries = new string[] { };
-            ExcludedChannels = new string[] { };
+            EnabledChannels = new string[] { };
         }
         }
     }
     }
 }
 }

+ 3 - 1
MediaBrowser.Model/Users/UserPolicy.cs

@@ -52,6 +52,9 @@ namespace MediaBrowser.Model.Users
         public string[] EnabledDevices { get; set; }
         public string[] EnabledDevices { get; set; }
         public bool EnableAllDevices { get; set; }
         public bool EnableAllDevices { get; set; }
 
 
+        public string[] EnabledChannels { get; set; }
+        public bool EnableAllChannels { get; set; }
+        
         public UserPolicy()
         public UserPolicy()
         {
         {
             EnableLiveTvManagement = true;
             EnableLiveTvManagement = true;
@@ -61,7 +64,6 @@ namespace MediaBrowser.Model.Users
 
 
             BlockedMediaFolders = new string[] { };
             BlockedMediaFolders = new string[] { };
             BlockedTags = new string[] { };
             BlockedTags = new string[] { };
-            BlockedChannels = new string[] { };
             BlockUnratedItems = new UnratedItem[] { };
             BlockUnratedItems = new UnratedItem[] { };
 
 
             EnableUserPreferenceAccess = true;
             EnableUserPreferenceAccess = true;

+ 1 - 1
MediaBrowser.Providers/Manager/ImageSaver.cs

@@ -183,7 +183,7 @@ namespace MediaBrowser.Providers.Manager
                             currentFile.Attributes &= ~FileAttributes.Hidden;
                             currentFile.Attributes &= ~FileAttributes.Hidden;
                         }
                         }
 
 
-                        currentFile.Delete();
+                        _fileSystem.DeleteFile(currentFile.FullName);
                     }
                     }
                 }
                 }
                 finally
                 finally

+ 1 - 1
MediaBrowser.Providers/Manager/ItemImageProvider.cs

@@ -349,7 +349,7 @@ namespace MediaBrowser.Providers.Manager
                         currentFile.Attributes &= ~FileAttributes.Hidden;
                         currentFile.Attributes &= ~FileAttributes.Hidden;
                     }
                     }
 
 
-                    currentFile.Delete();
+                    _fileSystem.DeleteFile(currentFile.FullName);
                     deleted = true;
                     deleted = true;
                 }
                 }
             }
             }

+ 1 - 1
MediaBrowser.Providers/Subtitles/SubtitleManager.cs

@@ -245,7 +245,7 @@ namespace MediaBrowser.Providers.Subtitles
 
 
             try
             try
             {
             {
-                File.Delete(path);
+                _fileSystem.DeleteFile(path);
             }
             }
             finally
             finally
             {
             {

+ 1 - 1
MediaBrowser.Providers/TV/TvdbSeriesProvider.cs

@@ -1108,7 +1108,7 @@ namespace MediaBrowser.Providers.TV
                     .EnumerateFiles("*.xml", SearchOption.AllDirectories)
                     .EnumerateFiles("*.xml", SearchOption.AllDirectories)
                     .ToList())
                     .ToList())
                 {
                 {
-                    file.Delete();
+                    _fileSystem.DeleteFile(file.FullName);
                 }
                 }
             }
             }
             catch (DirectoryNotFoundException)
             catch (DirectoryNotFoundException)

+ 2 - 2
MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs

@@ -96,7 +96,7 @@ namespace MediaBrowser.Server.Implementations.Channels
 
 
         public static string GetUserDistinctValue(User user)
         public static string GetUserDistinctValue(User user)
         {
         {
-            var channels = user.Policy.BlockedChannels
+            var channels = user.Policy.EnabledChannels
                 .OrderBy(i => i)
                 .OrderBy(i => i)
                 .ToList();
                 .ToList();
 
 
@@ -374,7 +374,7 @@ namespace MediaBrowser.Server.Implementations.Channels
         {
         {
             try
             try
             {
             {
-                File.Delete(path);
+                _fileSystem.DeleteFile(path);
             }
             }
             catch (IOException ex)
             catch (IOException ex)
             {
             {

+ 2 - 2
MediaBrowser.Server.Implementations/Channels/ChannelManager.cs

@@ -1492,7 +1492,7 @@ namespace MediaBrowser.Server.Implementations.Channels
             }
             }
             else
             else
             {
             {
-                File.Delete(response.TempFilePath);
+                _fileSystem.DeleteFile(response.TempFilePath);
 
 
                 throw new ApplicationException("Unexpected response type encountered: " + response.ContentType);
                 throw new ApplicationException("Unexpected response type encountered: " + response.ContentType);
             }
             }
@@ -1501,7 +1501,7 @@ namespace MediaBrowser.Server.Implementations.Channels
 
 
             try
             try
             {
             {
-                File.Delete(response.TempFilePath);
+                _fileSystem.DeleteFile(response.TempFilePath);
             }
             }
             catch
             catch
             {
             {

+ 1 - 1
MediaBrowser.Server.Implementations/Collections/CollectionManager.cs

@@ -258,7 +258,7 @@ namespace MediaBrowser.Server.Implementations.Collections
             {
             {
                 foreach (var file in shortcutFilesToDelete)
                 foreach (var file in shortcutFilesToDelete)
                 {
                 {
-                    File.Delete(file);
+                    _fileSystem.DeleteFile(file);
                 }
                 }
 
 
                 foreach (var child in list)
                 foreach (var child in list)

+ 4 - 3
MediaBrowser.Server.Implementations/Connect/ConnectManager.cs

@@ -548,7 +548,7 @@ namespace MediaBrowser.Server.Implementations.Connect
                     ImageUrl = response.UserImageUrl,
                     ImageUrl = response.UserImageUrl,
                     UserName = response.UserName,
                     UserName = response.UserName,
                     ExcludedLibraries = request.ExcludedLibraries,
                     ExcludedLibraries = request.ExcludedLibraries,
-                    ExcludedChannels = request.ExcludedChannels,
+                    EnabledChannels = request.EnabledChannels,
                     EnableLiveTv = request.EnableLiveTv,
                     EnableLiveTv = request.EnableLiveTv,
                     AccessToken = accessToken
                     AccessToken = accessToken
                 });
                 });
@@ -810,7 +810,8 @@ namespace MediaBrowser.Server.Implementations.Connect
                             {
                             {
                                 user.Policy.EnableLiveTvAccess = currentPendingEntry.EnableLiveTv;
                                 user.Policy.EnableLiveTvAccess = currentPendingEntry.EnableLiveTv;
                                 user.Policy.BlockedMediaFolders = currentPendingEntry.ExcludedLibraries;
                                 user.Policy.BlockedMediaFolders = currentPendingEntry.ExcludedLibraries;
-                                user.Policy.BlockedChannels = currentPendingEntry.ExcludedChannels;
+                                user.Policy.EnabledChannels = currentPendingEntry.EnabledChannels;
+                                user.Policy.EnableAllChannels = false;
                             }
                             }
 
 
                             await _userManager.UpdateConfiguration(user.Id.ToString("N"), user.Configuration);
                             await _userManager.UpdateConfiguration(user.Id.ToString("N"), user.Configuration);
@@ -937,7 +938,7 @@ namespace MediaBrowser.Server.Implementations.Connect
             {
             {
                 ConnectUserId = i.ConnectUserId,
                 ConnectUserId = i.ConnectUserId,
                 EnableLiveTv = i.EnableLiveTv,
                 EnableLiveTv = i.EnableLiveTv,
-                ExcludedChannels = i.ExcludedChannels,
+                EnabledChannels = i.EnabledChannels,
                 ExcludedLibraries = i.ExcludedLibraries,
                 ExcludedLibraries = i.ExcludedLibraries,
                 Id = i.Id,
                 Id = i.Id,
                 ImageUrl = i.ImageUrl,
                 ImageUrl = i.ImageUrl,

+ 6 - 3
MediaBrowser.Server.Implementations/Devices/DeviceRepository.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Controller.Devices;
 using MediaBrowser.Controller.Devices;
 using MediaBrowser.Model.Devices;
 using MediaBrowser.Model.Devices;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
@@ -21,14 +22,16 @@ namespace MediaBrowser.Server.Implementations.Devices
         private readonly IApplicationPaths _appPaths;
         private readonly IApplicationPaths _appPaths;
         private readonly IJsonSerializer _json;
         private readonly IJsonSerializer _json;
         private readonly ILogger _logger;
         private readonly ILogger _logger;
+        private readonly IFileSystem _fileSystem;
 
 
         private ConcurrentBag<DeviceInfo> _devices;
         private ConcurrentBag<DeviceInfo> _devices;
 
 
-        public DeviceRepository(IApplicationPaths appPaths, IJsonSerializer json, ILogger logger)
+        public DeviceRepository(IApplicationPaths appPaths, IJsonSerializer json, ILogger logger, IFileSystem fileSystem)
         {
         {
             _appPaths = appPaths;
             _appPaths = appPaths;
             _json = json;
             _json = json;
             _logger = logger;
             _logger = logger;
+            _fileSystem = fileSystem;
         }
         }
 
 
         private string GetDevicesPath()
         private string GetDevicesPath()
@@ -129,12 +132,12 @@ namespace MediaBrowser.Server.Implementations.Devices
             {
             {
                 try
                 try
                 {
                 {
-                    Directory.Delete(path, true);
+                    _fileSystem.DeleteDirectory(path, true);
                 }
                 }
                 catch (DirectoryNotFoundException)
                 catch (DirectoryNotFoundException)
                 {
                 {
                 }
                 }
-
+                
                 _devices = null;
                 _devices = null;
             }
             }
 
 

+ 16 - 25
MediaBrowser.Server.Implementations/EntryPoints/ServerEventNotifier.cs

@@ -2,7 +2,6 @@
 using MediaBrowser.Common.ScheduledTasks;
 using MediaBrowser.Common.ScheduledTasks;
 using MediaBrowser.Common.Updates;
 using MediaBrowser.Common.Updates;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
-using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Net;
@@ -44,28 +43,15 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
         /// </summary>
         /// </summary>
         private readonly ITaskManager _taskManager;
         private readonly ITaskManager _taskManager;
 
 
-        private readonly IDtoService _dtoService;
-
         private readonly ISessionManager _sessionManager;
         private readonly ISessionManager _sessionManager;
 
 
-        /// <summary>
-        /// Initializes a new instance of the <see cref="ServerEventNotifier" /> class.
-        /// </summary>
-        /// <param name="serverManager">The server manager.</param>
-        /// <param name="appHost">The application host.</param>
-        /// <param name="userManager">The user manager.</param>
-        /// <param name="installationManager">The installation manager.</param>
-        /// <param name="taskManager">The task manager.</param>
-        /// <param name="dtoService">The dto service.</param>
-        /// <param name="sessionManager">The session manager.</param>
-        public ServerEventNotifier(IServerManager serverManager, IServerApplicationHost appHost, IUserManager userManager, IInstallationManager installationManager, ITaskManager taskManager, IDtoService dtoService, ISessionManager sessionManager)
+        public ServerEventNotifier(IServerManager serverManager, IServerApplicationHost appHost, IUserManager userManager, IInstallationManager installationManager, ITaskManager taskManager, ISessionManager sessionManager)
         {
         {
             _serverManager = serverManager;
             _serverManager = serverManager;
             _userManager = userManager;
             _userManager = userManager;
             _installationManager = installationManager;
             _installationManager = installationManager;
             _appHost = appHost;
             _appHost = appHost;
             _taskManager = taskManager;
             _taskManager = taskManager;
-            _dtoService = dtoService;
             _sessionManager = sessionManager;
             _sessionManager = sessionManager;
         }
         }
 
 
@@ -86,13 +72,6 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
             _taskManager.TaskCompleted += _taskManager_TaskCompleted;
             _taskManager.TaskCompleted += _taskManager_TaskCompleted;
         }
         }
 
 
-        void _userManager_UserConfigurationUpdated(object sender, GenericEventArgs<User> e)
-        {
-            var dto = _userManager.GetUserDto(e.Argument);
-
-            _serverManager.SendWebSocketMessage("UserConfigurationUpdated", dto);
-        }
-
         void _installationManager_PackageInstalling(object sender, InstallationEventArgs e)
         void _installationManager_PackageInstalling(object sender, InstallationEventArgs e)
         {
         {
             _serverManager.SendWebSocketMessage("PackageInstalling", e.InstallationInfo);
             _serverManager.SendWebSocketMessage("PackageInstalling", e.InstallationInfo);
@@ -146,8 +125,8 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
         void userManager_UserUpdated(object sender, GenericEventArgs<User> e)
         void userManager_UserUpdated(object sender, GenericEventArgs<User> e)
         {
         {
             var dto = _userManager.GetUserDto(e.Argument);
             var dto = _userManager.GetUserDto(e.Argument);
-            
-            _serverManager.SendWebSocketMessage("UserUpdated", dto);
+
+            SendMessageToUserSession(e.Argument, "UserUpdated", dto);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -157,7 +136,19 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
         /// <param name="e">The e.</param>
         /// <param name="e">The e.</param>
         void userManager_UserDeleted(object sender, GenericEventArgs<User> e)
         void userManager_UserDeleted(object sender, GenericEventArgs<User> e)
         {
         {
-            _serverManager.SendWebSocketMessage("UserDeleted", e.Argument.Id.ToString("N"));
+            SendMessageToUserSession(e.Argument, "UserDeleted", e.Argument.Id.ToString("N"));
+        }
+
+        void _userManager_UserConfigurationUpdated(object sender, GenericEventArgs<User> e)
+        {
+            var dto = _userManager.GetUserDto(e.Argument);
+
+            SendMessageToUserSession(e.Argument, "UserConfigurationUpdated", dto);
+        }
+
+        private async void SendMessageToUserSession<T>(User user, string name, T data)
+        {
+            await _sessionManager.SendMessageToUserSessions(user.Id.ToString("N"), name, data, CancellationToken.None);
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 1 - 1
MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs

@@ -108,7 +108,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
             {
             {
                 var userId = pair.Key;
                 var userId = pair.Key;
                 var userSessions = _sessionManager.Sessions
                 var userSessions = _sessionManager.Sessions
-                    .Where(u => u.UserId.HasValue && u.UserId.Value == userId && u.SessionController != null && u.IsActive)
+                    .Where(u => u.ContainsUser(userId) && u.SessionController != null && u.IsActive)
                     .ToList();
                     .ToList();
 
 
                 if (userSessions.Count > 0)
                 if (userSessions.Count > 0)

+ 2 - 2
MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs

@@ -209,7 +209,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
 
 
                     try
                     try
                     {
                     {
-                        File.Delete(path);
+                        _fileSystem.DeleteFile(path);
                     }
                     }
                     catch (IOException ex)
                     catch (IOException ex)
                     {
                     {
@@ -315,7 +315,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
             {
             {
                 try
                 try
                 {
                 {
-                    File.Delete(result.OriginalPath);
+                    _fileSystem.DeleteFile(result.OriginalPath);
                 }
                 }
                 catch (Exception ex)
                 catch (Exception ex)
                 {
                 {

+ 1 - 1
MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs

@@ -85,7 +85,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
             _logger.Info("Requested to delete {0}", result.OriginalPath);
             _logger.Info("Requested to delete {0}", result.OriginalPath);
             try
             try
             {
             {
-                File.Delete(result.OriginalPath);
+                _fileSystem.DeleteFile(result.OriginalPath);
             }
             }
             catch (Exception ex)
             catch (Exception ex)
             {
             {

+ 1 - 1
MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs

@@ -166,7 +166,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
             {
             {
                 try
                 try
                 {
                 {
-                    File.Delete(file.FullName);
+                    _fileSystem.DeleteFile(file.FullName);
                 }
                 }
                 catch (Exception ex)
                 catch (Exception ex)
                 {
                 {

+ 0 - 25
MediaBrowser.Server.Implementations/HttpServer/SocketSharp/RequestMono.cs

@@ -556,31 +556,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
                     return (stream);
                     return (stream);
                 }
                 }
             }
             }
-
-            public void SaveAs(string filename)
-            {
-                byte[] buffer = new byte[16 * 1024];
-                long old_post = stream.Position;
-
-                try
-                {
-                    File.Delete(filename);
-                    using (FileStream fs = File.Create(filename))
-                    {
-                        stream.Position = 0;
-                        int n;
-
-                        while ((n = stream.Read(buffer, 0, 16 * 1024)) != 0)
-                        {
-                            fs.Write(buffer, 0, n);
-                        }
-                    }
-                }
-                finally
-                {
-                    stream.Position = old_post;
-                }
-            }
         }
         }
 
 
         class Helpers
         class Helpers

+ 23 - 6
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -401,11 +401,11 @@ namespace MediaBrowser.Server.Implementations.Library
 
 
                 try
                 try
                 {
                 {
-                    Directory.Delete(metadataPath, true);
+                    _fileSystem.DeleteDirectory(metadataPath, true);
                 }
                 }
                 catch (DirectoryNotFoundException)
                 catch (DirectoryNotFoundException)
                 {
                 {
-
+                    
                 }
                 }
                 catch (Exception ex)
                 catch (Exception ex)
                 {
                 {
@@ -420,12 +420,12 @@ namespace MediaBrowser.Server.Implementations.Library
                     if (Directory.Exists(path))
                     if (Directory.Exists(path))
                     {
                     {
                         _logger.Debug("Deleting path {0}", path);
                         _logger.Debug("Deleting path {0}", path);
-                        Directory.Delete(path, true);
+                        _fileSystem.DeleteDirectory(path, true);
                     }
                     }
                     else if (File.Exists(path))
                     else if (File.Exists(path))
                     {
                     {
                         _logger.Debug("Deleting path {0}", path);
                         _logger.Debug("Deleting path {0}", path);
-                        File.Delete(path);
+                        _fileSystem.DeleteFile(path);
                     }
                     }
                 }
                 }
 
 
@@ -840,6 +840,23 @@ namespace MediaBrowser.Server.Implementations.Library
             return GetItemByName<Year>(ConfigurationManager.ApplicationPaths.YearPath, value.ToString(UsCulture));
             return GetItemByName<Year>(ConfigurationManager.ApplicationPaths.YearPath, value.ToString(UsCulture));
         }
         }
 
 
+        /// <summary>
+        /// Gets the artists path.
+        /// </summary>
+        /// <value>The artists path.</value>
+        public string ArtistsPath
+        {
+            get
+            {
+                if (ConfigurationManager.Configuration.StoreArtistsInMetadata)
+                {
+                    return Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "artists");
+                }
+
+                return Path.Combine(ConfigurationManager.ApplicationPaths.ItemsByNamePath, "artists");
+            }
+        }
+
         /// <summary>
         /// <summary>
         /// Gets a Genre
         /// Gets a Genre
         /// </summary>
         /// </summary>
@@ -847,7 +864,7 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <returns>Task{Genre}.</returns>
         /// <returns>Task{Genre}.</returns>
         public MusicArtist GetArtist(string name)
         public MusicArtist GetArtist(string name)
         {
         {
-            return GetItemByName<MusicArtist>(ConfigurationManager.ApplicationPaths.ArtistsPath, name);
+            return GetItemByName<MusicArtist>(ArtistsPath, name);
         }
         }
 
 
         private T GetItemByName<T>(string path, string name)
         private T GetItemByName<T>(string path, string name)
@@ -976,7 +993,7 @@ namespace MediaBrowser.Server.Implementations.Library
         public Task ValidateArtists(CancellationToken cancellationToken, IProgress<double> progress)
         public Task ValidateArtists(CancellationToken cancellationToken, IProgress<double> progress)
         {
         {
             // Ensure the location is unavailable.
             // Ensure the location is unavailable.
-            Directory.CreateDirectory(ConfigurationManager.ApplicationPaths.ArtistsPath);
+            Directory.CreateDirectory(ArtistsPath);
 
 
             return new ArtistsValidator(this, _userManager, _logger).Run(progress, cancellationToken);
             return new ArtistsValidator(this, _userManager, _logger).Run(progress, cancellationToken);
         }
         }

+ 54 - 18
MediaBrowser.Server.Implementations/Library/UserManager.cs

@@ -1,7 +1,9 @@
 using MediaBrowser.Common.Events;
 using MediaBrowser.Common.Events;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
+using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Connect;
 using MediaBrowser.Controller.Connect;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Drawing;
@@ -11,6 +13,7 @@ using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Channels;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Connect;
 using MediaBrowser.Model.Connect;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Dto;
@@ -69,9 +72,11 @@ namespace MediaBrowser.Server.Implementations.Library
         private readonly Func<IImageProcessor> _imageProcessorFactory;
         private readonly Func<IImageProcessor> _imageProcessorFactory;
         private readonly Func<IDtoService> _dtoServiceFactory;
         private readonly Func<IDtoService> _dtoServiceFactory;
         private readonly Func<IConnectManager> _connectFactory;
         private readonly Func<IConnectManager> _connectFactory;
+        private readonly Func<IChannelManager> _channelManager;
         private readonly IServerApplicationHost _appHost;
         private readonly IServerApplicationHost _appHost;
+        private readonly IFileSystem _fileSystem;
 
 
-        public UserManager(ILogger logger, IServerConfigurationManager configurationManager, IUserRepository userRepository, IXmlSerializer xmlSerializer, INetworkManager networkManager, Func<IImageProcessor> imageProcessorFactory, Func<IDtoService> dtoServiceFactory, Func<IConnectManager> connectFactory, IServerApplicationHost appHost, IJsonSerializer jsonSerializer)
+        public UserManager(ILogger logger, IServerConfigurationManager configurationManager, IUserRepository userRepository, IXmlSerializer xmlSerializer, INetworkManager networkManager, Func<IImageProcessor> imageProcessorFactory, Func<IDtoService> dtoServiceFactory, Func<IConnectManager> connectFactory, IServerApplicationHost appHost, IJsonSerializer jsonSerializer, IFileSystem fileSystem, Func<IChannelManager> channelManager)
         {
         {
             _logger = logger;
             _logger = logger;
             UserRepository = userRepository;
             UserRepository = userRepository;
@@ -82,6 +87,8 @@ namespace MediaBrowser.Server.Implementations.Library
             _connectFactory = connectFactory;
             _connectFactory = connectFactory;
             _appHost = appHost;
             _appHost = appHost;
             _jsonSerializer = jsonSerializer;
             _jsonSerializer = jsonSerializer;
+            _fileSystem = fileSystem;
+            _channelManager = channelManager;
             ConfigurationManager = configurationManager;
             ConfigurationManager = configurationManager;
             Users = new List<User>();
             Users = new List<User>();
 
 
@@ -165,6 +172,7 @@ namespace MediaBrowser.Server.Implementations.Library
             foreach (var user in users)
             foreach (var user in users)
             {
             {
                 await DoPolicyMigration(user).ConfigureAwait(false);
                 await DoPolicyMigration(user).ConfigureAwait(false);
+                await DoChannelMigration(user).ConfigureAwait(false);
             }
             }
 
 
             // If there are no local users with admin rights, make them all admins
             // If there are no local users with admin rights, make them all admins
@@ -204,7 +212,7 @@ namespace MediaBrowser.Server.Implementations.Library
             {
             {
                 return username;
                 return username;
             }
             }
-            
+
             // Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)
             // Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)
             var builder = new StringBuilder();
             var builder = new StringBuilder();
 
 
@@ -329,22 +337,12 @@ namespace MediaBrowser.Server.Implementations.Library
         {
         {
             if (!user.Configuration.HasMigratedToPolicy)
             if (!user.Configuration.HasMigratedToPolicy)
             {
             {
-                user.Policy.AccessSchedules = user.Configuration.AccessSchedules;
-                user.Policy.BlockedChannels = user.Configuration.BlockedChannels;
-                user.Policy.BlockedMediaFolders = user.Configuration.BlockedMediaFolders;
-                user.Policy.BlockedTags = user.Configuration.BlockedTags;
                 user.Policy.BlockUnratedItems = user.Configuration.BlockUnratedItems;
                 user.Policy.BlockUnratedItems = user.Configuration.BlockUnratedItems;
                 user.Policy.EnableContentDeletion = user.Configuration.EnableContentDeletion;
                 user.Policy.EnableContentDeletion = user.Configuration.EnableContentDeletion;
                 user.Policy.EnableLiveTvAccess = user.Configuration.EnableLiveTvAccess;
                 user.Policy.EnableLiveTvAccess = user.Configuration.EnableLiveTvAccess;
                 user.Policy.EnableLiveTvManagement = user.Configuration.EnableLiveTvManagement;
                 user.Policy.EnableLiveTvManagement = user.Configuration.EnableLiveTvManagement;
                 user.Policy.EnableMediaPlayback = user.Configuration.EnableMediaPlayback;
                 user.Policy.EnableMediaPlayback = user.Configuration.EnableMediaPlayback;
-                user.Policy.EnableRemoteControlOfOtherUsers = user.Configuration.EnableRemoteControlOfOtherUsers;
-                user.Policy.EnableSharedDeviceControl = user.Configuration.EnableSharedDeviceControl;
-                user.Policy.EnableUserPreferenceAccess = user.Configuration.EnableUserPreferenceAccess;
                 user.Policy.IsAdministrator = user.Configuration.IsAdministrator;
                 user.Policy.IsAdministrator = user.Configuration.IsAdministrator;
-                user.Policy.IsDisabled = user.Configuration.IsDisabled;
-                user.Policy.IsHidden = user.Configuration.IsHidden;
-                user.Policy.MaxParentalRating = user.Configuration.MaxParentalRating;
 
 
                 await UpdateUserPolicy(user, user.Policy, false);
                 await UpdateUserPolicy(user, user.Policy, false);
 
 
@@ -353,6 +351,44 @@ namespace MediaBrowser.Server.Implementations.Library
             }
             }
         }
         }
 
 
+        private async Task DoChannelMigration(User user)
+        {
+            if (user.Policy.BlockedChannels != null)
+            {
+                if (user.Policy.BlockedChannels.Length > 0)
+                {
+                    user.Policy.EnableAllChannels = false;
+
+                    try
+                    {
+                        var channelResult = await _channelManager().GetChannelsInternal(new ChannelQuery
+                        {
+                            UserId = user.Id.ToString("N")
+
+                        }, CancellationToken.None).ConfigureAwait(false);
+
+                        user.Policy.EnabledChannels = channelResult.Items
+                            .Select(i => i.Id.ToString("N"))
+                            .Except(user.Policy.BlockedChannels)
+                            .ToArray();
+                    }
+                    catch
+                    {
+                        user.Policy.EnabledChannels = new string[] { };
+                    }
+                }
+                else
+                {
+                    user.Policy.EnableAllChannels = true;
+                    user.Policy.EnabledChannels = new string[] { };
+                }
+
+                user.Policy.BlockedChannels = null;
+
+                await UpdateUserPolicy(user, user.Policy, false);
+            }
+        }
+
         public UserDto GetUserDto(User user, string remoteEndPoint = null)
         public UserDto GetUserDto(User user, string remoteEndPoint = null)
         {
         {
             if (user == null)
             if (user == null)
@@ -591,7 +627,7 @@ namespace MediaBrowser.Server.Implementations.Library
 
 
                 try
                 try
                 {
                 {
-                    File.Delete(configPath);
+                    _fileSystem.DeleteFile(configPath);
                 }
                 }
                 catch (IOException ex)
                 catch (IOException ex)
                 {
                 {
@@ -817,7 +853,7 @@ namespace MediaBrowser.Server.Implementations.Library
         {
         {
             try
             try
             {
             {
-                File.Delete(PasswordResetFile);
+                _fileSystem.DeleteFile(PasswordResetFile);
             }
             }
             catch
             catch
             {
             {
@@ -881,7 +917,7 @@ namespace MediaBrowser.Server.Implementations.Library
                 var json = _jsonSerializer.SerializeToString(userPolicy);
                 var json = _jsonSerializer.SerializeToString(userPolicy);
                 userPolicy = _jsonSerializer.DeserializeFromString<UserPolicy>(json);
                 userPolicy = _jsonSerializer.DeserializeFromString<UserPolicy>(json);
             }
             }
-            
+
             var path = GetPolifyFilePath(user);
             var path = GetPolifyFilePath(user);
 
 
             Directory.CreateDirectory(Path.GetDirectoryName(path));
             Directory.CreateDirectory(Path.GetDirectoryName(path));
@@ -909,7 +945,7 @@ namespace MediaBrowser.Server.Implementations.Library
             {
             {
                 lock (_policySyncLock)
                 lock (_policySyncLock)
                 {
                 {
-                    File.Delete(path);
+                    _fileSystem.DeleteFile(path);
                 }
                 }
             }
             }
             catch (IOException)
             catch (IOException)
@@ -971,14 +1007,14 @@ namespace MediaBrowser.Server.Implementations.Library
             var path = GetConfigurationFilePath(user);
             var path = GetConfigurationFilePath(user);
 
 
             // The xml serializer will output differently if the type is not exact
             // The xml serializer will output differently if the type is not exact
-            if (config.GetType() != typeof (UserConfiguration))
+            if (config.GetType() != typeof(UserConfiguration))
             {
             {
                 var json = _jsonSerializer.SerializeToString(config);
                 var json = _jsonSerializer.SerializeToString(config);
                 config = _jsonSerializer.DeserializeFromString<UserConfiguration>(json);
                 config = _jsonSerializer.DeserializeFromString<UserConfiguration>(json);
             }
             }
 
 
             Directory.CreateDirectory(Path.GetDirectoryName(path));
             Directory.CreateDirectory(Path.GetDirectoryName(path));
-            
+
             lock (_configSyncLock)
             lock (_configSyncLock)
             {
             {
                 _xmlSerializer.SerializeToFile(config, path);
                 _xmlSerializer.SerializeToFile(config, path);

+ 1 - 0
MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json

@@ -42,6 +42,7 @@
     "LabelFailed": "(failed)",
     "LabelFailed": "(failed)",
     "ButtonHelp": "Help",
     "ButtonHelp": "Help",
     "ButtonSave": "Save",
     "ButtonSave": "Save",
+    "HeaderDevices": "Devices",
     "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
     "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client",
     "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client",

+ 1 - 0
MediaBrowser.Server.Implementations/Localization/Server/server.json

@@ -86,6 +86,7 @@
     "TabCollectionTitles": "Titles",
     "TabCollectionTitles": "Titles",
     "HeaderDeviceAccess": "Device Access",
     "HeaderDeviceAccess": "Device Access",
     "OptionEnableAccessFromAllDevices": "Enable access from all devices",
     "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+    "OptionEnableAccessToAllChannels": "Enable access to all channels",
     "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
     "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
     "LabelDisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons",
     "LabelDisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons",
     "LabelUnairedMissingEpisodesWithinSeasons": "Display unaired episodes within seasons",
     "LabelUnairedMissingEpisodesWithinSeasons": "Display unaired episodes within seasons",

+ 1 - 1
MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs

@@ -215,7 +215,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
 
 
                 try
                 try
                 {
                 {
-                    File.Delete(image);
+                    _fileSystem.DeleteFile(image);
                 }
                 }
                 catch (IOException ex)
                 catch (IOException ex)
                 {
                 {

+ 0 - 13
MediaBrowser.Server.Implementations/ServerApplicationPaths.cs

@@ -197,19 +197,6 @@ namespace MediaBrowser.Server.Implementations
             }
             }
         }
         }
 
 
-        /// <summary>
-        /// Gets the artists path.
-        /// </summary>
-        /// <value>The artists path.</value>
-        public string ArtistsPath
-        {
-            get
-            {
-                return Path.Combine(ItemsByNamePath, "artists");
-            }
-        }
-
-
         /// <summary>
         /// <summary>
         /// Gets the game genre path.
         /// Gets the game genre path.
         /// </summary>
         /// </summary>

+ 6 - 0
MediaBrowser.Server.Implementations/Session/HttpSessionController.cs

@@ -209,6 +209,12 @@ namespace MediaBrowser.Server.Implementations.Session
             return SendMessage(command.Name, command.Arguments, cancellationToken);
             return SendMessage(command.Name, command.Arguments, cancellationToken);
         }
         }
 
 
+        public Task SendMessage<T>(string name, T data, CancellationToken cancellationToken)
+        {
+            // Not supported or needed right now
+            return Task.FromResult(true);
+        }
+
         private string ToQueryString(Dictionary<string, string> nvc)
         private string ToQueryString(Dictionary<string, string> nvc)
         {
         {
             var array = (from item in nvc
             var array = (from item in nvc

+ 21 - 0
MediaBrowser.Server.Implementations/Session/SessionManager.cs

@@ -1632,5 +1632,26 @@ namespace MediaBrowser.Server.Implementations.Session
             return Sessions.FirstOrDefault(i => string.Equals(i.DeviceId, deviceId) &&
             return Sessions.FirstOrDefault(i => string.Equals(i.DeviceId, deviceId) &&
                 string.Equals(i.Client, client));
                 string.Equals(i.Client, client));
         }
         }
+
+        public Task SendMessageToUserSessions<T>(string userId, string name, T data,
+            CancellationToken cancellationToken)
+        {
+            var sessions = Sessions.Where(i => i.IsActive && i.SessionController != null && i.ContainsUser(userId)).ToList();
+
+            var tasks = sessions.Select(session => Task.Run(async () =>
+            {
+                try
+                {
+                    await session.SessionController.SendMessage(name, data, cancellationToken).ConfigureAwait(false);
+                }
+                catch (Exception ex)
+                {
+                    _logger.ErrorException("Error in SendPlaybackStoppedNotification.", ex);
+                }
+
+            }, cancellationToken));
+
+            return Task.WhenAll(tasks);
+        }
     }
     }
 }
 }

+ 23 - 13
MediaBrowser.Server.Implementations/Session/WebSocketController.cs

@@ -90,7 +90,7 @@ namespace MediaBrowser.Server.Implementations.Session
 
 
         public Task SendPlayCommand(PlayRequest command, CancellationToken cancellationToken)
         public Task SendPlayCommand(PlayRequest command, CancellationToken cancellationToken)
         {
         {
-            return SendMessage(new WebSocketMessage<PlayRequest>
+            return SendMessageInternal(new WebSocketMessage<PlayRequest>
             {
             {
                 MessageType = "Play",
                 MessageType = "Play",
                 Data = command
                 Data = command
@@ -100,7 +100,7 @@ namespace MediaBrowser.Server.Implementations.Session
 
 
         public Task SendPlaystateCommand(PlaystateRequest command, CancellationToken cancellationToken)
         public Task SendPlaystateCommand(PlaystateRequest command, CancellationToken cancellationToken)
         {
         {
-            return SendMessage(new WebSocketMessage<PlaystateRequest>
+            return SendMessageInternal(new WebSocketMessage<PlaystateRequest>
             {
             {
                 MessageType = "Playstate",
                 MessageType = "Playstate",
                 Data = command
                 Data = command
@@ -110,7 +110,7 @@ namespace MediaBrowser.Server.Implementations.Session
 
 
         public Task SendLibraryUpdateInfo(LibraryUpdateInfo info, CancellationToken cancellationToken)
         public Task SendLibraryUpdateInfo(LibraryUpdateInfo info, CancellationToken cancellationToken)
         {
         {
-            return SendMessages(new WebSocketMessage<LibraryUpdateInfo>
+            return SendMessagesInternal(new WebSocketMessage<LibraryUpdateInfo>
             {
             {
                 MessageType = "LibraryChanged",
                 MessageType = "LibraryChanged",
                 Data = info
                 Data = info
@@ -126,7 +126,7 @@ namespace MediaBrowser.Server.Implementations.Session
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         public Task SendRestartRequiredNotification(SystemInfo info, CancellationToken cancellationToken)
         public Task SendRestartRequiredNotification(SystemInfo info, CancellationToken cancellationToken)
         {
         {
-            return SendMessages(new WebSocketMessage<SystemInfo>
+            return SendMessagesInternal(new WebSocketMessage<SystemInfo>
             {
             {
                 MessageType = "RestartRequired",
                 MessageType = "RestartRequired",
                 Data = info
                 Data = info
@@ -143,7 +143,7 @@ namespace MediaBrowser.Server.Implementations.Session
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         public Task SendUserDataChangeInfo(UserDataChangeInfo info, CancellationToken cancellationToken)
         public Task SendUserDataChangeInfo(UserDataChangeInfo info, CancellationToken cancellationToken)
         {
         {
-            return SendMessages(new WebSocketMessage<UserDataChangeInfo>
+            return SendMessagesInternal(new WebSocketMessage<UserDataChangeInfo>
             {
             {
                 MessageType = "UserDataChanged",
                 MessageType = "UserDataChanged",
                 Data = info
                 Data = info
@@ -158,7 +158,7 @@ namespace MediaBrowser.Server.Implementations.Session
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         public Task SendServerShutdownNotification(CancellationToken cancellationToken)
         public Task SendServerShutdownNotification(CancellationToken cancellationToken)
         {
         {
-            return SendMessages(new WebSocketMessage<string>
+            return SendMessagesInternal(new WebSocketMessage<string>
             {
             {
                 MessageType = "ServerShuttingDown",
                 MessageType = "ServerShuttingDown",
                 Data = string.Empty
                 Data = string.Empty
@@ -173,7 +173,7 @@ namespace MediaBrowser.Server.Implementations.Session
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         public Task SendServerRestartNotification(CancellationToken cancellationToken)
         public Task SendServerRestartNotification(CancellationToken cancellationToken)
         {
         {
-            return SendMessages(new WebSocketMessage<string>
+            return SendMessagesInternal(new WebSocketMessage<string>
             {
             {
                 MessageType = "ServerRestarting",
                 MessageType = "ServerRestarting",
                 Data = string.Empty
                 Data = string.Empty
@@ -183,7 +183,7 @@ namespace MediaBrowser.Server.Implementations.Session
 
 
         public Task SendGeneralCommand(GeneralCommand command, CancellationToken cancellationToken)
         public Task SendGeneralCommand(GeneralCommand command, CancellationToken cancellationToken)
         {
         {
-            return SendMessage(new WebSocketMessage<GeneralCommand>
+            return SendMessageInternal(new WebSocketMessage<GeneralCommand>
             {
             {
                 MessageType = "GeneralCommand",
                 MessageType = "GeneralCommand",
                 Data = command
                 Data = command
@@ -193,7 +193,7 @@ namespace MediaBrowser.Server.Implementations.Session
 
 
         public Task SendSessionEndedNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken)
         public Task SendSessionEndedNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken)
         {
         {
-            return SendMessages(new WebSocketMessage<SessionInfoDto>
+            return SendMessagesInternal(new WebSocketMessage<SessionInfoDto>
             {
             {
                 MessageType = "SessionEnded",
                 MessageType = "SessionEnded",
                 Data = sessionInfo
                 Data = sessionInfo
@@ -203,7 +203,7 @@ namespace MediaBrowser.Server.Implementations.Session
 
 
         public Task SendPlaybackStartNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken)
         public Task SendPlaybackStartNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken)
         {
         {
-            return SendMessages(new WebSocketMessage<SessionInfoDto>
+            return SendMessagesInternal(new WebSocketMessage<SessionInfoDto>
             {
             {
                 MessageType = "PlaybackStart",
                 MessageType = "PlaybackStart",
                 Data = sessionInfo
                 Data = sessionInfo
@@ -213,7 +213,7 @@ namespace MediaBrowser.Server.Implementations.Session
 
 
         public Task SendPlaybackStoppedNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken)
         public Task SendPlaybackStoppedNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken)
         {
         {
-            return SendMessages(new WebSocketMessage<SessionInfoDto>
+            return SendMessagesInternal(new WebSocketMessage<SessionInfoDto>
             {
             {
                 MessageType = "PlaybackStopped",
                 MessageType = "PlaybackStopped",
                 Data = sessionInfo
                 Data = sessionInfo
@@ -221,7 +221,17 @@ namespace MediaBrowser.Server.Implementations.Session
             }, cancellationToken);
             }, cancellationToken);
         }
         }
 
 
-        private Task SendMessage<T>(WebSocketMessage<T> message, CancellationToken cancellationToken)
+        public Task SendMessage<T>(string name, T data, CancellationToken cancellationToken)
+        {
+            return SendMessagesInternal(new WebSocketMessage<T>
+            {
+                Data = data,
+                MessageType = name
+
+            }, cancellationToken);
+        }
+
+        private Task SendMessageInternal<T>(WebSocketMessage<T> message, CancellationToken cancellationToken)
         {
         {
             if (SkipSending()) return Task.FromResult(true);
             if (SkipSending()) return Task.FromResult(true);
 
 
@@ -230,7 +240,7 @@ namespace MediaBrowser.Server.Implementations.Session
             return socket.SendAsync(message, cancellationToken);
             return socket.SendAsync(message, cancellationToken);
         }
         }
 
 
-        private Task SendMessages<T>(WebSocketMessage<T> message, CancellationToken cancellationToken)
+        private Task SendMessagesInternal<T>(WebSocketMessage<T> message, CancellationToken cancellationToken)
         {
         {
             if (SkipSending()) return Task.FromResult(true);
             if (SkipSending()) return Task.FromResult(true);
 
 

+ 5 - 2
MediaBrowser.Server.Implementations/Sync/SyncManager.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Common;
 using MediaBrowser.Common;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Dto;
@@ -37,10 +38,11 @@ namespace MediaBrowser.Server.Implementations.Sync
         private readonly IApplicationHost _appHost;
         private readonly IApplicationHost _appHost;
         private readonly ITVSeriesManager _tvSeriesManager;
         private readonly ITVSeriesManager _tvSeriesManager;
         private readonly Func<IMediaEncoder> _mediaEncoder;
         private readonly Func<IMediaEncoder> _mediaEncoder;
+        private readonly IFileSystem _fileSystem;
 
 
         private ISyncProvider[] _providers = { };
         private ISyncProvider[] _providers = { };
 
 
-        public SyncManager(ILibraryManager libraryManager, ISyncRepository repo, IImageProcessor imageProcessor, ILogger logger, IUserManager userManager, Func<IDtoService> dtoService, IApplicationHost appHost, ITVSeriesManager tvSeriesManager, Func<IMediaEncoder> mediaEncoder)
+        public SyncManager(ILibraryManager libraryManager, ISyncRepository repo, IImageProcessor imageProcessor, ILogger logger, IUserManager userManager, Func<IDtoService> dtoService, IApplicationHost appHost, ITVSeriesManager tvSeriesManager, Func<IMediaEncoder> mediaEncoder, IFileSystem fileSystem)
         {
         {
             _libraryManager = libraryManager;
             _libraryManager = libraryManager;
             _repo = repo;
             _repo = repo;
@@ -51,6 +53,7 @@ namespace MediaBrowser.Server.Implementations.Sync
             _appHost = appHost;
             _appHost = appHost;
             _tvSeriesManager = tvSeriesManager;
             _tvSeriesManager = tvSeriesManager;
             _mediaEncoder = mediaEncoder;
             _mediaEncoder = mediaEncoder;
+            _fileSystem = fileSystem;
         }
         }
 
 
         public void AddParts(IEnumerable<ISyncProvider> providers)
         public void AddParts(IEnumerable<ISyncProvider> providers)
@@ -396,7 +399,7 @@ namespace MediaBrowser.Server.Implementations.Sync
             {
             {
                 try
                 try
                 {
                 {
-                    File.Delete(jobItem.OutputPath);
+                    _fileSystem.DeleteFile(jobItem.OutputPath);
                 }
                 }
                 catch (Exception ex)
                 catch (Exception ex)
                 {
                 {

+ 1 - 1
MediaBrowser.Server.Implementations/Sync/SyncScheduledTask.cs

@@ -67,7 +67,7 @@ namespace MediaBrowser.Server.Implementations.Sync
 
 
         public bool IsHidden
         public bool IsHidden
         {
         {
-            get { return true; }
+            get { return false; }
         }
         }
 
 
         public bool IsEnabled
         public bool IsEnabled

+ 6 - 6
MediaBrowser.Server.Startup.Common/ApplicationHost.cs

@@ -365,11 +365,11 @@ namespace MediaBrowser.Server.Startup.Common
         {
         {
             var migrations = new List<IVersionMigration>
             var migrations = new List<IVersionMigration>
             {
             {
-                new MigrateUserFolders(ApplicationPaths),
+                new MigrateUserFolders(ApplicationPaths, FileSystemManager),
                 new RenameXbmcOptions(ServerConfigurationManager),
                 new RenameXbmcOptions(ServerConfigurationManager),
                 new RenameXmlOptions(ServerConfigurationManager),
                 new RenameXmlOptions(ServerConfigurationManager),
-                new DeprecatePlugins(ApplicationPaths),
-                new DeleteDlnaProfiles(ApplicationPaths)
+                new DeprecatePlugins(ApplicationPaths, FileSystemManager),
+                new DeleteDlnaProfiles(ApplicationPaths, FileSystemManager)
             };
             };
 
 
             foreach (var task in migrations)
             foreach (var task in migrations)
@@ -435,7 +435,7 @@ namespace MediaBrowser.Server.Startup.Common
             SyncRepository = await GetSyncRepository().ConfigureAwait(false);
             SyncRepository = await GetSyncRepository().ConfigureAwait(false);
             RegisterSingleInstance(SyncRepository);
             RegisterSingleInstance(SyncRepository);
 
 
-            UserManager = new UserManager(LogManager.GetLogger("UserManager"), ServerConfigurationManager, UserRepository, XmlSerializer, NetworkManager, () => ImageProcessor, () => DtoService, () => ConnectManager, this, JsonSerializer);
+            UserManager = new UserManager(LogManager.GetLogger("UserManager"), ServerConfigurationManager, UserRepository, XmlSerializer, NetworkManager, () => ImageProcessor, () => DtoService, () => ConnectManager, this, JsonSerializer, FileSystemManager, () => ChannelManager);
             RegisterSingleInstance(UserManager);
             RegisterSingleInstance(UserManager);
 
 
             LibraryManager = new LibraryManager(Logger, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager);
             LibraryManager = new LibraryManager(Logger, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager);
@@ -483,7 +483,7 @@ namespace MediaBrowser.Server.Startup.Common
             TVSeriesManager = new TVSeriesManager(UserManager, UserDataManager, LibraryManager);
             TVSeriesManager = new TVSeriesManager(UserManager, UserDataManager, LibraryManager);
             RegisterSingleInstance(TVSeriesManager);
             RegisterSingleInstance(TVSeriesManager);
 
 
-            SyncManager = new SyncManager(LibraryManager, SyncRepository, ImageProcessor, LogManager.GetLogger("SyncManager"), UserManager, () => DtoService, this, TVSeriesManager, () => MediaEncoder);
+            SyncManager = new SyncManager(LibraryManager, SyncRepository, ImageProcessor, LogManager.GetLogger("SyncManager"), UserManager, () => DtoService, this, TVSeriesManager, () => MediaEncoder, FileSystemManager);
             RegisterSingleInstance(SyncManager);
             RegisterSingleInstance(SyncManager);
 
 
             DtoService = new DtoService(Logger, LibraryManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager, () => ChannelManager, SyncManager, this);
             DtoService = new DtoService(Logger, LibraryManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager, () => ChannelManager, SyncManager, this);
@@ -495,7 +495,7 @@ namespace MediaBrowser.Server.Startup.Common
             ConnectManager = new ConnectManager(LogManager.GetLogger("Connect"), ApplicationPaths, JsonSerializer, encryptionManager, HttpClient, this, ServerConfigurationManager, UserManager, ProviderManager);
             ConnectManager = new ConnectManager(LogManager.GetLogger("Connect"), ApplicationPaths, JsonSerializer, encryptionManager, HttpClient, this, ServerConfigurationManager, UserManager, ProviderManager);
             RegisterSingleInstance(ConnectManager);
             RegisterSingleInstance(ConnectManager);
 
 
-            DeviceManager = new DeviceManager(new DeviceRepository(ApplicationPaths, JsonSerializer, Logger), UserManager, FileSystemManager, LibraryMonitor, ConfigurationManager, LogManager.GetLogger("DeviceManager"));
+            DeviceManager = new DeviceManager(new DeviceRepository(ApplicationPaths, JsonSerializer, Logger, FileSystemManager), UserManager, FileSystemManager, LibraryMonitor, ConfigurationManager, LogManager.GetLogger("DeviceManager"));
             RegisterSingleInstance(DeviceManager);
             RegisterSingleInstance(DeviceManager);
 
 
             SessionManager = new SessionManager(UserDataManager, Logger, UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, ItemRepository, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager);
             SessionManager = new SessionManager(UserDataManager, Logger, UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, ItemRepository, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager);

+ 4 - 4
MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloader.cs

@@ -129,7 +129,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
         {
         {
             try
             try
             {
             {
-                Directory.Delete(path, true);
+                _fileSystem.DeleteDirectory(path, true);
             }
             }
             catch (Exception ex)
             catch (Exception ex)
             {
             {
@@ -272,7 +272,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
         {
         {
             try
             try
             {
             {
-                File.Delete(path);
+                _fileSystem.DeleteFile(path);
             }
             }
             catch (IOException ex)
             catch (IOException ex)
             {
             {
@@ -380,10 +380,10 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
             }
             }
 
 
             Extract7zArchive(tempFile, fontsDirectory);
             Extract7zArchive(tempFile, fontsDirectory);
-
+            
             try
             try
             {
             {
-                File.Delete(tempFile);
+                _fileSystem.DeleteFile(tempFile);
             }
             }
             catch (IOException ex)
             catch (IOException ex)
             {
             {

+ 7 - 4
MediaBrowser.Server.Startup.Common/Migrations/DeleteDlnaProfiles.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller;
 using System.IO;
 using System.IO;
 
 
 namespace MediaBrowser.Server.Startup.Common.Migrations
 namespace MediaBrowser.Server.Startup.Common.Migrations
@@ -6,10 +7,12 @@ namespace MediaBrowser.Server.Startup.Common.Migrations
     public class DeleteDlnaProfiles : IVersionMigration
     public class DeleteDlnaProfiles : IVersionMigration
     {
     {
         private readonly IServerApplicationPaths _appPaths;
         private readonly IServerApplicationPaths _appPaths;
+        private readonly IFileSystem _fileSystem;
 
 
-        public DeleteDlnaProfiles(IServerApplicationPaths appPaths)
+        public DeleteDlnaProfiles(IServerApplicationPaths appPaths, IFileSystem fileSystem)
         {
         {
             _appPaths = appPaths;
             _appPaths = appPaths;
+            _fileSystem = fileSystem;
         }
         }
 
 
         public void Run()
         public void Run()
@@ -23,7 +26,7 @@ namespace MediaBrowser.Server.Startup.Common.Migrations
         {
         {
             try
             try
             {
             {
-                File.Delete(Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "system", filename + ".xml"));
+                _fileSystem.DeleteFile(Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "system", filename + ".xml"));
             }
             }
             catch
             catch
             {
             {
@@ -31,7 +34,7 @@ namespace MediaBrowser.Server.Startup.Common.Migrations
             }
             }
             try
             try
             {
             {
-                File.Delete(Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "user", filename + ".xml"));
+                _fileSystem.DeleteFile(Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "user", filename + ".xml"));
             }
             }
             catch
             catch
             {
             {

+ 6 - 3
MediaBrowser.Server.Startup.Common/Migrations/DeprecatePlugins.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller;
 using System.IO;
 using System.IO;
 
 
 namespace MediaBrowser.Server.Startup.Common.Migrations
 namespace MediaBrowser.Server.Startup.Common.Migrations
@@ -6,10 +7,12 @@ namespace MediaBrowser.Server.Startup.Common.Migrations
     public class DeprecatePlugins : IVersionMigration
     public class DeprecatePlugins : IVersionMigration
     {
     {
         private readonly IServerApplicationPaths _appPaths;
         private readonly IServerApplicationPaths _appPaths;
+        private readonly IFileSystem _fileSystem;
 
 
-        public DeprecatePlugins(IServerApplicationPaths appPaths)
+        public DeprecatePlugins(IServerApplicationPaths appPaths, IFileSystem fileSystem)
         {
         {
             _appPaths = appPaths;
             _appPaths = appPaths;
+            _fileSystem = fileSystem;
         }
         }
 
 
         public void Run()
         public void Run()
@@ -21,7 +24,7 @@ namespace MediaBrowser.Server.Startup.Common.Migrations
         {
         {
             try
             try
             {
             {
-                File.Delete(Path.Combine(_appPaths.PluginsPath, filename));
+                _fileSystem.DeleteFile(Path.Combine(_appPaths.PluginsPath, filename));
             }
             }
             catch
             catch
             {
             {

+ 6 - 3
MediaBrowser.Server.Startup.Common/Migrations/MigrateUserFolders.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller;
 using System;
 using System;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
@@ -8,10 +9,12 @@ namespace MediaBrowser.Server.Startup.Common.Migrations
     public class MigrateUserFolders : IVersionMigration
     public class MigrateUserFolders : IVersionMigration
     {
     {
         private readonly IServerApplicationPaths _appPaths;
         private readonly IServerApplicationPaths _appPaths;
+        private readonly IFileSystem _fileSystem;
 
 
-        public MigrateUserFolders(IServerApplicationPaths appPaths)
+        public MigrateUserFolders(IServerApplicationPaths appPaths, IFileSystem fileSystem)
         {
         {
             _appPaths = appPaths;
             _appPaths = appPaths;
+            _fileSystem = fileSystem;
         }
         }
 
 
         public void Run()
         public void Run()
@@ -25,7 +28,7 @@ namespace MediaBrowser.Server.Startup.Common.Migrations
 
 
                 foreach (var folder in folders)
                 foreach (var folder in folders)
                 {
                 {
-                    Directory.Delete(folder.FullName, true);
+                    _fileSystem.DeleteDirectory(folder.FullName, true);
                 }
                 }
             }
             }
             catch (IOException)
             catch (IOException)

+ 1 - 1
MediaBrowser.ServerApplication/MainStartup.cs

@@ -203,7 +203,7 @@ namespace MediaBrowser.ServerApplication
         {
         {
             var fileSystem = new NativeFileSystem(logManager.GetLogger("FileSystem"), false);
             var fileSystem = new NativeFileSystem(logManager.GetLogger("FileSystem"), false);
 
 
-            var nativeApp = new WindowsApp
+            var nativeApp = new WindowsApp(fileSystem)
             {
             {
                 IsRunningAsService = runService
                 IsRunningAsService = runService
             };
             };

+ 5 - 3
MediaBrowser.ServerApplication/Native/Autorun.cs

@@ -1,4 +1,5 @@
-using System;
+using MediaBrowser.Common.IO;
+using System;
 using System.IO;
 using System.IO;
 
 
 namespace MediaBrowser.ServerApplication.Native
 namespace MediaBrowser.ServerApplication.Native
@@ -12,7 +13,8 @@ namespace MediaBrowser.ServerApplication.Native
         /// Configures the specified autorun.
         /// Configures the specified autorun.
         /// </summary>
         /// </summary>
         /// <param name="autorun">if set to <c>true</c> [autorun].</param>
         /// <param name="autorun">if set to <c>true</c> [autorun].</param>
-        public static void Configure(bool autorun)
+        /// <param name="fileSystem">The file system.</param>
+        public static void Configure(bool autorun, IFileSystem fileSystem)
         {
         {
             var shortcutPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.StartMenu), "Media Browser 3", "Media Browser Server.lnk");
             var shortcutPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.StartMenu), "Media Browser 3", "Media Browser Server.lnk");
 
 
@@ -26,7 +28,7 @@ namespace MediaBrowser.ServerApplication.Native
             else
             else
             {
             {
                 //Remove our shortcut from the startup folder for this user
                 //Remove our shortcut from the startup folder for this user
-                File.Delete(Path.Combine(startupPath, Path.GetFileName(shortcutPath) ?? "MBstartup.lnk"));
+                fileSystem.DeleteFile(Path.Combine(startupPath, Path.GetFileName(shortcutPath) ?? "MBstartup.lnk"));
             }
             }
         }
         }
     }
     }

+ 10 - 2
MediaBrowser.ServerApplication/Native/WindowsApp.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Net;
 using MediaBrowser.IsoMounter;
 using MediaBrowser.IsoMounter;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Server.Startup.Common;
 using MediaBrowser.Server.Startup.Common;
@@ -10,6 +11,13 @@ namespace MediaBrowser.ServerApplication.Native
 {
 {
     public class WindowsApp : INativeApp
     public class WindowsApp : INativeApp
     {
     {
+        private readonly IFileSystem _fileSystem;
+
+        public WindowsApp(IFileSystem fileSystem)
+        {
+            _fileSystem = fileSystem;
+        }
+
         public List<Assembly> GetAssembliesWithParts()
         public List<Assembly> GetAssembliesWithParts()
         {
         {
             var list = new List<Assembly>();
             var list = new List<Assembly>();
@@ -89,7 +97,7 @@ namespace MediaBrowser.ServerApplication.Native
 
 
         public void ConfigureAutoRun(bool autorun)
         public void ConfigureAutoRun(bool autorun)
         {
         {
-            Autorun.Configure(autorun);
+            Autorun.Configure(autorun, _fileSystem);
         }
         }
 
 
         public INetworkManager CreateNetworkManager(ILogger logger)
         public INetworkManager CreateNetworkManager(ILogger logger)

+ 2 - 2
MediaBrowser.WebDashboard/Api/DashboardService.cs

@@ -275,11 +275,11 @@ namespace MediaBrowser.WebDashboard.Api
 
 
             try
             try
             {
             {
-                Directory.Delete(path, true);
+                _fileSystem.DeleteDirectory(path, true);
             }
             }
             catch (IOException)
             catch (IOException)
             {
             {
-
+                
             }
             }
 
 
             var creator = GetPackageCreator();
             var creator = GetPackageCreator();

+ 2 - 2
SharedVersion.cs

@@ -1,4 +1,4 @@
 using System.Reflection;
 using System.Reflection;
 
 
-//[assembly: AssemblyVersion("3.0.*")]
-[assembly: AssemblyVersion("3.0.5490.2")]
+[assembly: AssemblyVersion("3.0.*")]
+//[assembly: AssemblyVersion("3.0.5490.2")]