aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Api
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Api')
-rw-r--r--MediaBrowser.Api/BaseApiService.cs5
-rw-r--r--MediaBrowser.Api/DisplayPreferencesService.cs101
-rw-r--r--MediaBrowser.Api/FilterService.cs243
-rw-r--r--MediaBrowser.Api/Images/ImageByNameService.cs277
-rw-r--r--MediaBrowser.Api/Images/ImageService.cs160
-rw-r--r--MediaBrowser.Api/Images/RemoteImageService.cs297
-rw-r--r--MediaBrowser.Api/ItemRefreshService.cs83
-rw-r--r--MediaBrowser.Api/ItemUpdateService.cs396
-rw-r--r--MediaBrowser.Api/Library/LibraryService.cs16
-rw-r--r--MediaBrowser.Api/Library/LibraryStructureService.cs412
-rw-r--r--MediaBrowser.Api/LiveTv/LiveTvService.cs3
-rw-r--r--MediaBrowser.Api/LocalizationService.cs111
-rw-r--r--MediaBrowser.Api/Movies/MoviesService.cs11
-rw-r--r--MediaBrowser.Api/Music/InstantMixService.cs1
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs3
-rw-r--r--MediaBrowser.Api/Playback/MediaInfoService.cs36
-rw-r--r--MediaBrowser.Api/PluginService.cs268
-rw-r--r--MediaBrowser.Api/Sessions/SessionService.cs498
-rw-r--r--MediaBrowser.Api/Subtitles/SubtitleService.cs300
-rw-r--r--MediaBrowser.Api/SuggestionsService.cs97
-rw-r--r--MediaBrowser.Api/TvShowsService.cs8
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs1
-rw-r--r--MediaBrowser.Api/UserLibrary/ItemsService.cs19
-rw-r--r--MediaBrowser.Api/UserLibrary/PlaystateService.cs2
-rw-r--r--MediaBrowser.Api/UserLibrary/UserLibraryService.cs2
-rw-r--r--MediaBrowser.Api/UserService.cs600
26 files changed, 213 insertions, 3737 deletions
diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs
index 2cd68ac1b..2ece16ee1 100644
--- a/MediaBrowser.Api/BaseApiService.cs
+++ b/MediaBrowser.Api/BaseApiService.cs
@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Linq;
+using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
@@ -94,8 +95,8 @@ namespace MediaBrowser.Api
var authenticatedUser = auth.User;
// If they're going to update the record of another user, they must be an administrator
- if ((!userId.Equals(auth.UserId) && !authenticatedUser.Policy.IsAdministrator)
- || (restrictUserPreferences && !authenticatedUser.Policy.EnableUserPreferenceAccess))
+ if ((!userId.Equals(auth.UserId) && !authenticatedUser.HasPermission(PermissionKind.IsAdministrator))
+ || (restrictUserPreferences && !authenticatedUser.EnableUserPreferenceAccess))
{
throw new SecurityException("Unauthorized access.");
}
diff --git a/MediaBrowser.Api/DisplayPreferencesService.cs b/MediaBrowser.Api/DisplayPreferencesService.cs
deleted file mode 100644
index 62c4ff43f..000000000
--- a/MediaBrowser.Api/DisplayPreferencesService.cs
+++ /dev/null
@@ -1,101 +0,0 @@
-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
-{
- /// <summary>
- /// Class UpdateDisplayPreferences
- /// </summary>
- [Route("/DisplayPreferences/{DisplayPreferencesId}", "POST", Summary = "Updates a user's display preferences for an item")]
- public class UpdateDisplayPreferences : DisplayPreferences, IReturnVoid
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "DisplayPreferencesId", Description = "DisplayPreferences Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string DisplayPreferencesId { get; set; }
-
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string UserId { get; set; }
- }
-
- [Route("/DisplayPreferences/{Id}", "GET", Summary = "Gets a user's display preferences for an item")]
- public class GetDisplayPreferences : IReturn<DisplayPreferences>
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Id { get; set; }
-
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string UserId { get; set; }
-
- [ApiMember(Name = "Client", Description = "Client", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string Client { get; set; }
- }
-
- /// <summary>
- /// Class DisplayPreferencesService
- /// </summary>
- [Authenticated]
- public class DisplayPreferencesService : BaseApiService
- {
- /// <summary>
- /// The _display preferences manager
- /// </summary>
- private readonly IDisplayPreferencesRepository _displayPreferencesManager;
- /// <summary>
- /// The _json serializer
- /// </summary>
- private readonly IJsonSerializer _jsonSerializer;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="DisplayPreferencesService" /> class.
- /// </summary>
- /// <param name="jsonSerializer">The json serializer.</param>
- /// <param name="displayPreferencesManager">The display preferences manager.</param>
- public DisplayPreferencesService(
- ILogger<DisplayPreferencesService> logger,
- IServerConfigurationManager serverConfigurationManager,
- IHttpResultFactory httpResultFactory,
- IJsonSerializer jsonSerializer,
- IDisplayPreferencesRepository displayPreferencesManager)
- : base(logger, serverConfigurationManager, httpResultFactory)
- {
- _jsonSerializer = jsonSerializer;
- _displayPreferencesManager = displayPreferencesManager;
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public object Get(GetDisplayPreferences request)
- {
- var result = _displayPreferencesManager.GetDisplayPreferences(request.Id, request.UserId, request.Client);
-
- return ToOptimizedResult(result);
- }
-
- /// <summary>
- /// Posts the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public void Post(UpdateDisplayPreferences request)
- {
- // Serialize to json and then back so that the core doesn't see the request dto type
- var displayPreferences = _jsonSerializer.DeserializeFromString<DisplayPreferences>(_jsonSerializer.SerializeToString(request));
-
- _displayPreferencesManager.SaveDisplayPreferences(displayPreferences, request.UserId, request.Client, CancellationToken.None);
- }
- }
-}
diff --git a/MediaBrowser.Api/FilterService.cs b/MediaBrowser.Api/FilterService.cs
deleted file mode 100644
index 5eb72cdb1..000000000
--- a/MediaBrowser.Api/FilterService.cs
+++ /dev/null
@@ -1,243 +0,0 @@
-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
-{
- [Route("/Items/Filters", "GET", Summary = "Gets branding configuration")]
- public class GetQueryFiltersLegacy : IReturn<QueryFiltersLegacy>
- {
- /// <summary>
- /// Gets or sets the user id.
- /// </summary>
- /// <value>The user id.</value>
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public Guid UserId { get; set; }
-
- [ApiMember(Name = "ParentId", Description = "Specify this to localize the search to a specific item or folder. Omit to use the root", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string ParentId { get; set; }
-
- [ApiMember(Name = "IncludeItemTypes", Description = "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
- public string IncludeItemTypes { get; set; }
-
- [ApiMember(Name = "MediaTypes", Description = "Optional filter by MediaType. Allows multiple, comma delimited.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
- public string MediaTypes { get; set; }
-
- public string[] GetMediaTypes()
- {
- return (MediaTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- }
-
- public string[] GetIncludeItemTypes()
- {
- return (IncludeItemTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- }
- }
-
- [Route("/Items/Filters2", "GET", Summary = "Gets branding configuration")]
- public class GetQueryFilters : IReturn<QueryFilters>
- {
- /// <summary>
- /// Gets or sets the user id.
- /// </summary>
- /// <value>The user id.</value>
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public Guid UserId { get; set; }
-
- [ApiMember(Name = "ParentId", Description = "Specify this to localize the search to a specific item or folder. Omit to use the root", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string ParentId { get; set; }
-
- [ApiMember(Name = "IncludeItemTypes", Description = "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
- public string IncludeItemTypes { get; set; }
-
- [ApiMember(Name = "MediaTypes", Description = "Optional filter by MediaType. Allows multiple, comma delimited.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
- public string MediaTypes { get; set; }
-
- public string[] GetMediaTypes()
- {
- return (MediaTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- }
-
- public string[] GetIncludeItemTypes()
- {
- return (IncludeItemTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- }
-
- public bool? IsAiring { get; set; }
- public bool? IsMovie { get; set; }
- public bool? IsSports { get; set; }
- public bool? IsKids { get; set; }
- public bool? IsNews { get; set; }
- public bool? IsSeries { get; set; }
- public bool? Recursive { get; set; }
- }
-
- [Authenticated]
- public class FilterService : BaseApiService
- {
- private readonly ILibraryManager _libraryManager;
- private readonly IUserManager _userManager;
-
- public FilterService(
- ILogger<FilterService> logger,
- IServerConfigurationManager serverConfigurationManager,
- IHttpResultFactory httpResultFactory,
- ILibraryManager libraryManager,
- IUserManager userManager)
- : base(logger, serverConfigurationManager, httpResultFactory)
- {
- _libraryManager = libraryManager;
- _userManager = userManager;
- }
-
- public object Get(GetQueryFilters request)
- {
- var parentItem = string.IsNullOrEmpty(request.ParentId) ? null : _libraryManager.GetItemById(request.ParentId);
- var user = !request.UserId.Equals(Guid.Empty) ? _userManager.GetUserById(request.UserId) : null;
-
- if (string.Equals(request.IncludeItemTypes, "BoxSet", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(request.IncludeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(request.IncludeItemTypes, typeof(Trailer).Name, StringComparison.OrdinalIgnoreCase) ||
- string.Equals(request.IncludeItemTypes, "Program", StringComparison.OrdinalIgnoreCase))
- {
- parentItem = null;
- }
-
- var filters = new QueryFilters();
-
- var genreQuery = new InternalItemsQuery(user)
- {
- IncludeItemTypes = request.GetIncludeItemTypes(),
- DtoOptions = new Controller.Dto.DtoOptions
- {
- Fields = new ItemFields[] { },
- EnableImages = false,
- EnableUserData = false
- },
- IsAiring = request.IsAiring,
- IsMovie = request.IsMovie,
- IsSports = request.IsSports,
- IsKids = request.IsKids,
- IsNews = request.IsNews,
- IsSeries = request.IsSeries
- };
-
- // Non recursive not yet supported for library folders
- if ((request.Recursive ?? true) || parentItem is UserView || parentItem is ICollectionFolder)
- {
- genreQuery.AncestorIds = parentItem == null ? Array.Empty<Guid>() : new[] { parentItem.Id };
- }
- else
- {
- genreQuery.Parent = parentItem;
- }
-
- if (string.Equals(request.IncludeItemTypes, "MusicAlbum", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(request.IncludeItemTypes, "MusicVideo", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(request.IncludeItemTypes, "MusicArtist", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(request.IncludeItemTypes, "Audio", StringComparison.OrdinalIgnoreCase))
- {
- filters.Genres = _libraryManager.GetMusicGenres(genreQuery).Items.Select(i => new NameGuidPair
- {
- Name = i.Item1.Name,
- Id = i.Item1.Id
-
- }).ToArray();
- }
- else
- {
- filters.Genres = _libraryManager.GetGenres(genreQuery).Items.Select(i => new NameGuidPair
- {
- Name = i.Item1.Name,
- Id = i.Item1.Id
-
- }).ToArray();
- }
-
- return ToOptimizedResult(filters);
- }
-
- public object Get(GetQueryFiltersLegacy request)
- {
- var parentItem = string.IsNullOrEmpty(request.ParentId) ? null : _libraryManager.GetItemById(request.ParentId);
- var user = !request.UserId.Equals(Guid.Empty) ? _userManager.GetUserById(request.UserId) : null;
-
- if (string.Equals(request.IncludeItemTypes, "BoxSet", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(request.IncludeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(request.IncludeItemTypes, typeof(Trailer).Name, StringComparison.OrdinalIgnoreCase) ||
- string.Equals(request.IncludeItemTypes, "Program", StringComparison.OrdinalIgnoreCase))
- {
- parentItem = null;
- }
-
- var item = string.IsNullOrEmpty(request.ParentId) ?
- user == null ? _libraryManager.RootFolder : _libraryManager.GetUserRootFolder() :
- parentItem;
-
- var result = ((Folder)item).GetItemList(GetItemsQuery(request, user));
-
- var filters = GetFilters(result);
-
- return ToOptimizedResult(filters);
- }
-
- private QueryFiltersLegacy GetFilters(IReadOnlyCollection<BaseItem> items)
- {
- var result = new QueryFiltersLegacy();
-
- result.Years = items.Select(i => i.ProductionYear ?? -1)
- .Where(i => i > 0)
- .Distinct()
- .OrderBy(i => i)
- .ToArray();
-
- result.Genres = items.SelectMany(i => i.Genres)
- .DistinctNames()
- .OrderBy(i => i)
- .ToArray();
-
- result.Tags = items
- .SelectMany(i => i.Tags)
- .Distinct(StringComparer.OrdinalIgnoreCase)
- .OrderBy(i => i)
- .ToArray();
-
- result.OfficialRatings = items
- .Select(i => i.OfficialRating)
- .Where(i => !string.IsNullOrWhiteSpace(i))
- .Distinct(StringComparer.OrdinalIgnoreCase)
- .OrderBy(i => i)
- .ToArray();
-
- return result;
- }
-
- private InternalItemsQuery GetItemsQuery(GetQueryFiltersLegacy request, User user)
- {
- var query = new InternalItemsQuery
- {
- User = user,
- MediaTypes = request.GetMediaTypes(),
- IncludeItemTypes = request.GetIncludeItemTypes(),
- Recursive = true,
- EnableTotalRecordCount = false,
- DtoOptions = new Controller.Dto.DtoOptions
- {
- Fields = new[] { ItemFields.Genres, ItemFields.Tags },
- EnableImages = false,
- EnableUserData = false
- }
- };
-
- return query;
- }
- }
-}
diff --git a/MediaBrowser.Api/Images/ImageByNameService.cs b/MediaBrowser.Api/Images/ImageByNameService.cs
deleted file mode 100644
index 45b7d0c10..000000000
--- a/MediaBrowser.Api/Images/ImageByNameService.cs
+++ /dev/null
@@ -1,277 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-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
-{
- /// <summary>
- /// Class GetGeneralImage
- /// </summary>
- [Route("/Images/General/{Name}/{Type}", "GET", Summary = "Gets a general image by name")]
- public class GetGeneralImage
- {
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- /// <value>The name.</value>
- [ApiMember(Name = "Name", Description = "The name of the image", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Name { get; set; }
-
- [ApiMember(Name = "Type", Description = "Image Type (primary, backdrop, logo, etc).", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Type { get; set; }
- }
-
- /// <summary>
- /// Class GetRatingImage
- /// </summary>
- [Route("/Images/Ratings/{Theme}/{Name}", "GET", Summary = "Gets a rating image by name")]
- public class GetRatingImage
- {
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- /// <value>The name.</value>
- [ApiMember(Name = "Name", Description = "The name of the image", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Name { get; set; }
-
- /// <summary>
- /// Gets or sets the theme.
- /// </summary>
- /// <value>The theme.</value>
- [ApiMember(Name = "Theme", Description = "The theme to get the image from", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Theme { get; set; }
- }
-
- /// <summary>
- /// Class GetMediaInfoImage
- /// </summary>
- [Route("/Images/MediaInfo/{Theme}/{Name}", "GET", Summary = "Gets a media info image by name")]
- public class GetMediaInfoImage
- {
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- /// <value>The name.</value>
- [ApiMember(Name = "Name", Description = "The name of the image", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Name { get; set; }
-
- /// <summary>
- /// Gets or sets the theme.
- /// </summary>
- /// <value>The theme.</value>
- [ApiMember(Name = "Theme", Description = "The theme to get the image from", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Theme { get; set; }
- }
-
- [Route("/Images/MediaInfo", "GET", Summary = "Gets all media info image by name")]
- [Authenticated]
- public class GetMediaInfoImages : IReturn<List<ImageByNameInfo>>
- {
- }
-
- [Route("/Images/Ratings", "GET", Summary = "Gets all rating images by name")]
- [Authenticated]
- public class GetRatingImages : IReturn<List<ImageByNameInfo>>
- {
- }
-
- [Route("/Images/General", "GET", Summary = "Gets all general images by name")]
- [Authenticated]
- public class GetGeneralImages : IReturn<List<ImageByNameInfo>>
- {
- }
-
- /// <summary>
- /// Class ImageByNameService
- /// </summary>
- public class ImageByNameService : BaseApiService
- {
- /// <summary>
- /// The _app paths
- /// </summary>
- private readonly IServerApplicationPaths _appPaths;
-
- private readonly IFileSystem _fileSystem;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ImageByNameService" /> class.
- /// </summary>
- public ImageByNameService(
- ILogger<ImageByNameService> logger,
- IServerConfigurationManager serverConfigurationManager,
- IHttpResultFactory resultFactory,
- IFileSystem fileSystem)
- : base(logger, serverConfigurationManager, resultFactory)
- {
- _appPaths = serverConfigurationManager.ApplicationPaths;
- _fileSystem = fileSystem;
- }
-
- public object Get(GetMediaInfoImages request)
- {
- return ToOptimizedResult(GetImageList(_appPaths.MediaInfoImagesPath, true));
- }
-
- public object Get(GetRatingImages request)
- {
- return ToOptimizedResult(GetImageList(_appPaths.RatingsPath, true));
- }
-
- public object Get(GetGeneralImages request)
- {
- return ToOptimizedResult(GetImageList(_appPaths.GeneralPath, false));
- }
-
- private List<ImageByNameInfo> GetImageList(string path, bool supportsThemes)
- {
- try
- {
- return _fileSystem.GetFiles(path, BaseItem.SupportedImageExtensions, false, true)
- .Select(i => new ImageByNameInfo
- {
- Name = _fileSystem.GetFileNameWithoutExtension(i),
- FileLength = i.Length,
-
- // For themeable images, use the Theme property
- // For general images, the same object structure is fine,
- // but it's not owned by a theme, so call it Context
- Theme = supportsThemes ? GetThemeName(i.FullName, path) : null,
- Context = supportsThemes ? null : GetThemeName(i.FullName, path),
-
- Format = i.Extension.ToLowerInvariant().TrimStart('.')
- })
- .OrderBy(i => i.Name)
- .ToList();
- }
- catch (IOException)
- {
- return new List<ImageByNameInfo>();
- }
- }
-
- private string GetThemeName(string path, string rootImagePath)
- {
- var parentName = Path.GetDirectoryName(path);
-
- if (string.Equals(parentName, rootImagePath, StringComparison.OrdinalIgnoreCase))
- {
- return null;
- }
-
- parentName = Path.GetFileName(parentName);
-
- return string.Equals(parentName, "all", StringComparison.OrdinalIgnoreCase) ?
- null :
- parentName;
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public Task<object> Get(GetGeneralImage request)
- {
- var filename = string.Equals(request.Type, "primary", StringComparison.OrdinalIgnoreCase)
- ? "folder"
- : request.Type;
-
- var paths = BaseItem.SupportedImageExtensions.Select(i => Path.Combine(_appPaths.GeneralPath, request.Name, filename + i)).ToList();
-
- var path = paths.FirstOrDefault(File.Exists) ?? paths.FirstOrDefault();
-
- return ResultFactory.GetStaticFileResult(Request, path);
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public object Get(GetRatingImage request)
- {
- var themeFolder = Path.Combine(_appPaths.RatingsPath, request.Theme);
-
- if (Directory.Exists(themeFolder))
- {
- var path = BaseItem.SupportedImageExtensions
- .Select(i => Path.Combine(themeFolder, request.Name + i))
- .FirstOrDefault(File.Exists);
-
- if (!string.IsNullOrEmpty(path))
- {
- return ResultFactory.GetStaticFileResult(Request, path);
- }
- }
-
- var allFolder = Path.Combine(_appPaths.RatingsPath, "all");
-
- if (Directory.Exists(allFolder))
- {
- // Avoid implicitly captured closure
- var currentRequest = request;
-
- var path = BaseItem.SupportedImageExtensions
- .Select(i => Path.Combine(allFolder, currentRequest.Name + i))
- .FirstOrDefault(File.Exists);
-
- if (!string.IsNullOrEmpty(path))
- {
- return ResultFactory.GetStaticFileResult(Request, path);
- }
- }
-
- throw new ResourceNotFoundException("MediaInfo image not found: " + request.Name);
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public Task<object> Get(GetMediaInfoImage request)
- {
- var themeFolder = Path.Combine(_appPaths.MediaInfoImagesPath, request.Theme);
-
- if (Directory.Exists(themeFolder))
- {
- var path = BaseItem.SupportedImageExtensions.Select(i => Path.Combine(themeFolder, request.Name + i))
- .FirstOrDefault(File.Exists);
-
- if (!string.IsNullOrEmpty(path))
- {
- return ResultFactory.GetStaticFileResult(Request, path);
- }
- }
-
- var allFolder = Path.Combine(_appPaths.MediaInfoImagesPath, "all");
-
- if (Directory.Exists(allFolder))
- {
- // Avoid implicitly captured closure
- var currentRequest = request;
-
- var path = BaseItem.SupportedImageExtensions.Select(i => Path.Combine(allFolder, currentRequest.Name + i))
- .FirstOrDefault(File.Exists);
-
- if (!string.IsNullOrEmpty(path))
- {
- return ResultFactory.GetStaticFileResult(Request, path);
- }
- }
-
- throw new ResourceNotFoundException("MediaInfo image not found: " + request.Name);
- }
- }
-}
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index fdb15d96a..0b8ddeacd 100644
--- a/MediaBrowser.Api/Images/ImageService.cs
+++ b/MediaBrowser.Api/Images/ImageService.cs
@@ -18,9 +18,11 @@ using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Net;
using MediaBrowser.Model.Services;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
+using User = Jellyfin.Data.Entities.User;
namespace MediaBrowser.Api.Images
{
@@ -408,14 +410,14 @@ namespace MediaBrowser.Api.Images
{
var item = _userManager.GetUserById(request.Id);
- return GetImage(request, Guid.Empty, item, false);
+ return GetImage(request, item, false);
}
public object Head(GetUserImage request)
{
var item = _userManager.GetUserById(request.Id);
- return GetImage(request, Guid.Empty, item, true);
+ return GetImage(request, item, true);
}
public object Get(GetItemByNameImage request)
@@ -448,9 +450,9 @@ namespace MediaBrowser.Api.Images
request.Type = Enum.Parse<ImageType>(GetPathValue(3).ToString(), true);
- var item = _userManager.GetUserById(id);
+ var user = _userManager.GetUserById(id);
- return PostImage(item, request.RequestStream, request.Type, Request.ContentType);
+ return PostImage(user, request.RequestStream, Request.ContentType);
}
/// <summary>
@@ -477,9 +479,17 @@ namespace MediaBrowser.Api.Images
var userId = request.Id;
AssertCanUpdateUser(_authContext, _userManager, userId, true);
- var item = _userManager.GetUserById(userId);
+ var user = _userManager.GetUserById(userId);
+ try
+ {
+ File.Delete(user.ProfileImage.Path);
+ }
+ catch (IOException e)
+ {
+ Logger.LogError(e, "Error deleting user profile image:");
+ }
- item.DeleteImage(request.Type, request.Index ?? 0);
+ _userManager.ClearProfileImage(user);
}
/// <summary>
@@ -567,14 +577,14 @@ namespace MediaBrowser.Api.Images
throw new ResourceNotFoundException(string.Format("{0} does not have an image of type {1}", item.Name, request.Type));
}
- bool cropwhitespace;
+ bool cropWhitespace;
if (request.CropWhitespace.HasValue)
{
- cropwhitespace = request.CropWhitespace.Value;
+ cropWhitespace = request.CropWhitespace.Value;
}
else
{
- cropwhitespace = request.Type == ImageType.Logo || request.Type == ImageType.Art;
+ cropWhitespace = request.Type == ImageType.Logo || request.Type == ImageType.Art;
}
var outputFormats = GetOutputFormats(request);
@@ -597,7 +607,35 @@ namespace MediaBrowser.Api.Images
itemId,
request,
imageInfo,
- cropwhitespace,
+ cropWhitespace,
+ outputFormats,
+ cacheDuration,
+ responseHeaders,
+ isHeadRequest);
+ }
+
+ public Task<object> GetImage(ImageRequest request, User user, bool isHeadRequest)
+ {
+ var imageInfo = GetImageInfo(request, user);
+
+ TimeSpan? cacheDuration = null;
+
+ if (!string.IsNullOrEmpty(request.Tag))
+ {
+ cacheDuration = TimeSpan.FromDays(365);
+ }
+
+ var responseHeaders = new Dictionary<string, string>
+ {
+ {"transferMode.dlna.org", "Interactive"},
+ {"realTimeInfo.dlna.org", "DLNA.ORG_TLAG=*"}
+ };
+
+ var outputFormats = GetOutputFormats(request);
+
+ return GetImageResult(user.Id,
+ request,
+ imageInfo,
outputFormats,
cacheDuration,
responseHeaders,
@@ -605,6 +643,55 @@ namespace MediaBrowser.Api.Images
}
private async Task<object> GetImageResult(
+ Guid itemId,
+ ImageRequest request,
+ ItemImageInfo info,
+ IReadOnlyCollection<ImageFormat> supportedFormats,
+ TimeSpan? cacheDuration,
+ IDictionary<string, string> headers,
+ bool isHeadRequest)
+ {
+ info.Type = ImageType.Profile;
+ var options = new ImageProcessingOptions
+ {
+ CropWhiteSpace = true,
+ Height = request.Height,
+ ImageIndex = request.Index ?? 0,
+ Image = info,
+ Item = null, // Hack alert
+ ItemId = itemId,
+ MaxHeight = request.MaxHeight,
+ MaxWidth = request.MaxWidth,
+ Quality = request.Quality ?? 100,
+ Width = request.Width,
+ AddPlayedIndicator = request.AddPlayedIndicator,
+ PercentPlayed = 0,
+ UnplayedCount = request.UnplayedCount,
+ Blur = request.Blur,
+ BackgroundColor = request.BackgroundColor,
+ ForegroundLayer = request.ForegroundLayer,
+ SupportedOutputFormats = supportedFormats
+ };
+
+ var imageResult = await _imageProcessor.ProcessImage(options).ConfigureAwait(false);
+
+ headers[HeaderNames.Vary] = HeaderNames.Accept;
+
+ return await ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
+ {
+ CacheDuration = cacheDuration,
+ ResponseHeaders = headers,
+ ContentType = imageResult.Item2,
+ DateLastModified = imageResult.Item3,
+ IsHeadRequest = isHeadRequest,
+ Path = imageResult.Item1,
+
+ FileShare = FileShare.Read
+
+ }).ConfigureAwait(false);
+ }
+
+ private async Task<object> GetImageResult(
BaseItem item,
Guid itemId,
ImageRequest request,
@@ -741,13 +828,35 @@ namespace MediaBrowser.Api.Images
/// <param name="request">The request.</param>
/// <param name="item">The item.</param>
/// <returns>System.String.</returns>
- private ItemImageInfo GetImageInfo(ImageRequest request, BaseItem item)
+ private static ItemImageInfo GetImageInfo(ImageRequest request, BaseItem item)
{
var index = request.Index ?? 0;
return item.GetImageInfo(request.Type, index);
}
+ private static ItemImageInfo GetImageInfo(ImageRequest request, User user)
+ {
+ var info = new ItemImageInfo
+ {
+ Path = user.ProfileImage.Path,
+ Type = ImageType.Primary,
+ DateModified = user.ProfileImage.LastModified,
+ };
+
+ if (request.Width.HasValue)
+ {
+ info.Width = request.Width.Value;
+ }
+
+ if (request.Height.HasValue)
+ {
+ info.Height = request.Height.Value;
+ }
+
+ return info;
+ }
+
/// <summary>
/// Posts the image.
/// </summary>
@@ -758,22 +867,41 @@ namespace MediaBrowser.Api.Images
/// <returns>Task.</returns>
public async Task PostImage(BaseItem entity, Stream inputStream, ImageType imageType, string mimeType)
{
+ var memoryStream = await GetMemoryStream(inputStream);
+
+ // Handle image/png; charset=utf-8
+ mimeType = mimeType.Split(';').FirstOrDefault();
+
+ await _providerManager.SaveImage(entity, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false);
+
+ entity.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None);
+ }
+
+ private static async Task<MemoryStream> GetMemoryStream(Stream inputStream)
+ {
using var reader = new StreamReader(inputStream);
var text = await reader.ReadToEndAsync().ConfigureAwait(false);
var bytes = Convert.FromBase64String(text);
-
- var memoryStream = new MemoryStream(bytes)
+ return new MemoryStream(bytes)
{
Position = 0
};
+ }
+
+ private async Task PostImage(User user, Stream inputStream, string mimeType)
+ {
+ var memoryStream = await GetMemoryStream(inputStream);
// Handle image/png; charset=utf-8
mimeType = mimeType.Split(';').FirstOrDefault();
+ var userDataPath = Path.Combine(ServerConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username);
+ user.ProfileImage = new Jellyfin.Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType)));
- await _providerManager.SaveImage(entity, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false);
-
- entity.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None);
+ await _providerManager
+ .SaveImage(user, memoryStream, mimeType, user.ProfileImage.Path)
+ .ConfigureAwait(false);
+ await _userManager.UpdateUserAsync(user);
}
}
}
diff --git a/MediaBrowser.Api/Images/RemoteImageService.cs b/MediaBrowser.Api/Images/RemoteImageService.cs
deleted file mode 100644
index 358ac30fa..000000000
--- a/MediaBrowser.Api/Images/RemoteImageService.cs
+++ /dev/null
@@ -1,297 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Providers;
-using MediaBrowser.Model.Services;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.Api.Images
-{
- public class BaseRemoteImageRequest : IReturn<RemoteImageResult>
- {
- [ApiMember(Name = "Type", Description = "The image type", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public ImageType? Type { get; set; }
-
- /// <summary>
- /// Skips over a given number of items within the results. Use for paging.
- /// </summary>
- /// <value>The start index.</value>
- [ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
- public int? StartIndex { get; set; }
-
- /// <summary>
- /// The maximum number of items to return
- /// </summary>
- /// <value>The limit.</value>
- [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
- public int? Limit { get; set; }
-
- [ApiMember(Name = "ProviderName", Description = "Optional. The image provider to use", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string ProviderName { get; set; }
-
- [ApiMember(Name = "IncludeAllLanguages", Description = "Optional.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
- public bool IncludeAllLanguages { get; set; }
- }
-
- [Route("/Items/{Id}/RemoteImages", "GET", Summary = "Gets available remote images for an item")]
- [Authenticated]
- public class GetRemoteImages : BaseRemoteImageRequest
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Id { get; set; }
- }
-
- [Route("/Items/{Id}/RemoteImages/Providers", "GET", Summary = "Gets available remote image providers for an item")]
- [Authenticated]
- public class GetRemoteImageProviders : IReturn<List<ImageProviderInfo>>
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Id { get; set; }
- }
-
- public class BaseDownloadRemoteImage : IReturnVoid
- {
- [ApiMember(Name = "Type", Description = "The image type", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
- public ImageType Type { get; set; }
-
- [ApiMember(Name = "ProviderName", Description = "The image provider", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
- public string ProviderName { get; set; }
-
- [ApiMember(Name = "ImageUrl", Description = "The image url", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
- public string ImageUrl { get; set; }
- }
-
- [Route("/Items/{Id}/RemoteImages/Download", "POST", Summary = "Downloads a remote image for an item")]
- [Authenticated(Roles = "Admin")]
- public class DownloadRemoteImage : BaseDownloadRemoteImage
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
- }
-
- [Route("/Images/Remote", "GET", Summary = "Gets a remote image")]
- public class GetRemoteImage
- {
- [ApiMember(Name = "ImageUrl", Description = "The image url", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string ImageUrl { get; set; }
- }
-
- public class RemoteImageService : BaseApiService
- {
- private readonly IProviderManager _providerManager;
-
- private readonly IServerApplicationPaths _appPaths;
- private readonly IHttpClient _httpClient;
- private readonly IFileSystem _fileSystem;
-
- private readonly 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;
- _appPaths = appPaths;
- _httpClient = httpClient;
- _fileSystem = fileSystem;
- _libraryManager = libraryManager;
- }
-
- public object Get(GetRemoteImageProviders request)
- {
- var item = _libraryManager.GetItemById(request.Id);
-
- var result = GetImageProviders(item);
-
- return ToOptimizedResult(result);
- }
-
- private List<ImageProviderInfo> GetImageProviders(BaseItem item)
- {
- return _providerManager.GetRemoteImageProviderInfo(item).ToList();
- }
-
- public async Task<object> Get(GetRemoteImages request)
- {
- var item = _libraryManager.GetItemById(request.Id);
-
- var images = await _providerManager.GetAvailableRemoteImages(item, new RemoteImageQuery(request.ProviderName)
- {
- IncludeAllLanguages = request.IncludeAllLanguages,
- IncludeDisabledProviders = true,
- ImageType = request.Type
-
- }, CancellationToken.None).ConfigureAwait(false);
-
- var imagesList = images.ToArray();
-
- var allProviders = _providerManager.GetRemoteImageProviderInfo(item);
-
- if (request.Type.HasValue)
- {
- allProviders = allProviders.Where(i => i.SupportedImages.Contains(request.Type.Value));
- }
-
- var result = new RemoteImageResult
- {
- TotalRecordCount = imagesList.Length,
- Providers = allProviders.Select(i => i.Name)
- .Distinct(StringComparer.OrdinalIgnoreCase)
- .ToArray()
- };
-
- if (request.StartIndex.HasValue)
- {
- imagesList = imagesList.Skip(request.StartIndex.Value)
- .ToArray();
- }
-
- if (request.Limit.HasValue)
- {
- imagesList = imagesList.Take(request.Limit.Value)
- .ToArray();
- }
-
- result.Images = imagesList;
-
- return result;
- }
-
- /// <summary>
- /// Posts the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public Task Post(DownloadRemoteImage request)
- {
- var item = _libraryManager.GetItemById(request.Id);
-
- return DownloadRemoteImage(item, request);
- }
-
- /// <summary>
- /// Downloads the remote image.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="request">The request.</param>
- /// <returns>Task.</returns>
- private async Task DownloadRemoteImage(BaseItem item, BaseDownloadRemoteImage request)
- {
- await _providerManager.SaveImage(item, request.ImageUrl, request.Type, null, CancellationToken.None).ConfigureAwait(false);
-
- item.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None);
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public async Task<object> Get(GetRemoteImage request)
- {
- var urlHash = request.ImageUrl.GetMD5();
- var pointerCachePath = GetFullCachePath(urlHash.ToString());
-
- string contentPath;
-
- try
- {
- contentPath = File.ReadAllText(pointerCachePath);
-
- if (File.Exists(contentPath))
- {
- return await ResultFactory.GetStaticFileResult(Request, contentPath).ConfigureAwait(false);
- }
- }
- catch (FileNotFoundException)
- {
- // Means the file isn't cached yet
- }
- catch (IOException)
- {
- // Means the file isn't cached yet
- }
-
- await DownloadImage(request.ImageUrl, urlHash, pointerCachePath).ConfigureAwait(false);
-
- // Read the pointer file again
- contentPath = File.ReadAllText(pointerCachePath);
-
- return await ResultFactory.GetStaticFileResult(Request, contentPath).ConfigureAwait(false);
- }
-
- /// <summary>
- /// Downloads the image.
- /// </summary>
- /// <param name="url">The URL.</param>
- /// <param name="urlHash">The URL hash.</param>
- /// <param name="pointerCachePath">The pointer cache path.</param>
- /// <returns>Task.</returns>
- private async Task DownloadImage(string url, Guid urlHash, string pointerCachePath)
- {
- using var result = await _httpClient.GetResponse(new HttpRequestOptions
- {
- Url = url,
- BufferContent = false
- }).ConfigureAwait(false);
- var ext = result.ContentType.Split('/')[^1];
-
- var fullCachePath = GetFullCachePath(urlHash + "." + ext);
-
- Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath));
- var stream = result.Content;
- await using (stream.ConfigureAwait(false))
- {
- var filestream = new FileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true);
- await using (filestream.ConfigureAwait(false))
- {
- await stream.CopyToAsync(filestream).ConfigureAwait(false);
- }
- }
-
- Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath));
- File.WriteAllText(pointerCachePath, fullCachePath);
- }
-
- /// <summary>
- /// Gets the full cache path.
- /// </summary>
- /// <param name="filename">The filename.</param>
- /// <returns>System.String.</returns>
- private string GetFullCachePath(string filename)
- {
- return Path.Combine(_appPaths.CachePath, "remote-images", filename.Substring(0, 1), filename);
- }
- }
-}
diff --git a/MediaBrowser.Api/ItemRefreshService.cs b/MediaBrowser.Api/ItemRefreshService.cs
deleted file mode 100644
index 5e86f04a8..000000000
--- a/MediaBrowser.Api/ItemRefreshService.cs
+++ /dev/null
@@ -1,83 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Services;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.Api
-{
- public class BaseRefreshRequest : IReturnVoid
- {
- [ApiMember(Name = "MetadataRefreshMode", Description = "Specifies the metadata refresh mode", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")]
- public MetadataRefreshMode MetadataRefreshMode { get; set; }
-
- [ApiMember(Name = "ImageRefreshMode", Description = "Specifies the image refresh mode", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")]
- public MetadataRefreshMode ImageRefreshMode { get; set; }
-
- [ApiMember(Name = "ReplaceAllMetadata", Description = "Determines if metadata should be replaced. Only applicable if mode is FullRefresh", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")]
- public bool ReplaceAllMetadata { get; set; }
-
- [ApiMember(Name = "ReplaceAllImages", Description = "Determines if images should be replaced. Only applicable if mode is FullRefresh", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")]
- public bool ReplaceAllImages { get; set; }
- }
-
- [Route("/Items/{Id}/Refresh", "POST", Summary = "Refreshes metadata for an item")]
- public class RefreshItem : BaseRefreshRequest
- {
- [ApiMember(Name = "Recursive", Description = "Indicates if the refresh should occur recursively.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
- public bool Recursive { get; set; }
-
- [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
- }
-
- [Authenticated]
- public class ItemRefreshService : BaseApiService
- {
- private readonly ILibraryManager _libraryManager;
- private readonly IProviderManager _providerManager;
- private readonly IFileSystem _fileSystem;
-
- 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;
- }
-
- /// <summary>
- /// Posts the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public void Post(RefreshItem request)
- {
- var item = _libraryManager.GetItemById(request.Id);
-
- var options = GetRefreshOptions(request);
-
- _providerManager.QueueRefresh(item.Id, options, RefreshPriority.High);
- }
-
- private MetadataRefreshOptions GetRefreshOptions(RefreshItem request)
- {
- return new MetadataRefreshOptions(new DirectoryService(_fileSystem))
- {
- MetadataRefreshMode = request.MetadataRefreshMode,
- ImageRefreshMode = request.ImageRefreshMode,
- ReplaceAllImages = request.ReplaceAllImages,
- ReplaceAllMetadata = request.ReplaceAllMetadata,
- ForceSave = request.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || request.ImageRefreshMode == MetadataRefreshMode.FullRefresh || request.ReplaceAllImages || request.ReplaceAllMetadata,
- IsAutomated = false
- };
- }
- }
-}
diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs
deleted file mode 100644
index 2db6d717a..000000000
--- a/MediaBrowser.Api/ItemUpdateService.cs
+++ /dev/null
@@ -1,396 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Globalization;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Services;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.Api
-{
- [Route("/Items/{ItemId}", "POST", Summary = "Updates an item")]
- public class UpdateItem : BaseItemDto, IReturnVoid
- {
- [ApiMember(Name = "ItemId", Description = "The id of the item", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string ItemId { get; set; }
- }
-
- [Route("/Items/{ItemId}/MetadataEditor", "GET", Summary = "Gets metadata editor info for an item")]
- public class GetMetadataEditorInfo : IReturn<MetadataEditorInfo>
- {
- [ApiMember(Name = "ItemId", Description = "The id of the item", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string ItemId { get; set; }
- }
-
- [Route("/Items/{ItemId}/ContentType", "POST", Summary = "Updates an item's content type")]
- public class UpdateItemContentType : IReturnVoid
- {
- [ApiMember(Name = "ItemId", Description = "The id of the item", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public Guid ItemId { get; set; }
-
- [ApiMember(Name = "ContentType", Description = "The content type of the item", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string ContentType { get; set; }
- }
-
- [Authenticated(Roles = "admin")]
- public class ItemUpdateService : BaseApiService
- {
- private readonly ILibraryManager _libraryManager;
- private readonly IProviderManager _providerManager;
- private readonly ILocalizationManager _localizationManager;
- private readonly IFileSystem _fileSystem;
-
- 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;
- _fileSystem = fileSystem;
- }
-
- public object Get(GetMetadataEditorInfo request)
- {
- var item = _libraryManager.GetItemById(request.ItemId);
-
- var info = new MetadataEditorInfo
- {
- ParentalRatingOptions = _localizationManager.GetParentalRatings().ToArray(),
- ExternalIdInfos = _providerManager.GetExternalIdInfos(item).ToArray(),
- Countries = _localizationManager.GetCountries().ToArray(),
- Cultures = _localizationManager.GetCultures().ToArray()
- };
-
- if (!item.IsVirtualItem && !(item is ICollectionFolder) && !(item is UserView) && !(item is AggregateFolder) && !(item is LiveTvChannel) && !(item is IItemByName) &&
- item.SourceType == SourceType.Library)
- {
- var inheritedContentType = _libraryManager.GetInheritedContentType(item);
- var configuredContentType = _libraryManager.GetConfiguredContentType(item);
-
- if (string.IsNullOrWhiteSpace(inheritedContentType) || !string.IsNullOrWhiteSpace(configuredContentType))
- {
- info.ContentTypeOptions = GetContentTypeOptions(true).ToArray();
- info.ContentType = configuredContentType;
-
- if (string.IsNullOrWhiteSpace(inheritedContentType) || string.Equals(inheritedContentType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
- {
- info.ContentTypeOptions = info.ContentTypeOptions
- .Where(i => string.IsNullOrWhiteSpace(i.Value) || string.Equals(i.Value, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
- .ToArray();
- }
- }
- }
-
- return ToOptimizedResult(info);
- }
-
- public void Post(UpdateItemContentType request)
- {
- var item = _libraryManager.GetItemById(request.ItemId);
- var path = item.ContainingFolderPath;
-
- var types = ServerConfigurationManager.Configuration.ContentTypes
- .Where(i => !string.IsNullOrWhiteSpace(i.Name))
- .Where(i => !string.Equals(i.Name, path, StringComparison.OrdinalIgnoreCase))
- .ToList();
-
- if (!string.IsNullOrWhiteSpace(request.ContentType))
- {
- types.Add(new NameValuePair
- {
- Name = path,
- Value = request.ContentType
- });
- }
-
- ServerConfigurationManager.Configuration.ContentTypes = types.ToArray();
- ServerConfigurationManager.SaveConfiguration();
- }
-
- private List<NameValuePair> GetContentTypeOptions(bool isForItem)
- {
- var list = new List<NameValuePair>();
-
- if (isForItem)
- {
- list.Add(new NameValuePair
- {
- Name = "Inherit",
- Value = ""
- });
- }
-
- list.Add(new NameValuePair
- {
- Name = "Movies",
- Value = "movies"
- });
- list.Add(new NameValuePair
- {
- Name = "Music",
- Value = "music"
- });
- list.Add(new NameValuePair
- {
- Name = "Shows",
- Value = "tvshows"
- });
-
- if (!isForItem)
- {
- list.Add(new NameValuePair
- {
- Name = "Books",
- Value = "books"
- });
- }
-
- list.Add(new NameValuePair
- {
- Name = "HomeVideos",
- Value = "homevideos"
- });
- list.Add(new NameValuePair
- {
- Name = "MusicVideos",
- Value = "musicvideos"
- });
- list.Add(new NameValuePair
- {
- Name = "Photos",
- Value = "photos"
- });
-
- if (!isForItem)
- {
- list.Add(new NameValuePair
- {
- Name = "MixedContent",
- Value = ""
- });
- }
-
- foreach (var val in list)
- {
- val.Name = _localizationManager.GetLocalizedString(val.Name);
- }
-
- return list;
- }
-
- public void Post(UpdateItem request)
- {
- var item = _libraryManager.GetItemById(request.ItemId);
-
- var newLockData = request.LockData ?? false;
- var isLockedChanged = item.IsLocked != newLockData;
-
- var series = item as Series;
- var displayOrderChanged = series != null && !string.Equals(series.DisplayOrder ?? string.Empty, request.DisplayOrder ?? string.Empty, StringComparison.OrdinalIgnoreCase);
-
- // Do this first so that metadata savers can pull the updates from the database.
- if (request.People != null)
- {
- _libraryManager.UpdatePeople(item, request.People.Select(x => new PersonInfo { Name = x.Name, Role = x.Role, Type = x.Type }).ToList());
- }
-
- UpdateItem(request, item);
-
- item.OnMetadataChanged();
-
- item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None);
-
- if (isLockedChanged && item.IsFolder)
- {
- var folder = (Folder)item;
-
- foreach (var child in folder.GetRecursiveChildren())
- {
- child.IsLocked = newLockData;
- child.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None);
- }
- }
-
- if (displayOrderChanged)
- {
- _providerManager.QueueRefresh(
- series.Id,
- new MetadataRefreshOptions(new DirectoryService(_fileSystem))
- {
- MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
- ImageRefreshMode = MetadataRefreshMode.FullRefresh,
- ReplaceAllMetadata = true
- },
- RefreshPriority.High);
- }
- }
-
- private DateTime NormalizeDateTime(DateTime val)
- {
- return DateTime.SpecifyKind(val, DateTimeKind.Utc);
- }
-
- private void UpdateItem(BaseItemDto request, BaseItem item)
- {
- item.Name = request.Name;
- item.ForcedSortName = request.ForcedSortName;
-
- item.OriginalTitle = string.IsNullOrWhiteSpace(request.OriginalTitle) ? null : request.OriginalTitle;
-
- item.CriticRating = request.CriticRating;
-
- item.CommunityRating = request.CommunityRating;
- item.IndexNumber = request.IndexNumber;
- item.ParentIndexNumber = request.ParentIndexNumber;
- item.Overview = request.Overview;
- item.Genres = request.Genres;
-
- if (item is Episode episode)
- {
- episode.AirsAfterSeasonNumber = request.AirsAfterSeasonNumber;
- episode.AirsBeforeEpisodeNumber = request.AirsBeforeEpisodeNumber;
- episode.AirsBeforeSeasonNumber = request.AirsBeforeSeasonNumber;
- }
-
- item.Tags = request.Tags;
-
- if (request.Taglines != null)
- {
- item.Tagline = request.Taglines.FirstOrDefault();
- }
-
- if (request.Studios != null)
- {
- item.Studios = request.Studios.Select(x => x.Name).ToArray();
- }
-
- if (request.DateCreated.HasValue)
- {
- item.DateCreated = NormalizeDateTime(request.DateCreated.Value);
- }
-
- item.EndDate = request.EndDate.HasValue ? NormalizeDateTime(request.EndDate.Value) : (DateTime?)null;
- item.PremiereDate = request.PremiereDate.HasValue ? NormalizeDateTime(request.PremiereDate.Value) : (DateTime?)null;
- item.ProductionYear = request.ProductionYear;
- item.OfficialRating = string.IsNullOrWhiteSpace(request.OfficialRating) ? null : request.OfficialRating;
- item.CustomRating = request.CustomRating;
-
- if (request.ProductionLocations != null)
- {
- item.ProductionLocations = request.ProductionLocations;
- }
-
- item.PreferredMetadataCountryCode = request.PreferredMetadataCountryCode;
- item.PreferredMetadataLanguage = request.PreferredMetadataLanguage;
-
- if (item is IHasDisplayOrder hasDisplayOrder)
- {
- hasDisplayOrder.DisplayOrder = request.DisplayOrder;
- }
-
- if (item is IHasAspectRatio hasAspectRatio)
- {
- hasAspectRatio.AspectRatio = request.AspectRatio;
- }
-
- item.IsLocked = request.LockData ?? false;
-
- if (request.LockedFields != null)
- {
- item.LockedFields = request.LockedFields;
- }
-
- // Only allow this for series. Runtimes for media comes from ffprobe.
- if (item is Series)
- {
- item.RunTimeTicks = request.RunTimeTicks;
- }
-
- foreach (var pair in request.ProviderIds.ToList())
- {
- if (string.IsNullOrEmpty(pair.Value))
- {
- request.ProviderIds.Remove(pair.Key);
- }
- }
-
- item.ProviderIds = request.ProviderIds;
-
- if (item is Video video)
- {
- video.Video3DFormat = request.Video3DFormat;
- }
-
- if (request.AlbumArtists != null)
- {
- if (item is IHasAlbumArtist hasAlbumArtists)
- {
- hasAlbumArtists.AlbumArtists = request
- .AlbumArtists
- .Select(i => i.Name)
- .ToArray();
- }
- }
-
- if (request.ArtistItems != null)
- {
- if (item is IHasArtist hasArtists)
- {
- hasArtists.Artists = request
- .ArtistItems
- .Select(i => i.Name)
- .ToArray();
- }
- }
-
- if (item is Audio song)
- {
- song.Album = request.Album;
- }
-
- if (item is MusicVideo musicVideo)
- {
- musicVideo.Album = request.Album;
- }
-
- if (item is Series series)
- {
- series.Status = GetSeriesStatus(request);
-
- if (request.AirDays != null)
- {
- series.AirDays = request.AirDays;
- series.AirTime = request.AirTime;
- }
- }
- }
-
- private SeriesStatus? GetSeriesStatus(BaseItemDto item)
- {
- if (string.IsNullOrEmpty(item.Status))
- {
- return null;
- }
-
- return (SeriesStatus)Enum.Parse(typeof(SeriesStatus), item.Status, true);
- }
- }
-}
diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs
index 9d53a2610..e96875403 100644
--- a/MediaBrowser.Api/Library/LibraryService.cs
+++ b/MediaBrowser.Api/Library/LibraryService.cs
@@ -6,6 +6,7 @@ using System.Net;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Entities;
using MediaBrowser.Api.Movies;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Progress;
@@ -14,7 +15,6 @@ using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Providers;
@@ -27,6 +27,12 @@ using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Services;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
+using Book = MediaBrowser.Controller.Entities.Book;
+using Episode = MediaBrowser.Controller.Entities.TV.Episode;
+using MetadataProvider = MediaBrowser.Model.Entities.MetadataProvider;
+using Movie = MediaBrowser.Controller.Entities.Movies.Movie;
+using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum;
+using Series = MediaBrowser.Controller.Entities.TV.Series;
namespace MediaBrowser.Api.Library
{
@@ -350,6 +356,7 @@ namespace MediaBrowser.Api.Library
_moviesServiceLogger = moviesServiceLogger;
}
+ // Content Types available for each Library
private string[] GetRepresentativeItemTypes(string contentType)
{
return contentType switch
@@ -359,7 +366,7 @@ namespace MediaBrowser.Api.Library
CollectionType.Movies => new[] {"Movie"},
CollectionType.TvShows => new[] {"Series", "Season", "Episode"},
CollectionType.Books => new[] {"Book"},
- CollectionType.Music => new[] {"MusicAlbum", "MusicArtist", "Audio", "MusicVideo"},
+ CollectionType.Music => new[] {"MusicArtist", "MusicAlbum", "Audio", "MusicVideo"},
CollectionType.HomeVideos => new[] {"Video", "Photo"},
CollectionType.Photos => new[] {"Video", "Photo"},
CollectionType.MusicVideos => new[] {"MusicVideo"},
@@ -425,7 +432,6 @@ namespace MediaBrowser.Api.Library
return string.Equals(name, "TheTVDB", StringComparison.OrdinalIgnoreCase)
|| string.Equals(name, "Screen Grabber", StringComparison.OrdinalIgnoreCase)
|| string.Equals(name, "TheAudioDB", StringComparison.OrdinalIgnoreCase)
- || string.Equals(name, "Emby Designs", StringComparison.OrdinalIgnoreCase)
|| string.Equals(name, "Image Extractor", StringComparison.OrdinalIgnoreCase);
}
@@ -763,8 +769,8 @@ namespace MediaBrowser.Api.Library
{
try
{
- _activityManager.Create(new Jellyfin.Data.Entities.ActivityLog(
- string.Format(_localization.GetLocalizedString("UserDownloadingItemWithValues"), user.Name, item.Name),
+ _activityManager.Create(new ActivityLog(
+ string.Format(_localization.GetLocalizedString("UserDownloadingItemWithValues"), user.Username, item.Name),
"UserDownloadingContent",
auth.UserId)
{
diff --git a/MediaBrowser.Api/Library/LibraryStructureService.cs b/MediaBrowser.Api/Library/LibraryStructureService.cs
deleted file mode 100644
index 1e300814f..000000000
--- a/MediaBrowser.Api/Library/LibraryStructureService.cs
+++ /dev/null
@@ -1,412 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-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.Services;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.Api.Library
-{
- /// <summary>
- /// Class GetDefaultVirtualFolders
- /// </summary>
- [Route("/Library/VirtualFolders", "GET")]
- public class GetVirtualFolders : IReturn<List<VirtualFolderInfo>>
- {
- /// <summary>
- /// Gets or sets the user id.
- /// </summary>
- /// <value>The user id.</value>
- public string UserId { get; set; }
- }
-
- [Route("/Library/VirtualFolders", "POST")]
- public class AddVirtualFolder : IReturnVoid
- {
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name { get; set; }
-
- /// <summary>
- /// Gets or sets the type of the collection.
- /// </summary>
- /// <value>The type of the collection.</value>
- public string CollectionType { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether [refresh library].
- /// </summary>
- /// <value><c>true</c> if [refresh library]; otherwise, <c>false</c>.</value>
- public bool RefreshLibrary { get; set; }
-
- /// <summary>
- /// Gets or sets the path.
- /// </summary>
- /// <value>The path.</value>
- public string[] Paths { get; set; }
-
- public LibraryOptions LibraryOptions { get; set; }
- }
-
- [Route("/Library/VirtualFolders", "DELETE")]
- public class RemoveVirtualFolder : IReturnVoid
- {
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether [refresh library].
- /// </summary>
- /// <value><c>true</c> if [refresh library]; otherwise, <c>false</c>.</value>
- public bool RefreshLibrary { get; set; }
- }
-
- [Route("/Library/VirtualFolders/Name", "POST")]
- public class RenameVirtualFolder : IReturnVoid
- {
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name { get; set; }
-
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- /// <value>The name.</value>
- public string NewName { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether [refresh library].
- /// </summary>
- /// <value><c>true</c> if [refresh library]; otherwise, <c>false</c>.</value>
- public bool RefreshLibrary { get; set; }
- }
-
- [Route("/Library/VirtualFolders/Paths", "POST")]
- public class AddMediaPath : IReturnVoid
- {
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name { get; set; }
-
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Path { get; set; }
-
- public MediaPathInfo PathInfo { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether [refresh library].
- /// </summary>
- /// <value><c>true</c> if [refresh library]; otherwise, <c>false</c>.</value>
- public bool RefreshLibrary { get; set; }
- }
-
- [Route("/Library/VirtualFolders/Paths/Update", "POST")]
- public class UpdateMediaPath : IReturnVoid
- {
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name { get; set; }
-
- public MediaPathInfo PathInfo { get; set; }
- }
-
- [Route("/Library/VirtualFolders/Paths", "DELETE")]
- public class RemoveMediaPath : IReturnVoid
- {
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name { get; set; }
-
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Path { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether [refresh library].
- /// </summary>
- /// <value><c>true</c> if [refresh library]; otherwise, <c>false</c>.</value>
- public bool RefreshLibrary { get; set; }
- }
-
- [Route("/Library/VirtualFolders/LibraryOptions", "POST")]
- public class UpdateLibraryOptions : IReturnVoid
- {
- public string Id { get; set; }
-
- public LibraryOptions LibraryOptions { get; set; }
- }
-
- /// <summary>
- /// Class LibraryStructureService
- /// </summary>
- [Authenticated(Roles = "Admin", AllowBeforeStartupWizard = true)]
- public class LibraryStructureService : BaseApiService
- {
- /// <summary>
- /// The _app paths
- /// </summary>
- private readonly IServerApplicationPaths _appPaths;
-
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
- private readonly ILibraryMonitor _libraryMonitor;
-
-
- /// <summary>
- /// Initializes a new instance of the <see cref="LibraryStructureService" /> class.
- /// </summary>
- public LibraryStructureService(
- ILogger<LibraryStructureService> logger,
- IServerConfigurationManager serverConfigurationManager,
- IHttpResultFactory httpResultFactory,
- ILibraryManager libraryManager,
- ILibraryMonitor libraryMonitor)
- : base(logger, serverConfigurationManager, httpResultFactory)
- {
- _appPaths = serverConfigurationManager.ApplicationPaths;
- _libraryManager = libraryManager;
- _libraryMonitor = libraryMonitor;
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public object Get(GetVirtualFolders request)
- {
- var result = _libraryManager.GetVirtualFolders(true);
-
- return ToOptimizedResult(result);
- }
-
- public void Post(UpdateLibraryOptions request)
- {
- var collectionFolder = (CollectionFolder)_libraryManager.GetItemById(request.Id);
-
- collectionFolder.UpdateLibraryOptions(request.LibraryOptions);
- }
-
- /// <summary>
- /// Posts the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public Task Post(AddVirtualFolder request)
- {
- var libraryOptions = request.LibraryOptions ?? new LibraryOptions();
-
- if (request.Paths != null && request.Paths.Length > 0)
- {
- libraryOptions.PathInfos = request.Paths.Select(i => new MediaPathInfo { Path = i }).ToArray();
- }
-
- return _libraryManager.AddVirtualFolder(request.Name, request.CollectionType, libraryOptions, request.RefreshLibrary);
- }
-
- /// <summary>
- /// Posts the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public void Post(RenameVirtualFolder request)
- {
- if (string.IsNullOrWhiteSpace(request.Name))
- {
- throw new ArgumentNullException(nameof(request));
- }
-
- if (string.IsNullOrWhiteSpace(request.NewName))
- {
- throw new ArgumentNullException(nameof(request));
- }
-
- var rootFolderPath = _appPaths.DefaultUserViewsPath;
-
- var currentPath = Path.Combine(rootFolderPath, request.Name);
- var newPath = Path.Combine(rootFolderPath, request.NewName);
-
- if (!Directory.Exists(currentPath))
- {
- throw new FileNotFoundException("The media collection does not exist");
- }
-
- if (!string.Equals(currentPath, newPath, StringComparison.OrdinalIgnoreCase) && Directory.Exists(newPath))
- {
- throw new ArgumentException("Media library already exists at " + newPath + ".");
- }
-
- _libraryMonitor.Stop();
-
- try
- {
- // Changing capitalization. Handle windows case insensitivity
- if (string.Equals(currentPath, newPath, StringComparison.OrdinalIgnoreCase))
- {
- var tempPath = Path.Combine(rootFolderPath, Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture));
- Directory.Move(currentPath, tempPath);
- currentPath = tempPath;
- }
-
- Directory.Move(currentPath, newPath);
- }
- finally
- {
- CollectionFolder.OnCollectionFolderChange();
-
- Task.Run(() =>
- {
- // No need to start if scanning the library because it will handle it
- if (request.RefreshLibrary)
- {
- _libraryManager.ValidateMediaLibrary(new SimpleProgress<double>(), CancellationToken.None);
- }
- else
- {
- // Need to add a delay here or directory watchers may still pick up the changes
- var task = Task.Delay(1000);
- // Have to block here to allow exceptions to bubble
- Task.WaitAll(task);
-
- _libraryMonitor.Start();
- }
- });
- }
- }
-
- /// <summary>
- /// Deletes the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public Task Delete(RemoveVirtualFolder request)
- {
- return _libraryManager.RemoveVirtualFolder(request.Name, request.RefreshLibrary);
- }
-
- /// <summary>
- /// Posts the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public void Post(AddMediaPath request)
- {
- if (string.IsNullOrWhiteSpace(request.Name))
- {
- throw new ArgumentNullException(nameof(request));
- }
-
- _libraryMonitor.Stop();
-
- try
- {
- var mediaPath = request.PathInfo ?? new MediaPathInfo
- {
- Path = request.Path
- };
-
- _libraryManager.AddMediaPath(request.Name, mediaPath);
- }
- finally
- {
- Task.Run(() =>
- {
- // No need to start if scanning the library because it will handle it
- if (request.RefreshLibrary)
- {
- _libraryManager.ValidateMediaLibrary(new SimpleProgress<double>(), CancellationToken.None);
- }
- else
- {
- // Need to add a delay here or directory watchers may still pick up the changes
- var task = Task.Delay(1000);
- // Have to block here to allow exceptions to bubble
- Task.WaitAll(task);
-
- _libraryMonitor.Start();
- }
- });
- }
- }
-
- /// <summary>
- /// Posts the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public void Post(UpdateMediaPath request)
- {
- if (string.IsNullOrWhiteSpace(request.Name))
- {
- throw new ArgumentNullException(nameof(request));
- }
-
- _libraryManager.UpdateMediaPath(request.Name, request.PathInfo);
- }
-
- /// <summary>
- /// Deletes the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public void Delete(RemoveMediaPath request)
- {
- if (string.IsNullOrWhiteSpace(request.Name))
- {
- throw new ArgumentNullException(nameof(request));
- }
-
- _libraryMonitor.Stop();
-
- try
- {
- _libraryManager.RemoveMediaPath(request.Name, request.Path);
- }
- finally
- {
- Task.Run(() =>
- {
- // No need to start if scanning the library because it will handle it
- if (request.RefreshLibrary)
- {
- _libraryManager.ValidateMediaLibrary(new SimpleProgress<double>(), CancellationToken.None);
- }
- else
- {
- // Need to add a delay here or directory watchers may still pick up the changes
- var task = Task.Delay(1000);
- // Have to block here to allow exceptions to bubble
- Task.WaitAll(task);
-
- _libraryMonitor.Start();
- }
- });
- }
- }
- }
-}
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index 5fe4c0cca..279fd6ee9 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -7,6 +7,7 @@ using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Enums;
using MediaBrowser.Api.UserLibrary;
using MediaBrowser.Common;
using MediaBrowser.Common.Configuration;
@@ -859,7 +860,7 @@ namespace MediaBrowser.Api.LiveTv
throw new SecurityException("Anonymous live tv management is not allowed.");
}
- if (!user.Policy.EnableLiveTvManagement)
+ if (!user.HasPermission(PermissionKind.EnableLiveTvManagement))
{
throw new SecurityException("The current user does not have permission to manage live tv.");
}
diff --git a/MediaBrowser.Api/LocalizationService.cs b/MediaBrowser.Api/LocalizationService.cs
deleted file mode 100644
index 6a69d2656..000000000
--- a/MediaBrowser.Api/LocalizationService.cs
+++ /dev/null
@@ -1,111 +0,0 @@
-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
-{
- /// <summary>
- /// Class GetCultures
- /// </summary>
- [Route("/Localization/Cultures", "GET", Summary = "Gets known cultures")]
- public class GetCultures : IReturn<CultureDto[]>
- {
- }
-
- /// <summary>
- /// Class GetCountries
- /// </summary>
- [Route("/Localization/Countries", "GET", Summary = "Gets known countries")]
- public class GetCountries : IReturn<CountryInfo[]>
- {
- }
-
- /// <summary>
- /// Class ParentalRatings
- /// </summary>
- [Route("/Localization/ParentalRatings", "GET", Summary = "Gets known parental ratings")]
- public class GetParentalRatings : IReturn<ParentalRating[]>
- {
- }
-
- /// <summary>
- /// Class ParentalRatings
- /// </summary>
- [Route("/Localization/Options", "GET", Summary = "Gets localization options")]
- public class GetLocalizationOptions : IReturn<LocalizationOption[]>
- {
- }
-
- /// <summary>
- /// Class CulturesService
- /// </summary>
- [Authenticated(AllowBeforeStartupWizard = true)]
- public class LocalizationService : BaseApiService
- {
- /// <summary>
- /// The _localization
- /// </summary>
- private readonly ILocalizationManager _localization;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="LocalizationService"/> class.
- /// </summary>
- /// <param name="localization">The localization.</param>
- public LocalizationService(
- ILogger<LocalizationService> logger,
- IServerConfigurationManager serverConfigurationManager,
- IHttpResultFactory httpResultFactory,
- ILocalizationManager localization)
- : base(logger, serverConfigurationManager, httpResultFactory)
- {
- _localization = localization;
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public object Get(GetParentalRatings request)
- {
- var result = _localization.GetParentalRatings();
-
- return ToOptimizedResult(result);
- }
-
- public object Get(GetLocalizationOptions request)
- {
- var result = _localization.GetLocalizationOptions();
-
- return ToOptimizedResult(result);
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public object Get(GetCountries request)
- {
- var result = _localization.GetCountries();
-
- return ToOptimizedResult(result);
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public object Get(GetCultures request)
- {
- var result = _localization.GetCultures();
-
- return ToOptimizedResult(result);
- }
- }
-
-}
diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs
index a9c7f5d6f..2d61299c7 100644
--- a/MediaBrowser.Api/Movies/MoviesService.cs
+++ b/MediaBrowser.Api/Movies/MoviesService.cs
@@ -2,11 +2,11 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
+using Jellyfin.Data.Entities;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Net;
@@ -15,6 +15,8 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Services;
using Microsoft.Extensions.Logging;
+using MetadataProvider = MediaBrowser.Model.Entities.MetadataProvider;
+using Movie = MediaBrowser.Controller.Entities.Movies.Movie;
namespace MediaBrowser.Api.Movies
{
@@ -251,7 +253,12 @@ namespace MediaBrowser.Api.Movies
return categories.OrderBy(i => i.RecommendationType);
}
- private IEnumerable<RecommendationDto> GetWithDirector(User user, IEnumerable<string> names, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
+ private IEnumerable<RecommendationDto> GetWithDirector(
+ User user,
+ IEnumerable<string> names,
+ int itemLimit,
+ DtoOptions dtoOptions,
+ RecommendationType type)
{
var itemTypes = new List<string> { typeof(Movie).Name };
if (ServerConfigurationManager.Configuration.EnableExternalContentInSuggestions)
diff --git a/MediaBrowser.Api/Music/InstantMixService.cs b/MediaBrowser.Api/Music/InstantMixService.cs
index cacec8d64..7d10c9427 100644
--- a/MediaBrowser.Api/Music/InstantMixService.cs
+++ b/MediaBrowser.Api/Music/InstantMixService.cs
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
+using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index 24297d500..957e4ae91 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -7,6 +7,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Enums;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Configuration;
@@ -196,7 +197,7 @@ namespace MediaBrowser.Api.Playback
if (state.VideoRequest != null && !EncodingHelper.IsCopyCodec(state.OutputVideoCodec))
{
var auth = AuthorizationContext.GetAuthorizationInfo(Request);
- if (auth.User != null && !auth.User.Policy.EnableVideoPlaybackTranscoding)
+ if (auth.User != null && !auth.User.HasPermission(PermissionKind.EnableVideoPlaybackTranscoding))
{
ApiEntryPoint.Instance.OnTranscodeFailedToStart(outputPath, TranscodingJobType, state);
diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs
index e2d771ec6..2c6534cc0 100644
--- a/MediaBrowser.Api/Playback/MediaInfoService.cs
+++ b/MediaBrowser.Api/Playback/MediaInfoService.cs
@@ -9,6 +9,7 @@ using System.Linq;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Enums;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Devices;
@@ -400,21 +401,24 @@ namespace MediaBrowser.Api.Playback
if (item is Audio)
{
- Logger.LogInformation("User policy for {0}. EnableAudioPlaybackTranscoding: {1}", user.Name, user.Policy.EnableAudioPlaybackTranscoding);
+ Logger.LogInformation(
+ "User policy for {0}. EnableAudioPlaybackTranscoding: {1}",
+ user.Username,
+ user.HasPermission(PermissionKind.EnableAudioPlaybackTranscoding));
}
else
{
Logger.LogInformation("User policy for {0}. EnablePlaybackRemuxing: {1} EnableVideoPlaybackTranscoding: {2} EnableAudioPlaybackTranscoding: {3}",
- user.Name,
- user.Policy.EnablePlaybackRemuxing,
- user.Policy.EnableVideoPlaybackTranscoding,
- user.Policy.EnableAudioPlaybackTranscoding);
+ user.Username,
+ user.HasPermission(PermissionKind.EnablePlaybackRemuxing),
+ user.HasPermission(PermissionKind.EnableVideoPlaybackTranscoding),
+ user.HasPermission(PermissionKind.EnableAudioPlaybackTranscoding));
}
// Beginning of Playback Determination: Attempt DirectPlay first
if (mediaSource.SupportsDirectPlay)
{
- if (mediaSource.IsRemote && user.Policy.ForceRemoteSourceTranscoding)
+ if (mediaSource.IsRemote && user.HasPermission(PermissionKind.ForceRemoteSourceTranscoding))
{
mediaSource.SupportsDirectPlay = false;
}
@@ -428,14 +432,16 @@ namespace MediaBrowser.Api.Playback
if (item is Audio)
{
- if (!user.Policy.EnableAudioPlaybackTranscoding)
+ if (!user.HasPermission(PermissionKind.EnableAudioPlaybackTranscoding))
{
options.ForceDirectPlay = true;
}
}
else if (item is Video)
{
- if (!user.Policy.EnableAudioPlaybackTranscoding && !user.Policy.EnableVideoPlaybackTranscoding && !user.Policy.EnablePlaybackRemuxing)
+ if (!user.HasPermission(PermissionKind.EnableAudioPlaybackTranscoding)
+ && !user.HasPermission(PermissionKind.EnableVideoPlaybackTranscoding)
+ && !user.HasPermission(PermissionKind.EnablePlaybackRemuxing))
{
options.ForceDirectPlay = true;
}
@@ -463,7 +469,7 @@ namespace MediaBrowser.Api.Playback
if (mediaSource.SupportsDirectStream)
{
- if (mediaSource.IsRemote && user.Policy.ForceRemoteSourceTranscoding)
+ if (mediaSource.IsRemote && user.HasPermission(PermissionKind.ForceRemoteSourceTranscoding))
{
mediaSource.SupportsDirectStream = false;
}
@@ -473,14 +479,16 @@ namespace MediaBrowser.Api.Playback
if (item is Audio)
{
- if (!user.Policy.EnableAudioPlaybackTranscoding)
+ if (!user.HasPermission(PermissionKind.EnableAudioPlaybackTranscoding))
{
options.ForceDirectStream = true;
}
}
else if (item is Video)
{
- if (!user.Policy.EnableAudioPlaybackTranscoding && !user.Policy.EnableVideoPlaybackTranscoding && !user.Policy.EnablePlaybackRemuxing)
+ if (!user.HasPermission(PermissionKind.EnableAudioPlaybackTranscoding)
+ && !user.HasPermission(PermissionKind.EnableVideoPlaybackTranscoding)
+ && !user.HasPermission(PermissionKind.EnablePlaybackRemuxing))
{
options.ForceDirectStream = true;
}
@@ -512,7 +520,7 @@ namespace MediaBrowser.Api.Playback
? streamBuilder.BuildAudioItem(options)
: streamBuilder.BuildVideoItem(options);
- if (mediaSource.IsRemote && user.Policy.ForceRemoteSourceTranscoding)
+ if (mediaSource.IsRemote && user.HasPermission(PermissionKind.ForceRemoteSourceTranscoding))
{
if (streamInfo != null)
{
@@ -576,10 +584,10 @@ namespace MediaBrowser.Api.Playback
}
}
- private long? GetMaxBitrate(long? clientMaxBitrate, User user)
+ private long? GetMaxBitrate(long? clientMaxBitrate, Jellyfin.Data.Entities.User user)
{
var maxBitrate = clientMaxBitrate;
- var remoteClientMaxBitrate = user?.Policy.RemoteClientBitrateLimit ?? 0;
+ var remoteClientMaxBitrate = user?.RemoteClientBitrateLimit ?? 0;
if (remoteClientMaxBitrate <= 0)
{
diff --git a/MediaBrowser.Api/PluginService.cs b/MediaBrowser.Api/PluginService.cs
deleted file mode 100644
index 7f74511ee..000000000
--- a/MediaBrowser.Api/PluginService.cs
+++ /dev/null
@@ -1,268 +0,0 @@
-using System;
-using System.IO;
-using System.Linq;
-using System.Threading.Tasks;
-using MediaBrowser.Common;
-using MediaBrowser.Common.Plugins;
-using MediaBrowser.Common.Updates;
-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
-{
- /// <summary>
- /// Class Plugins
- /// </summary>
- [Route("/Plugins", "GET", Summary = "Gets a list of currently installed plugins")]
- [Authenticated]
- public class GetPlugins : IReturn<PluginInfo[]>
- {
- public bool? IsAppStoreEnabled { get; set; }
- }
-
- /// <summary>
- /// Class UninstallPlugin
- /// </summary>
- [Route("/Plugins/{Id}", "DELETE", Summary = "Uninstalls a plugin")]
- [Authenticated(Roles = "Admin")]
- public class UninstallPlugin : IReturnVoid
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Plugin Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
- public string Id { get; set; }
- }
-
- /// <summary>
- /// Class GetPluginConfiguration
- /// </summary>
- [Route("/Plugins/{Id}/Configuration", "GET", Summary = "Gets a plugin's configuration")]
- [Authenticated]
- public class GetPluginConfiguration
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Plugin Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Id { get; set; }
- }
-
- /// <summary>
- /// Class UpdatePluginConfiguration
- /// </summary>
- [Route("/Plugins/{Id}/Configuration", "POST", Summary = "Updates a plugin's configuration")]
- [Authenticated]
- public class UpdatePluginConfiguration : IRequiresRequestStream, IReturnVoid
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Plugin Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
-
- /// <summary>
- /// The raw Http Request Input Stream
- /// </summary>
- /// <value>The request stream.</value>
- public Stream RequestStream { get; set; }
- }
-
- //TODO Once we have proper apps and plugins and decide to break compatibility with paid plugins,
- // delete all these registration endpoints. They are only kept for compatibility.
- [Route("/Registrations/{Name}", "GET", Summary = "Gets registration status for a feature", IsHidden = true)]
- [Authenticated]
- public class GetRegistration : IReturn<RegistrationInfo>
- {
- [ApiMember(Name = "Name", Description = "Feature Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Name { get; set; }
- }
-
- /// <summary>
- /// Class GetPluginSecurityInfo
- /// </summary>
- [Route("/Plugins/SecurityInfo", "GET", Summary = "Gets plugin registration information", IsHidden = true)]
- [Authenticated]
- public class GetPluginSecurityInfo : IReturn<PluginSecurityInfo>
- {
- }
-
- /// <summary>
- /// Class UpdatePluginSecurityInfo
- /// </summary>
- [Route("/Plugins/SecurityInfo", "POST", Summary = "Updates plugin registration information", IsHidden = true)]
- [Authenticated(Roles = "Admin")]
- public class UpdatePluginSecurityInfo : PluginSecurityInfo, IReturnVoid
- {
- }
-
- [Route("/Plugins/RegistrationRecords/{Name}", "GET", Summary = "Gets registration status for a feature", IsHidden = true)]
- [Authenticated]
- public class GetRegistrationStatus
- {
- [ApiMember(Name = "Name", Description = "Feature Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Name { get; set; }
- }
-
- // TODO these two classes are only kept for compability with paid plugins and should be removed
- public class RegistrationInfo
- {
- public string Name { get; set; }
- public DateTime ExpirationDate { get; set; }
- public bool IsTrial { get; set; }
- public bool IsRegistered { get; set; }
- }
-
- public class MBRegistrationRecord
- {
- public DateTime ExpirationDate { get; set; }
- public bool IsRegistered { get; set; }
- public bool RegChecked { get; set; }
- public bool RegError { get; set; }
- public bool TrialVersion { get; set; }
- public bool IsValid { get; set; }
- }
-
- public class PluginSecurityInfo
- {
- public string SupporterKey { get; set; }
- public bool IsMBSupporter { get; set; }
- }
- /// <summary>
- /// Class PluginsService
- /// </summary>
- public class PluginService : BaseApiService
- {
- /// <summary>
- /// The _json serializer
- /// </summary>
- private readonly IJsonSerializer _jsonSerializer;
-
- /// <summary>
- /// The _app host
- /// </summary>
- private readonly IApplicationHost _appHost;
- private readonly IInstallationManager _installationManager;
-
- public PluginService(
- ILogger<PluginService> logger,
- IServerConfigurationManager serverConfigurationManager,
- IHttpResultFactory httpResultFactory,
- IJsonSerializer jsonSerializer,
- IApplicationHost appHost,
- IInstallationManager installationManager)
- : base(logger, serverConfigurationManager, httpResultFactory)
- {
- _appHost = appHost;
- _installationManager = installationManager;
- _jsonSerializer = jsonSerializer;
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public object Get(GetRegistrationStatus request)
- {
- var record = new MBRegistrationRecord
- {
- IsRegistered = true,
- RegChecked = true,
- TrialVersion = false,
- IsValid = true,
- RegError = false
- };
-
- return ToOptimizedResult(record);
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public object Get(GetPlugins request)
- {
- var result = _appHost.Plugins.OrderBy(p => p.Name).Select(p => p.GetPluginInfo()).ToArray();
- return ToOptimizedResult(result);
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public object Get(GetPluginConfiguration request)
- {
- var guid = new Guid(request.Id);
- var plugin = _appHost.Plugins.First(p => p.Id == guid) as IHasPluginConfiguration;
-
- return ToOptimizedResult(plugin.Configuration);
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public object Get(GetPluginSecurityInfo request)
- {
- var result = new PluginSecurityInfo
- {
- IsMBSupporter = true,
- SupporterKey = "IAmTotallyLegit"
- };
-
- return ToOptimizedResult(result);
- }
-
- /// <summary>
- /// Posts the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public Task Post(UpdatePluginSecurityInfo request)
- {
- return Task.CompletedTask;
- }
-
- /// <summary>
- /// Posts the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public async Task Post(UpdatePluginConfiguration request)
- {
- // 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 = Guid.Parse(GetPathValue(1));
-
- if (!(_appHost.Plugins.First(p => p.Id == id) is IHasPluginConfiguration plugin))
- {
- throw new FileNotFoundException();
- }
-
- var configuration = (await _jsonSerializer.DeserializeFromStreamAsync(request.RequestStream, plugin.ConfigurationType).ConfigureAwait(false)) as BasePluginConfiguration;
-
- plugin.UpdateConfiguration(configuration);
- }
-
- /// <summary>
- /// Deletes the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public void Delete(UninstallPlugin request)
- {
- var guid = new Guid(request.Id);
- var plugin = _appHost.Plugins.First(p => p.Id == guid);
-
- _installationManager.UninstallPlugin(plugin);
- }
- }
-}
diff --git a/MediaBrowser.Api/Sessions/SessionService.cs b/MediaBrowser.Api/Sessions/SessionService.cs
deleted file mode 100644
index 020bb5042..000000000
--- a/MediaBrowser.Api/Sessions/SessionService.cs
+++ /dev/null
@@ -1,498 +0,0 @@
-using System;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Devices;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Services;
-using MediaBrowser.Model.Session;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.Api.Sessions
-{
- /// <summary>
- /// Class GetSessions.
- /// </summary>
- [Route("/Sessions", "GET", Summary = "Gets a list of sessions")]
- [Authenticated]
- public class GetSessions : IReturn<SessionInfo[]>
- {
- [ApiMember(Name = "ControllableByUserId", Description = "Filter by sessions that a given user is allowed to remote control.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public Guid ControllableByUserId { get; set; }
-
- [ApiMember(Name = "DeviceId", Description = "Filter by device Id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string DeviceId { get; set; }
-
- public int? ActiveWithinSeconds { get; set; }
- }
-
- /// <summary>
- /// Class DisplayContent.
- /// </summary>
- [Route("/Sessions/{Id}/Viewing", "POST", Summary = "Instructs a session to browse to an item or view")]
- [Authenticated]
- public class DisplayContent : IReturnVoid
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
-
- /// <summary>
- /// Artist, Genre, Studio, Person, or any kind of BaseItem
- /// </summary>
- /// <value>The type of the item.</value>
- [ApiMember(Name = "ItemType", Description = "The type of item to browse to.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string ItemType { get; set; }
-
- /// <summary>
- /// Artist name, genre name, item Id, etc
- /// </summary>
- /// <value>The item identifier.</value>
- [ApiMember(Name = "ItemId", Description = "The Id of the item.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string ItemId { get; set; }
-
- /// <summary>
- /// Gets or sets the name of the item.
- /// </summary>
- /// <value>The name of the item.</value>
- [ApiMember(Name = "ItemName", Description = "The name of the item.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string ItemName { get; set; }
- }
-
- [Route("/Sessions/{Id}/Playing", "POST", Summary = "Instructs a session to play an item")]
- [Authenticated]
- public class Play : PlayRequest
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
- }
-
- [Route("/Sessions/{Id}/Playing/{Command}", "POST", Summary = "Issues a playstate command to a client")]
- [Authenticated]
- public class SendPlaystateCommand : PlaystateRequest, IReturnVoid
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
- }
-
- [Route("/Sessions/{Id}/System/{Command}", "POST", Summary = "Issues a system command to a client")]
- [Authenticated]
- public class SendSystemCommand : IReturnVoid
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
-
- /// <summary>
- /// Gets or sets the command.
- /// </summary>
- /// <value>The play command.</value>
- [ApiMember(Name = "Command", Description = "The command to send.", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Command { get; set; }
- }
-
- [Route("/Sessions/{Id}/Command/{Command}", "POST", Summary = "Issues a system command to a client")]
- [Authenticated]
- public class SendGeneralCommand : IReturnVoid
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
-
- /// <summary>
- /// Gets or sets the command.
- /// </summary>
- /// <value>The play command.</value>
- [ApiMember(Name = "Command", Description = "The command to send.", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Command { get; set; }
- }
-
- [Route("/Sessions/{Id}/Command", "POST", Summary = "Issues a system command to a client")]
- [Authenticated]
- public class SendFullGeneralCommand : GeneralCommand, IReturnVoid
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
- }
-
- [Route("/Sessions/{Id}/Message", "POST", Summary = "Issues a command to a client to display a message to the user")]
- [Authenticated]
- public class SendMessageCommand : IReturnVoid
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
-
- [ApiMember(Name = "Text", Description = "The message text.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string Text { get; set; }
-
- [ApiMember(Name = "Header", Description = "The message header.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string Header { get; set; }
-
- [ApiMember(Name = "TimeoutMs", Description = "The message timeout. If omitted the user will have to confirm viewing the message.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
- public long? TimeoutMs { get; set; }
- }
-
- [Route("/Sessions/{Id}/Users/{UserId}", "POST", Summary = "Adds an additional user to a session")]
- [Authenticated]
- public class AddUserToSession : IReturnVoid
- {
- [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
-
- [ApiMember(Name = "UserId", Description = "UserId Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string UserId { get; set; }
- }
-
- [Route("/Sessions/{Id}/Users/{UserId}", "DELETE", Summary = "Removes an additional user from a session")]
- [Authenticated]
- public class RemoveUserFromSession : IReturnVoid
- {
- [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
-
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string UserId { get; set; }
- }
-
- [Route("/Sessions/Capabilities", "POST", Summary = "Updates capabilities for a device")]
- [Authenticated]
- public class PostCapabilities : IReturnVoid
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string Id { get; set; }
-
- [ApiMember(Name = "PlayableMediaTypes", Description = "A list of playable media types, comma delimited. Audio, Video, Book, Photo.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string PlayableMediaTypes { get; set; }
-
- [ApiMember(Name = "SupportedCommands", Description = "A list of supported remote control commands, comma delimited", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string SupportedCommands { get; set; }
-
- [ApiMember(Name = "SupportsMediaControl", Description = "Determines whether media can be played remotely.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
- public bool SupportsMediaControl { get; set; }
-
- [ApiMember(Name = "SupportsSync", Description = "Determines whether sync is supported.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
- public bool SupportsSync { get; set; }
-
- [ApiMember(Name = "SupportsPersistentIdentifier", Description = "Determines whether the device supports a unique identifier.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
- public bool SupportsPersistentIdentifier { get; set; }
-
- public PostCapabilities()
- {
- SupportsPersistentIdentifier = true;
- }
- }
-
- [Route("/Sessions/Capabilities/Full", "POST", Summary = "Updates capabilities for a device")]
- [Authenticated]
- public class PostFullCapabilities : ClientCapabilities, IReturnVoid
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string Id { get; set; }
- }
-
- [Route("/Sessions/Viewing", "POST", Summary = "Reports that a session is viewing an item")]
- [Authenticated]
- public class ReportViewing : IReturnVoid
- {
- [ApiMember(Name = "SessionId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string SessionId { get; set; }
-
- [ApiMember(Name = "ItemId", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string ItemId { get; set; }
- }
-
- [Route("/Sessions/Logout", "POST", Summary = "Reports that a session has ended")]
- [Authenticated]
- public class ReportSessionEnded : IReturnVoid
- {
- }
-
- [Route("/Auth/Providers", "GET")]
- [Authenticated(Roles = "Admin")]
- public class GetAuthProviders : IReturn<NameIdPair[]>
- {
- }
-
- [Route("/Auth/PasswordResetProviders", "GET")]
- [Authenticated(Roles = "Admin")]
- public class GetPasswordResetProviders : IReturn<NameIdPair[]>
- {
- }
-
- /// <summary>
- /// Class SessionsService.
- /// </summary>
- public class SessionService : BaseApiService
- {
- /// <summary>
- /// The session manager.
- /// </summary>
- private readonly ISessionManager _sessionManager;
-
- private readonly IUserManager _userManager;
- private readonly IAuthorizationContext _authContext;
- private readonly IDeviceManager _deviceManager;
- private readonly ISessionContext _sessionContext;
-
- public SessionService(
- ILogger<SessionService> logger,
- IServerConfigurationManager serverConfigurationManager,
- IHttpResultFactory httpResultFactory,
- ISessionManager sessionManager,
- IUserManager userManager,
- IAuthorizationContext authContext,
- IDeviceManager deviceManager,
- ISessionContext sessionContext)
- : base(logger, serverConfigurationManager, httpResultFactory)
- {
- _sessionManager = sessionManager;
- _userManager = userManager;
- _authContext = authContext;
- _deviceManager = deviceManager;
- _sessionContext = sessionContext;
- }
-
- public object Get(GetAuthProviders request)
- {
- return _userManager.GetAuthenticationProviders();
- }
-
- public object Get(GetPasswordResetProviders request)
- {
- return _userManager.GetPasswordResetProviders();
- }
-
- public void Post(ReportSessionEnded request)
- {
- var auth = _authContext.GetAuthorizationInfo(Request);
-
- _sessionManager.Logout(auth.Token);
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public object Get(GetSessions request)
- {
- var result = _sessionManager.Sessions;
-
- if (!string.IsNullOrEmpty(request.DeviceId))
- {
- result = result.Where(i => string.Equals(i.DeviceId, request.DeviceId, StringComparison.OrdinalIgnoreCase));
- }
-
- if (!request.ControllableByUserId.Equals(Guid.Empty))
- {
- result = result.Where(i => i.SupportsRemoteControl);
-
- var user = _userManager.GetUserById(request.ControllableByUserId);
-
- if (!user.Policy.EnableRemoteControlOfOtherUsers)
- {
- result = result.Where(i => i.UserId.Equals(Guid.Empty) || i.ContainsUser(request.ControllableByUserId));
- }
-
- if (!user.Policy.EnableSharedDeviceControl)
- {
- result = result.Where(i => !i.UserId.Equals(Guid.Empty));
- }
-
- if (request.ActiveWithinSeconds.HasValue && request.ActiveWithinSeconds.Value > 0)
- {
- var minActiveDate = DateTime.UtcNow.AddSeconds(0 - request.ActiveWithinSeconds.Value);
- result = result.Where(i => i.LastActivityDate >= minActiveDate);
- }
-
- result = result.Where(i =>
- {
- var deviceId = i.DeviceId;
-
- if (!string.IsNullOrWhiteSpace(deviceId))
- {
- if (!_deviceManager.CanAccessDevice(user, deviceId))
- {
- return false;
- }
- }
-
- return true;
- });
- }
-
- return ToOptimizedResult(result.ToArray());
- }
-
- public Task Post(SendPlaystateCommand request)
- {
- return _sessionManager.SendPlaystateCommand(GetSession(_sessionContext).Id, request.Id, request, CancellationToken.None);
- }
-
- /// <summary>
- /// Posts the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public Task Post(DisplayContent request)
- {
- var command = new BrowseRequest
- {
- ItemId = request.ItemId,
- ItemName = request.ItemName,
- ItemType = request.ItemType
- };
-
- return _sessionManager.SendBrowseCommand(GetSession(_sessionContext).Id, request.Id, command, CancellationToken.None);
- }
-
- /// <summary>
- /// Posts the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public Task Post(SendSystemCommand request)
- {
- var name = request.Command;
- if (Enum.TryParse(name, true, out GeneralCommandType commandType))
- {
- name = commandType.ToString();
- }
-
- var currentSession = GetSession(_sessionContext);
- var command = new GeneralCommand
- {
- Name = name,
- ControllingUserId = currentSession.UserId
- };
-
- return _sessionManager.SendGeneralCommand(currentSession.Id, request.Id, command, CancellationToken.None);
- }
-
- /// <summary>
- /// Posts the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public Task Post(SendMessageCommand request)
- {
- var command = new MessageCommand
- {
- Header = string.IsNullOrEmpty(request.Header) ? "Message from Server" : request.Header,
- TimeoutMs = request.TimeoutMs,
- Text = request.Text
- };
-
- return _sessionManager.SendMessageCommand(GetSession(_sessionContext).Id, request.Id, command, CancellationToken.None);
- }
-
- /// <summary>
- /// Posts the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public Task Post(Play request)
- {
- return _sessionManager.SendPlayCommand(GetSession(_sessionContext).Id, request.Id, request, CancellationToken.None);
- }
-
- public Task Post(SendGeneralCommand request)
- {
- var currentSession = GetSession(_sessionContext);
-
- var command = new GeneralCommand
- {
- Name = request.Command,
- ControllingUserId = currentSession.UserId
- };
-
- return _sessionManager.SendGeneralCommand(currentSession.Id, request.Id, command, CancellationToken.None);
- }
-
- public Task Post(SendFullGeneralCommand request)
- {
- var currentSession = GetSession(_sessionContext);
-
- request.ControllingUserId = currentSession.UserId;
-
- return _sessionManager.SendGeneralCommand(currentSession.Id, request.Id, request, CancellationToken.None);
- }
-
- public void Post(AddUserToSession request)
- {
- _sessionManager.AddAdditionalUser(request.Id, new Guid(request.UserId));
- }
-
- public void Delete(RemoveUserFromSession request)
- {
- _sessionManager.RemoveAdditionalUser(request.Id, new Guid(request.UserId));
- }
-
- public void Post(PostCapabilities request)
- {
- if (string.IsNullOrWhiteSpace(request.Id))
- {
- request.Id = GetSession(_sessionContext).Id;
- }
-
- _sessionManager.ReportCapabilities(request.Id, new ClientCapabilities
- {
- PlayableMediaTypes = SplitValue(request.PlayableMediaTypes, ','),
- SupportedCommands = SplitValue(request.SupportedCommands, ','),
- SupportsMediaControl = request.SupportsMediaControl,
- SupportsSync = request.SupportsSync,
- SupportsPersistentIdentifier = request.SupportsPersistentIdentifier
- });
- }
-
- public void Post(PostFullCapabilities request)
- {
- if (string.IsNullOrWhiteSpace(request.Id))
- {
- request.Id = GetSession(_sessionContext).Id;
- }
-
- _sessionManager.ReportCapabilities(request.Id, request);
- }
-
- public void Post(ReportViewing request)
- {
- request.SessionId = GetSession(_sessionContext).Id;
-
- _sessionManager.ReportNowViewingItem(request.SessionId, request.ItemId);
- }
- }
-}
diff --git a/MediaBrowser.Api/Subtitles/SubtitleService.cs b/MediaBrowser.Api/Subtitles/SubtitleService.cs
deleted file mode 100644
index f2968c6b5..000000000
--- a/MediaBrowser.Api/Subtitles/SubtitleService.cs
+++ /dev/null
@@ -1,300 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-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;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Controller.Subtitles;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Providers;
-using MediaBrowser.Model.Services;
-using Microsoft.Extensions.Logging;
-using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
-
-namespace MediaBrowser.Api.Subtitles
-{
- [Route("/Videos/{Id}/Subtitles/{Index}", "DELETE", Summary = "Deletes an external subtitle file")]
- [Authenticated(Roles = "Admin")]
- public class DeleteSubtitle
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
- public Guid Id { get; set; }
-
- [ApiMember(Name = "Index", Description = "The subtitle stream index", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "DELETE")]
- public int Index { get; set; }
- }
-
- [Route("/Items/{Id}/RemoteSearch/Subtitles/{Language}", "GET")]
- [Authenticated]
- public class SearchRemoteSubtitles : IReturn<RemoteSubtitleInfo[]>
- {
- [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public Guid Id { get; set; }
-
- [ApiMember(Name = "Language", Description = "Language", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Language { get; set; }
-
- public bool? IsPerfectMatch { get; set; }
- }
-
- [Route("/Items/{Id}/RemoteSearch/Subtitles/{SubtitleId}", "POST")]
- [Authenticated]
- public class DownloadRemoteSubtitles : IReturnVoid
- {
- [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public Guid Id { get; set; }
-
- [ApiMember(Name = "SubtitleId", Description = "SubtitleId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string SubtitleId { get; set; }
- }
-
- [Route("/Providers/Subtitles/Subtitles/{Id}", "GET")]
- [Authenticated]
- public class GetRemoteSubtitles : IReturnVoid
- {
- [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Id { get; set; }
- }
-
- [Route("/Videos/{Id}/{MediaSourceId}/Subtitles/{Index}/Stream.{Format}", "GET", Summary = "Gets subtitles in a specified format.")]
- [Route("/Videos/{Id}/{MediaSourceId}/Subtitles/{Index}/{StartPositionTicks}/Stream.{Format}", "GET", Summary = "Gets subtitles in a specified format.")]
- public class GetSubtitle
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public Guid Id { get; set; }
-
- [ApiMember(Name = "MediaSourceId", Description = "MediaSourceId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string MediaSourceId { get; set; }
-
- [ApiMember(Name = "Index", Description = "The subtitle stream index", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "GET")]
- public int Index { get; set; }
-
- [ApiMember(Name = "Format", Description = "Format", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Format { get; set; }
-
- [ApiMember(Name = "StartPositionTicks", Description = "StartPositionTicks", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public long StartPositionTicks { get; set; }
-
- [ApiMember(Name = "EndPositionTicks", Description = "EndPositionTicks", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public long? EndPositionTicks { get; set; }
-
- [ApiMember(Name = "CopyTimestamps", Description = "CopyTimestamps", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
- public bool CopyTimestamps { get; set; }
- public bool AddVttTimeMap { get; set; }
- }
-
- [Route("/Videos/{Id}/{MediaSourceId}/Subtitles/{Index}/subtitles.m3u8", "GET", Summary = "Gets an HLS subtitle playlist.")]
- [Authenticated]
- public class GetSubtitlePlaylist
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Id { get; set; }
-
- [ApiMember(Name = "MediaSourceId", Description = "MediaSourceId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string MediaSourceId { get; set; }
-
- [ApiMember(Name = "Index", Description = "The subtitle stream index", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "GET")]
- public int Index { get; set; }
-
- [ApiMember(Name = "SegmentLength", Description = "The subtitle srgment length", IsRequired = true, DataType = "int", ParameterType = "query", Verb = "GET")]
- public int SegmentLength { get; set; }
- }
-
- public class SubtitleService : BaseApiService
- {
- private readonly ILibraryManager _libraryManager;
- private readonly ISubtitleManager _subtitleManager;
- private readonly ISubtitleEncoder _subtitleEncoder;
- private readonly IMediaSourceManager _mediaSourceManager;
- private readonly IProviderManager _providerManager;
- private readonly IFileSystem _fileSystem;
- private readonly 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;
- _subtitleEncoder = subtitleEncoder;
- _mediaSourceManager = mediaSourceManager;
- _providerManager = providerManager;
- _fileSystem = fileSystem;
- _authContext = authContext;
- }
-
- public async Task<object> Get(GetSubtitlePlaylist request)
- {
- var item = (Video)_libraryManager.GetItemById(new Guid(request.Id));
-
- var mediaSource = await _mediaSourceManager.GetMediaSource(item, request.MediaSourceId, null, false, CancellationToken.None).ConfigureAwait(false);
-
- var builder = new StringBuilder();
-
- var runtime = mediaSource.RunTimeTicks ?? -1;
-
- if (runtime <= 0)
- {
- throw new ArgumentException("HLS Subtitles are not supported for this media.");
- }
-
- var segmentLengthTicks = TimeSpan.FromSeconds(request.SegmentLength).Ticks;
- if (segmentLengthTicks <= 0)
- {
- throw new ArgumentException("segmentLength was not given, or it was given incorrectly. (It should be bigger than 0)");
- }
-
- builder.AppendLine("#EXTM3U");
- builder.AppendLine("#EXT-X-TARGETDURATION:" + request.SegmentLength.ToString(CultureInfo.InvariantCulture));
- builder.AppendLine("#EXT-X-VERSION:3");
- builder.AppendLine("#EXT-X-MEDIA-SEQUENCE:0");
- builder.AppendLine("#EXT-X-PLAYLIST-TYPE:VOD");
-
- long positionTicks = 0;
-
- var accessToken = _authContext.GetAuthorizationInfo(Request).Token;
-
- while (positionTicks < runtime)
- {
- var remaining = runtime - positionTicks;
- var lengthTicks = Math.Min(remaining, segmentLengthTicks);
-
- builder.AppendLine("#EXTINF:" + TimeSpan.FromTicks(lengthTicks).TotalSeconds.ToString(CultureInfo.InvariantCulture) + ",");
-
- var endPositionTicks = Math.Min(runtime, positionTicks + segmentLengthTicks);
-
- var url = string.Format("stream.vtt?CopyTimestamps=true&AddVttTimeMap=true&StartPositionTicks={0}&EndPositionTicks={1}&api_key={2}",
- positionTicks.ToString(CultureInfo.InvariantCulture),
- endPositionTicks.ToString(CultureInfo.InvariantCulture),
- accessToken);
-
- builder.AppendLine(url);
-
- positionTicks += segmentLengthTicks;
- }
-
- builder.AppendLine("#EXT-X-ENDLIST");
-
- return ResultFactory.GetResult(Request, builder.ToString(), MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
- }
-
- public async Task<object> Get(GetSubtitle request)
- {
- if (string.Equals(request.Format, "js", StringComparison.OrdinalIgnoreCase))
- {
- request.Format = "json";
- }
- if (string.IsNullOrEmpty(request.Format))
- {
- var item = (Video)_libraryManager.GetItemById(request.Id);
-
- var idString = request.Id.ToString("N", CultureInfo.InvariantCulture);
- var mediaSource = _mediaSourceManager.GetStaticMediaSources(item, false, null)
- .First(i => string.Equals(i.Id, request.MediaSourceId ?? idString));
-
- var subtitleStream = mediaSource.MediaStreams
- .First(i => i.Type == MediaStreamType.Subtitle && i.Index == request.Index);
-
- return await ResultFactory.GetStaticFileResult(Request, subtitleStream.Path).ConfigureAwait(false);
- }
-
- if (string.Equals(request.Format, "vtt", StringComparison.OrdinalIgnoreCase) && request.AddVttTimeMap)
- {
- using var stream = await GetSubtitles(request).ConfigureAwait(false);
- using var reader = new StreamReader(stream);
-
- var text = reader.ReadToEnd();
-
- text = text.Replace("WEBVTT", "WEBVTT\nX-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000");
-
- return ResultFactory.GetResult(Request, text, MimeTypes.GetMimeType("file." + request.Format));
- }
-
- return ResultFactory.GetResult(Request, await GetSubtitles(request).ConfigureAwait(false), MimeTypes.GetMimeType("file." + request.Format));
- }
-
- private Task<Stream> GetSubtitles(GetSubtitle request)
- {
- var item = _libraryManager.GetItemById(request.Id);
-
- return _subtitleEncoder.GetSubtitles(item,
- request.MediaSourceId,
- request.Index,
- request.Format,
- request.StartPositionTicks,
- request.EndPositionTicks ?? 0,
- request.CopyTimestamps,
- CancellationToken.None);
- }
-
- public async Task<object> Get(SearchRemoteSubtitles request)
- {
- var video = (Video)_libraryManager.GetItemById(request.Id);
-
- return await _subtitleManager.SearchSubtitles(video, request.Language, request.IsPerfectMatch, CancellationToken.None).ConfigureAwait(false);
- }
-
- public Task Delete(DeleteSubtitle request)
- {
- var item = _libraryManager.GetItemById(request.Id);
- return _subtitleManager.DeleteSubtitles(item, request.Index);
- }
-
- public async Task<object> Get(GetRemoteSubtitles request)
- {
- var result = await _subtitleManager.GetRemoteSubtitles(request.Id, CancellationToken.None).ConfigureAwait(false);
-
- return ResultFactory.GetResult(Request, result.Stream, MimeTypes.GetMimeType("file." + result.Format));
- }
-
- public void Post(DownloadRemoteSubtitles request)
- {
- var video = (Video)_libraryManager.GetItemById(request.Id);
-
- Task.Run(async () =>
- {
- try
- {
- await _subtitleManager.DownloadSubtitles(video, request.SubtitleId, CancellationToken.None)
- .ConfigureAwait(false);
-
- _providerManager.QueueRefresh(video.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), RefreshPriority.High);
- }
- catch (Exception ex)
- {
- Logger.LogError(ex, "Error downloading subtitles");
- }
- });
- }
- }
-}
diff --git a/MediaBrowser.Api/SuggestionsService.cs b/MediaBrowser.Api/SuggestionsService.cs
deleted file mode 100644
index 91f85db6f..000000000
--- a/MediaBrowser.Api/SuggestionsService.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-using System;
-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.Model.Dto;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Querying;
-using MediaBrowser.Model.Services;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.Api
-{
- [Route("/Users/{UserId}/Suggestions", "GET", Summary = "Gets items based on a query.")]
- public class GetSuggestedItems : IReturn<QueryResult<BaseItemDto>>
- {
- public string MediaType { get; set; }
- public string Type { get; set; }
- public Guid UserId { get; set; }
- public bool EnableTotalRecordCount { get; set; }
- public int? StartIndex { get; set; }
- public int? Limit { get; set; }
-
- public string[] GetMediaTypes()
- {
- return (MediaType ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- }
-
- public string[] GetIncludeItemTypes()
- {
- return (Type ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- }
- }
-
- public class SuggestionsService : BaseApiService
- {
- private readonly IDtoService _dtoService;
- private readonly IAuthorizationContext _authContext;
- private readonly IUserManager _userManager;
- private readonly 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;
- _userManager = userManager;
- _libraryManager = libraryManager;
- }
-
- public object Get(GetSuggestedItems request)
- {
- return GetResultItems(request);
- }
-
- private QueryResult<BaseItemDto> GetResultItems(GetSuggestedItems request)
- {
- var user = !request.UserId.Equals(Guid.Empty) ? _userManager.GetUserById(request.UserId) : null;
-
- var dtoOptions = GetDtoOptions(_authContext, request);
- var result = GetItems(request, user, dtoOptions);
-
- var dtoList = _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user);
-
- return new QueryResult<BaseItemDto>
- {
- TotalRecordCount = result.TotalRecordCount,
- Items = dtoList
- };
- }
-
- private QueryResult<BaseItem> GetItems(GetSuggestedItems request, User user, DtoOptions dtoOptions)
- {
- return _libraryManager.GetItemsResult(new InternalItemsQuery(user)
- {
- OrderBy = new[] { ItemSortBy.Random }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray(),
- MediaTypes = request.GetMediaTypes(),
- IncludeItemTypes = request.GetIncludeItemTypes(),
- IsVirtualItem = false,
- StartIndex = request.StartIndex,
- Limit = request.Limit,
- DtoOptions = dtoOptions,
- EnableTotalRecordCount = request.EnableTotalRecordCount,
- Recursive = true
- });
- }
- }
-}
diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs
index cd8e8dfbe..0c23d8b29 100644
--- a/MediaBrowser.Api/TvShowsService.cs
+++ b/MediaBrowser.Api/TvShowsService.cs
@@ -378,7 +378,7 @@ namespace MediaBrowser.Api
{
var user = _userManager.GetUserById(request.UserId);
- var series = GetSeries(request.Id, user);
+ var series = GetSeries(request.Id);
if (series == null)
{
@@ -404,7 +404,7 @@ namespace MediaBrowser.Api
};
}
- private Series GetSeries(string seriesId, User user)
+ private Series GetSeries(string seriesId)
{
if (!string.IsNullOrWhiteSpace(seriesId))
{
@@ -433,7 +433,7 @@ namespace MediaBrowser.Api
}
else if (request.Season.HasValue)
{
- var series = GetSeries(request.Id, user);
+ var series = GetSeries(request.Id);
if (series == null)
{
@@ -446,7 +446,7 @@ namespace MediaBrowser.Api
}
else
{
- var series = GetSeries(request.Id, user);
+ var series = GetSeries(request.Id);
if (series == null)
{
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
index 559082ff4..a1ec08467 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index f3c0441e1..49d534c36 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -2,10 +2,11 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
+using Jellyfin.Data.Entities;
+using Jellyfin.Data.Enums;
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.Model.Dto;
@@ -14,6 +15,7 @@ using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Services;
using Microsoft.Extensions.Logging;
+using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum;
namespace MediaBrowser.Api.UserLibrary
{
@@ -86,7 +88,7 @@ namespace MediaBrowser.Api.UserLibrary
var ancestorIds = Array.Empty<Guid>();
- var excludeFolderIds = user.Configuration.LatestItemsExcludes;
+ var excludeFolderIds = user.GetPreference(PreferenceKind.LatestItemExcludes);
if (parentIdGuid.Equals(Guid.Empty) && excludeFolderIds.Length > 0)
{
ancestorIds = _libraryManager.GetUserRootFolder().GetChildren(user, true)
@@ -211,14 +213,14 @@ namespace MediaBrowser.Api.UserLibrary
request.IncludeItemTypes = "Playlist";
}
- bool isInEnabledFolder = user.Policy.EnabledFolders.Any(i => new Guid(i) == item.Id)
+ bool isInEnabledFolder = user.GetPreference(PreferenceKind.EnabledFolders).Any(i => new Guid(i) == item.Id)
// Assume all folders inside an EnabledChannel are enabled
- || user.Policy.EnabledChannels.Any(i => new Guid(i) == item.Id);
+ || user.GetPreference(PreferenceKind.EnabledChannels).Any(i => new Guid(i) == item.Id);
var collectionFolders = _libraryManager.GetCollectionFolders(item);
foreach (var collectionFolder in collectionFolders)
{
- if (user.Policy.EnabledFolders.Contains(
+ if (user.GetPreference(PreferenceKind.EnabledFolders).Contains(
collectionFolder.Id.ToString("N", CultureInfo.InvariantCulture),
StringComparer.OrdinalIgnoreCase))
{
@@ -226,9 +228,12 @@ namespace MediaBrowser.Api.UserLibrary
}
}
- if (!(item is UserRootFolder) && !user.Policy.EnableAllFolders && !isInEnabledFolder && !user.Policy.EnableAllChannels)
+ if (!(item is UserRootFolder)
+ && !isInEnabledFolder
+ && !user.HasPermission(PermissionKind.EnableAllFolders)
+ && !user.HasPermission(PermissionKind.EnableAllChannels))
{
- Logger.LogWarning("{UserName} is not permitted to access Library {ItemName}.", user.Name, item.Name);
+ Logger.LogWarning("{UserName} is not permitted to access Library {ItemName}.", user.Username, item.Name);
return new QueryResult<BaseItem>
{
Items = Array.Empty<BaseItem>(),
diff --git a/MediaBrowser.Api/UserLibrary/PlaystateService.cs b/MediaBrowser.Api/UserLibrary/PlaystateService.cs
index d0faca163..ab231626b 100644
--- a/MediaBrowser.Api/UserLibrary/PlaystateService.cs
+++ b/MediaBrowser.Api/UserLibrary/PlaystateService.cs
@@ -1,8 +1,8 @@
using System;
using System.Globalization;
using System.Threading.Tasks;
+using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Session;
diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
index 7fa750adb..f75852885 100644
--- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
+++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
@@ -312,7 +312,7 @@ namespace MediaBrowser.Api.UserLibrary
if (!request.IsPlayed.HasValue)
{
- if (user.Configuration.HidePlayedInLatest)
+ if (user.HidePlayedInLatest)
{
request.IsPlayed = false;
}
diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs
deleted file mode 100644
index 78fc6c694..000000000
--- a/MediaBrowser.Api/UserService.cs
+++ /dev/null
@@ -1,600 +0,0 @@
-using System;
-using System.Linq;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Authentication;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Devices;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Services;
-using MediaBrowser.Model.Users;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.Api
-{
- /// <summary>
- /// Class GetUsers
- /// </summary>
- [Route("/Users", "GET", Summary = "Gets a list of users")]
- [Authenticated]
- public class GetUsers : IReturn<UserDto[]>
- {
- [ApiMember(Name = "IsHidden", Description = "Optional filter by IsHidden=true or false", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
- public bool? IsHidden { get; set; }
-
- [ApiMember(Name = "IsDisabled", Description = "Optional filter by IsDisabled=true or false", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
- public bool? IsDisabled { get; set; }
-
- [ApiMember(Name = "IsGuest", Description = "Optional filter by IsGuest=true or false", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
- public bool? IsGuest { get; set; }
- }
-
- [Route("/Users/Public", "GET", Summary = "Gets a list of publicly visible users for display on a login screen.")]
- public class GetPublicUsers : IReturn<UserDto[]>
- {
- }
-
- /// <summary>
- /// Class GetUser
- /// </summary>
- [Route("/Users/{Id}", "GET", Summary = "Gets a user by Id")]
- [Authenticated(EscapeParentalControl = true)]
- public class GetUser : IReturn<UserDto>
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public Guid Id { get; set; }
- }
-
- /// <summary>
- /// Class DeleteUser
- /// </summary>
- [Route("/Users/{Id}", "DELETE", Summary = "Deletes a user")]
- [Authenticated(Roles = "Admin")]
- public class DeleteUser : IReturnVoid
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
- public Guid Id { get; set; }
- }
-
- /// <summary>
- /// Class AuthenticateUser
- /// </summary>
- [Route("/Users/{Id}/Authenticate", "POST", Summary = "Authenticates a user")]
- public class AuthenticateUser : IReturn<AuthenticationResult>
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public Guid Id { get; set; }
-
- [ApiMember(Name = "Pw", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
- public string Pw { get; set; }
-
- /// <summary>
- /// Gets or sets the password.
- /// </summary>
- /// <value>The password.</value>
- [ApiMember(Name = "Password", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
- public string Password { get; set; }
- }
-
- /// <summary>
- /// Class AuthenticateUser
- /// </summary>
- [Route("/Users/AuthenticateByName", "POST", Summary = "Authenticates a user")]
- public class AuthenticateUserByName : IReturn<AuthenticationResult>
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Username", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
- public string Username { get; set; }
-
- /// <summary>
- /// Gets or sets the password.
- /// </summary>
- /// <value>The password.</value>
- [ApiMember(Name = "Password", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
- public string Password { get; set; }
-
- [ApiMember(Name = "Pw", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
- public string Pw { get; set; }
- }
-
- /// <summary>
- /// Class UpdateUserPassword
- /// </summary>
- [Route("/Users/{Id}/Password", "POST", Summary = "Updates a user's password")]
- [Authenticated]
- public class UpdateUserPassword : IReturnVoid
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- public Guid Id { get; set; }
-
- /// <summary>
- /// Gets or sets the password.
- /// </summary>
- /// <value>The password.</value>
- public string CurrentPassword { get; set; }
-
- public string CurrentPw { get; set; }
-
- public string NewPw { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether [reset password].
- /// </summary>
- /// <value><c>true</c> if [reset password]; otherwise, <c>false</c>.</value>
- public bool ResetPassword { get; set; }
- }
-
- /// <summary>
- /// Class UpdateUserEasyPassword
- /// </summary>
- [Route("/Users/{Id}/EasyPassword", "POST", Summary = "Updates a user's easy password")]
- [Authenticated]
- public class UpdateUserEasyPassword : IReturnVoid
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- public Guid Id { get; set; }
-
- /// <summary>
- /// Gets or sets the new password.
- /// </summary>
- /// <value>The new password.</value>
- public string NewPassword { get; set; }
-
- public string NewPw { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether [reset password].
- /// </summary>
- /// <value><c>true</c> if [reset password]; otherwise, <c>false</c>.</value>
- public bool ResetPassword { get; set; }
- }
-
- /// <summary>
- /// Class UpdateUser
- /// </summary>
- [Route("/Users/{Id}", "POST", Summary = "Updates a user")]
- [Authenticated]
- public class UpdateUser : UserDto, IReturnVoid
- {
- }
-
- /// <summary>
- /// Class UpdateUser
- /// </summary>
- [Route("/Users/{Id}/Policy", "POST", Summary = "Updates a user policy")]
- [Authenticated(Roles = "admin")]
- public class UpdateUserPolicy : UserPolicy, IReturnVoid
- {
- [ApiMember(Name = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public Guid Id { get; set; }
- }
-
- /// <summary>
- /// Class UpdateUser
- /// </summary>
- [Route("/Users/{Id}/Configuration", "POST", Summary = "Updates a user configuration")]
- [Authenticated]
- public class UpdateUserConfiguration : UserConfiguration, IReturnVoid
- {
- [ApiMember(Name = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public Guid Id { get; set; }
- }
-
- /// <summary>
- /// Class CreateUser
- /// </summary>
- [Route("/Users/New", "POST", Summary = "Creates a user")]
- [Authenticated(Roles = "Admin")]
- public class CreateUserByName : IReturn<UserDto>
- {
- [ApiMember(Name = "Name", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
- public string Name { get; set; }
-
- [ApiMember(Name = "Password", IsRequired = false, DataType = "string", ParameterType = "body", Verb = "POST")]
- public string Password { get; set; }
- }
-
- [Route("/Users/ForgotPassword", "POST", Summary = "Initiates the forgot password process for a local user")]
- public class ForgotPassword : IReturn<ForgotPasswordResult>
- {
- [ApiMember(Name = "EnteredUsername", IsRequired = false, DataType = "string", ParameterType = "body", Verb = "POST")]
- public string EnteredUsername { get; set; }
- }
-
- [Route("/Users/ForgotPassword/Pin", "POST", Summary = "Redeems a forgot password pin")]
- public class ForgotPasswordPin : IReturn<PinRedeemResult>
- {
- [ApiMember(Name = "Pin", IsRequired = false, DataType = "string", ParameterType = "body", Verb = "POST")]
- public string Pin { get; set; }
- }
-
- /// <summary>
- /// Class UsersService
- /// </summary>
- public class UserService : BaseApiService
- {
- /// <summary>
- /// The user manager.
- /// </summary>
- private readonly IUserManager _userManager;
- private readonly ISessionManager _sessionMananger;
- 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,
- INetworkManager networkManager,
- IDeviceManager deviceManager,
- IAuthorizationContext authContext)
- : base(logger, serverConfigurationManager, httpResultFactory)
- {
- _userManager = userManager;
- _sessionMananger = sessionMananger;
- _networkManager = networkManager;
- _deviceManager = deviceManager;
- _authContext = authContext;
- }
-
- public object Get(GetPublicUsers request)
- {
- // If the startup wizard hasn't been completed then just return all users
- if (!ServerConfigurationManager.Configuration.IsStartupWizardCompleted)
- {
- return Get(new GetUsers
- {
- IsDisabled = false
- });
- }
-
- return Get(new GetUsers
- {
- IsHidden = false,
- IsDisabled = false
- }, true, true);
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public object Get(GetUsers request)
- {
- return Get(request, false, false);
- }
-
- private object Get(GetUsers request, bool filterByDevice, bool filterByNetwork)
- {
- var users = _userManager.Users;
-
- if (request.IsDisabled.HasValue)
- {
- users = users.Where(i => i.Policy.IsDisabled == request.IsDisabled.Value);
- }
-
- if (request.IsHidden.HasValue)
- {
- users = users.Where(i => i.Policy.IsHidden == request.IsHidden.Value);
- }
-
- if (filterByDevice)
- {
- var deviceId = _authContext.GetAuthorizationInfo(Request).DeviceId;
-
- if (!string.IsNullOrWhiteSpace(deviceId))
- {
- users = users.Where(i => _deviceManager.CanAccessDevice(i, deviceId));
- }
- }
-
- if (filterByNetwork)
- {
- if (!_networkManager.IsInLocalNetwork(Request.RemoteIp))
- {
- users = users.Where(i => i.Policy.EnableRemoteAccess);
- }
- }
-
- var result = users
- .OrderBy(u => u.Name)
- .Select(i => _userManager.GetUserDto(i, Request.RemoteIp))
- .ToArray();
-
- return ToOptimizedResult(result);
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public object Get(GetUser request)
- {
- var user = _userManager.GetUserById(request.Id);
-
- if (user == null)
- {
- throw new ResourceNotFoundException("User not found");
- }
-
- var result = _userManager.GetUserDto(user, Request.RemoteIp);
-
- return ToOptimizedResult(result);
- }
-
- /// <summary>
- /// Deletes the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public Task Delete(DeleteUser request)
- {
- return DeleteAsync(request);
- }
-
- public Task DeleteAsync(DeleteUser request)
- {
- var user = _userManager.GetUserById(request.Id);
-
- if (user == null)
- {
- throw new ResourceNotFoundException("User not found");
- }
-
- _sessionMananger.RevokeUserTokens(user.Id, null);
- _userManager.DeleteUser(user);
- return Task.CompletedTask;
- }
-
- /// <summary>
- /// Posts the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public object Post(AuthenticateUser request)
- {
- var user = _userManager.GetUserById(request.Id);
-
- if (user == null)
- {
- throw new ResourceNotFoundException("User not found");
- }
-
- if (!string.IsNullOrEmpty(request.Password) && string.IsNullOrEmpty(request.Pw))
- {
- throw new MethodNotAllowedException("Hashed-only passwords are not valid for this API.");
- }
-
- // Password should always be null
- return Post(new AuthenticateUserByName
- {
- Username = user.Name,
- Password = null,
- Pw = request.Pw
- });
- }
-
- public async Task<object> Post(AuthenticateUserByName request)
- {
- var auth = _authContext.GetAuthorizationInfo(Request);
-
- try
- {
- var result = await _sessionMananger.AuthenticateNewSession(new AuthenticationRequest
- {
- App = auth.Client,
- AppVersion = auth.Version,
- DeviceId = auth.DeviceId,
- DeviceName = auth.Device,
- Password = request.Pw,
- PasswordSha1 = request.Password,
- RemoteEndPoint = Request.RemoteIp,
- Username = request.Username
- }).ConfigureAwait(false);
-
- return ToOptimizedResult(result);
- }
- catch (SecurityException e)
- {
- // rethrow adding IP address to message
- throw new SecurityException($"[{Request.RemoteIp}] {e.Message}", e);
- }
- }
-
- /// <summary>
- /// Posts the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public Task Post(UpdateUserPassword request)
- {
- return PostAsync(request);
- }
-
- public async Task PostAsync(UpdateUserPassword request)
- {
- AssertCanUpdateUser(_authContext, _userManager, request.Id, true);
-
- var user = _userManager.GetUserById(request.Id);
-
- if (user == null)
- {
- throw new ResourceNotFoundException("User not found");
- }
-
- if (request.ResetPassword)
- {
- await _userManager.ResetPassword(user).ConfigureAwait(false);
- }
- else
- {
- var success = await _userManager.AuthenticateUser(user.Name, request.CurrentPw, request.CurrentPassword, Request.RemoteIp, false).ConfigureAwait(false);
-
- if (success == null)
- {
- throw new ArgumentException("Invalid user or password entered.");
- }
-
- await _userManager.ChangePassword(user, request.NewPw).ConfigureAwait(false);
-
- var currentToken = _authContext.GetAuthorizationInfo(Request).Token;
-
- _sessionMananger.RevokeUserTokens(user.Id, currentToken);
- }
- }
-
- public void Post(UpdateUserEasyPassword request)
- {
- AssertCanUpdateUser(_authContext, _userManager, request.Id, true);
-
- var user = _userManager.GetUserById(request.Id);
-
- if (user == null)
- {
- throw new ResourceNotFoundException("User not found");
- }
-
- if (request.ResetPassword)
- {
- _userManager.ResetEasyPassword(user);
- }
- else
- {
- _userManager.ChangeEasyPassword(user, request.NewPw, request.NewPassword);
- }
- }
-
- /// <summary>
- /// Posts the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public async Task Post(UpdateUser request)
- {
- var id = Guid.Parse(GetPathValue(1));
-
- AssertCanUpdateUser(_authContext, _userManager, id, false);
-
- var dtoUser = request;
-
- var user = _userManager.GetUserById(id);
-
- if (string.Equals(user.Name, dtoUser.Name, StringComparison.Ordinal))
- {
- _userManager.UpdateUser(user);
- _userManager.UpdateConfiguration(user, dtoUser.Configuration);
- }
- else
- {
- await _userManager.RenameUser(user, dtoUser.Name).ConfigureAwait(false);
-
- _userManager.UpdateConfiguration(dtoUser.Id, dtoUser.Configuration);
- }
- }
-
- /// <summary>
- /// Posts the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public async Task<object> Post(CreateUserByName request)
- {
- var newUser = _userManager.CreateUser(request.Name);
-
- // no need to authenticate password for new user
- if (request.Password != null)
- {
- await _userManager.ChangePassword(newUser, request.Password).ConfigureAwait(false);
- }
-
- var result = _userManager.GetUserDto(newUser, Request.RemoteIp);
-
- return ToOptimizedResult(result);
- }
-
- public async Task<object> Post(ForgotPassword request)
- {
- var isLocal = Request.IsLocal || _networkManager.IsInLocalNetwork(Request.RemoteIp);
-
- var result = await _userManager.StartForgotPasswordProcess(request.EnteredUsername, isLocal).ConfigureAwait(false);
-
- return result;
- }
-
- public async Task<object> Post(ForgotPasswordPin request)
- {
- var result = await _userManager.RedeemPasswordResetPin(request.Pin).ConfigureAwait(false);
-
- return result;
- }
-
- public void Post(UpdateUserConfiguration request)
- {
- AssertCanUpdateUser(_authContext, _userManager, request.Id, false);
-
- _userManager.UpdateConfiguration(request.Id, request);
-
- }
-
- public void Post(UpdateUserPolicy request)
- {
- var user = _userManager.GetUserById(request.Id);
-
- // If removing admin access
- if (!request.IsAdministrator && user.Policy.IsAdministrator)
- {
- if (_userManager.Users.Count(i => i.Policy.IsAdministrator) == 1)
- {
- throw new ArgumentException("There must be at least one user in the system with administrative access.");
- }
- }
-
- // If disabling
- if (request.IsDisabled && user.Policy.IsAdministrator)
- {
- throw new ArgumentException("Administrators cannot be disabled.");
- }
-
- // If disabling
- if (request.IsDisabled && !user.Policy.IsDisabled)
- {
- if (_userManager.Users.Count(i => !i.Policy.IsDisabled) == 1)
- {
- throw new ArgumentException("There must be at least one enabled user in the system.");
- }
-
- var currentToken = _authContext.GetAuthorizationInfo(Request).Token;
- _sessionMananger.RevokeUserTokens(user.Id, currentToken);
- }
-
- _userManager.UpdateUserPolicy(request.Id, request);
- }
- }
-}