Add api key functions

This commit is contained in:
Luke Pulverenti 2014-07-11 22:31:08 -04:00
parent 59de5c0d14
commit b5641013ce
16 changed files with 168 additions and 39 deletions

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.Extensions; using MediaBrowser.Api.Playback.Hls;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO; using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
@ -317,7 +318,7 @@ namespace MediaBrowser.Api.Playback
switch (qualitySetting) switch (qualitySetting)
{ {
case EncodingQuality.HighSpeed: case EncodingQuality.HighSpeed:
param = "-preset ultrafast"; param = "-preset superfast";
break; break;
case EncodingQuality.HighQuality: case EncodingQuality.HighQuality:
param = "-preset superfast"; param = "-preset superfast";
@ -945,7 +946,8 @@ namespace MediaBrowser.Api.Playback
} }
// Allow a small amount of time to buffer a little // Allow a small amount of time to buffer a little
if (state.IsInputVideo) // But not with HLS because it already has it's own wait
if (state.IsInputVideo && TranscodingJobType != TranscodingJobType.Hls)
{ {
await Task.Delay(500, cancellationTokenSource.Token).ConfigureAwait(false); await Task.Delay(500, cancellationTokenSource.Token).ConfigureAwait(false);
} }

View File

@ -1,5 +1,6 @@
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Security;
using MediaBrowser.Controller.Session; using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Session; using MediaBrowser.Model.Session;
using ServiceStack; using ServiceStack;
@ -241,6 +242,25 @@ namespace MediaBrowser.Api
{ {
} }
[Route("/Auth/Keys", "GET")]
public class GetApiKeys
{
}
[Route("/Auth/Keys/{Key}", "DELETE")]
public class RevokeKey
{
[ApiMember(Name = "Key", Description = "Auth Key", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
public string Key { get; set; }
}
[Route("/Auth/Keys", "POST")]
public class CreateKey
{
[ApiMember(Name = "App", Description = "App", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
public string App { get; set; }
}
/// <summary> /// <summary>
/// Class SessionsService /// Class SessionsService
/// </summary> /// </summary>
@ -253,19 +273,43 @@ namespace MediaBrowser.Api
private readonly IUserManager _userManager; private readonly IUserManager _userManager;
private readonly IAuthorizationContext _authContext; private readonly IAuthorizationContext _authContext;
private readonly IAuthenticationRepository _authRepo;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="SessionsService" /> class. /// Initializes a new instance of the <see cref="SessionsService" /> class.
/// </summary> /// </summary>
/// <param name="sessionManager">The session manager.</param> /// <param name="sessionManager">The session manager.</param>
/// <param name="userManager">The user manager.</param> /// <param name="userManager">The user manager.</param>
public SessionsService(ISessionManager sessionManager, IUserManager userManager, IAuthorizationContext authContext) /// <param name="authContext">The authentication context.</param>
/// <param name="authRepo">The authentication repo.</param>
public SessionsService(ISessionManager sessionManager, IUserManager userManager, IAuthorizationContext authContext, IAuthenticationRepository authRepo)
{ {
_sessionManager = sessionManager; _sessionManager = sessionManager;
_userManager = userManager; _userManager = userManager;
_authContext = authContext; _authContext = authContext;
_authRepo = authRepo;
} }
public void Delete(RevokeKey request)
{
var task = _sessionManager.RevokeToken(request.Key);
Task.WaitAll(task);
}
public void Post(CreateKey request)
{
var task = _authRepo.Create(new AuthenticationInfo
{
AppName = request.App,
IsActive = true,
AccessToken = Guid.NewGuid().ToString("N"),
DateCreated = DateTime.UtcNow
}, CancellationToken.None);
Task.WaitAll(task);
}
public void Post(ReportSessionEnded request) public void Post(ReportSessionEnded request)
{ {
@ -274,6 +318,16 @@ namespace MediaBrowser.Api
_sessionManager.Logout(auth.Token); _sessionManager.Logout(auth.Token);
} }
public object Get(GetApiKeys request)
{
var result = _authRepo.Get(new AuthenticationInfoQuery
{
IsActive = true
});
return ToOptimizedResult(result);
}
/// <summary> /// <summary>
/// Gets the specified request. /// Gets the specified request.
/// </summary> /// </summary>

View File

@ -276,6 +276,13 @@ namespace MediaBrowser.Controller.Session
/// <returns>Task.</returns> /// <returns>Task.</returns>
Task RevokeUserTokens(string userId); Task RevokeUserTokens(string userId);
/// <summary>
/// Revokes the token.
/// </summary>
/// <param name="id">The identifier.</param>
/// <returns>Task.</returns>
Task RevokeToken(string id);
/// <summary> /// <summary>
/// Determines whether the specified remote endpoint is local. /// Determines whether the specified remote endpoint is local.
/// </summary> /// </summary>

View File

@ -255,6 +255,8 @@ namespace MediaBrowser.Providers.MediaInfo
AddDummyChapters(video, chapters); AddDummyChapters(video, chapters);
} }
NormalizeChapterNames(chapters);
await _encodingManager.RefreshChapterImages(new ChapterImageRefreshOptions await _encodingManager.RefreshChapterImages(new ChapterImageRefreshOptions
{ {
Chapters = chapters, Chapters = chapters,
@ -268,6 +270,25 @@ namespace MediaBrowser.Providers.MediaInfo
} }
} }
private void NormalizeChapterNames(List<ChapterInfo> chapters)
{
var index = 1;
foreach (var chapter in chapters)
{
TimeSpan time;
// Check if the name is empty and/or if the name is a time
// Some ripping programs do that.
if (string.IsNullOrWhiteSpace(chapter.Name) ||
TimeSpan.TryParse(chapter.Name, out time))
{
chapter.Name = string.Format(_localization.GetLocalizedString("LabelChapterName"), index.ToString(CultureInfo.InvariantCulture));
}
index++;
}
}
private ChapterInfo GetChapterInfo(MediaChapter chapter) private ChapterInfo GetChapterInfo(MediaChapter chapter)
{ {
var info = new ChapterInfo(); var info = new ChapterInfo();
@ -570,7 +591,6 @@ namespace MediaBrowser.Providers.MediaInfo
{ {
chapters.Add(new ChapterInfo chapters.Add(new ChapterInfo
{ {
Name = "Chapter " + index,
StartPositionTicks = currentChapterTicks StartPositionTicks = currentChapterTicks
}); });

View File

@ -233,5 +233,8 @@
"OptionBlockGames": "Games", "OptionBlockGames": "Games",
"OptionBlockLiveTvPrograms": "Live TV Programs", "OptionBlockLiveTvPrograms": "Live TV Programs",
"OptionBlockLiveTvChannels": "Live TV Channels", "OptionBlockLiveTvChannels": "Live TV Channels",
"OptionBlockChannelContent": "Internet Channel Content" "OptionBlockChannelContent": "Internet Channel Content",
"ButtonRevoke": "Revoke",
"MessageConfirmRevokeApiKey": "Are you sure you wish to revoke this api key? The application's connection to Media Browser will be abruptly terminated.",
"HeaderConfirmRevokeApiKey": "Revoke Api Key"
} }

View File

@ -849,7 +849,7 @@
"LabelXbmcMetadataEnablePathSubstitutionHelp2": "See path substitution.", "LabelXbmcMetadataEnablePathSubstitutionHelp2": "See path substitution.",
"LabelGroupChannelsIntoViews": "Display the following channels directly within my views:", "LabelGroupChannelsIntoViews": "Display the following channels directly within my views:",
"LabelGroupChannelsIntoViewsHelp": "If enabled, these channels will be displayed directly alongside other views. If disabled, they'll be displayed within a separate Channels view.", "LabelGroupChannelsIntoViewsHelp": "If enabled, these channels will be displayed directly alongside other views. If disabled, they'll be displayed within a separate Channels view.",
"LabelDisplayCollectionsView": "Display a Collections view to show movie collections", "LabelDisplayCollectionsView": "Display a collections view to show movie collections",
"LabelXbmcMetadataEnableExtraThumbs": "Copy extrafanart into extrathumbs", "LabelXbmcMetadataEnableExtraThumbs": "Copy extrafanart into extrathumbs",
"LabelXbmcMetadataEnableExtraThumbsHelp": "When downloading images they can be saved into both extrafanart and extrathumbs for maximum Xbmc skin compatibility.", "LabelXbmcMetadataEnableExtraThumbsHelp": "When downloading images they can be saved into both extrafanart and extrathumbs for maximum Xbmc skin compatibility.",
"TabServices": "Services", "TabServices": "Services",
@ -870,5 +870,17 @@
"LabelImagesByName": "Images by name:", "LabelImagesByName": "Images by name:",
"LabelTranscodingTemporaryFiles": "Transcoding temporary files:", "LabelTranscodingTemporaryFiles": "Transcoding temporary files:",
"HeaderLatestMusic": "Latest Music", "HeaderLatestMusic": "Latest Music",
"HeaderBranding": "Branding" "HeaderBranding": "Branding",
"HeaderApiKeys": "Api Keys",
"HeaderApiKeysHelp": "External applications are required to have an Api key in order to communicate with Media Browser. Keys are issued by logging in with a Media Browser account, or by manually granting the application a key.",
"HeaderApiKey": "Api Key",
"HeaderApp": "App",
"HeaderDevice": "Device",
"HeaderUser": "User",
"HeaderDateIssued": "Date Issued",
"LabelChapterName": "Chapter {0}",
"HeaderNewApiKey": "New Api Key",
"LabelAppName": "App name",
"LabelAppNameExample": "Example: Sickbeard, NzbDrone",
"HeaderNewApiKeyHelp": "Grant an application permission to communicate with Media Browser."
} }

View File

@ -283,11 +283,11 @@ namespace MediaBrowser.Server.Implementations.Security
} }
info.IsActive = reader.GetBoolean(6); info.IsActive = reader.GetBoolean(6);
info.DateCreated = reader.GetDateTime(7); info.DateCreated = reader.GetDateTime(7).ToUniversalTime();
if (!reader.IsDBNull(8)) if (!reader.IsDBNull(8))
{ {
info.DateRevoked = reader.GetDateTime(8); info.DateRevoked = reader.GetDateTime(8).ToUniversalTime();
} }
return info; return info;

