Browse Source

* Add support for multi segment base urls
* Make baseurl case-insensitive

Bond_009 5 years ago
parent
commit
3221e837f9
73 changed files with 1275 additions and 732 deletions
  1. 81 29
      Emby.Dlna/Api/DlnaServerService.cs
  2. 2 3
      Emby.Dlna/ContentDirectory/ContentDirectory.cs
  3. 1 5
      Emby.Server.Implementations/Library/UserDataManager.cs
  4. 0 4
      Emby.Server.Implementations/Library/UserManager.cs
  5. 4 5
      Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs
  6. 43 213
      MediaBrowser.Api/ApiEntryPoint.cs
  7. 102 37
      MediaBrowser.Api/BaseApiService.cs
  8. 10 6
      MediaBrowser.Api/BrandingService.cs
  9. 9 1
      MediaBrowser.Api/ChannelService.cs
  10. 10 11
      MediaBrowser.Api/ConfigurationService.cs
  11. 10 2
      MediaBrowser.Api/Devices/DeviceService.cs
  12. 9 1
      MediaBrowser.Api/DisplayPreferencesService.cs
  13. 11 8
      MediaBrowser.Api/EnvironmentService.cs
  14. 9 1
      MediaBrowser.Api/FilterService.cs
  15. 14 10
      MediaBrowser.Api/Images/ImageByNameService.cs
  16. 21 12
      MediaBrowser.Api/Images/ImageService.cs
  17. 12 4
      MediaBrowser.Api/Images/RemoteImageService.cs
  18. 11 2
      MediaBrowser.Api/ItemLookupService.cs
  19. 9 3
      MediaBrowser.Api/ItemRefreshService.cs
  20. 14 7
      MediaBrowser.Api/ItemUpdateService.cs
  21. 26 26
      MediaBrowser.Api/Library/LibraryService.cs
  22. 10 11
      MediaBrowser.Api/Library/LibraryStructureService.cs
  23. 8 10
      MediaBrowser.Api/LiveTv/LiveTvService.cs
  24. 8 1
      MediaBrowser.Api/LocalizationService.cs
  25. 10 1
      MediaBrowser.Api/Movies/CollectionService.cs
  26. 15 8
      MediaBrowser.Api/Movies/MoviesService.cs
  27. 22 10
      MediaBrowser.Api/Movies/TrailersService.cs
  28. 13 1
      MediaBrowser.Api/Music/AlbumsService.cs
  29. 12 1
      MediaBrowser.Api/Music/InstantMixService.cs
  30. 8 5
      MediaBrowser.Api/PackageService.cs
  31. 5 9
      MediaBrowser.Api/Playback/BaseStreamingService.cs
  32. 33 29
      MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
  33. 7 3
      MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
  34. 11 6
      MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs
  35. 8 2
      MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
  36. 7 9
      MediaBrowser.Api/Playback/MediaInfoService.cs
  37. 20 14
      MediaBrowser.Api/Playback/Progressive/AudioService.cs
  38. 8 2
      MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
  39. 9 3
      MediaBrowser.Api/Playback/Progressive/VideoService.cs
  40. 38 30
      MediaBrowser.Api/Playback/UniversalAudioService.cs
  41. 12 1
      MediaBrowser.Api/PlaylistService.cs
  42. 10 17
      MediaBrowser.Api/PluginService.cs
  43. 2 0
      MediaBrowser.Api/Properties/AssemblyInfo.cs
  44. 18 21
      MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs
  45. 11 1
      MediaBrowser.Api/SearchService.cs
  46. 18 5
      MediaBrowser.Api/Session/SessionsService.cs
  47. 20 25
      MediaBrowser.Api/StartupWizardService.cs
  48. 13 1
      MediaBrowser.Api/Subtitles/SubtitleService.cs
  49. 11 1
      MediaBrowser.Api/SuggestionsService.cs
  50. 8 1
      MediaBrowser.Api/System/ActivityLogService.cs
  51. 10 3
      MediaBrowser.Api/System/SystemService.cs
  52. 160 0
      MediaBrowser.Api/TranscodingJob.cs
  53. 13 10
      MediaBrowser.Api/TvShowsService.cs
  54. 23 5
      MediaBrowser.Api/UserLibrary/ArtistsService.cs
  55. 28 17
      MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
  56. 23 4
      MediaBrowser.Api/UserLibrary/GenresService.cs
  57. 11 19
      MediaBrowser.Api/UserLibrary/ItemsService.cs
  58. 23 5
      MediaBrowser.Api/UserLibrary/MusicGenresService.cs
  59. 23 4
      MediaBrowser.Api/UserLibrary/PersonsService.cs
  60. 14 3
      MediaBrowser.Api/UserLibrary/PlaystateService.cs
  61. 23 5
      MediaBrowser.Api/UserLibrary/StudiosService.cs
  62. 14 1
      MediaBrowser.Api/UserLibrary/UserLibraryService.cs
  63. 5 0
      MediaBrowser.Api/UserLibrary/UserViewsService.cs
  64. 23 4
      MediaBrowser.Api/UserLibrary/YearsService.cs
  65. 7 6
      MediaBrowser.Api/UserService.cs
  66. 12 12
      MediaBrowser.Api/VideosService.cs
  67. 1 3
      MediaBrowser.Controller/Library/IUserDataManager.cs
  68. 1 8
      MediaBrowser.Controller/Library/IUserManager.cs
  69. 5 3
      MediaBrowser.Model/Configuration/ServerConfiguration.cs
  70. 1 2
      MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
  71. 7 0
      MediaBrowser.sln
  72. 45 0
      tests/Jellyfin.Api.Tests/GetPathValueTests.cs
  73. 20 0
      tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj

+ 81 - 29
Emby.Dlna/Api/DlnaServerService.cs

@@ -1,7 +1,5 @@
 using System;
-using System.Collections.Generic;
 using System.IO;
-using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 using Emby.Dlna.Main;
@@ -195,7 +193,7 @@ namespace Emby.Dlna.Api
 
         private ControlResponse PostAsync(Stream requestStream, IUpnpService service)
         {
-            var id = GetPathValue(2);
+            var id = GetPathValue(2).ToString();
 
             return service.ProcessControlRequest(new ControlRequest
             {
@@ -206,49 +204,103 @@ namespace Emby.Dlna.Api
             });
         }
 
-        protected string GetPathValue(int index)
+        // Copied from MediaBrowser.Api/BaseApiService.cs
+        // TODO: Remove code duplication
+        /// <summary>
+        /// Gets the path segment at the specified index.
+        /// </summary>
+        /// <param name="index">The index of the path segment.</param>
+        /// <returns>The path segment at the specified index.</returns>
+        /// <exception cref="IndexOutOfRangeException" >Path doesn't contain enough segments.</exception>
+        /// <exception cref="InvalidDataException" >Path doesn't start with the base url.</exception>
+        protected internal ReadOnlySpan<char> GetPathValue(int index)
         {
-            var pathInfo = Parse(Request.PathInfo);
-            var first = pathInfo[0];
+            static void ThrowIndexOutOfRangeException()
+            {
+                throw new IndexOutOfRangeException("Path doesn't contain enough segments.");
+            }
 
-            string baseUrl = _configurationManager.Configuration.BaseUrl;
+            static void ThrowInvalidDataException()
+            {
+                throw new InvalidDataException("Path doesn't start with the base url.");
+            }
+
+            ReadOnlySpan<char> path = Request.PathInfo;
+
+            // Remove the protocol part from the url
+            int pos = path.LastIndexOf("://");
+            if (pos != -1)
+            {
+                path = path.Slice(pos + 3);
+            }
 
-            // backwards compatibility
-            if (baseUrl.Length == 0
-                && (string.Equals(first, "mediabrowser", StringComparison.OrdinalIgnoreCase)
-                    || string.Equals(first, "emby", StringComparison.OrdinalIgnoreCase)))
+            // Remove the query string
+            pos = path.LastIndexOf('?');
+            if (pos != -1)
             {
-                index++;
+                path = path.Slice(0, pos);
             }
-            else if (string.Equals(first, baseUrl.Remove(0, 1)))
+
+            // Remove the domain
+            pos = path.IndexOf('/');
+            if (pos != -1)
+            {
+                path = path.Slice(pos);
+            }
+
+            // Remove base url
+            string baseUrl = _configurationManager.Configuration.BaseUrl;
+            int baseUrlLen = baseUrl.Length;
+            if (baseUrlLen != 0)
             {
-                index++;
-                var second = pathInfo[1];
-                if (string.Equals(second, "mediabrowser", StringComparison.OrdinalIgnoreCase)
-                    || string.Equals(second, "emby", StringComparison.OrdinalIgnoreCase))
+                if (path.StartsWith(baseUrl, StringComparison.OrdinalIgnoreCase))
                 {
-                    index++;
+                    path = path.Slice(baseUrlLen);
+                }
+                else
+                {
+                    // The path doesn't start with the base url,
+                    // how did we get here?
+                    ThrowInvalidDataException();
                 }
             }
 
-            return pathInfo[index];
-        }
+            // Remove leading /
+            path = path.Slice(1);
 
-        private List<string> Parse(string pathUri)
-        {
-            var actionParts = pathUri.Split(new[] { "://" }, StringSplitOptions.None);
+            // Backwards compatibility
+            const string Emby = "emby/";
+            if (path.StartsWith(Emby, StringComparison.OrdinalIgnoreCase))
+            {
+                path = path.Slice(Emby.Length);
+            }
 
-            var pathInfo = actionParts[actionParts.Length - 1];
+            const string MediaBrowser = "mediabrowser/";
+            if (path.StartsWith(MediaBrowser, StringComparison.OrdinalIgnoreCase))
+            {
+                path = path.Slice(MediaBrowser.Length);
+            }
 
-            var optionsPos = pathInfo.LastIndexOf('?');
-            if (optionsPos != -1)
+            // Skip segments until we are at the right index
+            for (int i = 0; i < index; i++)
             {
-                pathInfo = pathInfo.Substring(0, optionsPos);
+                pos = path.IndexOf('/');
+                if (pos == -1)
+                {
+                    ThrowIndexOutOfRangeException();
+                }
+
+                path = path.Slice(pos + 1);
             }
 
-            var args = pathInfo.Split('/');
+            // Remove the rest
+            pos = path.IndexOf('/');
+            if (pos != -1)
+            {
+                path = path.Slice(0, pos);
+            }
 
-            return args.Skip(1).ToList();
+            return path;
         }
 
         public object Get(GetIcon request)

+ 2 - 3
Emby.Dlna/ContentDirectory/ContentDirectory.cs

@@ -1,5 +1,4 @@
 using System;
-using System.Collections.Generic;
 using Emby.Dlna.Service;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
@@ -104,7 +103,7 @@ namespace Emby.Dlna.ContentDirectory
         {
             if (!string.IsNullOrEmpty(profile.UserId))
             {
-                var user = _userManager.GetUserById(profile.UserId);
+                var user = _userManager.GetUserById(Guid.Parse(profile.UserId));
 
                 if (user != null)
                 {
@@ -116,7 +115,7 @@ namespace Emby.Dlna.ContentDirectory
 
             if (!string.IsNullOrEmpty(userId))
             {
-                var user = _userManager.GetUserById(userId);
+                var user = _userManager.GetUserById(Guid.Parse(userId));
 
                 if (user != null)
                 {

+ 1 - 5
Emby.Server.Implementations/Library/UserDataManager.cs

@@ -55,6 +55,7 @@ namespace Emby.Server.Implementations.Library
             {
                 throw new ArgumentNullException(nameof(userData));
             }
+
             if (item == null)
             {
                 throw new ArgumentNullException(nameof(item));
@@ -160,11 +161,6 @@ namespace Emby.Server.Implementations.Library
             return GetUserData(user, item.Id, item.GetUserDataKeys());
         }
 
-        public UserItemData GetUserData(string userId, BaseItem item)
-        {
-            return GetUserData(new Guid(userId), item);
-        }
-
         public UserItemData GetUserData(Guid userId, BaseItem item)
         {
             return GetUserData(userId, item.Id, item.GetUserDataKeys());

+ 0 - 4
Emby.Server.Implementations/Library/UserManager.cs

@@ -194,10 +194,6 @@ namespace Emby.Server.Implementations.Library
             return user;
         }
 
-        /// <inheritdoc />
-        public User GetUserById(string id)
-            => GetUserById(new Guid(id));
-
         public User GetUserByName(string name)
         {
             if (string.IsNullOrWhiteSpace(name))

+ 4 - 5
Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs

@@ -31,13 +31,13 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
         }
 
         /// <summary>
-        /// Creates the triggers that define when the task will run
+        /// Creates the triggers that define when the task will run.
         /// </summary>
         /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
         public IEnumerable<TaskTriggerInfo> GetDefaultTriggers() => new List<TaskTriggerInfo>();
 
         /// <summary>
-        /// Returns the task to be executed
+        /// Returns the task to be executed.
         /// </summary>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
@@ -47,14 +47,13 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
             var minDateModified = DateTime.UtcNow.AddDays(-1);
             progress.Report(50);
 
-            DeleteTempFilesFromDirectory(cancellationToken, _configurationManager.GetTranscodingTempPath(), minDateModified, progress);
+            DeleteTempFilesFromDirectory(cancellationToken, _configurationManager.GetTranscodePath(), minDateModified, progress);
 
             return Task.CompletedTask;
         }
 
-
         /// <summary>
-        /// Deletes the transcoded temp files from directory with a last write time less than a given date
+        /// Deletes the transcoded temp files from directory with a last write time less than a given date.
         /// </summary>
         /// <param name="cancellationToken">The task cancellation token.</param>
         /// <param name="directory">The directory.</param>

+ 43 - 213
MediaBrowser.Api/ApiEntryPoint.cs

@@ -10,11 +10,9 @@ using MediaBrowser.Common.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Plugins;
 using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Diagnostics;
-using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Session;
 using Microsoft.Extensions.Logging;
@@ -22,26 +20,24 @@ using Microsoft.Extensions.Logging;
 namespace MediaBrowser.Api
 {
     /// <summary>
-    /// Class ServerEntryPoint
+    /// Class ServerEntryPoint.
     /// </summary>
     public class ApiEntryPoint : IServerEntryPoint
     {
         /// <summary>
-        /// The instance
+        /// The instance.
         /// </summary>
         public static ApiEntryPoint Instance;
 
         /// <summary>
-        /// Gets or sets the logger.
+        /// The logger.
         /// </summary>
-        /// <value>The logger.</value>
-        internal ILogger Logger { get; private set; }
-        internal IHttpResultFactory ResultFactory { get; private set; }
+        private ILogger _logger;
 
         /// <summary>
-        /// Gets the configuration manager.
+        /// The configuration manager.
         /// </summary>
-        internal IServerConfigurationManager ConfigurationManager { get; }
+        private IServerConfigurationManager _serverConfigurationManager;
 
         private readonly ISessionManager _sessionManager;
         private readonly IFileSystem _fileSystem;
@@ -70,18 +66,16 @@ namespace MediaBrowser.Api
             ISessionManager sessionManager,
             IServerConfigurationManager config,
             IFileSystem fileSystem,
-            IMediaSourceManager mediaSourceManager,
-            IHttpResultFactory resultFactory)
+            IMediaSourceManager mediaSourceManager)
         {
-            Logger = logger;
+            _logger = logger;
             _sessionManager = sessionManager;
-            ConfigurationManager = config;
+            _serverConfigurationManager = config;
             _fileSystem = fileSystem;
             _mediaSourceManager = mediaSourceManager;
-            ResultFactory = resultFactory;
 
-            _sessionManager.PlaybackProgress += _sessionManager_PlaybackProgress;
-            _sessionManager.PlaybackStart += _sessionManager_PlaybackStart;
+            _sessionManager.PlaybackProgress += OnPlaybackProgress;
+            _sessionManager.PlaybackStart += OnPlaybackStart;
 
             Instance = this;
         }
@@ -115,7 +109,7 @@ namespace MediaBrowser.Api
             }
         }
 
-        private void _sessionManager_PlaybackStart(object sender, PlaybackProgressEventArgs e)
+        private void OnPlaybackStart(object sender, PlaybackProgressEventArgs e)
         {
             if (!string.IsNullOrWhiteSpace(e.PlaySessionId))
             {
@@ -123,7 +117,7 @@ namespace MediaBrowser.Api
             }
         }
 
-        void _sessionManager_PlaybackProgress(object sender, PlaybackProgressEventArgs e)
+        private void OnPlaybackProgress(object sender, PlaybackProgressEventArgs e)
         {
             if (!string.IsNullOrWhiteSpace(e.PlaySessionId))
             {
@@ -140,17 +134,9 @@ namespace MediaBrowser.Api
             {
                 DeleteEncodedMediaCache();
             }
-            catch (FileNotFoundException)
-            {
-                // Don't clutter the log
-            }
-            catch (IOException)
-            {
-                // Don't clutter the log
-            }
             catch (Exception ex)
             {
-                Logger.LogError(ex, "Error deleting encoded media cache");
+                _logger.LogError(ex, "Error deleting encoded media cache");
             }
 
             return Task.CompletedTask;
@@ -161,8 +147,7 @@ namespace MediaBrowser.Api
         /// </summary>
         private void DeleteEncodedMediaCache()
         {
-            var path = ConfigurationManager.GetTranscodePath();
-
+            var path = _serverConfigurationManager.GetTranscodePath();
             if (!Directory.Exists(path))
             {
                 return;
@@ -174,9 +159,7 @@ namespace MediaBrowser.Api
             }
         }
 
-        /// <summary>
-        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
-        /// </summary>
+        /// <inheritdoc />
         public void Dispose()
         {
             Dispose(true);
@@ -219,8 +202,8 @@ namespace MediaBrowser.Api
             _activeTranscodingJobs.Clear();
             _transcodingLocks.Clear();
 
-            _sessionManager.PlaybackProgress -= _sessionManager_PlaybackProgress;
-            _sessionManager.PlaybackStart -= _sessionManager_PlaybackStart;
+            _sessionManager.PlaybackProgress -= OnPlaybackProgress;
+            _sessionManager.PlaybackStart -= OnPlaybackStart;
 
             _disposed = true;
         }
@@ -252,7 +235,7 @@ namespace MediaBrowser.Api
         {
             lock (_activeTranscodingJobs)
             {
-                var job = new TranscodingJob(Logger)
+                var job = new TranscodingJob(_logger)
                 {
                     Type = type,
                     Path = path,
@@ -406,12 +389,13 @@ namespace MediaBrowser.Api
         public void OnTranscodeEndRequest(TranscodingJob job)
         {
             job.ActiveRequestCount--;
-            Logger.LogDebug("OnTranscodeEndRequest job.ActiveRequestCount={0}", job.ActiveRequestCount);
+            _logger.LogDebug("OnTranscodeEndRequest job.ActiveRequestCount={0}", job.ActiveRequestCount);
             if (job.ActiveRequestCount <= 0)
             {
                 PingTimer(job, false);
             }
         }
+
         internal void PingTranscodingJob(string playSessionId, bool? isUserPaused)
         {
             if (string.IsNullOrEmpty(playSessionId))
@@ -419,7 +403,7 @@ namespace MediaBrowser.Api
                 throw new ArgumentNullException(nameof(playSessionId));
             }
 
-            Logger.LogDebug("PingTranscodingJob PlaySessionId={0} isUsedPaused: {1}", playSessionId, isUserPaused);
+            _logger.LogDebug("PingTranscodingJob PlaySessionId={0} isUsedPaused: {1}", playSessionId, isUserPaused);
 
             List<TranscodingJob> jobs;
 
@@ -434,9 +418,10 @@ namespace MediaBrowser.Api
             {
                 if (isUserPaused.HasValue)
                 {
-                    Logger.LogDebug("Setting job.IsUserPaused to {0}. jobId: {1}", isUserPaused, job.Id);
+                    _logger.LogDebug("Setting job.IsUserPaused to {0}. jobId: {1}", isUserPaused, job.Id);
                     job.IsUserPaused = isUserPaused.Value;
                 }
+
                 PingTimer(job, true);
             }
         }
@@ -489,7 +474,7 @@ namespace MediaBrowser.Api
                 }
             }
 
-            Logger.LogInformation("Transcoding kill timer stopped for JobId {0} PlaySessionId {1}. Killing transcoding", job.Id, job.PlaySessionId);
+            _logger.LogInformation("Transcoding kill timer stopped for JobId {0} PlaySessionId {1}. Killing transcoding", job.Id, job.PlaySessionId);
 
             await KillTranscodingJob(job, true, path => true);
         }
@@ -558,7 +543,7 @@ namespace MediaBrowser.Api
         {
             job.DisposeKillTimer();
 
-            Logger.LogDebug("KillTranscodingJob - JobId {0} PlaySessionId {1}. Killing transcoding", job.Id, job.PlaySessionId);
+            _logger.LogDebug("KillTranscodingJob - JobId {0} PlaySessionId {1}. Killing transcoding", job.Id, job.PlaySessionId);
 
             lock (_activeTranscodingJobs)
             {
@@ -590,14 +575,14 @@ namespace MediaBrowser.Api
                 {
                     try
                     {
-                        Logger.LogInformation("Stopping ffmpeg process with q command for {Path}", job.Path);
+                        _logger.LogInformation("Stopping ffmpeg process with q command for {Path}", job.Path);
 
                         process.StandardInput.WriteLine("q");
 
                         // Need to wait because killing is asynchronous
                         if (!process.WaitForExit(5000))
                         {
-                            Logger.LogInformation("Killing ffmpeg process for {Path}", job.Path);
+                            _logger.LogInformation("Killing ffmpeg process for {Path}", job.Path);
                             process.Kill();
                         }
                     }
@@ -620,7 +605,7 @@ namespace MediaBrowser.Api
                 }
                 catch (Exception ex)
                 {
-                    Logger.LogError(ex, "Error closing live stream for {Path}", job.Path);
+                    _logger.LogError(ex, "Error closing live stream for {Path}", job.Path);
                 }
             }
         }
@@ -632,7 +617,7 @@ namespace MediaBrowser.Api
                 return;
             }
 
-            Logger.LogInformation("Deleting partial stream file(s) {Path}", path);
+            _logger.LogInformation("Deleting partial stream file(s) {Path}", path);
 
             await Task.Delay(delayMs).ConfigureAwait(false);
 
@@ -646,20 +631,16 @@ namespace MediaBrowser.Api
                 {
                     DeleteHlsPartialStreamFiles(path);
                 }
-            }
-            catch (FileNotFoundException)
-            {
-
             }
             catch (IOException ex)
             {
-                Logger.LogError(ex, "Error deleting partial stream file(s) {Path}", path);
+                _logger.LogError(ex, "Error deleting partial stream file(s) {Path}", path);
 
                 await DeletePartialStreamFiles(path, jobType, retryCount + 1, 500).ConfigureAwait(false);
             }
             catch (Exception ex)
             {
-                Logger.LogError(ex, "Error deleting partial stream file(s) {Path}", path);
+                _logger.LogError(ex, "Error deleting partial stream file(s) {Path}", path);
             }
         }
 