View File

@ -1210,15 +1210,15 @@ namespace MediaBrowser.Server.Implementations.Session
/// <returns>Task{SessionInfo}.</returns> /// <returns>Task{SessionInfo}.</returns>
/// <exception cref="System.UnauthorizedAccessException">Invalid user or password entered.</exception> /// <exception cref="System.UnauthorizedAccessException">Invalid user or password entered.</exception>
/// <exception cref="UnauthorizedAccessException"></exception> /// <exception cref="UnauthorizedAccessException"></exception>
public async Task<AuthenticationResult> AuthenticateNewSession(string username, public async Task<AuthenticationResult> AuthenticateNewSession(string username,
string password, string password,
string clientType, string clientType,
string appVersion, string appVersion,
string deviceId, string deviceId,
string deviceName, string deviceName,
string remoteEndPoint) string remoteEndPoint)
{ {
var result = (IsLocalhost(remoteEndPoint) && string.Equals(clientType, "Dashboard", StringComparison.OrdinalIgnoreCase)) || var result = (IsLocalhost(remoteEndPoint) && string.Equals(clientType, "Dashboard", StringComparison.OrdinalIgnoreCase)) ||
await _userManager.AuthenticateUser(username, password).ConfigureAwait(false); await _userManager.AuthenticateUser(username, password).ConfigureAwait(false);
if (!result) if (!result)
@ -1332,6 +1332,11 @@ namespace MediaBrowser.Server.Implementations.Session
} }
} }
public Task RevokeToken(string token)
{
return Logout(token);
}
private bool IsLocalhost(string remoteEndpoint) private bool IsLocalhost(string remoteEndpoint)
{ {
if (string.IsNullOrWhiteSpace(remoteEndpoint)) if (string.IsNullOrWhiteSpace(remoteEndpoint))

View File

@ -62,14 +62,28 @@ namespace MediaBrowser.Server.Implementations.Session
void connection_Closed(object sender, EventArgs e) void connection_Closed(object sender, EventArgs e)
{ {
var capabilities = new SessionCapabilities if (!GetActiveSockets().Any())
{ {
PlayableMediaTypes = Session.PlayableMediaTypes, try
SupportedCommands = Session.SupportedCommands, {
SupportsMediaControl = SupportsMediaControl _sessionManager.ReportSessionEnded(Session.Id);
}; }
catch (Exception ex)
{
_logger.ErrorException("Error reporting session ended.", ex);
}
}
else
{
var capabilities = new SessionCapabilities
{
PlayableMediaTypes = Session.PlayableMediaTypes,
SupportedCommands = Session.SupportedCommands,
SupportsMediaControl = SupportsMediaControl
};
_sessionManager.ReportCapabilities(Session.Id, capabilities); _sessionManager.ReportCapabilities(Session.Id, capabilities);
}
} }
private IWebSocketConnection GetActiveSocket() private IWebSocketConnection GetActiveSocket()

View File

@ -3,6 +3,7 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Logging;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
@ -14,8 +15,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
{ {
public class AlbumNfoSaver : BaseNfoSaver public class AlbumNfoSaver : BaseNfoSaver
{ {
public AlbumNfoSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager) public AlbumNfoSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger) : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger)
: base(fileSystem, configurationManager, libraryManager, userManager, userDataManager)
{ {
} }

View File

@ -3,6 +3,7 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Logging;
using MediaBrowser.XbmcMetadata.Configuration; using MediaBrowser.XbmcMetadata.Configuration;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
@ -14,8 +15,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
{ {
public class ArtistNfoSaver : BaseNfoSaver public class ArtistNfoSaver : BaseNfoSaver
{ {
public ArtistNfoSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager) public ArtistNfoSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger) : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger)
: base(fileSystem, configurationManager, libraryManager, userManager, userDataManager)
{ {
} }

View File

@ -9,6 +9,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.XbmcMetadata.Configuration; using MediaBrowser.XbmcMetadata.Configuration;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -98,8 +99,9 @@ namespace MediaBrowser.XbmcMetadata.Savers
}.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); }.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
protected BaseNfoSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager) protected BaseNfoSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger)
{ {
Logger = logger;
UserDataManager = userDataManager; UserDataManager = userDataManager;
UserManager = userManager; UserManager = userManager;
LibraryManager = libraryManager; LibraryManager = libraryManager;
@ -112,6 +114,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
protected ILibraryManager LibraryManager { get; private set; } protected ILibraryManager LibraryManager { get; private set; }
protected IUserManager UserManager { get; private set; } protected IUserManager UserManager { get; private set; }
protected IUserDataManager UserDataManager { get; private set; } protected IUserDataManager UserDataManager { get; private set; }
protected ILogger Logger { get; private set; }
public string Name public string Name
{ {
@ -232,11 +235,11 @@ namespace MediaBrowser.XbmcMetadata.Savers
try try
{ {
AddCustomTags(xmlPath, tagsUsed, writer); AddCustomTags(xmlPath, tagsUsed, writer, Logger);
} }
catch (FileNotFoundException) catch (FileNotFoundException)
{ {
} }
writer.WriteEndElement(); writer.WriteEndElement();
@ -950,7 +953,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
return string.Equals(person.Type, type, StringComparison.OrdinalIgnoreCase) || string.Equals(person.Role, type, StringComparison.OrdinalIgnoreCase); return string.Equals(person.Type, type, StringComparison.OrdinalIgnoreCase) || string.Equals(person.Role, type, StringComparison.OrdinalIgnoreCase);
} }
private static void AddCustomTags(string path, List<string> xmlTagsUsed, XmlWriter writer) private static void AddCustomTags(string path, List<string> xmlTagsUsed, XmlWriter writer, ILogger logger)
{ {
var settings = new XmlReaderSettings var settings = new XmlReaderSettings
{ {
@ -965,7 +968,15 @@ namespace MediaBrowser.XbmcMetadata.Savers
// Use XmlReader for best performance // Use XmlReader for best performance
using (var reader = XmlReader.Create(streamReader, settings)) using (var reader = XmlReader.Create(streamReader, settings))
{ {
reader.MoveToContent(); try
{
reader.MoveToContent();
}
catch (Exception ex)
{
logger.ErrorException("Error reading existing xml tags from {0}.", ex, path);
return;
}
// Loop through each element // Loop through each element
while (reader.Read()) while (reader.Read())

View File

@ -3,6 +3,7 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Logging;
using MediaBrowser.XbmcMetadata.Configuration; using MediaBrowser.XbmcMetadata.Configuration;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
@ -13,8 +14,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
{ {
public class EpisodeNfoSaver : BaseNfoSaver public class EpisodeNfoSaver : BaseNfoSaver
{ {
public EpisodeNfoSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager) public EpisodeNfoSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger) : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger)
: base(fileSystem, configurationManager, libraryManager, userManager, userDataManager)
{ {
} }

View File

@ -5,6 +5,7 @@ using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
@ -14,8 +15,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
{ {
public class MovieNfoSaver : BaseNfoSaver public class MovieNfoSaver : BaseNfoSaver
{ {
public MovieNfoSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager) public MovieNfoSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger) : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger)
: base(fileSystem, configurationManager, libraryManager, userManager, userDataManager)
{ {
} }

View File

@ -3,6 +3,7 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Logging;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
@ -12,7 +13,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
{ {
public class SeasonNfoSaver : BaseNfoSaver public class SeasonNfoSaver : BaseNfoSaver
{ {
public SeasonNfoSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager) : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager) public SeasonNfoSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger) : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger)
{ {
} }

View File

@ -4,6 +4,7 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
@ -13,8 +14,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
{ {
public class SeriesNfoSaver : BaseNfoSaver public class SeriesNfoSaver : BaseNfoSaver
{ {
public SeriesNfoSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager) public SeriesNfoSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger) : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger)
: base(fileSystem, configurationManager, libraryManager, userManager, userDataManager)
{ {
} }