@@ -669,7 +650,10 @@ namespace MediaBrowser.Api
         /// <param name="outputFilePath">The output file path.</param>
         private void DeleteProgressivePartialStreamFiles(string outputFilePath)
         {
-            _fileSystem.DeleteFile(outputFilePath);
+            if (File.Exists(outputFilePath))
+            {
+                _fileSystem.DeleteFile(outputFilePath);
+            }
         }
 
         /// <summary>
@@ -684,178 +668,24 @@ namespace MediaBrowser.Api
             var filesToDelete = _fileSystem.GetFilePaths(directory)
                 .Where(f => f.IndexOf(name, StringComparison.OrdinalIgnoreCase) != -1);
 
-            Exception e = null;
-
+            List<Exception> exs = null;
             foreach (var file in filesToDelete)
             {
                 try
                 {
-                    Logger.LogDebug("Deleting HLS file {0}", file);
+                    _logger.LogDebug("Deleting HLS file {0}", file);
                     _fileSystem.DeleteFile(file);
-                }
-                catch (FileNotFoundException)
-                {
-
                 }
                 catch (IOException ex)
                 {
-                    e = ex;
-                    Logger.LogError(ex, "Error deleting HLS file {Path}", file);
-                }
-            }
-
-            if (e != null)
-            {
-                throw e;
-            }
-        }
-    }
-
-    /// <summary>
-    /// Class TranscodingJob
-    /// </summary>
-    public class TranscodingJob
-    {
-        /// <summary>
-        /// Gets or sets the play session identifier.
-        /// </summary>
-        /// <value>The play session identifier.</value>
-        public string PlaySessionId { get; set; }
-        /// <summary>
-        /// Gets or sets the live stream identifier.
-        /// </summary>
-        /// <value>The live stream identifier.</value>
-        public string LiveStreamId { get; set; }
-
-        public bool IsLiveOutput { get; set; }
-
-        /// <summary>
-        /// Gets or sets the path.
-        /// </summary>
-        /// <value>The path.</value>
-        public MediaSourceInfo MediaSource { get; set; }
-        public string Path { get; set; }
-        /// <summary>
-        /// Gets or sets the type.
-        /// </summary>
-        /// <value>The type.</value>
-        public TranscodingJobType Type { get; set; }
-        /// <summary>
-        /// Gets or sets the process.
-        /// </summary>
-        /// <value>The process.</value>
-        public Process Process { get; set; }
-        public ILogger Logger { get; private set; }
-        /// <summary>
-        /// Gets or sets the active request count.
-        /// </summary>
-        /// <value>The active request count.</value>
-        public int ActiveRequestCount { get; set; }
-        /// <summary>
-        /// Gets or sets the kill timer.
-        /// </summary>
-        /// <value>The kill timer.</value>
-        private Timer KillTimer { get; set; }
-
-        public string DeviceId { get; set; }
-
-        public CancellationTokenSource CancellationTokenSource { get; set; }
-
-        public object ProcessLock = new object();
-
-        public bool HasExited { get; set; }
-        public bool IsUserPaused { get; set; }
-
-        public string Id { get; set; }
-
-        public float? Framerate { get; set; }
-        public double? CompletionPercentage { get; set; }
-
-        public long? BytesDownloaded { get; set; }
-        public long? BytesTranscoded { get; set; }
-        public int? BitRate { get; set; }
-
-        public long? TranscodingPositionTicks { get; set; }
-        public long? DownloadPositionTicks { get; set; }
-
-        public TranscodingThrottler TranscodingThrottler { get; set; }
-
-        private readonly object _timerLock = new object();
-
-        public DateTime LastPingDate { get; set; }
-        public int PingTimeout { get; set; }
-
-        public TranscodingJob(ILogger logger)
-        {
-            Logger = logger;
-        }
-
-        public void StopKillTimer()
-        {
-            lock (_timerLock)
-            {
-                if (KillTimer != null)
-                {
-                    KillTimer.Change(Timeout.Infinite, Timeout.Infinite);
-                }
-            }
-        }
-
-        public void DisposeKillTimer()
-        {
-            lock (_timerLock)
-            {
-                if (KillTimer != null)
-                {
-                    KillTimer.Dispose();
-                    KillTimer = null;
-                }
-            }
-        }
-
-        public void StartKillTimer(Action<object> callback)
-        {
-            StartKillTimer(callback, PingTimeout);
-        }
-
-        public void StartKillTimer(Action<object> callback, int intervalMs)
-        {
-            if (HasExited)
-            {
-                return;
-            }
-
-            lock (_timerLock)
-            {
-                if (KillTimer == null)
-                {
-                    Logger.LogDebug("Starting kill timer at {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
-                    KillTimer = new Timer(new TimerCallback(callback), this, intervalMs, Timeout.Infinite);
+                    (exs ??= new List<Exception>(4)).Add(ex);
+                    _logger.LogError(ex, "Error deleting HLS file {Path}", file);
                 }
-                else
-                {
-                    Logger.LogDebug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
-                    KillTimer.Change(intervalMs, Timeout.Infinite);
-                }
-            }
-        }
-
-        public void ChangeKillTimerIfStarted()
-        {
-            if (HasExited)
-            {
-                return;
             }
 
-            lock (_timerLock)
+            if (exs != null)
             {
-                if (KillTimer != null)
-                {
-                    var intervalMs = PingTimeout;
-
-                    Logger.LogDebug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
-                    KillTimer.Change(intervalMs, Timeout.Infinite);
-                }
+                throw new AggregateException("Error deleting HLS files", exs);
             }
         }
     }

+ 102 - 37
MediaBrowser.Api/BaseApiService.cs

@@ -1,5 +1,7 @@
 using System;
+using System.IO;
 using System.Linq;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
@@ -16,19 +18,35 @@ namespace MediaBrowser.Api
     /// <summary>
     /// Class BaseApiService
     /// </summary>
-    public class BaseApiService : IService, IRequiresRequest
+    public abstract class BaseApiService : IService, IRequiresRequest
     {
+        public BaseApiService(
+            ILogger logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory)
+        {
+            Logger = logger;
+            ServerConfigurationManager = serverConfigurationManager;
+            ResultFactory = httpResultFactory;
+        }
+
         /// <summary>
-        /// Gets or sets the logger.
+        /// Gets the logger.
         /// </summary>
         /// <value>The logger.</value>
-        public ILogger Logger => ApiEntryPoint.Instance.Logger;
+        protected ILogger Logger { get; }
+
+        /// <summary>
+        /// Gets or sets the server configuration manager.
+        /// </summary>
+        /// <value>The server configuration manager.</value>
+        protected IServerConfigurationManager ServerConfigurationManager { get; }
 
         /// <summary>
-        /// Gets or sets the HTTP result factory.
+        /// Gets the HTTP result factory.
         /// </summary>
         /// <value>The HTTP result factory.</value>
-        public IHttpResultFactory ResultFactory => ApiEntryPoint.Instance.ResultFactory;
+        protected IHttpResultFactory ResultFactory { get; }
 
         /// <summary>
         /// Gets or sets the request context.
@@ -36,10 +54,7 @@ namespace MediaBrowser.Api
         /// <value>The request context.</value>
         public IRequest Request { get; set; }
 
-        public string GetHeader(string name)
-        {
-            return Request.Headers[name];
-        }
+        public string GetHeader(string name) => Request.Headers[name];
 
         public static string[] SplitValue(string value, char delim)
         {
@@ -292,51 +307,101 @@ namespace MediaBrowser.Api
             return result;
         }
 
-        protected string GetPathValue(int index)
+        /// <summary>
+        /// Gets the path segment at the specified index.
+        /// </summary>
+        /// <param name="index">The index of the path segment.</param>
+        /// <returns>The path segment at the specified index.</returns>
+        /// <exception cref="IndexOutOfRangeException" >Path doesn't contain enough segments.</exception>
+        /// <exception cref="InvalidDataException" >Path doesn't start with the base url.</exception>
+        protected internal ReadOnlySpan<char> GetPathValue(int index)
         {
-            var pathInfo = Parse(Request.PathInfo);
-            var first = pathInfo[0];
+            static void ThrowIndexOutOfRangeException()
+            {
+                throw new IndexOutOfRangeException("Path doesn't contain enough segments.");
+            }
+
+            static void ThrowInvalidDataException()
+            {
+                throw new InvalidDataException("Path doesn't start with the base url.");
+            }
 
-            string baseUrl = ApiEntryPoint.Instance.ConfigurationManager.Configuration.BaseUrl;
+            ReadOnlySpan<char> path = Request.PathInfo;
 
-            // backwards compatibility
-            if (baseUrl.Length == 0)
+            // Remove the protocol part from the url
+            int pos = path.LastIndexOf("://");
+            if (pos != -1)
             {
-                if (string.Equals(first, "mediabrowser", StringComparison.OrdinalIgnoreCase)
-                    || string.Equals(first, "emby", StringComparison.OrdinalIgnoreCase))
-                {
-                    index++;
-                }
+                path = path.Slice(pos + 3);
             }
-            else if (string.Equals(first, baseUrl.Remove(0, 1)))
+
+            // Remove the query string
+            pos = path.LastIndexOf('?');
+            if (pos != -1)
             {
-                index++;
-                var second = pathInfo[1];
-                if (string.Equals(second, "mediabrowser", StringComparison.OrdinalIgnoreCase)
-                    || string.Equals(second, "emby", StringComparison.OrdinalIgnoreCase))
+                path = path.Slice(0, pos);
+            }
+
+            // Remove the domain
+            pos = path.IndexOf('/');
+            if (pos != -1)
+            {
+                path = path.Slice(pos);
+            }
+
+            // Remove base url
+            string baseUrl = ServerConfigurationManager.Configuration.BaseUrl;
+            int baseUrlLen = baseUrl.Length;
+            if (baseUrlLen != 0)
+            {
+                if (path.StartsWith(baseUrl, StringComparison.OrdinalIgnoreCase))
                 {
-                    index++;
+                    path = path.Slice(baseUrlLen);
+                }
+                else
+                {
+                    // The path doesn't start with the base url,
+                    // how did we get here?
+                    ThrowInvalidDataException();
                 }
             }
 
-            return pathInfo[index];
-        }
+            // Remove leading /
+            path = path.Slice(1);
 
-        private static string[] Parse(string pathUri)
-        {
-            var actionParts = pathUri.Split(new[] { "://" }, StringSplitOptions.None);
+            // Backwards compatibility
+            const string Emby = "emby/";
+            if (path.StartsWith(Emby, StringComparison.OrdinalIgnoreCase))
+            {
+                path = path.Slice(Emby.Length);
+            }
 
-            var pathInfo = actionParts[actionParts.Length - 1];
+            const string MediaBrowser = "mediabrowser/";
+            if (path.StartsWith(MediaBrowser, StringComparison.OrdinalIgnoreCase))
+            {
+                path = path.Slice(MediaBrowser.Length);
+            }
 
-            var optionsPos = pathInfo.LastIndexOf('?');
-            if (optionsPos != -1)
+            // Skip segments until we are at the right index
+            for (int i = 0; i < index; i++)
             {
-                pathInfo = pathInfo.Substring(0, optionsPos);
+                pos = path.IndexOf('/');
+                if (pos == -1)
+                {
+                    ThrowIndexOutOfRangeException();
+                }
+
+                path = path.Slice(pos + 1);
             }
 
-            var args = pathInfo.Split('/');
+            // Remove the rest
+            pos = path.IndexOf('/');
+            if (pos != -1)
+            {
+                path = path.Slice(0, pos);
+            }
 
-            return args.Skip(1).ToArray();
+            return path;
         }
 
         /// <summary>

+ 10 - 6
MediaBrowser.Api/BrandingService.cs

@@ -1,6 +1,9 @@
 using MediaBrowser.Common.Configuration;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Branding;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api
 {
@@ -17,21 +20,22 @@ namespace MediaBrowser.Api
 
     public class BrandingService : BaseApiService
     {
-        private readonly IConfigurationManager _config;
-
-        public BrandingService(IConfigurationManager config)
+        public BrandingService(
+            ILogger<BrandingService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
-            _config = config;
         }
 
         public object Get(GetBrandingOptions request)
         {
-            return _config.GetConfiguration<BrandingOptions>("branding");
+            return ServerConfigurationManager.GetConfiguration<BrandingOptions>("branding");
         }
 
         public object Get(GetBrandingCss request)
         {
-            var result = _config.GetConfiguration<BrandingOptions>("branding");
+            var result = ServerConfigurationManager.GetConfiguration<BrandingOptions>("branding");
 
             // When null this throws a 405 error under Mono OSX, so default to empty string
             return ResultFactory.GetResult(Request, result.CustomCss ?? string.Empty, "text/css");

+ 9 - 1
MediaBrowser.Api/ChannelService.cs

@@ -4,6 +4,7 @@ using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 using MediaBrowser.Api.UserLibrary;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
@@ -13,6 +14,7 @@ using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api
 {
@@ -188,7 +190,13 @@ namespace MediaBrowser.Api
         private readonly IChannelManager _channelManager;
         private IUserManager _userManager;
 
-        public ChannelService(IChannelManager channelManager, IUserManager userManager)
+        public ChannelService(
+            ILogger<ChannelService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IChannelManager channelManager,
+            IUserManager userManager)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _channelManager = channelManager;
             _userManager = userManager;

+ 10 - 11
MediaBrowser.Api/ConfigurationService.cs

@@ -1,14 +1,12 @@
 using System.IO;
 using System.Threading.Tasks;
 using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api
 {
@@ -78,18 +76,19 @@ namespace MediaBrowser.Api
         /// </summary>
         private readonly IServerConfigurationManager _configurationManager;
 
-        private readonly IFileSystem _fileSystem;
-        private readonly IProviderManager _providerManager;
-        private readonly ILibraryManager _libraryManager;
         private readonly IMediaEncoder _mediaEncoder;
 
-        public ConfigurationService(IJsonSerializer jsonSerializer, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IProviderManager providerManager, ILibraryManager libraryManager, IMediaEncoder mediaEncoder)
+        public ConfigurationService(
+            ILogger<ConfigurationService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IJsonSerializer jsonSerializer,
+            IServerConfigurationManager configurationManager,
+            IMediaEncoder mediaEncoder)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _jsonSerializer = jsonSerializer;
             _configurationManager = configurationManager;
-            _fileSystem = fileSystem;
-            _providerManager = providerManager;
-            _libraryManager = libraryManager;
             _mediaEncoder = mediaEncoder;
         }
 
@@ -131,7 +130,7 @@ namespace MediaBrowser.Api
 
         public async Task Post(UpdateNamedConfiguration request)
         {
-            var key = GetPathValue(2);
+            var key = GetPathValue(2).ToString();
 
             var configurationType = _configurationManager.GetConfigurationType(key);
             var configuration = await _jsonSerializer.DeserializeFromStreamAsync(request.RequestStream, configurationType).ConfigureAwait(false);

+ 10 - 2
MediaBrowser.Api/Devices/DeviceService.cs

@@ -1,6 +1,6 @@
-using System;
 using System.IO;
 using System.Threading.Tasks;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Devices;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Security;
@@ -8,6 +8,7 @@ using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.Devices;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.Devices
 {
@@ -81,7 +82,14 @@ namespace MediaBrowser.Api.Devices
         private readonly IAuthenticationRepository _authRepo;
         private readonly ISessionManager _sessionManager;
 
-        public DeviceService(IDeviceManager deviceManager, IAuthenticationRepository authRepo, ISessionManager sessionManager)
+        public DeviceService(
+            ILogger<DeviceService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IDeviceManager deviceManager,
+            IAuthenticationRepository authRepo,
+            ISessionManager sessionManager)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _deviceManager = deviceManager;
             _authRepo = authRepo;

+ 9 - 1
MediaBrowser.Api/DisplayPreferencesService.cs

@@ -1,9 +1,11 @@
 using System.Threading;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api
 {
@@ -61,7 +63,13 @@ namespace MediaBrowser.Api
         /// </summary>
         /// <param name="jsonSerializer">The json serializer.</param>
         /// <param name="displayPreferencesManager">The display preferences manager.</param>
-        public DisplayPreferencesService(IJsonSerializer jsonSerializer, IDisplayPreferencesRepository displayPreferencesManager)
+        public DisplayPreferencesService(
+            ILogger<DisplayPreferencesService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IJsonSerializer jsonSerializer,
+            IDisplayPreferencesRepository displayPreferencesManager)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _jsonSerializer = jsonSerializer;
             _displayPreferencesManager = displayPreferencesManager;

+ 11 - 8
MediaBrowser.Api/EnvironmentService.cs

@@ -3,10 +3,12 @@ using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api
 {
@@ -107,8 +109,8 @@ namespace MediaBrowser.Api
     [Authenticated(Roles = "Admin", AllowBeforeStartupWizard = true)]
     public class EnvironmentService : BaseApiService
     {
-        const char UncSeparator = '\\';
-        const string UncSeparatorString = "\\";
+        private const char UncSeparator = '\\';
+        private const string UncSeparatorString = "\\";
 
         /// <summary>
         /// The _network manager
@@ -120,13 +122,14 @@ namespace MediaBrowser.Api
         /// Initializes a new instance of the <see cref="EnvironmentService" /> class.
         /// </summary>
         /// <param name="networkManager">The network manager.</param>
-        public EnvironmentService(INetworkManager networkManager, IFileSystem fileSystem)
+        public EnvironmentService(
+            ILogger<EnvironmentService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            INetworkManager networkManager,
+            IFileSystem fileSystem)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
-            if (networkManager == null)
-            {
-                throw new ArgumentNullException(nameof(networkManager));
-            }
-
             _networkManager = networkManager;
             _fileSystem = fileSystem;
         }

+ 9 - 1
MediaBrowser.Api/FilterService.cs

@@ -1,12 +1,14 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api
 {
@@ -84,7 +86,13 @@ namespace MediaBrowser.Api
         private readonly ILibraryManager _libraryManager;
         private readonly IUserManager _userManager;
 
-        public FilterService(ILibraryManager libraryManager, IUserManager userManager)
+        public FilterService(
+            ILogger<FilterService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            ILibraryManager libraryManager,
+            IUserManager userManager)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _libraryManager = libraryManager;
             _userManager = userManager;

+ 14 - 10
MediaBrowser.Api/Images/ImageByNameService.cs

@@ -5,11 +5,13 @@ using System.Linq;
 using System.Threading.Tasks;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Controller;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.Images
 {
@@ -101,17 +103,19 @@ namespace MediaBrowser.Api.Images
         private readonly IServerApplicationPaths _appPaths;
 
         private readonly IFileSystem _fileSystem;
-        private readonly IHttpResultFactory _resultFactory;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="ImageByNameService" /> class.
         /// </summary>
-        /// <param name="appPaths">The app paths.</param>
-        public ImageByNameService(IServerApplicationPaths appPaths, IFileSystem fileSystem, IHttpResultFactory resultFactory)
+        public ImageByNameService(
+            ILogger<ImageByNameService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory resultFactory,
+            IFileSystem fileSystem)
+            : base(logger, serverConfigurationManager, resultFactory)
         {
-            _appPaths = appPaths;
+            _appPaths = serverConfigurationManager.ApplicationPaths;
             _fileSystem = fileSystem;
-            _resultFactory = resultFactory;
         }
 
         public object Get(GetMediaInfoImages request)
@@ -187,7 +191,7 @@ namespace MediaBrowser.Api.Images
 
             var path = paths.FirstOrDefault(File.Exists) ?? paths.FirstOrDefault();
 
-            return _resultFactory.GetStaticFileResult(Request, path);
+            return ResultFactory.GetStaticFileResult(Request, path);
         }
 
         /// <summary>
@@ -207,7 +211,7 @@ namespace MediaBrowser.Api.Images
 
                 if (!string.IsNullOrEmpty(path))
                 {
-                    return _resultFactory.GetStaticFileResult(Request, path);
+                    return ResultFactory.GetStaticFileResult(Request, path);
                 }
             }
 
@@ -224,7 +228,7 @@ namespace MediaBrowser.Api.Images
 
                 if (!string.IsNullOrEmpty(path))
                 {
-                    return _resultFactory.GetStaticFileResult(Request, path);
+                    return ResultFactory.GetStaticFileResult(Request, path);
                 }
             }
 
@@ -247,7 +251,7 @@ namespace MediaBrowser.Api.Images
 
                 if (!string.IsNullOrEmpty(path))
                 {
-                    return _resultFactory.GetStaticFileResult(Request, path);
+                    return ResultFactory.GetStaticFileResult(Request, path);
                 }
             }
 
@@ -263,7 +267,7 @@ namespace MediaBrowser.Api.Images
 
                 if (!string.IsNullOrEmpty(path))
                 {
-                    return _resultFactory.GetStaticFileResult(Request, path);
+                    return ResultFactory.GetStaticFileResult(Request, path);
                 }
             }
 

+ 21 - 12
MediaBrowser.Api/Images/ImageService.cs

@@ -6,12 +6,12 @@ using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 using MediaBrowser.Common.Extensions;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Dto;
@@ -231,7 +231,6 @@ namespace MediaBrowser.Api.Images
 
         private readonly IProviderManager _providerManager;
 
-        private readonly IItemRepository _itemRepo;
         private readonly IImageProcessor _imageProcessor;
         private readonly IFileSystem _fileSystem;
         private readonly IAuthorizationContext _authContext;
@@ -239,12 +238,21 @@ namespace MediaBrowser.Api.Images
         /// <summary>
         /// Initializes a new instance of the <see cref="ImageService" /> class.
         /// </summary>
-        public ImageService(IUserManager userManager, ILibraryManager libraryManager, IProviderManager providerManager, IItemRepository itemRepo, IImageProcessor imageProcessor, IFileSystem fileSystem, IAuthorizationContext authContext)
+        public ImageService(
+            Logger<ImageService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IUserManager userManager,
+            ILibraryManager libraryManager,
+            IProviderManager providerManager,
+            IImageProcessor imageProcessor,
+            IFileSystem fileSystem,
+            IAuthorizationContext authContext)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _userManager = userManager;
             _libraryManager = libraryManager;
             _providerManager = providerManager;
-            _itemRepo = itemRepo;
             _imageProcessor = imageProcessor;
             _fileSystem = fileSystem;
             _authContext = authContext;
@@ -402,7 +410,7 @@ namespace MediaBrowser.Api.Images
 
         public object Get(GetItemByNameImage request)
         {
-            var type = GetPathValue(0);
+            var type = GetPathValue(0).ToString();
 
             var item = GetItemByName(request.Name, type, _libraryManager, new DtoOptions(false));
 
@@ -411,7 +419,7 @@ namespace MediaBrowser.Api.Images
 
         public object Head(GetItemByNameImage request)
         {
-            var type = GetPathValue(0);
+            var type = GetPathValue(0).ToString();
 
             var item = GetItemByName(request.Name, type, _libraryManager, new DtoOptions(false));
 
@@ -424,12 +432,13 @@ namespace MediaBrowser.Api.Images
         /// <param name="request">The request.</param>
         public Task Post(PostUserImage request)
         {
-            var userId = GetPathValue(1);
-            AssertCanUpdateUser(_authContext, _userManager, new Guid(userId), true);
+            var id = Guid.Parse(GetPathValue(1));
 
-            request.Type = (ImageType)Enum.Parse(typeof(ImageType), GetPathValue(3), true);
+            AssertCanUpdateUser(_authContext, _userManager, id, true);
 
-            var item = _userManager.GetUserById(userId);
+            request.Type = Enum.Parse<ImageType>(GetPathValue(3).ToString(), true);
+
+            var item = _userManager.GetUserById(id);
 
             return PostImage(item, request.RequestStream, request.Type, Request.ContentType);
         }
@@ -440,9 +449,9 @@ namespace MediaBrowser.Api.Images
         /// <param name="request">The request.</param>
         public Task Post(PostItemImage request)
         {
-            var id = GetPathValue(1);
+            var id = Guid.Parse(GetPathValue(1));
 
-            request.Type = (ImageType)Enum.Parse(typeof(ImageType), GetPathValue(3), true);
+            request.Type = Enum.Parse<ImageType>(GetPathValue(3).ToString(), true);
 
             var item = _libraryManager.GetItemById(id);
 

+ 12 - 4
MediaBrowser.Api/Images/RemoteImageService.cs

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
-using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
@@ -16,6 +16,7 @@ using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Providers;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.Images
 {
@@ -108,13 +109,20 @@ namespace MediaBrowser.Api.Images
         private readonly IHttpClient _httpClient;
         private readonly IFileSystem _fileSystem;
 
-        private readonly IDtoService _dtoService;
         private readonly ILibraryManager _libraryManager;
 
-        public RemoteImageService(IProviderManager providerManager, IDtoService dtoService, IServerApplicationPaths appPaths, IHttpClient httpClient, IFileSystem fileSystem, ILibraryManager libraryManager)
+        public RemoteImageService(
+            ILogger<RemoteImageService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IProviderManager providerManager,
+            IServerApplicationPaths appPaths,
+            IHttpClient httpClient,
+            IFileSystem fileSystem,
+            ILibraryManager libraryManager)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _providerManager = providerManager;
-            _dtoService = dtoService;
             _appPaths = appPaths;
             _httpClient = httpClient;
             _fileSystem = fileSystem;

+ 11 - 2
MediaBrowser.Api/ItemLookupService.cs

@@ -6,6 +6,7 @@ using System.Threading;
 using System.Threading.Tasks;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Controller;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Entities.Movies;
@@ -121,10 +122,18 @@ namespace MediaBrowser.Api
         private readonly ILibraryManager _libraryManager;
         private readonly IJsonSerializer _json;
 
-        public ItemLookupService(IProviderManager providerManager, IServerApplicationPaths appPaths, IFileSystem fileSystem, ILibraryManager libraryManager, IJsonSerializer json)
+        public ItemLookupService(
+            ILogger<ItemLookupService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IProviderManager providerManager,
+            IFileSystem fileSystem,
+            ILibraryManager libraryManager,
+            IJsonSerializer json)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _providerManager = providerManager;
-            _appPaths = appPaths;
+            _appPaths = serverConfigurationManager.ApplicationPaths;
             _fileSystem = fileSystem;
             _libraryManager = libraryManager;
             _json = json;

+ 9 - 3
MediaBrowser.Api/ItemRefreshService.cs

@@ -1,3 +1,4 @@
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Providers;
@@ -38,14 +39,19 @@ namespace MediaBrowser.Api
         private readonly ILibraryManager _libraryManager;
         private readonly IProviderManager _providerManager;
         private readonly IFileSystem _fileSystem;
-        private readonly ILogger _logger;
 
-        public ItemRefreshService(ILibraryManager libraryManager, IProviderManager providerManager, IFileSystem fileSystem, ILogger logger)
+        public ItemRefreshService(
+            ILogger<ItemRefreshService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            ILibraryManager libraryManager,
+            IProviderManager providerManager,
+            IFileSystem fileSystem)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _libraryManager = libraryManager;
             _providerManager = providerManager;
             _fileSystem = fileSystem;
-            _logger = logger;
         }
 
         /// <summary>

+ 14 - 7
MediaBrowser.Api/ItemUpdateService.cs

@@ -16,6 +16,7 @@ using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Globalization;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api
 {
@@ -49,19 +50,25 @@ namespace MediaBrowser.Api
         private readonly ILibraryManager _libraryManager;
         private readonly IProviderManager _providerManager;
         private readonly ILocalizationManager _localizationManager;
-        private readonly IServerConfigurationManager _config;
         private readonly IFileSystem _fileSystem;
 
-        public ItemUpdateService(IFileSystem fileSystem, ILibraryManager libraryManager, IProviderManager providerManager, ILocalizationManager localizationManager, IServerConfigurationManager config)
+        public ItemUpdateService(
+            ILogger<ItemUpdateService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IFileSystem fileSystem,
+            ILibraryManager libraryManager,
+            IProviderManager providerManager,
+            ILocalizationManager localizationManager)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _libraryManager = libraryManager;
             _providerManager = providerManager;
             _localizationManager = localizationManager;
-            _config = config;
             _fileSystem = fileSystem;
         }
 
-        public async Task<object> Get(GetMetadataEditorInfo request)
+        public object Get(GetMetadataEditorInfo request)
         {
             var item = _libraryManager.GetItemById(request.ItemId);
 
@@ -101,7 +108,7 @@ namespace MediaBrowser.Api
             var item = _libraryManager.GetItemById(request.ItemId);
             var path = item.ContainingFolderPath;
 
-            var types = _config.Configuration.ContentTypes
+            var types = ServerConfigurationManager.Configuration.ContentTypes
                 .Where(i => !string.IsNullOrWhiteSpace(i.Name))
                 .Where(i => !string.Equals(i.Name, path, StringComparison.OrdinalIgnoreCase))
                 .ToList();
@@ -115,8 +122,8 @@ namespace MediaBrowser.Api
                 });
             }
 
-            _config.Configuration.ContentTypes = types.ToArray();
-            _config.SaveConfiguration();
+            ServerConfigurationManager.Configuration.ContentTypes = types.ToArray();
+            ServerConfigurationManager.SaveConfiguration();
         }
 
         private List<NameValuePair> GetContentTypeOptions(bool isForItem)

+ 26 - 26
MediaBrowser.Api/Library/LibraryService.cs

@@ -25,7 +25,6 @@ using MediaBrowser.Model.Activity;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.Globalization;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Querying;
@@ -315,46 +314,40 @@ namespace MediaBrowser.Api.Library
     /// </summary>
     public class LibraryService : BaseApiService
     {
-        /// <summary>
-        /// The _item repo
-        /// </summary>
-        private readonly IItemRepository _itemRepo;
-
+        private readonly IProviderManager _providerManager;
         private readonly ILibraryManager _libraryManager;
         private readonly IUserManager _userManager;
-        private readonly IUserDataManager _userDataManager;
-
         private readonly IDtoService _dtoService;
         private readonly IAuthorizationContext _authContext;
         private readonly IActivityManager _activityManager;
         private readonly ILocalizationManager _localization;
-        private readonly ILiveTvManager _liveTv;
-        private readonly ITVSeriesManager _tvManager;
         private readonly ILibraryMonitor _libraryMonitor;
-        private readonly IFileSystem _fileSystem;
-        private readonly IServerConfigurationManager _config;
-        private readonly IProviderManager _providerManager;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="LibraryService" /> class.
         /// </summary>
-        public LibraryService(IProviderManager providerManager, IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager,
-                              IDtoService dtoService, IUserDataManager userDataManager, IAuthorizationContext authContext, IActivityManager activityManager, ILocalizationManager localization, ILiveTvManager liveTv, ITVSeriesManager tvManager, ILibraryMonitor libraryMonitor, IFileSystem fileSystem, IServerConfigurationManager config)
+        public LibraryService(
+            ILogger<LibraryService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IProviderManager providerManager,
+            ILibraryManager libraryManager,
+            IUserManager userManager,
+            IDtoService dtoService,
+            IAuthorizationContext authContext,
+            IActivityManager activityManager,
+            ILocalizationManager localization,
+            ILibraryMonitor libraryMonitor)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
-            _itemRepo = itemRepo;
+            _providerManager = providerManager;
             _libraryManager = libraryManager;
             _userManager = userManager;
             _dtoService = dtoService;
-            _userDataManager = userDataManager;
             _authContext = authContext;
             _activityManager = activityManager;
             _localization = localization;
-            _liveTv = liveTv;
-            _tvManager = tvManager;
             _libraryMonitor = libraryMonitor;
-            _fileSystem = fileSystem;
-            _config = config;
-            _providerManager = providerManager;
         }
 
         private string[] GetRepresentativeItemTypes(string contentType)
@@ -390,7 +383,7 @@ namespace MediaBrowser.Api.Library
                 return false;
             }
 
-            var metadataOptions = _config.Configuration.MetadataOptions
+            var metadataOptions = ServerConfigurationManager.Configuration.MetadataOptions
                 .Where(i => itemTypes.Contains(i.ItemType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
                 .ToArray();
 
@@ -446,7 +439,7 @@ namespace MediaBrowser.Api.Library
                 return false;
             }
 
-            var metadataOptions = _config.Configuration.MetadataOptions
+            var metadataOptions = ServerConfigurationManager.Configuration.MetadataOptions
                 .Where(i => string.Equals(i.ItemType, type, StringComparison.OrdinalIgnoreCase))
                 .ToArray();
 
@@ -510,7 +503,7 @@ namespace MediaBrowser.Api.Library
                 return false;
             }
 
-            var metadataOptions = _config.Configuration.MetadataOptions
+            var metadataOptions = ServerConfigurationManager.Configuration.MetadataOptions
                 .Where(i => string.Equals(i.ItemType, type, StringComparison.OrdinalIgnoreCase))
                 .ToArray();
 
@@ -630,7 +623,14 @@ namespace MediaBrowser.Api.Library
 
             if (item is Movie || (program != null && program.IsMovie) || item is Trailer)
             {
-                return new MoviesService(_userManager, _libraryManager, _dtoService, _config, _authContext)
+                return new MoviesService(
+                    Logger,
+                    ServerConfigurationManager,
+                    ResultFactory,
+                    _userManager,
+                    _libraryManager,
+                    _dtoService,
+                    _authContext)
                 {
                     Request = Request,
 

+ 10 - 11
MediaBrowser.Api/Library/LibraryStructureService.cs

@@ -7,13 +7,14 @@ using System.Threading;
 using System.Threading.Tasks;
 using MediaBrowser.Common.Progress;
 using MediaBrowser.Controller;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.Library
 {
@@ -179,25 +180,23 @@ namespace MediaBrowser.Api.Library
         /// The _library manager
         /// </summary>
         private readonly ILibraryManager _libraryManager;
-
         private readonly ILibraryMonitor _libraryMonitor;
 
-        private readonly IFileSystem _fileSystem;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="LibraryStructureService" /> class.
         /// </summary>
-        public LibraryStructureService(IServerApplicationPaths appPaths, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IFileSystem fileSystem)
+        public LibraryStructureService(
+            ILogger<LibraryStructureService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            ILibraryManager libraryManager,
+            ILibraryMonitor libraryMonitor)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
-            if (appPaths == null)
-            {
-                throw new ArgumentNullException(nameof(appPaths));
-            }
-
-            _appPaths = appPaths;
+            _appPaths = serverConfigurationManager.ApplicationPaths;
             _libraryManager = libraryManager;
             _libraryMonitor = libraryMonitor;
-            _fileSystem = fileSystem;
         }
 
         /// <summary>

+ 8 - 10
MediaBrowser.Api/LiveTv/LiveTvService.cs

@@ -18,13 +18,13 @@ using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Controller.Net;
-using MediaBrowser.Model.Cryptography;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.LiveTv;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 using Microsoft.Net.Http.Headers;
 
 namespace MediaBrowser.Api.LiveTv
@@ -692,35 +692,33 @@ namespace MediaBrowser.Api.LiveTv
     {
         private readonly ILiveTvManager _liveTvManager;
         private readonly IUserManager _userManager;
-        private readonly IServerConfigurationManager _config;
         private readonly IHttpClient _httpClient;
         private readonly ILibraryManager _libraryManager;
         private readonly IDtoService _dtoService;
         private readonly IAuthorizationContext _authContext;
         private readonly ISessionContext _sessionContext;
-        private readonly ICryptoProvider _cryptographyProvider;
         private readonly IStreamHelper _streamHelper;
         private readonly IMediaSourceManager _mediaSourceManager;
 
         public LiveTvService(
-            ICryptoProvider crypto,
+            ILogger<LiveTvService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
             IMediaSourceManager mediaSourceManager,
             IStreamHelper streamHelper,
             ILiveTvManager liveTvManager,
             IUserManager userManager,
-            IServerConfigurationManager config,
             IHttpClient httpClient,
             ILibraryManager libraryManager,
             IDtoService dtoService,
             IAuthorizationContext authContext,
             ISessionContext sessionContext)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
-            _cryptographyProvider = crypto;
             _mediaSourceManager = mediaSourceManager;
             _streamHelper = streamHelper;
             _liveTvManager = liveTvManager;
             _userManager = userManager;
-            _config = config;
             _httpClient = httpClient;
             _libraryManager = libraryManager;
             _dtoService = dtoService;
@@ -911,17 +909,17 @@ namespace MediaBrowser.Api.LiveTv
 
             config.TunerHosts = config.TunerHosts.Where(i => !string.Equals(request.Id, i.Id, StringComparison.OrdinalIgnoreCase)).ToArray();
 
-            _config.SaveConfiguration("livetv", config);
+            ServerConfigurationManager.SaveConfiguration("livetv", config);
         }
 
         private LiveTvOptions GetConfiguration()
         {
-            return _config.GetConfiguration<LiveTvOptions>("livetv");
+            return ServerConfigurationManager.GetConfiguration<LiveTvOptions>("livetv");
         }
 
         private void UpdateConfiguration(LiveTvOptions options)
         {
-            _config.SaveConfiguration("livetv", options);
+            ServerConfigurationManager.SaveConfiguration("livetv", options);
         }
 
         public async Task<object> Get(GetLineups request)

+ 8 - 1
MediaBrowser.Api/LocalizationService.cs

@@ -1,7 +1,9 @@
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Globalization;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api
 {
@@ -52,7 +54,12 @@ namespace MediaBrowser.Api
         /// Initializes a new instance of the <see cref="LocalizationService"/> class.
         /// </summary>
         /// <param name="localization">The localization.</param>
-        public LocalizationService(ILocalizationManager localization)
+        public LocalizationService(
+            ILogger<LocalizationService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            ILocalizationManager localization)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _localization = localization;
         }

+ 10 - 1
MediaBrowser.Api/Movies/CollectionService.cs

@@ -1,9 +1,11 @@
 using System;
 using MediaBrowser.Controller.Collections;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Collections;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.Movies
 {
@@ -50,7 +52,14 @@ namespace MediaBrowser.Api.Movies
         private readonly IDtoService _dtoService;
         private readonly IAuthorizationContext _authContext;
 
-        public CollectionService(ICollectionManager collectionManager, IDtoService dtoService, IAuthorizationContext authContext)
+        public CollectionService(
+            ILogger<CollectionService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            ICollectionManager collectionManager,
+            IDtoService dtoService,
+            IAuthorizationContext authContext)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _collectionManager = collectionManager;
             _dtoService = dtoService;

+ 15 - 8
MediaBrowser.Api/Movies/MoviesService.cs

@@ -14,6 +14,7 @@ using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.Movies
 {
@@ -75,18 +76,24 @@ namespace MediaBrowser.Api.Movies
         private readonly ILibraryManager _libraryManager;
 
         private readonly IDtoService _dtoService;
-        private readonly IServerConfigurationManager _config;
         private readonly IAuthorizationContext _authContext;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="MoviesService" /> class.
         /// </summary>
-        public MoviesService(IUserManager userManager, ILibraryManager libraryManager, IDtoService dtoService, IServerConfigurationManager config, IAuthorizationContext authContext)
+        public MoviesService(
+            ILogger logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IUserManager userManager,
+            ILibraryManager libraryManager,
+            IDtoService dtoService,
+            IAuthorizationContext authContext)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _userManager = userManager;
             _libraryManager = libraryManager;
             _dtoService = dtoService;
-            _config = config;
             _authContext = authContext;
         }
 
@@ -110,7 +117,7 @@ namespace MediaBrowser.Api.Movies
                 _libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id);
 
             var itemTypes = new List<string> { typeof(Movie).Name };
-            if (_config.Configuration.EnableExternalContentInSuggestions)
+            if (ServerConfigurationManager.Configuration.EnableExternalContentInSuggestions)
             {
                 itemTypes.Add(typeof(Trailer).Name);
                 itemTypes.Add(typeof(LiveTvProgram).Name);
@@ -167,7 +174,7 @@ namespace MediaBrowser.Api.Movies
             var recentlyPlayedMovies = _libraryManager.GetItemList(query);
 
             var itemTypes = new List<string> { typeof(Movie).Name };
-            if (_config.Configuration.EnableExternalContentInSuggestions)
+            if (ServerConfigurationManager.Configuration.EnableExternalContentInSuggestions)
             {
                 itemTypes.Add(typeof(Trailer).Name);
                 itemTypes.Add(typeof(LiveTvProgram).Name);
@@ -249,7 +256,7 @@ namespace MediaBrowser.Api.Movies
         private IEnumerable<RecommendationDto> GetWithDirector(User user, IEnumerable<string> names, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
         {
             var itemTypes = new List<string> { typeof(Movie).Name };
-            if (_config.Configuration.EnableExternalContentInSuggestions)
+            if (ServerConfigurationManager.Configuration.EnableExternalContentInSuggestions)
             {
                 itemTypes.Add(typeof(Trailer).Name);
                 itemTypes.Add(typeof(LiveTvProgram).Name);
@@ -291,7 +298,7 @@ namespace MediaBrowser.Api.Movies
         private IEnumerable<RecommendationDto> GetWithActor(User user, IEnumerable<string> names, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
         {
             var itemTypes = new List<string> { typeof(Movie).Name };
-            if (_config.Configuration.EnableExternalContentInSuggestions)
+            if (ServerConfigurationManager.Configuration.EnableExternalContentInSuggestions)
             {
                 itemTypes.Add(typeof(Trailer).Name);
                 itemTypes.Add(typeof(LiveTvProgram).Name);
@@ -332,7 +339,7 @@ namespace MediaBrowser.Api.Movies
         private IEnumerable<RecommendationDto> GetSimilarTo(User user, List<BaseItem> baselineItems, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
         {
             var itemTypes = new List<string> { typeof(Movie).Name };
-            if (_config.Configuration.EnableExternalContentInSuggestions)
+            if (ServerConfigurationManager.Configuration.EnableExternalContentInSuggestions)
             {
                 itemTypes.Add(typeof(Trailer).Name);
                 itemTypes.Add(typeof(LiveTvProgram).Name);

+ 22 - 10
MediaBrowser.Api/Movies/TrailersService.cs

@@ -1,5 +1,5 @@
 using MediaBrowser.Api.UserLibrary;
-using MediaBrowser.Controller.Collections;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
@@ -8,6 +8,7 @@ using MediaBrowser.Model.Globalization;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.Movies
 {
@@ -27,28 +28,31 @@ namespace MediaBrowser.Api.Movies
         /// </summary>
         private readonly IUserManager _userManager;
 
-        /// <summary>
-        /// The _user data repository
-        /// </summary>
-        private readonly IUserDataManager _userDataRepository;
         /// <summary>
         /// The _library manager
         /// </summary>
         private readonly ILibraryManager _libraryManager;
 
         private readonly IDtoService _dtoService;
-        private readonly ICollectionManager _collectionManager;
         private readonly ILocalizationManager _localizationManager;
         private readonly IJsonSerializer _json;
         private readonly IAuthorizationContext _authContext;
 
-        public TrailersService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IDtoService dtoService, ICollectionManager collectionManager, ILocalizationManager localizationManager, IJsonSerializer json, IAuthorizationContext authContext)
+        public TrailersService(
+            ILogger<TrailersService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IUserManager userManager,
+            ILibraryManager libraryManager,
+            IDtoService dtoService,
+            ILocalizationManager localizationManager,
+            IJsonSerializer json,
+            IAuthorizationContext authContext)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _userManager = userManager;
-            _userDataRepository = userDataRepository;
             _libraryManager = libraryManager;
             _dtoService = dtoService;
-            _collectionManager = collectionManager;
             _localizationManager = localizationManager;
             _json = json;
             _authContext = authContext;
@@ -61,7 +65,15 @@ namespace MediaBrowser.Api.Movies
 
             getItems.IncludeItemTypes = "Trailer";
 
-            return new ItemsService(_userManager, _libraryManager, _localizationManager, _dtoService, _authContext)
+            return new ItemsService(
+                Logger,
+                ServerConfigurationManager,
+                ResultFactory,
+                _userManager,
+                _libraryManager,
+                _localizationManager,
+                _dtoService,
+                _authContext)
             {
                 Request = Request,
 

+ 13 - 1
MediaBrowser.Api/Music/AlbumsService.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
@@ -8,6 +9,7 @@ using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.Music
 {
@@ -41,7 +43,17 @@ namespace MediaBrowser.Api.Music
         private readonly IDtoService _dtoService;
         private readonly IAuthorizationContext _authContext;
 
-        public AlbumsService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService, IAuthorizationContext authContext)
+        public AlbumsService(
+            Logger<AlbumsService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IUserManager userManager,
+            IUserDataManager userDataRepository,
+            ILibraryManager libraryManager,
+            IItemRepository itemRepo,
+            IDtoService dtoService,
+            IAuthorizationContext authContext)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _userManager = userManager;
             _userDataRepository = userDataRepository;

+ 12 - 1
MediaBrowser.Api/Music/InstantMixService.cs

@@ -1,5 +1,6 @@
 using System.Collections.Generic;
 using System.Linq;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
@@ -8,6 +9,7 @@ using MediaBrowser.Controller.Playlists;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.Music
 {
@@ -62,7 +64,16 @@ namespace MediaBrowser.Api.Music
         private readonly IMusicManager _musicManager;
         private readonly IAuthorizationContext _authContext;
 
-        public InstantMixService(IUserManager userManager, IDtoService dtoService, IMusicManager musicManager, ILibraryManager libraryManager, IAuthorizationContext authContext)
+        public InstantMixService(
+            ILogger<InstantMixService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IUserManager userManager,
+            IDtoService dtoService,
+            IMusicManager musicManager,
+            ILibraryManager libraryManager,
+            IAuthorizationContext authContext)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _userManager = userManager;
             _dtoService = dtoService;

+ 8 - 5
MediaBrowser.Api/PackageService.cs

@@ -2,14 +2,14 @@ using System;
 using System.Collections.Generic;
 using System.Globalization;
 using System.Linq;
-using System.Threading;
 using System.Threading.Tasks;
-using MediaBrowser.Common;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Updates;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.Updates;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api
 {
@@ -118,12 +118,15 @@ namespace MediaBrowser.Api
     public class PackageService : BaseApiService
     {
         private readonly IInstallationManager _installationManager;
-        private readonly IApplicationHost _appHost;
 
-        public PackageService(IInstallationManager installationManager, IApplicationHost appHost)
+        public PackageService(
+            ILogger<PackageService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IInstallationManager installationManager)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _installationManager = installationManager;
-            _appHost = appHost;
         }
 
         /// <summary>

+ 5 - 9
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -33,12 +33,6 @@ namespace MediaBrowser.Api.Playback
     {
         protected virtual bool EnableOutputInSubFolder => false;
 
-        /// <summary>
-        /// Gets or sets the application paths.
-        /// </summary>
-        /// <value>The application paths.</value>
-        protected IServerConfigurationManager ServerConfigurationManager { get; private set; }
-
         /// <summary>
         /// Gets or sets the user manager.
         /// </summary>
@@ -89,7 +83,9 @@ namespace MediaBrowser.Api.Playback
         /// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
         /// </summary>
         protected BaseStreamingService(
-            IServerConfigurationManager serverConfig,
+            ILogger logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
             IUserManager userManager,
             ILibraryManager libraryManager,
             IIsoManager isoManager,
@@ -101,8 +97,8 @@ namespace MediaBrowser.Api.Playback
             IMediaSourceManager mediaSourceManager,
             IJsonSerializer jsonSerializer,
             IAuthorizationContext authorizationContext)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
-            ServerConfigurationManager = serverConfig;
             UserManager = userManager;
             LibraryManager = libraryManager;
             IsoManager = isoManager;
@@ -588,7 +584,7 @@ namespace MediaBrowser.Api.Playback
         }
 
         /// <summary>
-        /// Parses query parameters as StreamOptions
+        /// Parses query parameters as StreamOptions.
         /// </summary>
         /// <param name="request">The stream request.</param>
         private void ParseStreamOptions(StreamRequest request)

+ 33 - 29
MediaBrowser.Api/Playback/Hls/BaseHlsService.cs

@@ -12,7 +12,6 @@ using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Serialization;
@@ -25,6 +24,39 @@ namespace MediaBrowser.Api.Playback.Hls
     /// </summary>
     public abstract class BaseHlsService : BaseStreamingService
     {
+        public BaseHlsService(
+            ILogger logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IUserManager userManager,
+            ILibraryManager libraryManager,
+            IIsoManager isoManager,
+            IMediaEncoder mediaEncoder,
+            IFileSystem fileSystem,
+            IDlnaManager dlnaManager,
+            ISubtitleEncoder subtitleEncoder,
+            IDeviceManager deviceManager,
+            IMediaSourceManager mediaSourceManager,
+            IJsonSerializer jsonSerializer,
+            IAuthorizationContext authorizationContext)
+                : base(
+                    logger,
+                    serverConfigurationManager,
+                    httpResultFactory,
+                    userManager,
+                    libraryManager,
+                    isoManager,
+                    mediaEncoder,
+                    fileSystem,
+                    dlnaManager,
+                    subtitleEncoder,
+                    deviceManager,
+                    mediaSourceManager,
+                    jsonSerializer,
+                    authorizationContext)
+        {
+        }
+
         /// <summary>
         /// Gets the audio arguments.
         /// </summary>
@@ -313,33 +345,5 @@ namespace MediaBrowser.Api.Playback.Hls
         {
             return 0;
         }
-
-        public BaseHlsService(
-            IServerConfigurationManager serverConfig,
-            IUserManager userManager,
-            ILibraryManager libraryManager,
-            IIsoManager isoManager,
-            IMediaEncoder mediaEncoder,
-            IFileSystem fileSystem,
-            IDlnaManager dlnaManager,
-            ISubtitleEncoder subtitleEncoder,
-            IDeviceManager deviceManager,
-            IMediaSourceManager mediaSourceManager,
-            IJsonSerializer jsonSerializer,
-            IAuthorizationContext authorizationContext)
-                : base(serverConfig,
-                    userManager,
-                    libraryManager,
-                    isoManager,
-                    mediaEncoder,
-                    fileSystem,
-                    dlnaManager,
-                    subtitleEncoder,
-                    deviceManager,
-                    mediaSourceManager,
-                    jsonSerializer,
-                    authorizationContext)
-        {
-        }
     }
 }

+ 7 - 3
MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs

@@ -94,9 +94,10 @@ namespace MediaBrowser.Api.Playback.Hls
     [Authenticated]
     public class DynamicHlsService : BaseHlsService
     {
-
         public DynamicHlsService(
-            IServerConfigurationManager serverConfig,
+            ILogger logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
             IUserManager userManager,
             ILibraryManager libraryManager,
             IIsoManager isoManager,
@@ -109,7 +110,10 @@ namespace MediaBrowser.Api.Playback.Hls
             IJsonSerializer jsonSerializer,
             IAuthorizationContext authorizationContext,
             INetworkManager networkManager)
-            : base(serverConfig,
+            : base(
+                logger,
+                serverConfigurationManager,
+                httpResultFactory,
                 userManager,
                 libraryManager,
                 isoManager,

+ 11 - 6
MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs

@@ -8,6 +8,7 @@ using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.Playback.Hls
 {
@@ -83,19 +84,22 @@ namespace MediaBrowser.Api.Playback.Hls
 
     public class HlsSegmentService : BaseApiService
     {
-        private readonly IServerConfigurationManager _config;
         private readonly IFileSystem _fileSystem;
 
-        public HlsSegmentService(IServerConfigurationManager config, IFileSystem fileSystem)
+        public HlsSegmentService(
+            ILogger<HlsSegmentService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IFileSystem fileSystem)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
-            _config = config;
             _fileSystem = fileSystem;
         }
 
         public Task<object> Get(GetHlsPlaylistLegacy request)
         {
             var file = request.PlaylistId + Path.GetExtension(Request.PathInfo);
-            file = Path.Combine(_config.GetTranscodePath(), file);
+            file = Path.Combine(ServerConfigurationManager.GetTranscodePath(), file);
 
             return GetFileResult(file, file);
         }
@@ -113,7 +117,8 @@ namespace MediaBrowser.Api.Playback.Hls
         public Task<object> Get(GetHlsVideoSegmentLegacy request)
         {
             var file = request.SegmentId + Path.GetExtension(Request.PathInfo);
-            var transcodeFolderPath = _config.GetTranscodePath();
+            var transcodeFolderPath = ServerConfigurationManager.GetTranscodePath();
+
             file = Path.Combine(transcodeFolderPath, file);
 
             var normalizedPlaylistId = request.PlaylistId;
@@ -133,7 +138,7 @@ namespace MediaBrowser.Api.Playback.Hls
         {
             // TODO: Deprecate with new iOS app
             var file = request.SegmentId + Path.GetExtension(Request.PathInfo);
-            file = Path.Combine(_config.GetTranscodePath(), file);
+            file = Path.Combine(ServerConfigurationManager.GetTranscodePath(), file);
 
             return ResultFactory.GetStaticFileResult(Request, file, FileShareMode.ReadWrite);
         }

+ 8 - 2
MediaBrowser.Api/Playback/Hls/VideoHlsService.cs

@@ -12,6 +12,7 @@ using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.Playback.Hls
 {
@@ -137,7 +138,9 @@ namespace MediaBrowser.Api.Playback.Hls
         }
 
         public VideoHlsService(
-            IServerConfigurationManager serverConfig,
+            ILogger<VideoHlsService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
             IUserManager userManager,
             ILibraryManager libraryManager,
             IIsoManager isoManager,
@@ -149,7 +152,10 @@ namespace MediaBrowser.Api.Playback.Hls
             IMediaSourceManager mediaSourceManager,
             IJsonSerializer jsonSerializer,
             IAuthorizationContext authorizationContext)
-                : base(serverConfig,
+                : base(
+                    logger,
+                    serverConfigurationManager,
+                    httpResultFactory,
                     userManager,
                     libraryManager,
                     isoManager,

+ 7 - 9
MediaBrowser.Api/Playback/MediaInfoService.cs

@@ -69,36 +69,34 @@ namespace MediaBrowser.Api.Playback
         private readonly IMediaSourceManager _mediaSourceManager;
         private readonly IDeviceManager _deviceManager;
         private readonly ILibraryManager _libraryManager;
-        private readonly IServerConfigurationManager _config;
         private readonly INetworkManager _networkManager;
         private readonly IMediaEncoder _mediaEncoder;
         private readonly IUserManager _userManager;
         private readonly IJsonSerializer _json;
         private readonly IAuthorizationContext _authContext;
-        private readonly ILogger _logger;
 
         public MediaInfoService(
+            ILogger logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
             IMediaSourceManager mediaSourceManager,
             IDeviceManager deviceManager,
             ILibraryManager libraryManager,
-            IServerConfigurationManager config,
             INetworkManager networkManager,
             IMediaEncoder mediaEncoder,
             IUserManager userManager,
             IJsonSerializer json,
-            IAuthorizationContext authContext,
-            ILoggerFactory loggerFactory)
+            IAuthorizationContext authContext)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _mediaSourceManager = mediaSourceManager;
             _deviceManager = deviceManager;
             _libraryManager = libraryManager;
-            _config = config;
             _networkManager = networkManager;
             _mediaEncoder = mediaEncoder;
             _userManager = userManager;
             _json = json;
             _authContext = authContext;
-            _logger = loggerFactory.CreateLogger(nameof(MediaInfoService));
         }
 
         public object Get(GetBitrateTestBytes request)
@@ -275,7 +273,7 @@ namespace MediaBrowser.Api.Playback
                 catch (Exception ex)
                 {
                     mediaSources = new List<MediaSourceInfo>();
-                    _logger.LogError(ex, "Could not find media sources for item id {id}", id);
+                    Logger.LogError(ex, "Could not find media sources for item id {id}", id);
                     // TODO PlaybackException ??
                     //result.ErrorCode = ex.ErrorCode;
                 }
@@ -533,7 +531,7 @@ namespace MediaBrowser.Api.Playback
 
             if (remoteClientMaxBitrate <= 0)
             {
-                remoteClientMaxBitrate = _config.Configuration.RemoteClientBitrateLimit;
+                remoteClientMaxBitrate = ServerConfigurationManager.Configuration.RemoteClientBitrateLimit;
             }
 
             if (remoteClientMaxBitrate > 0)

+ 20 - 14
MediaBrowser.Api/Playback/Progressive/AudioService.cs

@@ -10,6 +10,7 @@ using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.Playback.Progressive
 {
@@ -32,8 +33,10 @@ namespace MediaBrowser.Api.Playback.Progressive
     public class AudioService : BaseProgressiveStreamingService
     {
         public AudioService(
+            ILogger logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
             IHttpClient httpClient,
-            IServerConfigurationManager serverConfig,
             IUserManager userManager,
             ILibraryManager libraryManager,
             IIsoManager isoManager,
@@ -45,19 +48,22 @@ namespace MediaBrowser.Api.Playback.Progressive
             IMediaSourceManager mediaSourceManager,
             IJsonSerializer jsonSerializer,
             IAuthorizationContext authorizationContext)
-                : base(httpClient,
-                    serverConfig,
-                    userManager,
-                    libraryManager,
-                    isoManager,
-                    mediaEncoder,
-                    fileSystem,
-                    dlnaManager,
-                    subtitleEncoder,
-                    deviceManager,
-                    mediaSourceManager,
-                    jsonSerializer,
-                    authorizationContext)
+            : base(
+                logger,
+                serverConfigurationManager,
+                httpResultFactory,
+                httpClient,
+                userManager,
+                libraryManager,
+                isoManager,
+                mediaEncoder,
+                fileSystem,
+                dlnaManager,
+                subtitleEncoder,
+                deviceManager,
+                mediaSourceManager,
+                jsonSerializer,
+                authorizationContext)
         {
         }
 

+ 8 - 2
MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs

@@ -15,6 +15,7 @@ using MediaBrowser.Model.IO;
 using MediaBrowser.Model.MediaInfo;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 using Microsoft.Net.Http.Headers;
 
 namespace MediaBrowser.Api.Playback.Progressive
@@ -27,8 +28,10 @@ namespace MediaBrowser.Api.Playback.Progressive
         protected IHttpClient HttpClient { get; private set; }
 
         public BaseProgressiveStreamingService(
+            ILogger logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
             IHttpClient httpClient,
-            IServerConfigurationManager serverConfig,
             IUserManager userManager,
             ILibraryManager libraryManager,
             IIsoManager isoManager,
@@ -40,7 +43,10 @@ namespace MediaBrowser.Api.Playback.Progressive
             IMediaSourceManager mediaSourceManager,
             IJsonSerializer jsonSerializer,
             IAuthorizationContext authorizationContext)
-            : base(serverConfig,
+            : base(
+                logger,
+                serverConfigurationManager,
+                httpResultFactory,
                 userManager,
                 libraryManager,
                 isoManager,

+ 9 - 3
MediaBrowser.Api/Playback/Progressive/VideoService.cs

@@ -10,6 +10,7 @@ using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.Playback.Progressive
 {
@@ -69,8 +70,10 @@ namespace MediaBrowser.Api.Playback.Progressive
     public class VideoService : BaseProgressiveStreamingService
     {
         public VideoService(
+            Logger<VideoService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
             IHttpClient httpClient,
-            IServerConfigurationManager serverConfig,
             IUserManager userManager,
             ILibraryManager libraryManager,
             IIsoManager isoManager,
@@ -82,8 +85,11 @@ namespace MediaBrowser.Api.Playback.Progressive
             IMediaSourceManager mediaSourceManager,
             IJsonSerializer jsonSerializer,
             IAuthorizationContext authorizationContext)
-            : base(httpClient,
-                serverConfig,
+            : base(
+                logger,
+                serverConfigurationManager,
+                httpResultFactory,
+                httpClient,
                 userManager,
                 libraryManager,
                 isoManager,

+ 38 - 30
MediaBrowser.Api/Playback/UniversalAudioService.cs

@@ -76,8 +76,10 @@ namespace MediaBrowser.Api.Playback
     public class UniversalAudioService : BaseApiService
     {
         public UniversalAudioService(
-            IHttpClient httpClient,
+            ILogger<UniversalAudioService> logger,
             IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IHttpClient httpClient,
             IUserManager userManager,
             ILibraryManager libraryManager,
             IIsoManager isoManager,
@@ -87,15 +89,12 @@ namespace MediaBrowser.Api.Playback
             IDeviceManager deviceManager,
             ISubtitleEncoder subtitleEncoder,
             IMediaSourceManager mediaSourceManager,
-            IZipClient zipClient,
             IJsonSerializer jsonSerializer,
             IAuthorizationContext authorizationContext,
-            IImageProcessor imageProcessor,
-            INetworkManager networkManager,
-            ILoggerFactory loggerFactory)
+            INetworkManager networkManager)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             HttpClient = httpClient;
-            ServerConfigurationManager = serverConfigurationManager;
             UserManager = userManager;
             LibraryManager = libraryManager;
             IsoManager = isoManager;
@@ -105,17 +104,12 @@ namespace MediaBrowser.Api.Playback
             DeviceManager = deviceManager;
             SubtitleEncoder = subtitleEncoder;
             MediaSourceManager = mediaSourceManager;
-            ZipClient = zipClient;
             JsonSerializer = jsonSerializer;
             AuthorizationContext = authorizationContext;
-            ImageProcessor = imageProcessor;
             NetworkManager = networkManager;
-            _loggerFactory = loggerFactory;
-            _logger = loggerFactory.CreateLogger(nameof(UniversalAudioService));
         }
 
         protected IHttpClient HttpClient { get; private set; }
-        protected IServerConfigurationManager ServerConfigurationManager { get; private set; }
         protected IUserManager UserManager { get; private set; }
         protected ILibraryManager LibraryManager { get; private set; }
         protected IIsoManager IsoManager { get; private set; }
@@ -125,13 +119,9 @@ namespace MediaBrowser.Api.Playback
         protected IDeviceManager DeviceManager { get; private set; }
         protected ISubtitleEncoder SubtitleEncoder { get; private set; }
         protected IMediaSourceManager MediaSourceManager { get; private set; }
-        protected IZipClient ZipClient { get; private set; }
         protected IJsonSerializer JsonSerializer { get; private set; }
         protected IAuthorizationContext AuthorizationContext { get; private set; }
-        protected IImageProcessor ImageProcessor { get; private set; }
         protected INetworkManager NetworkManager { get; private set; }
-        private ILoggerFactory _loggerFactory;
-        private ILogger _logger;
 
         public Task<object> Get(GetUniversalAudioStream request)
         {
@@ -242,7 +232,18 @@ namespace MediaBrowser.Api.Playback
 
             AuthorizationContext.GetAuthorizationInfo(Request).DeviceId = request.DeviceId;
 
-            var mediaInfoService = new MediaInfoService(MediaSourceManager, DeviceManager, LibraryManager, ServerConfigurationManager, NetworkManager, MediaEncoder, UserManager, JsonSerializer, AuthorizationContext, _loggerFactory)
+            var mediaInfoService = new MediaInfoService(
+                Logger,
+                ServerConfigurationManager,
+                ResultFactory,
+                MediaSourceManager,
+                DeviceManager,
+                LibraryManager,
+                NetworkManager,
+                MediaEncoder,
+                UserManager,
+                JsonSerializer,
+                AuthorizationContext)
             {
                 Request = Request
             };
@@ -276,19 +277,22 @@ namespace MediaBrowser.Api.Playback
 
             if (!isStatic && string.Equals(mediaSource.TranscodingSubProtocol, "hls", StringComparison.OrdinalIgnoreCase))
             {
-                var service = new DynamicHlsService(ServerConfigurationManager,
-                  UserManager,
-                  LibraryManager,
-                  IsoManager,
-                  MediaEncoder,
-                  FileSystem,
-                  DlnaManager,
-                  SubtitleEncoder,
-                  DeviceManager,
-                  MediaSourceManager,
-                  JsonSerializer,
-                  AuthorizationContext,
-                  NetworkManager)
+                var service = new DynamicHlsService(
+                    Logger,
+                    ServerConfigurationManager,
+                    ResultFactory,
+                    UserManager,
+                    LibraryManager,
+                    IsoManager,
+                    MediaEncoder,
+                    FileSystem,
+                    DlnaManager,
+                    SubtitleEncoder,
+                    DeviceManager,
+                    MediaSourceManager,
+                    JsonSerializer,
+                    AuthorizationContext,
+                    NetworkManager)
                 {
                     Request = Request
                 };
@@ -322,8 +326,11 @@ namespace MediaBrowser.Api.Playback
             }
             else
             {
-                var service = new AudioService(HttpClient,
+                var service = new AudioService(
+                    Logger,
                     ServerConfigurationManager,
+                    ResultFactory,
+                    HttpClient,
                     UserManager,
                     LibraryManager,
                     IsoManager,
@@ -360,6 +367,7 @@ namespace MediaBrowser.Api.Playback
                 {
                     return await service.Head(newRequest).ConfigureAwait(false);
                 }
+
                 return await service.Get(newRequest).ConfigureAwait(false);
             }
         }

+ 12 - 1
MediaBrowser.Api/PlaylistService.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Linq;
 using System.Threading.Tasks;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
@@ -9,6 +10,7 @@ using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Playlists;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api
 {
@@ -128,7 +130,16 @@ namespace MediaBrowser.Api
         private readonly ILibraryManager _libraryManager;
         private readonly IAuthorizationContext _authContext;
 
-        public PlaylistService(IDtoService dtoService, IPlaylistManager playlistManager, IUserManager userManager, ILibraryManager libraryManager, IAuthorizationContext authContext)
+        public PlaylistService(
+            ILogger<PlaylistService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IDtoService dtoService,
+            IPlaylistManager playlistManager,
+            IUserManager userManager,
+            ILibraryManager libraryManager,
+            IAuthorizationContext authContext)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _dtoService = dtoService;
             _playlistManager = playlistManager;

+ 10 - 17
MediaBrowser.Api/PluginService.cs

@@ -3,14 +3,14 @@ using System.IO;
 using System.Linq;
 using System.Threading.Tasks;
 using MediaBrowser.Common;
-using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Plugins;
 using MediaBrowser.Common.Updates;
-using MediaBrowser.Controller.Devices;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Plugins;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api
 {
@@ -150,25 +150,18 @@ namespace MediaBrowser.Api
         /// </summary>
         private readonly IApplicationHost _appHost;
         private readonly IInstallationManager _installationManager;
-        private readonly INetworkManager _network;
-        private readonly IDeviceManager _deviceManager;
 
-        public PluginService(IJsonSerializer jsonSerializer,
+        public PluginService(
+            ILogger<PluginService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IJsonSerializer jsonSerializer,
             IApplicationHost appHost,
-            IInstallationManager installationManager,
-            INetworkManager network,
-            IDeviceManager deviceManager)
-            : base()
+            IInstallationManager installationManager)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
-            if (jsonSerializer == null)
-            {
-                throw new ArgumentNullException(nameof(jsonSerializer));
-            }
-
             _appHost = appHost;
             _installationManager = installationManager;
-            _network = network;
-            _deviceManager = deviceManager;
             _jsonSerializer = jsonSerializer;
         }
 
@@ -248,7 +241,7 @@ namespace MediaBrowser.Api
         {
             // We need to parse this manually because we told service stack not to with IRequiresRequestStream
             // https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
-            var id = new Guid(GetPathValue(1));
+            var id = Guid.Parse(GetPathValue(1));
 
             var plugin = _appHost.Plugins.First(p => p.Id == id) as IHasPluginConfiguration;
 

+ 2 - 0
MediaBrowser.Api/Properties/AssemblyInfo.cs

@@ -1,5 +1,6 @@
 using System.Reflection;
 using System.Resources;
+using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 
 // General Information about an assembly is controlled through the following
@@ -14,6 +15,7 @@ using System.Runtime.InteropServices;
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
 [assembly: NeutralResourcesLanguage("en")]
+[assembly: InternalsVisibleTo("Jellyfin.Api.Tests")]
 
 // Setting ComVisible to false makes the types in this assembly not visible
 // to COM components.  If you need to access a type in this assembly from

+ 18 - 21
MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs

@@ -6,6 +6,7 @@ using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.Tasks;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.ScheduledTasks
 {
@@ -85,27 +86,23 @@ namespace MediaBrowser.Api.ScheduledTasks
     public class ScheduledTaskService : BaseApiService
     {
         /// <summary>
-        /// Gets or sets the task manager.
+        /// The task manager.
         /// </summary>
-        /// <value>The task manager.</value>
-        private ITaskManager TaskManager { get; set; }
-
-        private readonly IServerConfigurationManager _config;
+        private readonly ITaskManager _taskManager;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="ScheduledTaskService" /> class.
         /// </summary>
         /// <param name="taskManager">The task manager.</param>
         /// <exception cref="ArgumentNullException">taskManager</exception>
-        public ScheduledTaskService(ITaskManager taskManager, IServerConfigurationManager config)
+        public ScheduledTaskService(
+            ILogger<ScheduledTaskService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            ITaskManager taskManager)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
-            if (taskManager == null)
-            {
-                throw new ArgumentNullException(nameof(taskManager));
-            }
-
-            TaskManager = taskManager;
-            _config = config;
+            _taskManager = taskManager;
         }
 
         /// <summary>
@@ -115,7 +112,7 @@ namespace MediaBrowser.Api.ScheduledTasks
         /// <returns>IEnumerable{TaskInfo}.</returns>
         public object Get(GetScheduledTasks request)
         {
-            IEnumerable<IScheduledTaskWorker> result = TaskManager.ScheduledTasks
+            IEnumerable<IScheduledTaskWorker> result = _taskManager.ScheduledTasks
                 .OrderBy(i => i.Name);
 
             if (request.IsHidden.HasValue)
@@ -171,7 +168,7 @@ namespace MediaBrowser.Api.ScheduledTasks
         /// <exception cref="ResourceNotFoundException">Task not found</exception>
         public object Get(GetScheduledTask request)
         {
-            var task = TaskManager.ScheduledTasks.FirstOrDefault(i => string.Equals(i.Id, request.Id));
+            var task = _taskManager.ScheduledTasks.FirstOrDefault(i => string.Equals(i.Id, request.Id));
 
             if (task == null)
             {
@@ -190,14 +187,14 @@ namespace MediaBrowser.Api.ScheduledTasks
         /// <exception cref="ResourceNotFoundException">Task not found</exception>
         public void Post(StartScheduledTask request)
         {
-            var task = TaskManager.ScheduledTasks.FirstOrDefault(i => string.Equals(i.Id, request.Id));
+            var task = _taskManager.ScheduledTasks.FirstOrDefault(i => string.Equals(i.Id, request.Id));
 
             if (task == null)
             {
                 throw new ResourceNotFoundException("Task not found");
             }
 
-            TaskManager.Execute(task, new TaskOptions());
+            _taskManager.Execute(task, new TaskOptions());
         }
 
         /// <summary>
@@ -207,14 +204,14 @@ namespace MediaBrowser.Api.ScheduledTasks
         /// <exception cref="ResourceNotFoundException">Task not found</exception>
         public void Delete(StopScheduledTask request)
         {
-            var task = TaskManager.ScheduledTasks.FirstOrDefault(i => string.Equals(i.Id, request.Id));
+            var task = _taskManager.ScheduledTasks.FirstOrDefault(i => string.Equals(i.Id, request.Id));
 
             if (task == null)
             {
                 throw new ResourceNotFoundException("Task not found");
             }
 
-            TaskManager.Cancel(task);
+            _taskManager.Cancel(task);
         }
 
         /// <summary>
@@ -226,9 +223,9 @@ namespace MediaBrowser.Api.ScheduledTasks
         {
             // We need to parse this manually because we told service stack not to with IRequiresRequestStream
             // https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
-            var id = GetPathValue(1);
+            var id = GetPathValue(1).ToString();
 
-            var task = TaskManager.ScheduledTasks.FirstOrDefault(i => string.Equals(i.Id, id, StringComparison.Ordinal));
+            var task = _taskManager.ScheduledTasks.FirstOrDefault(i => string.Equals(i.Id, id, StringComparison.Ordinal));
 
             if (task == null)
             {

+ 11 - 1
MediaBrowser.Api/SearchService.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Globalization;
 using System.Linq;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
@@ -12,6 +13,7 @@ using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Search;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api
 {
@@ -122,7 +124,15 @@ namespace MediaBrowser.Api
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="dtoService">The dto service.</param>
         /// <param name="imageProcessor">The image processor.</param>
-        public SearchService(ISearchEngine searchEngine, ILibraryManager libraryManager, IDtoService dtoService, IImageProcessor imageProcessor)
+        public SearchService(
+            ILogger<SearchService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            ISearchEngine searchEngine,
+            ILibraryManager libraryManager,
+            IDtoService dtoService,
+            IImageProcessor imageProcessor)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _searchEngine = searchEngine;
             _libraryManager = libraryManager;

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

@@ -4,6 +4,7 @@ using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 using MediaBrowser.Controller;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Devices;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
@@ -12,6 +13,7 @@ using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.Session;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.Session
 {
@@ -269,12 +271,12 @@ namespace MediaBrowser.Api.Session
     }
 
     /// <summary>
-    /// Class SessionsService
+    /// Class SessionsService.
     /// </summary>
     public class SessionsService : BaseApiService
     {
         /// <summary>
-        /// The _session manager
+        /// The _session manager.
         /// </summary>
         private readonly ISessionManager _sessionManager;
 
@@ -283,9 +285,20 @@ namespace MediaBrowser.Api.Session
         private readonly IAuthenticationRepository _authRepo;
         private readonly IDeviceManager _deviceManager;
         private readonly ISessionContext _sessionContext;
-        private IServerApplicationHost _appHost;
-
-        public SessionsService(ISessionManager sessionManager, IServerApplicationHost appHost, IUserManager userManager, IAuthorizationContext authContext, IAuthenticationRepository authRepo, IDeviceManager deviceManager, ISessionContext sessionContext)
+        private readonly IServerApplicationHost _appHost;
+
+        public SessionsService(
+            ILogger<SessionsService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            ISessionManager sessionManager,
+            IServerApplicationHost appHost,
+            IUserManager userManager,
+            IAuthorizationContext authContext,
+            IAuthenticationRepository authRepo,
+            IDeviceManager deviceManager,
+            ISessionContext sessionContext)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _sessionManager = sessionManager;
             _userManager = userManager;

+ 20 - 25
MediaBrowser.Api/StartupWizardService.cs

@@ -1,12 +1,10 @@
 using System.Linq;
 using System.Threading.Tasks;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api
 {
@@ -45,35 +43,32 @@ namespace MediaBrowser.Api
     [Authenticated(AllowBeforeStartupWizard = true, Roles = "Admin")]
     public class StartupWizardService : BaseApiService
     {
-        private readonly IServerConfigurationManager _config;
-        private readonly IServerApplicationHost _appHost;
         private readonly IUserManager _userManager;
-        private readonly IMediaEncoder _mediaEncoder;
-        private readonly IHttpClient _httpClient;
 
-        public StartupWizardService(IServerConfigurationManager config, IHttpClient httpClient, IServerApplicationHost appHost, IUserManager userManager, IMediaEncoder mediaEncoder)
+        public StartupWizardService(
+            ILogger<StartupWizardService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IUserManager userManager)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
-            _config = config;
-            _appHost = appHost;
             _userManager = userManager;
-            _mediaEncoder = mediaEncoder;
-            _httpClient = httpClient;
         }
 
         public void Post(ReportStartupWizardComplete request)
         {
-            _config.Configuration.IsStartupWizardCompleted = true;
-            _config.SetOptimalValues();
-            _config.SaveConfiguration();
+            ServerConfigurationManager.Configuration.IsStartupWizardCompleted = true;
+            ServerConfigurationManager.SetOptimalValues();
+            ServerConfigurationManager.SaveConfiguration();
         }
 
         public object Get(GetStartupConfiguration request)
         {
             var result = new StartupConfiguration
             {
-                UICulture = _config.Configuration.UICulture,
-                MetadataCountryCode = _config.Configuration.MetadataCountryCode,
-                PreferredMetadataLanguage = _config.Configuration.PreferredMetadataLanguage
+                UICulture = ServerConfigurationManager.Configuration.UICulture,
+                MetadataCountryCode = ServerConfigurationManager.Configuration.MetadataCountryCode,
+                PreferredMetadataLanguage = ServerConfigurationManager.Configuration.PreferredMetadataLanguage
             };
 
             return result;
@@ -81,17 +76,17 @@ namespace MediaBrowser.Api
 
         public void Post(UpdateStartupConfiguration request)
         {
-            _config.Configuration.UICulture = request.UICulture;
-            _config.Configuration.MetadataCountryCode = request.MetadataCountryCode;
-            _config.Configuration.PreferredMetadataLanguage = request.PreferredMetadataLanguage;
-            _config.SaveConfiguration();
+            ServerConfigurationManager.Configuration.UICulture = request.UICulture;
+            ServerConfigurationManager.Configuration.MetadataCountryCode = request.MetadataCountryCode;
+            ServerConfigurationManager.Configuration.PreferredMetadataLanguage = request.PreferredMetadataLanguage;
+            ServerConfigurationManager.SaveConfiguration();
         }
 
         public void Post(UpdateRemoteAccessConfiguration request)
         {
-            _config.Configuration.EnableRemoteAccess = request.EnableRemoteAccess;
-            _config.Configuration.EnableUPnP = request.EnableAutomaticPortMapping;
-            _config.SaveConfiguration();
+            ServerConfigurationManager.Configuration.EnableRemoteAccess = request.EnableRemoteAccess;
+            ServerConfigurationManager.Configuration.EnableUPnP = request.EnableAutomaticPortMapping;
+            ServerConfigurationManager.SaveConfiguration();
         }
 
         public object Get(GetStartupUser request)

+ 13 - 1
MediaBrowser.Api/Subtitles/SubtitleService.cs

@@ -6,6 +6,7 @@ using System.Linq;
 using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.MediaEncoding;
@@ -130,7 +131,18 @@ namespace MediaBrowser.Api.Subtitles
         private readonly IFileSystem _fileSystem;
         private readonly IAuthorizationContext _authContext;
 
-        public SubtitleService(ILibraryManager libraryManager, ISubtitleManager subtitleManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager, IProviderManager providerManager, IFileSystem fileSystem, IAuthorizationContext authContext)
+        public SubtitleService(
+            ILogger<SubtitleService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            ILibraryManager libraryManager,
+            ISubtitleManager subtitleManager,
+            ISubtitleEncoder subtitleEncoder,
+            IMediaSourceManager mediaSourceManager,
+            IProviderManager providerManager,
+            IFileSystem fileSystem,
+            IAuthorizationContext authContext)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _libraryManager = libraryManager;
             _subtitleManager = subtitleManager;

+ 11 - 1
MediaBrowser.Api/SuggestionsService.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Linq;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
@@ -8,6 +9,7 @@ using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api
 {
@@ -39,7 +41,15 @@ namespace MediaBrowser.Api
         private readonly IUserManager _userManager;
         private readonly ILibraryManager _libraryManager;
 
-        public SuggestionsService(IDtoService dtoService, IAuthorizationContext authContext, IUserManager userManager, ILibraryManager libraryManager)
+        public SuggestionsService(
+            ILogger<SuggestionsService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IDtoService dtoService,
+            IAuthorizationContext authContext,
+            IUserManager userManager,
+            ILibraryManager libraryManager)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _dtoService = dtoService;
             _authContext = authContext;

+ 8 - 1
MediaBrowser.Api/System/ActivityLogService.cs

@@ -1,9 +1,11 @@
 using System;
 using System.Globalization;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Activity;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.System
 {
@@ -35,7 +37,12 @@ namespace MediaBrowser.Api.System
     {
         private readonly IActivityManager _activityManager;
 
-        public ActivityLogService(IActivityManager activityManager)
+        public ActivityLogService(
+            ILogger<ActivityLogService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IActivityManager activityManager)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _activityManager = activityManager;
         }

+ 10 - 3
MediaBrowser.Api/System/SystemService.cs

@@ -7,6 +7,7 @@ using System.Threading.Tasks;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Net;
@@ -103,13 +104,19 @@ namespace MediaBrowser.Api.System
         /// Initializes a new instance of the <see cref="SystemService" /> class.
         /// </summary>
         /// <param name="appHost">The app host.</param>
-        /// <param name="appPaths">The application paths.</param>
         /// <param name="fileSystem">The file system.</param>
         /// <exception cref="ArgumentNullException">jsonSerializer</exception>
-        public SystemService(IServerApplicationHost appHost, IApplicationPaths appPaths, IFileSystem fileSystem, INetworkManager network)
+        public SystemService(
+            ILogger<SystemService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IServerApplicationHost appHost,
+            IFileSystem fileSystem,
+            INetworkManager network)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
+            _appPaths = serverConfigurationManager.ApplicationPaths;
             _appHost = appHost;
-            _appPaths = appPaths;
             _fileSystem = fileSystem;
             _network = network;
         }

+ 160 - 0
MediaBrowser.Api/TranscodingJob.cs

@@ -0,0 +1,160 @@
+using System;
+using System.Diagnostics;
+using System.Threading;
+using MediaBrowser.Api.Playback;
+using MediaBrowser.Controller.MediaEncoding;
+using MediaBrowser.Model.Dto;
+using Microsoft.Extensions.Logging;
+
+namespace MediaBrowser.Api
+{
+    /// <summary>
+    /// Class TranscodingJob.
+    /// </summary>
+    public class TranscodingJob
+    {
+        /// <summary>
+        /// Gets or sets the play session identifier.
+        /// </summary>
+        /// <value>The play session identifier.</value>
+        public string PlaySessionId { get; set; }
+
+        /// <summary>
+        /// Gets or sets the live stream identifier.
+        /// </summary>
+        /// <value>The live stream identifier.</value>
+        public string LiveStreamId { get; set; }
+
+        public bool IsLiveOutput { get; set; }
+
+        /// <summary>
+        /// Gets or sets the path.
+        /// </summary>
+        /// <value>The path.</value>
+        public MediaSourceInfo MediaSource { get; set; }
+        public string Path { get; set; }
+        /// <summary>
+        /// Gets or sets the type.
+        /// </summary>
+        /// <value>The type.</value>
+        public TranscodingJobType Type { get; set; }
+        /// <summary>
+        /// Gets or sets the process.
+        /// </summary>
+        /// <value>The process.</value>
+        public Process Process { get; set; }
+        public ILogger Logger { get; private set; }
+        /// <summary>
+        /// Gets or sets the active request count.
+        /// </summary>
+        /// <value>The active request count.</value>
+        public int ActiveRequestCount { get; set; }
+        /// <summary>
+        /// Gets or sets the kill timer.
+        /// </summary>
+        /// <value>The kill timer.</value>
+        private Timer KillTimer { get; set; }
+
+        public string DeviceId { get; set; }
+
+        public CancellationTokenSource CancellationTokenSource { get; set; }
+
+        public object ProcessLock = new object();
+
+        public bool HasExited { get; set; }
+        public bool IsUserPaused { get; set; }
+
+        public string Id { get; set; }
+
+        public float? Framerate { get; set; }
+        public double? CompletionPercentage { get; set; }
+
+        public long? BytesDownloaded { get; set; }
+        public long? BytesTranscoded { get; set; }
+        public int? BitRate { get; set; }
+
+        public long? TranscodingPositionTicks { get; set; }
+        public long? DownloadPositionTicks { get; set; }
+
+        public TranscodingThrottler TranscodingThrottler { get; set; }
+
+        private readonly object _timerLock = new object();
+
+        public DateTime LastPingDate { get; set; }
+        public int PingTimeout { get; set; }
+
+        public TranscodingJob(ILogger logger)
+        {
+            Logger = logger;
+        }
+
+        public void StopKillTimer()
+        {
+            lock (_timerLock)
+            {
+                if (KillTimer != null)
+                {
+                    KillTimer.Change(Timeout.Infinite, Timeout.Infinite);
+                }
+            }
+        }
+
+        public void DisposeKillTimer()
+        {
+            lock (_timerLock)
+            {
+                if (KillTimer != null)
+                {
+                    KillTimer.Dispose();
+                    KillTimer = null;
+                }
+            }
+        }
+
+        public void StartKillTimer(Action<object> callback)
+        {
+            StartKillTimer(callback, PingTimeout);
+        }
+
+        public void StartKillTimer(Action<object> callback, int intervalMs)
+        {
+            if (HasExited)
+            {
+                return;
+            }
+
+            lock (_timerLock)
+            {
+                if (KillTimer == null)
+                {
+                    Logger.LogDebug("Starting kill timer at {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
+                    KillTimer = new Timer(new TimerCallback(callback), this, intervalMs, Timeout.Infinite);
+                }
+                else
+                {
+                    Logger.LogDebug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
+                    KillTimer.Change(intervalMs, Timeout.Infinite);
+                }
+            }
+        }
+
+        public void ChangeKillTimerIfStarted()
+        {
+            if (HasExited)
+            {
+                return;
+            }
+
+            lock (_timerLock)
+            {
+                if (KillTimer != null)
+                {
+                    var intervalMs = PingTimeout;
+
+                    Logger.LogDebug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
+                    KillTimer.Change(intervalMs, Timeout.Infinite);
+                }
+            }
+        }
+    }
+}

+ 13 - 10
MediaBrowser.Api/TvShowsService.cs

@@ -3,17 +3,18 @@ using System.Collections.Generic;
 using System.Globalization;
 using System.Linq;
 using MediaBrowser.Common.Extensions;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.TV;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Services;
+using MediaBrowser.Model.Querying;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api
 {
@@ -252,16 +253,11 @@ namespace MediaBrowser.Api
         /// </summary>
         private readonly IUserManager _userManager;
 
-        /// <summary>
-        /// The _user data repository
-        /// </summary>
-        private readonly IUserDataManager _userDataManager;
         /// <summary>
         /// The _library manager
         /// </summary>
         private readonly ILibraryManager _libraryManager;
 
-        private readonly IItemRepository _itemRepo;
         private readonly IDtoService _dtoService;
         private readonly ITVSeriesManager _tvSeriesManager;
         private readonly IAuthorizationContext _authContext;
@@ -272,12 +268,19 @@ namespace MediaBrowser.Api
         /// <param name="userManager">The user manager.</param>
         /// <param name="userDataManager">The user data repository.</param>
         /// <param name="libraryManager">The library manager.</param>
-        public TvShowsService(IUserManager userManager, IUserDataManager userDataManager, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService, ITVSeriesManager tvSeriesManager, IAuthorizationContext authContext)
+        public TvShowsService(
+            ILogger<TvShowsService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IUserManager userManager,
+            ILibraryManager libraryManager,
+            IDtoService dtoService,
+            ITVSeriesManager tvSeriesManager,
+            IAuthorizationContext authContext)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _userManager = userManager;
-            _userDataManager = userDataManager;
             _libraryManager = libraryManager;
-            _itemRepo = itemRepo;
             _dtoService = dtoService;
             _tvSeriesManager = tvSeriesManager;
             _authContext = authContext;

+ 23 - 5
MediaBrowser.Api/UserLibrary/ArtistsService.cs

@@ -1,14 +1,15 @@
 using System;
 using System.Collections.Generic;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.UserLibrary
 {
@@ -49,6 +50,27 @@ namespace MediaBrowser.Api.UserLibrary
     [Authenticated]
     public class ArtistsService : BaseItemsByNameService<MusicArtist>
     {
+        public ArtistsService(
+            ILogger<GenresService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IUserManager userManager,
+            ILibraryManager libraryManager,
+            IUserDataManager userDataRepository,
+            IDtoService dtoService,
+            IAuthorizationContext authorizationContext)
+            : base(
+                logger,
+                serverConfigurationManager,
+                httpResultFactory,
+                userManager,
+                libraryManager,
+                userDataRepository,
+                dtoService,
+                authorizationContext)
+        {
+        }
+
         /// <summary>
         /// Gets the specified request.
         /// </summary>
@@ -122,9 +144,5 @@ namespace MediaBrowser.Api.UserLibrary
         {
             throw new NotImplementedException();
         }
-
-        public ArtistsService(IUserManager userManager, ILibraryManager libraryManager, IUserDataManager userDataRepository, IItemRepository itemRepository, IDtoService dtoService, IAuthorizationContext authorizationContext) : base(userManager, libraryManager, userDataRepository, itemRepository, dtoService, authorizationContext)
-        {
-        }
     }
 }

+ 28 - 17
MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs

@@ -1,14 +1,15 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.UserLibrary
 {
@@ -19,37 +20,47 @@ namespace MediaBrowser.Api.UserLibrary
     public abstract class BaseItemsByNameService<TItemType> : BaseApiService
         where TItemType : BaseItem, IItemByName
     {
-        /// <summary>
-        /// The _user manager
-        /// </summary>
-        protected readonly IUserManager UserManager;
-        /// <summary>
-        /// The library manager
-        /// </summary>
-        protected readonly ILibraryManager LibraryManager;
-        protected readonly IUserDataManager UserDataRepository;
-        protected readonly IItemRepository ItemRepository;
-        protected IDtoService DtoService { get; private set; }
-        protected IAuthorizationContext AuthorizationContext { get; private set; }
-
         /// <summary>
         /// Initializes a new instance of the <see cref="BaseItemsByNameService{TItemType}" /> class.
         /// </summary>
         /// <param name="userManager">The user manager.</param>
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="userDataRepository">The user data repository.</param>
-        /// <param name="itemRepository">The item repository.</param>
         /// <param name="dtoService">The dto service.</param>
-        protected BaseItemsByNameService(IUserManager userManager, ILibraryManager libraryManager, IUserDataManager userDataRepository, IItemRepository itemRepository, IDtoService dtoService, IAuthorizationContext authorizationContext)
+        protected BaseItemsByNameService(
+            ILogger logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IUserManager userManager,
+            ILibraryManager libraryManager,
+            IUserDataManager userDataRepository,
+            IDtoService dtoService,
+            IAuthorizationContext authorizationContext)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             UserManager = userManager;
             LibraryManager = libraryManager;
             UserDataRepository = userDataRepository;
-            ItemRepository = itemRepository;
             DtoService = dtoService;
             AuthorizationContext = authorizationContext;
         }
 
+        /// <summary>
+        /// Gets the _user manager.
+        /// </summary>
+        protected IUserManager UserManager { get; }
+
+        /// <summary>
+        /// Gets the library manager
+        /// </summary>
+        protected ILibraryManager LibraryManager { get; }
+
+        protected IUserDataManager UserDataRepository { get; }
+
+        protected IDtoService DtoService { get; }
+
+        protected IAuthorizationContext AuthorizationContext { get; }
+
         protected BaseItem GetParentItem(GetItemsByName request)
         {
             BaseItem parentItem;

+ 23 - 4
MediaBrowser.Api/UserLibrary/GenresService.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
@@ -9,6 +10,7 @@ using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.UserLibrary
 {
@@ -47,6 +49,27 @@ namespace MediaBrowser.Api.UserLibrary
     [Authenticated]
     public class GenresService : BaseItemsByNameService<Genre>
     {
+        public GenresService(
+            ILogger<GenresService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IUserManager userManager,
+            ILibraryManager libraryManager,
+            IUserDataManager userDataRepository,
+            IDtoService dtoService,
+            IAuthorizationContext authorizationContext)
+            : base(
+                logger,
+                serverConfigurationManager,
+                httpResultFactory,
+                userManager,
+                libraryManager,
+                userDataRepository,
+                dtoService,
+                authorizationContext)
+        {
+        }
+
         /// <summary>
         /// Gets the specified request.
         /// </summary>
@@ -114,9 +137,5 @@ namespace MediaBrowser.Api.UserLibrary
         {
             throw new NotImplementedException();
         }
-
-        public GenresService(IUserManager userManager, ILibraryManager libraryManager, IUserDataManager userDataRepository, IItemRepository itemRepository, IDtoService dtoService, IAuthorizationContext authorizationContext) : base(userManager, libraryManager, userDataRepository, itemRepository, dtoService, authorizationContext)
-        {
-        }
     }
 }

+ 11 - 19
MediaBrowser.Api/UserLibrary/ItemsService.cs

@@ -1,8 +1,8 @@
 using System;
 using System.Collections.Generic;
-using System.Diagnostics;
 using System.Globalization;
 using System.Linq;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
@@ -58,25 +58,17 @@ namespace MediaBrowser.Api.UserLibrary
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="localization">The localization.</param>
         /// <param name="dtoService">The dto service.</param>
-        public ItemsService(IUserManager userManager, ILibraryManager libraryManager, ILocalizationManager localization, IDtoService dtoService, IAuthorizationContext authContext)
+        public ItemsService(
+            ILogger logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IUserManager userManager,
+            ILibraryManager libraryManager,
+            ILocalizationManager localization,
+            IDtoService dtoService,
+            IAuthorizationContext authContext)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
-            if (userManager == null)
-            {
-                throw new ArgumentNullException(nameof(userManager));
-            }
-            if (libraryManager == null)
-            {
-                throw new ArgumentNullException(nameof(libraryManager));
-            }
-            if (localization == null)
-            {
-                throw new ArgumentNullException(nameof(localization));
-            }
-            if (dtoService == null)
-            {
-                throw new ArgumentNullException(nameof(dtoService));
-            }
-
             _userManager = userManager;
             _libraryManager = libraryManager;
             _localization = localization;

+ 23 - 5
MediaBrowser.Api/UserLibrary/MusicGenresService.cs

@@ -1,14 +1,15 @@
 using System;
 using System.Collections.Generic;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.UserLibrary
 {
@@ -38,6 +39,27 @@ namespace MediaBrowser.Api.UserLibrary
     [Authenticated]
     public class MusicGenresService : BaseItemsByNameService<MusicGenre>
     {
+        public MusicGenresService(
+            ILogger<MusicGenresService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IUserManager userManager,
+            ILibraryManager libraryManager,
+            IUserDataManager userDataRepository,
+            IDtoService dtoService,
+            IAuthorizationContext authorizationContext)
+            : base(
+                logger,
+                serverConfigurationManager,
+                httpResultFactory,
+                userManager,
+                libraryManager,
+                userDataRepository,
+                dtoService,
+                authorizationContext)
+        {
+        }
+
         /// <summary>
         /// Gets the specified request.
         /// </summary>
@@ -98,9 +120,5 @@ namespace MediaBrowser.Api.UserLibrary
         {
             throw new NotImplementedException();
         }
-
-        public MusicGenresService(IUserManager userManager, ILibraryManager libraryManager, IUserDataManager userDataRepository, IItemRepository itemRepository, IDtoService dtoService, IAuthorizationContext authorizationContext) : base(userManager, libraryManager, userDataRepository, itemRepository, dtoService, authorizationContext)
-        {
-        }
     }
 }

+ 23 - 4
MediaBrowser.Api/UserLibrary/PersonsService.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
@@ -9,6 +10,7 @@ using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.UserLibrary
 {
@@ -47,6 +49,27 @@ namespace MediaBrowser.Api.UserLibrary
     [Authenticated]
     public class PersonsService : BaseItemsByNameService<Person>
     {
+        public PersonsService(
+            ILogger<PersonsService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IUserManager userManager,
+            ILibraryManager libraryManager,
+            IUserDataManager userDataRepository,
+            IDtoService dtoService,
+            IAuthorizationContext authorizationContext)
+            : base(
+                logger,
+                serverConfigurationManager,
+                httpResultFactory,
+                userManager,
+                libraryManager,
+                userDataRepository,
+                dtoService,
+                authorizationContext)
+        {
+        }
+
         /// <summary>
         /// Gets the specified request.
         /// </summary>
@@ -120,9 +143,5 @@ namespace MediaBrowser.Api.UserLibrary
                 Items = items.Take(query.Limit ?? int.MaxValue).Select(i => (i as BaseItem, new ItemCounts())).ToArray()
             };
         }
-
-        public PersonsService(IUserManager userManager, ILibraryManager libraryManager, IUserDataManager userDataRepository, IItemRepository itemRepository, IDtoService dtoService, IAuthorizationContext authorizationContext) : base(userManager, libraryManager, userDataRepository, itemRepository, dtoService, authorizationContext)
-        {
-        }
     }
 }

+ 14 - 3
MediaBrowser.Api/UserLibrary/PlaystateService.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Globalization;
 using System.Threading.Tasks;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
@@ -233,7 +234,17 @@ namespace MediaBrowser.Api.UserLibrary
         private readonly ISessionContext _sessionContext;
         private readonly IAuthorizationContext _authContext;
 
-        public PlaystateService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, ISessionManager sessionManager, ISessionContext sessionContext, IAuthorizationContext authContext)
+        public PlaystateService(
+            ILogger<PlaystateService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IUserManager userManager,
+            IUserDataManager userDataRepository,
+            ILibraryManager libraryManager,
+            ISessionManager sessionManager,
+            ISessionContext sessionContext,
+            IAuthorizationContext authContext)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _userManager = userManager;
             _userDataRepository = userDataRepository;
@@ -256,7 +267,7 @@ namespace MediaBrowser.Api.UserLibrary
 
         private UserItemDataDto MarkPlayed(MarkPlayedItem request)
         {
-            var user = _userManager.GetUserById(request.UserId);
+            var user = _userManager.GetUserById(Guid.Parse(request.UserId));
 
             DateTime? datePlayed = null;
 
@@ -406,7 +417,7 @@ namespace MediaBrowser.Api.UserLibrary
 
         private UserItemDataDto MarkUnplayed(MarkUnplayedItem request)
         {
-            var user = _userManager.GetUserById(request.UserId);
+            var user = _userManager.GetUserById(Guid.Parse(request.UserId));
 
             var session = GetSession(_sessionContext);
 

+ 23 - 5
MediaBrowser.Api/UserLibrary/StudiosService.cs

@@ -1,13 +1,14 @@
 using System;
 using System.Collections.Generic;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.UserLibrary
 {
@@ -46,6 +47,27 @@ namespace MediaBrowser.Api.UserLibrary
     [Authenticated]
     public class StudiosService : BaseItemsByNameService<Studio>
     {
+        public StudiosService(
+            ILogger<StudiosService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IUserManager userManager,
+            ILibraryManager libraryManager,
+            IUserDataManager userDataRepository,
+            IDtoService dtoService,
+            IAuthorizationContext authorizationContext)
+            : base(
+                logger,
+                serverConfigurationManager,
+                httpResultFactory,
+                userManager,
+                libraryManager,
+                userDataRepository,
+                dtoService,
+                authorizationContext)
+        {
+        }
+
         /// <summary>
         /// Gets the specified request.
         /// </summary>
@@ -106,9 +128,5 @@ namespace MediaBrowser.Api.UserLibrary
         {
             throw new NotImplementedException();
         }
-
-        public StudiosService(IUserManager userManager, ILibraryManager libraryManager, IUserDataManager userDataRepository, IItemRepository itemRepository, IDtoService dtoService, IAuthorizationContext authorizationContext) : base(userManager, libraryManager, userDataRepository, itemRepository, dtoService, authorizationContext)
-        {
-        }
     }
 }

+ 14 - 1
MediaBrowser.Api/UserLibrary/UserLibraryService.cs

@@ -3,6 +3,7 @@ using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 using MediaBrowser.Common.Extensions;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
@@ -14,6 +15,7 @@ using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.UserLibrary
 {
@@ -270,7 +272,18 @@ namespace MediaBrowser.Api.UserLibrary
         private readonly IFileSystem _fileSystem;
         private readonly IAuthorizationContext _authContext;
 
-        public UserLibraryService(IUserManager userManager, ILibraryManager libraryManager, IUserDataManager userDataRepository, IDtoService dtoService, IUserViewManager userViewManager, IFileSystem fileSystem, IAuthorizationContext authContext)
+        public UserLibraryService(
+            ILogger<UserLibraryService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IUserManager userManager,
+            ILibraryManager libraryManager,
+            IUserDataManager userDataRepository,
+            IDtoService dtoService,
+            IUserViewManager userViewManager,
+            IFileSystem fileSystem,
+            IAuthorizationContext authContext)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _userManager = userManager;
             _libraryManager = libraryManager;

+ 5 - 0
MediaBrowser.Api/UserLibrary/UserViewsService.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Globalization;
 using System.Linq;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
@@ -51,11 +52,15 @@ namespace MediaBrowser.Api.UserLibrary
         private readonly ILibraryManager _libraryManager;
 
         public UserViewsService(
+            ILogger<UserViewsService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
             IUserManager userManager,
             IUserViewManager userViewManager,
             IDtoService dtoService,
             IAuthorizationContext authContext,
             ILibraryManager libraryManager)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _userManager = userManager;
             _userViewManager = userViewManager;

+ 23 - 4
MediaBrowser.Api/UserLibrary/YearsService.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
@@ -8,6 +9,7 @@ using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.UserLibrary
 {
@@ -46,6 +48,27 @@ namespace MediaBrowser.Api.UserLibrary
     [Authenticated]
     public class YearsService : BaseItemsByNameService<Year>
     {
+        public YearsService(
+            ILogger<YearsService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            IUserManager userManager,
+            ILibraryManager libraryManager,
+            IUserDataManager userDataRepository,
+            IDtoService dtoService,
+            IAuthorizationContext authorizationContext)
+            : base(
+                logger,
+                serverConfigurationManager,
+                httpResultFactory,
+                userManager,
+                libraryManager,
+                userDataRepository,
+                dtoService,
+                authorizationContext)
+        {
+        }
+
         /// <summary>
         /// Gets the specified request.
         /// </summary>
@@ -105,9 +128,5 @@ namespace MediaBrowser.Api.UserLibrary
                 .Distinct()
                 .Select(year => LibraryManager.GetYear(year));
         }
-
-        public YearsService(IUserManager userManager, ILibraryManager libraryManager, IUserDataManager userDataRepository, IItemRepository itemRepository, IDtoService dtoService, IAuthorizationContext authorizationContext) : base(userManager, libraryManager, userDataRepository, itemRepository, dtoService, authorizationContext)
-        {
-        }
     }
 }

+ 7 - 6
MediaBrowser.Api/UserService.cs

@@ -244,22 +244,23 @@ namespace MediaBrowser.Api
         /// </summary>
         private readonly IUserManager _userManager;
         private readonly ISessionManager _sessionMananger;
-        private readonly IServerConfigurationManager _config;
         private readonly INetworkManager _networkManager;
         private readonly IDeviceManager _deviceManager;
         private readonly IAuthorizationContext _authContext;
 
         public UserService(
+            ILogger<UserService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
             IUserManager userManager,
             ISessionManager sessionMananger,
-            IServerConfigurationManager config,
             INetworkManager networkManager,
             IDeviceManager deviceManager,
             IAuthorizationContext authContext)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _userManager = userManager;
             _sessionMananger = sessionMananger;
-            _config = config;
             _networkManager = networkManager;
             _deviceManager = deviceManager;
             _authContext = authContext;
@@ -268,7 +269,7 @@ namespace MediaBrowser.Api
         public object Get(GetPublicUsers request)
         {
             // If the startup wizard hasn't been completed then just return all users
-            if (!_config.Configuration.IsStartupWizardCompleted)
+            if (!ServerConfigurationManager.Configuration.IsStartupWizardCompleted)
             {
                 return Get(new GetUsers
                 {
@@ -497,9 +498,9 @@ namespace MediaBrowser.Api
         /// <param name="request">The request.</param>
         public async Task Post(UpdateUser request)
         {
-            var id = GetPathValue(1);
+            var id = Guid.Parse(GetPathValue(1));
 
-            AssertCanUpdateUser(_authContext, _userManager, new Guid(id), false);
+            AssertCanUpdateUser(_authContext, _userManager, id, false);
 
             var dtoUser = request;
 

+ 12 - 12
MediaBrowser.Api/VideosService.cs

@@ -7,11 +7,10 @@ using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api
 {
@@ -51,19 +50,21 @@ namespace MediaBrowser.Api
         private readonly ILibraryManager _libraryManager;
         private readonly IUserManager _userManager;
         private readonly IDtoService _dtoService;
-        private readonly IFileSystem _fileSystem;
-        private readonly IItemRepository _itemRepo;
-        private readonly IServerConfigurationManager _config;
         private readonly IAuthorizationContext _authContext;
 
-        public VideosService(ILibraryManager libraryManager, IUserManager userManager, IDtoService dtoService, IItemRepository itemRepo, IFileSystem fileSystem, IServerConfigurationManager config, IAuthorizationContext authContext)
+        public VideosService(
+            ILogger<VideosService> logger,
+            IServerConfigurationManager serverConfigurationManager,
+            IHttpResultFactory httpResultFactory,
+            ILibraryManager libraryManager,
+            IUserManager userManager,
+            IDtoService dtoService,
+            IAuthorizationContext authContext)
+            : base(logger, serverConfigurationManager, httpResultFactory)
         {
             _libraryManager = libraryManager;
             _userManager = userManager;
             _dtoService = dtoService;
-            _itemRepo = itemRepo;
-            _fileSystem = fileSystem;
-            _config = config;
             _authContext = authContext;
         }
 
@@ -84,9 +85,8 @@ namespace MediaBrowser.Api
 
             var dtoOptions = GetDtoOptions(_authContext, request);
 
-            var video = item as Video;
             BaseItemDto[] items;
-            if (video != null)
+            if (item is Video video)
             {
                 items = video.GetAdditionalParts()
                     .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, video))
@@ -94,7 +94,7 @@ namespace MediaBrowser.Api
             }
             else
             {
-                items = new BaseItemDto[] { };
+                items = Array.Empty<BaseItemDto>();
             }
 
             var result = new QueryResult<BaseItemDto>

+ 1 - 3
MediaBrowser.Controller/Library/IUserDataManager.cs

@@ -9,7 +9,7 @@ using MediaBrowser.Model.Entities;
 namespace MediaBrowser.Controller.Library
 {
     /// <summary>
-    /// Interface IUserDataManager
+    /// Interface IUserDataManager.
     /// </summary>
     public interface IUserDataManager
     {
@@ -26,13 +26,11 @@ namespace MediaBrowser.Controller.Library
         /// <param name="userData">The user data.</param>
         /// <param name="reason">The reason.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task.</returns>
         void SaveUserData(Guid userId, BaseItem item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken);
         void SaveUserData(User userId, BaseItem item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken);
 
         UserItemData GetUserData(User user, BaseItem item);
 
-        UserItemData GetUserData(string userId, BaseItem item);
         UserItemData GetUserData(Guid userId, BaseItem item);
 
         /// <summary>

+ 1 - 8
MediaBrowser.Controller/Library/IUserManager.cs

@@ -49,20 +49,13 @@ namespace MediaBrowser.Controller.Library
         event EventHandler<GenericEventArgs<User>> UserLockedOut;
 
         /// <summary>
-        /// Gets a User by Id.
+        /// Gets a user by Id.
         /// </summary>
         /// <param name="id">The id.</param>
         /// <returns>The user with the specified Id, or <c>null</c> if the user doesn't exist.</returns>
         /// <exception cref="ArgumentException"><c>id</c> is an empty Guid.</exception>
         User GetUserById(Guid id);
 
-        /// <summary>
-        /// Gets the user by identifier.
-        /// </summary>
-        /// <param name="id">The identifier.</param>
-        /// <returns>User.</returns>
-        User GetUserById(string id);
-
         /// <summary>
         /// Gets the name of the user by.
         /// </summary>

+ 5 - 3
MediaBrowser.Model/Configuration/ServerConfiguration.cs

@@ -172,16 +172,18 @@ namespace MediaBrowser.Model.Configuration
                 if (string.IsNullOrWhiteSpace(value))
                 {
                     // If baseUrl is empty, set an empty prefix string
-                    value = string.Empty;
+                    _baseUrl = string.Empty;
+                    return;
                 }
-                else if (!value.StartsWith("/"))
+
+                if (value[0] != '/')
                 {
                     // If baseUrl was not configured with a leading slash, append one for consistency
                     value = "/" + value;
                 }
 
                 // Normalize the end of the string
-                if (value.EndsWith("/"))
+                if (value[value.Length - 1] == '/')
                 {
                     // If baseUrl was configured with a trailing slash, remove it for consistency
                     value = value.Remove(value.Length - 1);

+ 1 - 2
MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs

@@ -16,7 +16,6 @@ using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.IO;
 using MediaBrowser.XbmcMetadata.Configuration;
 using Microsoft.Extensions.Logging;
@@ -856,7 +855,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
                 return;
             }
 
-            var user = userManager.GetUserById(userId);
+            var user = userManager.GetUserById(Guid.Parse(userId));
 
             if (user == null)
             {

+ 7 - 0
MediaBrowser.sln

@@ -59,6 +59,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.MediaEncoding.Test
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Naming.Tests", "tests\Jellyfin.Naming.Tests\Jellyfin.Naming.Tests.csproj", "{3998657B-1CCC-49DD-A19F-275DC8495F57}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Api.Tests", "tests\Jellyfin.Api.Tests\Jellyfin.Api.Tests.csproj", "{A2FD0A10-8F62-4F9D-B171-FFDF9F0AFA9D}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -165,6 +167,10 @@ Global
 		{3998657B-1CCC-49DD-A19F-275DC8495F57}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{3998657B-1CCC-49DD-A19F-275DC8495F57}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{3998657B-1CCC-49DD-A19F-275DC8495F57}.Release|Any CPU.Build.0 = Release|Any CPU
+		{A2FD0A10-8F62-4F9D-B171-FFDF9F0AFA9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A2FD0A10-8F62-4F9D-B171-FFDF9F0AFA9D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A2FD0A10-8F62-4F9D-B171-FFDF9F0AFA9D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{A2FD0A10-8F62-4F9D-B171-FFDF9F0AFA9D}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -194,5 +200,6 @@ Global
 		{DF194677-DFD3-42AF-9F75-D44D5A416478} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
 		{28464062-0939-4AA7-9F7B-24DDDA61A7C0} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
 		{3998657B-1CCC-49DD-A19F-275DC8495F57} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
+		{A2FD0A10-8F62-4F9D-B171-FFDF9F0AFA9D} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
 	EndGlobalSection
 EndGlobal

+ 45 - 0
tests/Jellyfin.Api.Tests/GetPathValueTests.cs

@@ -0,0 +1,45 @@
+using MediaBrowser.Api;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Net;
+using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging.Abstractions;
+using Moq;
+using Xunit;
+
+namespace Jellyfin.Api.Tests
+{
+    public class GetPathValueTests
+    {
+        [Theory]
+        [InlineData("https://localhost:8096/ScheduledTasks/1234/Triggers", "", 1, "1234")]
+        [InlineData("https://localhost:8096/emby/ScheduledTasks/1234/Triggers", "", 1, "1234")]
+        [InlineData("https://localhost:8096/mediabrowser/ScheduledTasks/1234/Triggers", "", 1, "1234")]
+        [InlineData("https://localhost:8096/jellyfin/2/ScheduledTasks/1234/Triggers", "jellyfin/2", 1, "1234")]
+        [InlineData("https://localhost:8096/jellyfin/2/emby/ScheduledTasks/1234/Triggers", "jellyfin/2", 1, "1234")]
+        [InlineData("https://localhost:8096/jellyfin/2/mediabrowser/ScheduledTasks/1234/Triggers", "jellyfin/2", 1, "1234")]
+        [InlineData("https://localhost:8096/JELLYFIN/2/ScheduledTasks/1234/Triggers", "jellyfin/2", 1, "1234")]
+        [InlineData("https://localhost:8096/JELLYFIN/2/Emby/ScheduledTasks/1234/Triggers", "jellyfin/2", 1, "1234")]
+        [InlineData("https://localhost:8096/JELLYFIN/2/MediaBrowser/ScheduledTasks/1234/Triggers", "jellyfin/2", 1, "1234")]
+        public void GetPathValueTest(string path, string baseUrl, int index, string value)
+        {
+            var reqMock = Mock.Of<IRequest>(x => x.PathInfo == path);
+            var conf = new ServerConfiguration()
+            {
+                BaseUrl = baseUrl
+            };
+
+            var confManagerMock = Mock.Of<IServerConfigurationManager>(x => x.Configuration == conf);
+
+            var service = new BrandingService(
+                new NullLogger<BrandingService>(),
+                confManagerMock,
+                Mock.Of<IHttpResultFactory>())
+            {
+                Request = reqMock
+            };
+
+            Assert.Equal(value, service.GetPathValue(index).ToString());
+        }
+    }
+}

+ 20 - 0
tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj

@@ -0,0 +1,20 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp3.0</TargetFramework>
+    <IsPackable>false</IsPackable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
+    <PackageReference Include="xunit" Version="2.4.1" />
+    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
+    <PackageReference Include="coverlet.collector" Version="1.1.0" />
+    <PackageReference Include="Moq" Version="4.13.1" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="../../MediaBrowser.Api/MediaBrowser.Api.csproj" />
+  </ItemGroup>
+
+</Project>