aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Api
diff options
context:
space:
mode:
authorLuke <luke.pulverenti@gmail.com>2015-01-04 09:27:54 -0500
committerLuke <luke.pulverenti@gmail.com>2015-01-04 09:27:54 -0500
commitc5ff30f66e368efc2ca7dea7813fba6d9f6a657c (patch)
treec5552b898f66b7d510e9257eb8bbeafd6a003676 /MediaBrowser.Api
parent767590125b27c2498e3ad9544edbede30fb70f45 (diff)
parent59b6bc28c332701d5e383fbf99170bdc740fb6cc (diff)
Merge pull request #965 from MediaBrowser/dev
3.0.5482.0
Diffstat (limited to 'MediaBrowser.Api')
-rw-r--r--MediaBrowser.Api/ApiEntryPoint.cs26
-rw-r--r--MediaBrowser.Api/ConfigurationService.cs2
-rw-r--r--MediaBrowser.Api/Dlna/DlnaServerService.cs8
-rw-r--r--MediaBrowser.Api/IHasDtoOptions.cs14
-rw-r--r--MediaBrowser.Api/Images/ImageService.cs13
-rw-r--r--MediaBrowser.Api/ItemUpdateService.cs160
-rw-r--r--MediaBrowser.Api/Library/LibraryService.cs47
-rw-r--r--MediaBrowser.Api/LiveTv/LiveTvService.cs2
-rw-r--r--MediaBrowser.Api/Movies/CollectionService.cs5
-rw-r--r--MediaBrowser.Api/Movies/MoviesService.cs28
-rw-r--r--MediaBrowser.Api/NotificationsService.cs2
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs93
-rw-r--r--MediaBrowser.Api/Playback/Hls/BaseHlsService.cs29
-rw-r--r--MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs22
-rw-r--r--MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs5
-rw-r--r--MediaBrowser.Api/Playback/Hls/MpegDashService.cs18
-rw-r--r--MediaBrowser.Api/Playback/Hls/VideoHlsService.cs20
-rw-r--r--MediaBrowser.Api/Playback/Progressive/AudioService.cs2
-rw-r--r--MediaBrowser.Api/Playback/Progressive/VideoService.cs14
-rw-r--r--MediaBrowser.Api/Playback/StreamState.cs1
-rw-r--r--MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs1
-rw-r--r--MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs1
-rw-r--r--MediaBrowser.Api/Session/SessionsService.cs26
-rw-r--r--MediaBrowser.Api/Subtitles/SubtitleService.cs7
-rw-r--r--MediaBrowser.Api/Sync/SyncService.cs92
-rw-r--r--MediaBrowser.Api/System/ActivityLogWebSocketListener.cs4
-rw-r--r--MediaBrowser.Api/System/SystemInfoWebSocketListener.cs1
-rw-r--r--MediaBrowser.Api/UserLibrary/ArtistsService.cs9
-rw-r--r--MediaBrowser.Api/UserLibrary/GameGenresService.cs7
-rw-r--r--MediaBrowser.Api/UserLibrary/GenresService.cs7
-rw-r--r--MediaBrowser.Api/UserLibrary/MusicGenresService.cs7
-rw-r--r--MediaBrowser.Api/UserLibrary/PersonsService.cs7
-rw-r--r--MediaBrowser.Api/UserLibrary/StudiosService.cs7
-rw-r--r--MediaBrowser.Api/UserLibrary/UserLibraryService.cs45
-rw-r--r--MediaBrowser.Api/UserLibrary/YearsService.cs7
-rw-r--r--MediaBrowser.Api/UserService.cs150
-rw-r--r--MediaBrowser.Api/VideosService.cs16
37 files changed, 638 insertions, 267 deletions
diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs
index d386373d4b..0eb92d5a7e 100644
--- a/MediaBrowser.Api/ApiEntryPoint.cs
+++ b/MediaBrowser.Api/ApiEntryPoint.cs
@@ -1,7 +1,10 @@
using MediaBrowser.Api.Playback;
-using MediaBrowser.Controller;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Session;
using System;
@@ -33,7 +36,7 @@ namespace MediaBrowser.Api
/// <summary>
/// The application paths
/// </summary>
- private readonly IServerApplicationPaths _appPaths;
+ private readonly IServerConfigurationManager _config;
private readonly ISessionManager _sessionManager;
@@ -43,13 +46,13 @@ namespace MediaBrowser.Api
/// Initializes a new instance of the <see cref="ApiEntryPoint" /> class.
/// </summary>
/// <param name="logger">The logger.</param>
- /// <param name="appPaths">The application paths.</param>
/// <param name="sessionManager">The session manager.</param>
- public ApiEntryPoint(ILogger logger, IServerApplicationPaths appPaths, ISessionManager sessionManager)
+ /// <param name="config">The configuration.</param>
+ public ApiEntryPoint(ILogger logger, ISessionManager sessionManager, IServerConfigurationManager config)
{
Logger = logger;
- _appPaths = appPaths;
_sessionManager = sessionManager;
+ _config = config;
Instance = this;
}
@@ -73,12 +76,19 @@ namespace MediaBrowser.Api
}
}
+ public EncodingOptions GetEncodingOptions()
+ {
+ return _config.GetConfiguration<EncodingOptions>("encoding");
+ }
+
/// <summary>
/// Deletes the encoded media cache.
/// </summary>
private void DeleteEncodedMediaCache()
{
- foreach (var file in Directory.EnumerateFiles(_appPaths.TranscodingTempPath, "*", SearchOption.AllDirectories)
+ var path = Path.Combine(_config.ApplicationPaths.TranscodingTempPath, EncodingContext.Streaming.ToString().ToLower());
+
+ foreach (var file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)
.ToList())
{
File.Delete(file);
@@ -185,7 +195,9 @@ namespace MediaBrowser.Api
CompletionPercentage = percentComplete,
Width = state.OutputWidth,
Height = state.OutputHeight,
- AudioChannels = state.OutputAudioChannels
+ AudioChannels = state.OutputAudioChannels,
+ IsAudioDirect = string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase),
+ IsVideoDirect = string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)
});
}
}
diff --git a/MediaBrowser.Api/ConfigurationService.cs b/MediaBrowser.Api/ConfigurationService.cs
index 5fe606e16e..3eb0296fcb 100644
--- a/MediaBrowser.Api/ConfigurationService.cs
+++ b/MediaBrowser.Api/ConfigurationService.cs
@@ -123,7 +123,7 @@ namespace MediaBrowser.Api
public void Post(AutoSetMetadataOptions request)
{
- _configurationManager.DisableMetadataService("Media Browser Legacy Xml");
+ _configurationManager.DisableMetadataService("Media Browser Xml");
_configurationManager.SaveConfiguration();
}
diff --git a/MediaBrowser.Api/Dlna/DlnaServerService.cs b/MediaBrowser.Api/Dlna/DlnaServerService.cs
index 9981d506ee..94d6e25b03 100644
--- a/MediaBrowser.Api/Dlna/DlnaServerService.cs
+++ b/MediaBrowser.Api/Dlna/DlnaServerService.cs
@@ -1,5 +1,4 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Controller.Dlna;
+using MediaBrowser.Controller.Dlna;
using ServiceStack;
using ServiceStack.Text.Controller;
using ServiceStack.Web;
@@ -77,14 +76,11 @@ namespace MediaBrowser.Api.Dlna
private readonly IContentDirectory _contentDirectory;
private readonly IConnectionManager _connectionManager;
- private readonly IConfigurationManager _config;
-
- public DlnaServerService(IDlnaManager dlnaManager, IContentDirectory contentDirectory, IConnectionManager connectionManager, IConfigurationManager config)
+ public DlnaServerService(IDlnaManager dlnaManager, IContentDirectory contentDirectory, IConnectionManager connectionManager)
{
_dlnaManager = dlnaManager;
_contentDirectory = contentDirectory;
_connectionManager = connectionManager;
- _config = config;
}
public object Get(GetDescriptionXml request)
diff --git a/MediaBrowser.Api/IHasDtoOptions.cs b/MediaBrowser.Api/IHasDtoOptions.cs
index f7fb57f014..7fe47c4a1e 100644
--- a/MediaBrowser.Api/IHasDtoOptions.cs
+++ b/MediaBrowser.Api/IHasDtoOptions.cs
@@ -1,4 +1,4 @@
-using MediaBrowser.Model.Dto;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Model.Entities;
using System;
using System.Linq;
@@ -28,17 +28,7 @@ namespace MediaBrowser.Api
options.ImageTypeLimit = request.ImageTypeLimit.Value;
}
- if (string.IsNullOrWhiteSpace(request.EnableImageTypes))
- {
- if (options.EnableImages)
- {
- // Get everything
- options.ImageTypes = Enum.GetNames(typeof(ImageType))
- .Select(i => (ImageType)Enum.Parse(typeof(ImageType), i, true))
- .ToList();
- }
- }
- else
+ if (!string.IsNullOrWhiteSpace(request.EnableImageTypes))
{
options.ImageTypes = (request.EnableImageTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).Select(v => (ImageType)Enum.Parse(typeof(ImageType), v, true)).ToList();
}
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index 0e4ccf0b17..f2586b0438 100644
--- a/MediaBrowser.Api/Images/ImageService.cs
+++ b/MediaBrowser.Api/Images/ImageService.cs
@@ -18,6 +18,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
namespace MediaBrowser.Api.Images
{
@@ -668,26 +669,26 @@ namespace MediaBrowser.Api.Images
{
if (format == ImageFormat.Bmp)
{
- return Common.Net.MimeTypes.GetMimeType("i.bmp");
+ return MimeTypes.GetMimeType("i.bmp");
}
if (format == ImageFormat.Gif)
{
- return Common.Net.MimeTypes.GetMimeType("i.gif");
+ return MimeTypes.GetMimeType("i.gif");
}
if (format == ImageFormat.Jpg)
{
- return Common.Net.MimeTypes.GetMimeType("i.jpg");
+ return MimeTypes.GetMimeType("i.jpg");
}
if (format == ImageFormat.Png)
{
- return Common.Net.MimeTypes.GetMimeType("i.png");
+ return MimeTypes.GetMimeType("i.png");
}
if (format == ImageFormat.Webp)
{
- return Common.Net.MimeTypes.GetMimeType("i.webp");
+ return MimeTypes.GetMimeType("i.webp");
}
- return Common.Net.MimeTypes.GetMimeType(path);
+ return MimeTypes.GetMimeType(path);
}
/// <summary>
diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs
index 65c51befff..272dff3ecc 100644
--- a/MediaBrowser.Api/ItemUpdateService.cs
+++ b/MediaBrowser.Api/ItemUpdateService.cs
@@ -1,9 +1,14 @@
-using MediaBrowser.Controller.Entities;
+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.Localization;
using MediaBrowser.Controller.Net;
+using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Entities;
using ServiceStack;
using System;
using System.Collections.Generic;
@@ -20,14 +25,165 @@ namespace MediaBrowser.Api
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 string 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]
public class ItemUpdateService : BaseApiService
{
private readonly ILibraryManager _libraryManager;
+ private readonly IProviderManager _providerManager;
+ private readonly ILocalizationManager _localizationManager;
+ private readonly IServerConfigurationManager _config;
- public ItemUpdateService(ILibraryManager libraryManager)
+ public ItemUpdateService(ILibraryManager libraryManager, IProviderManager providerManager, ILocalizationManager localizationManager, IServerConfigurationManager config)
{
_libraryManager = libraryManager;
+ _providerManager = providerManager;
+ _localizationManager = localizationManager;
+ _config = config;
+ }
+
+ public object Get(GetMetadataEditorInfo request)
+ {
+ var item = _libraryManager.GetItemById(request.ItemId);
+
+ var info = new MetadataEditorInfo
+ {
+ ParentalRatingOptions = _localizationManager.GetParentalRatings().ToList(),
+ ExternalIdInfos = _providerManager.GetExternalIdInfos(item).ToList(),
+ Countries = _localizationManager.GetCountries().ToList(),
+ Cultures = _localizationManager.GetCultures().ToList()
+ };
+
+ var locationType = item.LocationType;
+ if (locationType == LocationType.FileSystem ||
+ locationType == LocationType.Offline)
+ {
+ if (!(item is ICollectionFolder) && !(item is UserView) && !(item is AggregateFolder) && !(item is LiveTvChannel) && !(item is IItemByName))
+ {
+ var collectionType = _libraryManager.GetInheritedContentType(item);
+ if (string.IsNullOrWhiteSpace(collectionType))
+ {
+ info.ContentTypeOptions = GetContentTypeOptions(true);
+ info.ContentType = _libraryManager.GetContentType(item);
+ }
+ }
+ }
+
+ return ToOptimizedResult(info);
+ }
+
+ public void Post(UpdateItemContentType request)
+ {
+ var item = _libraryManager.GetItemById(request.ItemId);
+ var path = item.ContainingFolderPath;
+
+ var types = _config.Configuration.ContentTypes
+ .Where(i => !string.Equals(i.Name, path, StringComparison.OrdinalIgnoreCase))
+ .ToList();
+
+ if (!string.IsNullOrWhiteSpace(request.ContentType))
+ {
+ types.Add(new NameValuePair
+ {
+ Name = path,
+ Value = request.ContentType
+ });
+ }
+
+ _config.Configuration.ContentTypes = types.ToArray();
+ _config.SaveConfiguration();
+ }
+
+ private List<NameValuePair> GetContentTypeOptions(bool isForItem)
+ {
+ var list = new List<NameValuePair>();
+
+ if (isForItem)
+ {
+ list.Add(new NameValuePair
+ {
+ Name = "FolderTypeInherit",
+ Value = ""
+ });
+ }
+
+ list.Add(new NameValuePair
+ {
+ Name = "FolderTypeMovies",
+ Value = "movies"
+ });
+ list.Add(new NameValuePair
+ {
+ Name = "FolderTypeMusic",
+ Value = "music"
+ });
+ list.Add(new NameValuePair
+ {
+ Name = "FolderTypeTvShows",
+ Value = "tvshows"
+ });
+
+ if (!isForItem)
+ {
+ list.Add(new NameValuePair
+ {
+ Name = "FolderTypeBooks",
+ Value = "books"
+ });
+ list.Add(new NameValuePair
+ {
+ Name = "FolderTypeGames",
+ Value = "games"
+ });
+ }
+
+ list.Add(new NameValuePair
+ {
+ Name = "FolderTypeHomeVideos",
+ Value = "homevideos"
+ });
+ list.Add(new NameValuePair
+ {
+ Name = "FolderTypeMusicVideos",
+ Value = "musicvideos"
+ });
+ list.Add(new NameValuePair
+ {
+ Name = "FolderTypePhotos",
+ Value = "photos"
+ });
+
+ if (!isForItem)
+ {
+ list.Add(new NameValuePair
+ {
+ Name = "FolderTypeMixed",
+ Value = ""
+ });
+ }
+
+ foreach (var val in list)
+ {
+ val.Name = _localizationManager.GetLocalizedString(val.Name);
+ }
+
+ return list;
}
public void Post(UpdateItem request)
diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs
index 5cb007f8fe..5e1619672f 100644
--- a/MediaBrowser.Api/Library/LibraryService.cs
+++ b/MediaBrowser.Api/Library/LibraryService.cs
@@ -272,16 +272,13 @@ namespace MediaBrowser.Api.Library
items = items.Where(i => i.IsHidden == val).ToList();
}
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields))
- .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
- .ToList();
+ var dtoOptions = new DtoOptions();
var result = new ItemsResult
{
TotalRecordCount = items.Count,
- Items = items.Select(i => _dtoService.GetBaseItemDto(i, fields)).ToArray()
+ Items = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions)).ToArray()
};
return ToOptimizedResult(result);
@@ -347,10 +344,7 @@ namespace MediaBrowser.Api.Library
var user = request.UserId.HasValue ? _userManager.GetUserById(request.UserId.Value) : null;
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields))
- .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
- .ToList();
+ var dtoOptions = new DtoOptions();
BaseItem parent = item.Parent;
@@ -361,7 +355,7 @@ namespace MediaBrowser.Api.Library
parent = TranslateParentItem(parent, user);
}
- baseItemDtos.Add(_dtoService.GetBaseItemDto(parent, fields, user));
+ baseItemDtos.Add(_dtoService.GetBaseItemDto(parent, dtoOptions, user));
parent = parent.Parent;
}
@@ -473,20 +467,20 @@ namespace MediaBrowser.Api.Library
var auth = _authContext.GetAuthorizationInfo(Request);
var user = _userManager.GetUserById(auth.UserId);
- if (item is Playlist)
+ if (item is Playlist || item is BoxSet)
{
// For now this is allowed if user can see the playlist
}
else if (item is ILiveTvRecording)
{
- if (!user.Configuration.EnableLiveTvManagement)
+ if (!user.Policy.EnableLiveTvManagement)
{
throw new UnauthorizedAccessException();
}
}
else
{
- if (!user.Configuration.EnableContentDeletion)
+ if (!user.Policy.EnableContentDeletion)
{
throw new UnauthorizedAccessException();
}
@@ -583,11 +577,6 @@ namespace MediaBrowser.Api.Library
item = item.Parent;
}
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields))
- .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
- .ToList();
-
var themeSongIds = GetThemeSongIds(item);
if (themeSongIds.Count == 0 && request.InheritFromParent)
@@ -607,10 +596,12 @@ namespace MediaBrowser.Api.Library
}
}
}
-
+
+ var dtoOptions = new DtoOptions();
+
var dtos = themeSongIds.Select(_libraryManager.GetItemById)
.OrderBy(i => i.SortName)
- .Select(i => _dtoService.GetBaseItemDto(i, fields, user, item));
+ .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
var items = dtos.ToArray();
@@ -651,11 +642,6 @@ namespace MediaBrowser.Api.Library
item = item.Parent;
}
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields))
- .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
- .ToList();
-
var themeVideoIds = GetThemeVideoIds(item);
if (themeVideoIds.Count == 0 && request.InheritFromParent)
@@ -681,9 +667,11 @@ namespace MediaBrowser.Api.Library
}
}
+ var dtoOptions = new DtoOptions();
+
var dtos = themeVideoIds.Select(_libraryManager.GetItemById)
.OrderBy(i => i.SortName)
- .Select(i => _dtoService.GetBaseItemDto(i, fields, user, item));
+ .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
var items = dtos.ToArray();
@@ -754,10 +742,7 @@ namespace MediaBrowser.Api.Library
: (Folder)_libraryManager.RootFolder)
: _libraryManager.GetItemById(id);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields))
- .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
- .ToList();
+ var dtoOptions = new DtoOptions();
var dtos = GetSoundtrackSongIds(item, inheritFromParent)
.Select(_libraryManager.GetItemById)
@@ -765,7 +750,7 @@ namespace MediaBrowser.Api.Library
.SelectMany(i => i.RecursiveChildren)
.OfType<Audio>()
.OrderBy(i => i.SortName)
- .Select(i => _dtoService.GetBaseItemDto(i, fields, user, item));
+ .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
var items = dtos.ToArray();
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index 3afe72866d..f3dcf57e03 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -319,7 +319,7 @@ namespace MediaBrowser.Api.LiveTv
throw new UnauthorizedAccessException("Anonymous live tv management is not allowed.");
}
- if (!user.Configuration.EnableLiveTvManagement)
+ if (!user.Policy.EnableLiveTvManagement)
{
throw new UnauthorizedAccessException("The current user does not have permission to manage live tv.");
}
diff --git a/MediaBrowser.Api/Movies/CollectionService.cs b/MediaBrowser.Api/Movies/CollectionService.cs
index 346c085f8c..97c6cd87da 100644
--- a/MediaBrowser.Api/Movies/CollectionService.cs
+++ b/MediaBrowser.Api/Movies/CollectionService.cs
@@ -2,6 +2,7 @@
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Collections;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying;
using ServiceStack;
using System;
@@ -70,7 +71,9 @@ namespace MediaBrowser.Api.Movies
}).ConfigureAwait(false);
- var dto = _dtoService.GetBaseItemDto(item, new List<ItemFields>());
+ var dtoOptions = new DtoOptions();
+
+ var dto = _dtoService.GetBaseItemDto(item, dtoOptions);
return ToOptimizedResult(new CollectionCreationResult
{
diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs
index fc03ab466e..ba3c15a90b 100644
--- a/MediaBrowser.Api/Movies/MoviesService.cs
+++ b/MediaBrowser.Api/Movies/MoviesService.cs
@@ -157,7 +157,11 @@ namespace MediaBrowser.Api.Movies
.DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString(), StringComparer.OrdinalIgnoreCase)
.ToList();
- var result = GetRecommendationCategories(user, listEligibleForCategories, listEligibleForSuggestion, request.CategoryLimit, request.ItemLimit, request.GetItemFields().ToList());
+ var dtoOptions = new DtoOptions();
+
+ dtoOptions.Fields = request.GetItemFields().ToList();
+
+ var result = GetRecommendationCategories(user, listEligibleForCategories, listEligibleForSuggestion, request.CategoryLimit, request.ItemLimit, dtoOptions);
return ToOptimizedResult(result);
}
@@ -232,7 +236,7 @@ namespace MediaBrowser.Api.Movies
return result;
}
- private IEnumerable<RecommendationDto> GetRecommendationCategories(User user, List<BaseItem> allMoviesForCategories, List<BaseItem> allMovies, int categoryLimit, int itemLimit, List<ItemFields> fields)
+ private IEnumerable<RecommendationDto> GetRecommendationCategories(User user, List<BaseItem> allMoviesForCategories, List<BaseItem> allMovies, int categoryLimit, int itemLimit, DtoOptions dtoOptions)
{
var categories = new List<RecommendationDto>();
@@ -282,11 +286,11 @@ namespace MediaBrowser.Api.Movies
.OrderBy(i => Guid.NewGuid())
.ToList();
- var similarToRecentlyPlayed = GetSimilarTo(user, allMovies, recentlyPlayedMovies.Take(7).OrderBy(i => Guid.NewGuid()), itemLimit, fields, RecommendationType.SimilarToRecentlyPlayed).GetEnumerator();
- var similarToLiked = GetSimilarTo(user, allMovies, likedMovies, itemLimit, fields, RecommendationType.SimilarToLikedItem).GetEnumerator();
+ var similarToRecentlyPlayed = GetSimilarTo(user, allMovies, recentlyPlayedMovies.Take(7).OrderBy(i => Guid.NewGuid()), itemLimit, dtoOptions, RecommendationType.SimilarToRecentlyPlayed).GetEnumerator();
+ var similarToLiked = GetSimilarTo(user, allMovies, likedMovies, itemLimit, dtoOptions, RecommendationType.SimilarToLikedItem).GetEnumerator();
- var hasDirectorFromRecentlyPlayed = GetWithDirector(user, allMovies, recentDirectors, itemLimit, fields, RecommendationType.HasDirectorFromRecentlyPlayed).GetEnumerator();
- var hasActorFromRecentlyPlayed = GetWithActor(user, allMovies, recentActors, itemLimit, fields, RecommendationType.HasActorFromRecentlyPlayed).GetEnumerator();
+ var hasDirectorFromRecentlyPlayed = GetWithDirector(user, allMovies, recentDirectors, itemLimit, dtoOptions, RecommendationType.HasDirectorFromRecentlyPlayed).GetEnumerator();
+ var hasActorFromRecentlyPlayed = GetWithActor(user, allMovies, recentActors, itemLimit, dtoOptions, RecommendationType.HasActorFromRecentlyPlayed).GetEnumerator();
var categoryTypes = new List<IEnumerator<RecommendationDto>>
{
@@ -329,7 +333,7 @@ namespace MediaBrowser.Api.Movies
return categories.OrderBy(i => i.RecommendationType).ThenBy(i => Guid.NewGuid());
}
- private IEnumerable<RecommendationDto> GetWithDirector(User user, List<BaseItem> allMovies, IEnumerable<string> directors, int itemLimit, List<ItemFields> fields, RecommendationType type)
+ private IEnumerable<RecommendationDto> GetWithDirector(User user, List<BaseItem> allMovies, IEnumerable<string> directors, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
{
var userId = user.Id;
@@ -347,13 +351,13 @@ namespace MediaBrowser.Api.Movies
BaselineItemName = director,
CategoryId = director.GetMD5().ToString("N"),
RecommendationType = type,
- Items = items.Select(i => _dtoService.GetBaseItemDto(i, fields, user)).ToArray()
+ Items = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray()
};
}
}
}
- private IEnumerable<RecommendationDto> GetWithActor(User user, List<BaseItem> allMovies, IEnumerable<string> names, int itemLimit, List<ItemFields> fields, RecommendationType type)
+ private IEnumerable<RecommendationDto> GetWithActor(User user, List<BaseItem> allMovies, IEnumerable<string> names, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
{
var userId = user.Id;
@@ -371,13 +375,13 @@ namespace MediaBrowser.Api.Movies
BaselineItemName = name,
CategoryId = name.GetMD5().ToString("N"),
RecommendationType = type,
- Items = items.Select(i => _dtoService.GetBaseItemDto(i, fields, user)).ToArray()
+ Items = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray()
};
}
}
}
- private IEnumerable<RecommendationDto> GetSimilarTo(User user, List<BaseItem> allMovies, IEnumerable<BaseItem> baselineItems, int itemLimit, List<ItemFields> fields, RecommendationType type)
+ private IEnumerable<RecommendationDto> GetSimilarTo(User user, List<BaseItem> allMovies, IEnumerable<BaseItem> baselineItems, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
{
var userId = user.Id;
@@ -395,7 +399,7 @@ namespace MediaBrowser.Api.Movies
BaselineItemName = item.Name,
CategoryId = item.Id.ToString("N"),
RecommendationType = type,
- Items = similar.Select(i => _dtoService.GetBaseItemDto(i, fields, user)).ToArray()
+ Items = similar.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray()
};
}
}
diff --git a/MediaBrowser.Api/NotificationsService.cs b/MediaBrowser.Api/NotificationsService.cs
index 69f1f34891..5103d1b5cd 100644
--- a/MediaBrowser.Api/NotificationsService.cs
+++ b/MediaBrowser.Api/NotificationsService.cs
@@ -135,7 +135,7 @@ namespace MediaBrowser.Api
Level = request.Level,
Name = request.Name,
Url = request.Url,
- UserIds = _userManager.Users.Where(i => i.Configuration.IsAdministrator).Select(i => i.Id.ToString("N")).ToList()
+ UserIds = _userManager.Users.Where(i => i.Policy.IsAdministrator).Select(i => i.Id.ToString("N")).ToList()
};
await _notificationManager.SendNotification(notification, CancellationToken.None).ConfigureAwait(false);
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index 12ccfb6b1d..8662e64b4f 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
@@ -118,8 +119,8 @@ namespace MediaBrowser.Api.Playback
/// <returns>System.String.</returns>
private string GetOutputFilePath(StreamState state)
{
- var folder = ServerConfigurationManager.ApplicationPaths.TranscodingTempPath;
-
+ var folder = Path.Combine(ServerConfigurationManager.ApplicationPaths.TranscodingTempPath, EncodingContext.Streaming.ToString().ToLower());
+
var outputFileExtension = GetOutputFileExtension(state);
var data = GetCommandLineArguments("dummy\\dummy", "dummyTranscodingId", state, false);
@@ -202,6 +203,10 @@ namespace MediaBrowser.Api.Playback
{
args += " -map -0:s";
}
+ else if (state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream)
+ {
+ args += " -map 1:0 -sn";
+ }
return args;
}
@@ -245,7 +250,7 @@ namespace MediaBrowser.Api.Playback
protected EncodingQuality GetQualitySetting()
{
- var quality = ServerConfigurationManager.Configuration.MediaEncodingQuality;
+ var quality = ApiEntryPoint.Instance.GetEncodingOptions().EncodingQuality;
if (quality == EncodingQuality.Auto)
{
@@ -273,7 +278,7 @@ namespace MediaBrowser.Api.Playback
// Recommended per docs
return Math.Max(Environment.ProcessorCount - 1, 2);
}
-
+
// Use more when this is true. -re will keep cpu usage under control
if (state.ReadInputAtNativeFramerate)
{
@@ -302,6 +307,21 @@ namespace MediaBrowser.Api.Playback
}
}
+ protected string H264Encoder
+ {
+ get
+ {
+ var lib = ApiEntryPoint.Instance.GetEncodingOptions().H264Encoder;
+
+ if (!string.IsNullOrWhiteSpace(lib))
+ {
+ return lib;
+ }
+
+ return "libx264";
+ }
+ }
+
/// <summary>
/// Gets the video bitrate to specify on the command line
/// </summary>
@@ -318,7 +338,7 @@ namespace MediaBrowser.Api.Playback
var qualitySetting = GetQualitySetting();
- if (string.Equals(videoCodec, "libx264", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(videoCodec, H264Encoder, StringComparison.OrdinalIgnoreCase))
{
switch (qualitySetting)
{
@@ -442,7 +462,7 @@ namespace MediaBrowser.Api.Playback
{
if (state.AudioStream != null && state.AudioStream.Channels.HasValue && state.AudioStream.Channels.Value > 5)
{
- volParam = ",volume=" + ServerConfigurationManager.Configuration.DownMixAudioBoost.ToString(UsCulture);
+ volParam = ",volume=" + ApiEntryPoint.Instance.GetEncodingOptions().DownMixAudioBoost.ToString(UsCulture);
}
}
@@ -651,9 +671,18 @@ namespace MediaBrowser.Api.Playback
videoSizeParam = string.Format(",scale={0}:{1}", state.VideoStream.Width.Value.ToString(UsCulture), state.VideoStream.Height.Value.ToString(UsCulture));
}
- return string.Format(" -filter_complex \"[0:{0}]format=yuva444p{3},lut=u=128:v=128:y=gammaval(.3)[sub] ; [0:{1}] [sub] overlay{2}\"",
- state.SubtitleStream.Index,
- state.VideoStream.Index,
+ var mapPrefix = state.SubtitleStream.IsExternal ?
+ 1 :
+ 0;
+
+ var subtitleStreamIndex = state.SubtitleStream.IsExternal
+ ? 0
+ : state.SubtitleStream.Index;
+
+ return string.Format(" -filter_complex \"[{0}:{1}]format=yuva444p{4},lut=u=128:v=128:y=gammaval(.3)[sub] ; [0:{2}] [sub] overlay{3}\"",
+ mapPrefix.ToString(UsCulture),
+ subtitleStreamIndex.ToString(UsCulture),
+ state.VideoStream.Index.ToString(UsCulture),
outputSizeParam,
videoSizeParam);
}
@@ -700,7 +729,8 @@ namespace MediaBrowser.Api.Playback
return Math.Min(request.MaxAudioChannels.Value, audioStream.Channels.Value);
}
- return request.MaxAudioChannels.Value;
+ // If we don't have any media info then limit it to 5 to prevent encoding errors due to asking for too many channels
+ return Math.Min(request.MaxAudioChannels.Value, 5);
}
return request.AudioChannels;
@@ -761,7 +791,7 @@ namespace MediaBrowser.Api.Playback
{
if (string.Equals(codec, "h264", StringComparison.OrdinalIgnoreCase))
{
- return "libx264";
+ return H264Encoder;
}
if (string.Equals(codec, "vpx", StringComparison.OrdinalIgnoreCase))
{
@@ -798,6 +828,21 @@ namespace MediaBrowser.Api.Playback
/// <returns>System.String.</returns>
protected string GetInputArgument(string transcodingJobId, StreamState state)
{
+ var arg = "-i " + GetInputPathArgument(transcodingJobId, state);
+
+ if (state.SubtitleStream != null)
+ {
+ if (state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream)
+ {
+ arg += " -i \"" + state.SubtitleStream.Path + "\"";
+ }
+ }
+
+ return arg;
+ }
+
+ private string GetInputPathArgument(string transcodingJobId, StreamState state)
+ {
if (state.InputProtocol == MediaProtocol.File &&
state.RunTimeTicks.HasValue &&
state.VideoType == VideoType.VideoFile &&
@@ -868,7 +913,7 @@ namespace MediaBrowser.Api.Playback
state.InputProtocol = streamInfo.Protocol;
await Task.Delay(1500, cancellationTokenSource.Token).ConfigureAwait(false);
-
+
AttachMediaStreamInfo(state, streamInfo, state.VideoRequest, state.RequestedUrl);
checkCodecs = true;
}
@@ -898,8 +943,8 @@ namespace MediaBrowser.Api.Playback
/// <param name="cancellationTokenSource">The cancellation token source.</param>
/// <param name="workingDirectory">The working directory.</param>
/// <returns>Task.</returns>
- protected async Task<TranscodingJob> StartFfMpeg(StreamState state,
- string outputPath,
+ protected async Task<TranscodingJob> StartFfMpeg(StreamState state,
+ string outputPath,
CancellationTokenSource cancellationTokenSource,
string workingDirectory = null)
{
@@ -910,7 +955,7 @@ namespace MediaBrowser.Api.Playback
var transcodingId = Guid.NewGuid().ToString("N");
var commandLineArgs = GetCommandLineArguments(outputPath, transcodingId, state, true);
- if (ServerConfigurationManager.Configuration.EnableDebugEncodingLogging)
+ if (ApiEntryPoint.Instance.GetEncodingOptions().EnableDebugLogging)
{
commandLineArgs = "-loglevel debug " + commandLineArgs;
}
@@ -1088,7 +1133,7 @@ namespace MediaBrowser.Api.Playback
if (scale.HasValue)
{
long val;
-
+
if (long.TryParse(size, NumberStyles.Any, UsCulture, out val))
{
bytesTranscoded = val * scale.Value;
@@ -1562,9 +1607,6 @@ namespace MediaBrowser.Api.Playback
mediaStreams = new List<MediaStream>();
state.DeInterlace = true;
- state.OutputAudioSync = "1000";
- state.InputVideoSync = "-1";
- state.InputAudioSync = "1";
// Just to prevent this from being null and causing other methods to fail
state.MediaPath = string.Empty;
@@ -1630,7 +1672,7 @@ namespace MediaBrowser.Api.Playback
if (string.IsNullOrEmpty(container))
{
- container = request.Static ?
+ container = request.Static ?
state.InputContainer :
(Path.GetExtension(GetOutputFilePath(state)) ?? string.Empty).TrimStart('.');
}
@@ -1696,9 +1738,16 @@ namespace MediaBrowser.Api.Playback
state.InputFileSize = mediaSource.Size;
state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate;
+ if (state.ReadInputAtNativeFramerate)
+ {
+ state.OutputAudioSync = "1000";
+ state.InputVideoSync = "-1";
+ state.InputAudioSync = "1";
+ }
+
AttachMediaStreamInfo(state, mediaSource.MediaStreams, videoRequest, requestedUrl);
}
-
+
private void AttachMediaStreamInfo(StreamState state,
List<MediaStream> mediaStreams,
VideoStreamRequest videoRequest,
diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
index c963636fdf..8a33a88f28 100644
--- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
@@ -6,7 +7,6 @@ using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.IO;
using System;
using System.Collections.Generic;
@@ -14,6 +14,7 @@ using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Model.Net;
namespace MediaBrowser.Api.Playback.Hls
{
@@ -119,11 +120,7 @@ namespace MediaBrowser.Api.Playback.Hls
if (isLive)
{
- //var file = request.PlaylistId + Path.GetExtension(Request.PathInfo);
-
- //file = Path.Combine(ServerConfigurationManager.ApplicationPaths.TranscodingTempPath, file);
-
- return ResultFactory.GetStaticFileResult(Request, playlist, FileShare.ReadWrite);
+ return ResultFactory.GetResult(GetLivePlaylistText(playlist, state.SegmentLength), MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
}
var audioBitrate = state.OutputAudioBitrate ?? 0;
@@ -144,6 +141,22 @@ namespace MediaBrowser.Api.Playback.Hls
return ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
}
+ private string GetLivePlaylistText(string path, int segmentLength)
+ {
+ using (var stream = FileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
+ {
+ using (var reader = new StreamReader(stream))
+ {
+ var text = reader.ReadToEnd();
+
+ var newDuration = "#EXT-X-TARGETDURATION:" + segmentLength.ToString(UsCulture) + Environment.NewLine + "#EXT-X-ALLOW-CACHE:NO";
+
+ // ffmpeg pads the reported length by a full second
+ return text.Replace("#EXT-X-TARGETDURATION:" + (segmentLength + 1).ToString(UsCulture), newDuration, StringComparison.OrdinalIgnoreCase);
+ }
+ }
+ }
+
private string GetMasterPlaylistFileText(string firstPlaylist, int bitrate, bool includeBaselineStream, int baselineStreamBitrate)
{
var builder = new StringBuilder();
@@ -227,7 +240,7 @@ namespace MediaBrowser.Api.Playback.Hls
"hls/" + Path.GetFileNameWithoutExtension(outputPath));
}
- var args = string.Format("{0} {1} -i {2} -map_metadata -1 -threads {3} {4} {5} -sc_threshold 0 {6} -hls_time {7} -start_number {8} -hls_list_size {9}{10} -y \"{11}\"",
+ var args = string.Format("{0} {1} {2} -map_metadata -1 -threads {3} {4} {5} -sc_threshold 0 {6} -hls_time {7} -start_number {8} -hls_list_size {9}{10} -y \"{11}\"",
itsOffset,
inputModifier,
GetInputArgument(transcodingJobId, state),
diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
index fe3bd12fb1..86866bdf5e 100644
--- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
@@ -20,6 +20,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
namespace MediaBrowser.Api.Playback.Hls
{
@@ -387,7 +388,7 @@ namespace MediaBrowser.Api.Playback.Hls
playlistText = GetMasterPlaylistFileText(state, videoBitrate + audioBitrate);
}
- return ResultFactory.GetResult(playlistText, Common.Net.MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
+ return ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
}
private string GetMasterPlaylistFileText(StreamState state, int totalBitrate)
@@ -603,7 +604,7 @@ namespace MediaBrowser.Api.Playback.Hls
var playlistText = builder.ToString();
- return ResultFactory.GetResult(playlistText, Common.Net.MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
+ return ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
}
protected override string GetAudioArguments(StreamState state)
@@ -640,10 +641,19 @@ namespace MediaBrowser.Api.Playback.Hls
{
var codec = state.OutputVideoCodec;
+ var args = "-codec:v:0 " + codec;
+
+ if (state.EnableMpegtsM2TsMode)
+ {
+ args += " -mpegts_m2ts_mode 1";
+ }
+
// See if we can save come cpu cycles by avoiding encoding
- if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
+ if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
{
- return state.VideoStream != null && IsH264(state.VideoStream) ? "-codec:v:0 copy -bsf:v h264_mp4toannexb" : "-codec:v:0 copy";
+ return state.VideoStream != null && IsH264(state.VideoStream) ?
+ args + " -bsf:v h264_mp4toannexb" :
+ args;
}
var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})",
@@ -651,7 +661,7 @@ namespace MediaBrowser.Api.Playback.Hls
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;
- var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, "libx264", true) + keyFrameArg;
+ args += " " + GetVideoQualityParam(state, H264Encoder, true) + keyFrameArg;
// Add resolution params, if specified
if (!hasGraphicalSubs)
@@ -677,7 +687,7 @@ namespace MediaBrowser.Api.Playback.Hls
// If isEncoding is true we're actually starting ffmpeg
var startNumberParam = isEncoding ? GetStartNumber(state).ToString(UsCulture) : "0";
- var args = string.Format("{0} -i {1} -map_metadata -1 -threads {2} {3} {4} -copyts -flags -global_header {5} -hls_time {6} -start_number {7} -hls_list_size {8} -y \"{9}\"",
+ var args = string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -copyts -flags -global_header {5} -hls_time {6} -start_number {7} -hls_list_size {8} -y \"{9}\"",
inputModifier,
GetInputArgument(transcodingJobId, state),
threads,
diff --git a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs
index 2263a2b371..14045b3a56 100644
--- a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs
+++ b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs
@@ -1,4 +1,5 @@
using MediaBrowser.Controller;
+using MediaBrowser.Model.Dlna;
using ServiceStack;
using System;
using System.IO;
@@ -65,7 +66,7 @@ namespace MediaBrowser.Api.Playback.Hls
{
var file = request.PlaylistId + Path.GetExtension(Request.PathInfo);
- file = Path.Combine(_appPaths.TranscodingTempPath, file);
+ file = Path.Combine(_appPaths.TranscodingTempPath, EncodingContext.Streaming.ToString().ToLower(), file);
return ResultFactory.GetStaticFileResult(Request, file, FileShare.ReadWrite);
}
@@ -84,7 +85,7 @@ namespace MediaBrowser.Api.Playback.Hls
{
var file = request.SegmentId + Path.GetExtension(Request.PathInfo);
- file = Path.Combine(_appPaths.TranscodingTempPath, file);
+ file = Path.Combine(_appPaths.TranscodingTempPath, EncodingContext.Streaming.ToString().ToLower(), file);
return ResultFactory.GetStaticFileResult(Request, file, FileShare.ReadWrite);
}
diff --git a/MediaBrowser.Api/Playback/Hls/MpegDashService.cs b/MediaBrowser.Api/Playback/Hls/MpegDashService.cs
index 260a4c467e..87e2eedcf5 100644
--- a/MediaBrowser.Api/Playback/Hls/MpegDashService.cs
+++ b/MediaBrowser.Api/Playback/Hls/MpegDashService.cs
@@ -18,6 +18,7 @@ using System.Security;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
namespace MediaBrowser.Api.Playback.Hls
{
@@ -97,7 +98,7 @@ namespace MediaBrowser.Api.Playback.Hls
playlistText = GetManifestText(state);
}
- return ResultFactory.GetResult(playlistText, Common.Net.MimeTypes.GetMimeType("playlist.mpd"), new Dictionary<string, string>());
+ return ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.mpd"), new Dictionary<string, string>());
}
private string GetManifestText(StreamState state)
@@ -583,10 +584,19 @@ namespace MediaBrowser.Api.Playback.Hls
{
var codec = state.OutputVideoCodec;
+ var args = "-codec:v:0 " + codec;
+
+ if (state.EnableMpegtsM2TsMode)
+ {
+ args += " -mpegts_m2ts_mode 1";
+ }
+
// See if we can save come cpu cycles by avoiding encoding
if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
{
- return IsH264(state.VideoStream) ? "-codec:v:0 copy -bsf:v h264_mp4toannexb" : "-codec:v:0 copy";
+ return state.VideoStream != null && IsH264(state.VideoStream) ?
+ args + " -bsf:v h264_mp4toannexb" :
+ args;
}
var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})",
@@ -594,7 +604,7 @@ namespace MediaBrowser.Api.Playback.Hls
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;
- var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, "libx264", true) + keyFrameArg;
+ args+= " " + GetVideoQualityParam(state, H264Encoder, true) + keyFrameArg;
args += " -r 24 -g 24";
@@ -627,7 +637,7 @@ namespace MediaBrowser.Api.Playback.Hls
var segmentFilename = Path.GetFileNameWithoutExtension(outputPath) + "%03d" + GetSegmentFileExtension(state);
- var args = string.Format("{0} -i {1} -map_metadata -1 -threads {2} {3} {4} -copyts {5} -f ssegment -segment_time {6} -segment_list_size {8} -segment_list \"{9}\" {10}",
+ var args = string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -copyts {5} -f ssegment -segment_time {6} -segment_list_size {8} -segment_list \"{9}\" {10}",
inputModifier,
GetInputArgument(transcodingJobId, state),
threads,
diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
index 06fa4065c2..d786b51b3a 100644
--- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
@@ -5,12 +5,11 @@ using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.MediaEncoding;
+using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.IO;
using ServiceStack;
using System;
using System.IO;
-using System.Linq;
-using System.Threading.Tasks;
namespace MediaBrowser.Api.Playback.Hls
{
@@ -72,7 +71,7 @@ namespace MediaBrowser.Api.Playback.Hls
{
var file = request.SegmentId + Path.GetExtension(Request.PathInfo);
- file = Path.Combine(ServerConfigurationManager.ApplicationPaths.TranscodingTempPath, file);
+ file = Path.Combine(ServerConfigurationManager.ApplicationPaths.TranscodingTempPath, EncodingContext.Streaming.ToString().ToLower(), file);
return ResultFactory.GetStaticFileResult(Request, file);
}
@@ -136,18 +135,27 @@ namespace MediaBrowser.Api.Playback.Hls
{
var codec = state.OutputVideoCodec;
+ var args = "-codec:v:0 " + codec;
+
+ if (state.EnableMpegtsM2TsMode)
+ {
+ args += " -mpegts_m2ts_mode 1";
+ }
+
// See if we can save come cpu cycles by avoiding encoding
if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
{
- return state.VideoStream != null && IsH264(state.VideoStream) ? "-codec:v:0 copy -bsf:v h264_mp4toannexb" : "-codec:v:0 copy";
+ return state.VideoStream != null && IsH264(state.VideoStream) ?
+ args + " -bsf:v h264_mp4toannexb" :
+ args;
}
-
+
var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})",
state.SegmentLength.ToString(UsCulture));
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;
- var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, "libx264", true) + keyFrameArg;
+ args += " " + GetVideoQualityParam(state, H264Encoder, true) + keyFrameArg;
// Add resolution params, if specified
if (!hasGraphicalSubs)
diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
index ae592c428a..725526ecdc 100644
--- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
@@ -82,7 +82,7 @@ namespace MediaBrowser.Api.Playback.Progressive
var inputModifier = GetInputModifier(state);
- return string.Format("{0} -i {1} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1 -y \"{5}\"",
+ return string.Format("{0} {1} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1 -y \"{5}\"",
inputModifier,
GetInputArgument(transcodingJobId, state),
threads,
diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
index a64866d68a..5ef72a4952 100644
--- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
@@ -103,7 +103,7 @@ namespace MediaBrowser.Api.Playback.Progressive
var inputModifier = GetInputModifier(state);
- return string.Format("{0} -i {1}{2} {3} {4} -map_metadata -1 -threads {5} {6}{7} -y \"{8}\"",
+ return string.Format("{0} {1}{2} {3} {4} -map_metadata -1 -threads {5} {6}{7} -y \"{8}\"",
inputModifier,
GetInputArgument(transcodingJobId, state),
keyFrame,
@@ -124,7 +124,7 @@ namespace MediaBrowser.Api.Playback.Progressive
/// <returns>System.String.</returns>
private string GetVideoArguments(StreamState state, string codec)
{
- var args = "-vcodec " + codec;
+ var args = "-codec:v:0 " + codec;
if (state.EnableMpegtsM2TsMode)
{
@@ -134,7 +134,9 @@ namespace MediaBrowser.Api.Playback.Progressive
// See if we can save come cpu cycles by avoiding encoding
if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
{
- return state.VideoStream != null && IsH264(state.VideoStream) ? args + " -bsf:v h264_mp4toannexb" : args;
+ return state.VideoStream != null && IsH264(state.VideoStream) && string.Equals(state.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) ?
+ args + " -bsf:v h264_mp4toannexb" :
+ args;
}
var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})",
@@ -182,13 +184,13 @@ namespace MediaBrowser.Api.Playback.Progressive
// Get the output codec name
var codec = state.OutputAudioCodec;
+ var args = "-codec:a:0 " + codec;
+
if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
{
- return "-acodec copy";
+ return args;
}
- var args = "-acodec " + codec;
-
// Add the number of audio channels
var channels = state.OutputAudioChannels;
diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs
index d26259a3ae..40e765f1ae 100644
--- a/MediaBrowser.Api/Playback/StreamState.cs
+++ b/MediaBrowser.Api/Playback/StreamState.cs
@@ -11,6 +11,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Threading;
+using MediaBrowser.Model.Net;
namespace MediaBrowser.Api.Playback
{
diff --git a/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs b/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs
index f34c53b168..cb8f91ab6e 100644
--- a/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs
+++ b/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Common.Net;
using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Tasks;
diff --git a/MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs b/MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs
index e6b525e534..25130776ee 100644
--- a/MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs
+++ b/MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Session;
diff --git a/MediaBrowser.Api/Session/SessionsService.cs b/MediaBrowser.Api/Session/SessionsService.cs
index d2881893ba..59b8e85c22 100644
--- a/MediaBrowser.Api/Session/SessionsService.cs
+++ b/MediaBrowser.Api/Session/SessionsService.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Devices;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Security;
using MediaBrowser.Controller.Session;
@@ -299,6 +300,7 @@ namespace MediaBrowser.Api.Session
private readonly IUserManager _userManager;
private readonly IAuthorizationContext _authContext;
private readonly IAuthenticationRepository _authRepo;
+ private readonly IDeviceManager _deviceManager;
/// <summary>
/// Initializes a new instance of the <see cref="SessionsService" /> class.
@@ -307,12 +309,13 @@ namespace MediaBrowser.Api.Session
/// <param name="userManager">The user manager.</param>
/// <param name="authContext">The authentication context.</param>
/// <param name="authRepo">The authentication repo.</param>
- public SessionsService(ISessionManager sessionManager, IUserManager userManager, IAuthorizationContext authContext, IAuthenticationRepository authRepo)
+ public SessionsService(ISessionManager sessionManager, IUserManager userManager, IAuthorizationContext authContext, IAuthenticationRepository authRepo, IDeviceManager deviceManager)
{
_sessionManager = sessionManager;
_userManager = userManager;
_authContext = authContext;
_authRepo = authRepo;
+ _deviceManager = deviceManager;
}
public void Delete(RevokeKey request)
@@ -373,15 +376,30 @@ namespace MediaBrowser.Api.Session
var user = _userManager.GetUserById(request.ControllableByUserId.Value);
- if (!user.Configuration.EnableRemoteControlOfOtherUsers)
+ if (!user.Policy.EnableRemoteControlOfOtherUsers)
{
result = result.Where(i => i.ContainsUser(request.ControllableByUserId.Value));
}
- if (!user.Configuration.EnableSharedDeviceControl)
+ if (!user.Policy.EnableSharedDeviceControl)
{
result = result.Where(i => !i.UserId.HasValue);
}
+
+ result = result.Where(i =>
+ {
+ var deviceId = i.DeviceId;
+
+ if (!string.IsNullOrWhiteSpace(deviceId))
+ {
+ if (!_deviceManager.CanAccessDevice(user.Id.ToString("N"), deviceId))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ });
}
return ToOptimizedResult(result.Select(_sessionManager.GetSessionInfoDto).ToList());
diff --git a/MediaBrowser.Api/Subtitles/SubtitleService.cs b/MediaBrowser.Api/Subtitles/SubtitleService.cs
index a2a93d50e3..32e6ba076d 100644
--- a/MediaBrowser.Api/Subtitles/SubtitleService.cs
+++ b/MediaBrowser.Api/Subtitles/SubtitleService.cs
@@ -15,6 +15,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
namespace MediaBrowser.Api.Subtitles
{
@@ -175,7 +176,7 @@ namespace MediaBrowser.Api.Subtitles
builder.AppendLine("#EXT-X-ENDLIST");
- return ResultFactory.GetResult(builder.ToString(), Common.Net.MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
+ return ResultFactory.GetResult(builder.ToString(), MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
}
public object Get(GetSubtitle request)
@@ -199,7 +200,7 @@ namespace MediaBrowser.Api.Subtitles
var stream = GetSubtitles(request).Result;
- return ResultFactory.GetResult(stream, Common.Net.MimeTypes.GetMimeType("file." + request.Format));
+ return ResultFactory.GetResult(stream, MimeTypes.GetMimeType("file." + request.Format));
}
private async Task<Stream> GetSubtitles(GetSubtitle request)
@@ -240,7 +241,7 @@ namespace MediaBrowser.Api.Subtitles
{
var result = _subtitleManager.GetRemoteSubtitles(request.Id, CancellationToken.None).Result;
- return ResultFactory.GetResult(result.Stream, Common.Net.MimeTypes.GetMimeType("file." + result.Format));
+ return ResultFactory.GetResult(result.Stream, MimeTypes.GetMimeType("file." + result.Format));
}
public void Post(DownloadRemoteSubtitles request)
diff --git a/MediaBrowser.Api/Sync/SyncService.cs b/MediaBrowser.Api/Sync/SyncService.cs
index cefb0e46e8..a7467c12f1 100644
--- a/MediaBrowser.Api/Sync/SyncService.cs
+++ b/MediaBrowser.Api/Sync/SyncService.cs
@@ -5,6 +5,7 @@ using MediaBrowser.Controller.Sync;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Sync;
+using MediaBrowser.Model.Users;
using ServiceStack;
using System;
using System.Collections.Generic;
@@ -27,6 +28,11 @@ namespace MediaBrowser.Api.Sync
public string Id { get; set; }
}
+ [Route("/Sync/Jobs/{Id}", "POST", Summary = "Updates a sync job.")]
+ public class UpdateSyncJob : SyncJob, IReturnVoid
+ {
+ }
+
[Route("/Sync/JobItems", "GET", Summary = "Gets sync job items.")]
public class GetSyncJobItems : SyncJobItemQuery, IReturn<QueryResult<SyncJobItem>>
{
@@ -55,8 +61,14 @@ namespace MediaBrowser.Api.Sync
[ApiMember(Name = "UserId", Description = "UserId", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
public string UserId { get; set; }
- [ApiMember(Name = "ItemIds", Description = "ItemIds", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+ [ApiMember(Name = "ItemIds", Description = "ItemIds", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string ItemIds { get; set; }
+
+ [ApiMember(Name = "ParentId", Description = "ParentId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string ParentId { get; set; }
+
+ [ApiMember(Name = "Category", Description = "Category", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public SyncCategory? Category { get; set; }
}
[Route("/Sync/JobItems/{Id}/Transferred", "POST", Summary = "Reports that a sync job item has successfully been transferred.")]
@@ -73,6 +85,23 @@ namespace MediaBrowser.Api.Sync
public string Id { get; set; }
}
+ [Route("/Sync/OfflineActions", "POST", Summary = "Reports an action that occurred while offline.")]
+ public class ReportOfflineActions : List<UserAction>, IReturnVoid
+ {
+ }
+
+ [Route("/Sync/Items/Ready", "GET", Summary = "Gets ready to download sync items.")]
+ public class GetReadySyncItems : IReturn<List<SyncedItem>>
+ {
+ [ApiMember(Name = "TargetId", Description = "TargetId", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string TargetId { get; set; }
+ }
+
+ [Route("/Sync/Data", "POST", Summary = "Syncs data between device and server")]
+ public class SyncData : SyncDataRequest, IReturn<SyncDataResponse>
+ {
+ }
+
[Authenticated]
public class SyncService : BaseApiService
{
@@ -94,9 +123,9 @@ namespace MediaBrowser.Api.Sync
return ToOptimizedResult(result);
}
- public object Get(GetSyncJobs request)
+ public async Task<object> Get(GetSyncJobs request)
{
- var result = _syncManager.GetJobs(request);
+ var result = await _syncManager.GetJobs(request).ConfigureAwait(false);
return ToOptimizedResult(result);
}
@@ -155,21 +184,64 @@ namespace MediaBrowser.Api.Sync
result.Targets = _syncManager.GetSyncTargets(request.UserId)
.ToList();
- var dtos = request.ItemIds.Split(',')
- .Select(_libraryManager.GetItemById)
- .Where(i => i != null)
- .Select(i => _dtoService.GetBaseItemDto(i, new DtoOptions
+ if (request.Category.HasValue)
+ {
+ result.Options = SyncHelper.GetSyncOptions(request.Category.Value);
+ }
+ else
+ {
+ var dtoOptions = new DtoOptions
{
Fields = new List<ItemFields>
{
ItemFields.SyncInfo
}
- }))
- .ToList();
+ };
- result.Options = SyncHelper.GetSyncOptions(dtos);
+ var dtos = request.ItemIds.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
+ .Select(_libraryManager.GetItemById)
+ .Where(i => i != null)
+ .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions))
+ .ToList();
+
+ result.Options = SyncHelper.GetSyncOptions(dtos);
+ }
return ToOptimizedResult(result);
}
+
+ public void Post(ReportOfflineActions request)
+ {
+ var task = PostAsync(request);
+
+ Task.WaitAll(task);
+ }
+
+ public async Task PostAsync(ReportOfflineActions request)
+ {
+ foreach (var action in request)
+ {
+ await _syncManager.ReportOfflineAction(action).ConfigureAwait(false);
+ }
+ }
+
+ public object Get(GetReadySyncItems request)
+ {
+ return ToOptimizedResult(_syncManager.GetReadySyncItems(request.TargetId));
+ }
+
+ public async Task<object> Post(SyncData request)
+ {
+ var response = await _syncManager.SyncData(request).ConfigureAwait(false);
+
+ return ToOptimizedResult(response);
+ }
+
+ public void Post(UpdateSyncJob request)
+ {
+ var task = _syncManager.UpdateJob(request);
+
+ Task.WaitAll(task);
+ }
}
}
diff --git a/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs b/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs
index 4629b2a8ce..a951cd3d68 100644
--- a/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs
+++ b/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs
@@ -1,5 +1,5 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Activity;
+using MediaBrowser.Controller.Activity;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Activity;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Logging;
diff --git a/MediaBrowser.Api/System/SystemInfoWebSocketListener.cs b/MediaBrowser.Api/System/SystemInfoWebSocketListener.cs
index c20cef3b38..49a3e3291e 100644
--- a/MediaBrowser.Api/System/SystemInfoWebSocketListener.cs
+++ b/MediaBrowser.Api/System/SystemInfoWebSocketListener.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.System;
using System.Threading.Tasks;
diff --git a/MediaBrowser.Api/UserLibrary/ArtistsService.cs b/MediaBrowser.Api/UserLibrary/ArtistsService.cs
index 2299b2b1aa..1284232388 100644
--- a/MediaBrowser.Api/UserLibrary/ArtistsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ArtistsService.cs
@@ -83,17 +83,16 @@ namespace MediaBrowser.Api.UserLibrary
{
var item = GetArtist(request.Name, LibraryManager);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
+ var dtoOptions = new DtoOptions();
if (request.UserId.HasValue)
{
var user = UserManager.GetUserById(request.UserId.Value);
-
- return DtoService.GetBaseItemDto(item, fields.ToList(), user);
+
+ return DtoService.GetBaseItemDto(item, dtoOptions, user);
}
- return DtoService.GetBaseItemDto(item, fields.ToList());
+ return DtoService.GetBaseItemDto(item, dtoOptions);
}
/// <summary>
diff --git a/MediaBrowser.Api/UserLibrary/GameGenresService.cs b/MediaBrowser.Api/UserLibrary/GameGenresService.cs
index adc21c362a..2f1c73acef 100644
--- a/MediaBrowser.Api/UserLibrary/GameGenresService.cs
+++ b/MediaBrowser.Api/UserLibrary/GameGenresService.cs
@@ -69,17 +69,16 @@ namespace MediaBrowser.Api.UserLibrary
{
var item = GetGameGenre(request.Name, LibraryManager);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
+ var dtoOptions = new DtoOptions();
if (request.UserId.HasValue)
{
var user = UserManager.GetUserById(request.UserId.Value);
- return DtoService.GetBaseItemDto(item, fields.ToList(), user);
+ return DtoService.GetBaseItemDto(item, dtoOptions, user);
}
- return DtoService.GetBaseItemDto(item, fields.ToList());
+ return DtoService.GetBaseItemDto(item, dtoOptions);
}
/// <summary>
diff --git a/MediaBrowser.Api/UserLibrary/GenresService.cs b/MediaBrowser.Api/UserLibrary/GenresService.cs
index 7b6b18c9ca..db0b0fe612 100644
--- a/MediaBrowser.Api/UserLibrary/GenresService.cs
+++ b/MediaBrowser.Api/UserLibrary/GenresService.cs
@@ -74,17 +74,16 @@ namespace MediaBrowser.Api.UserLibrary
{
var item = GetGenre(request.Name, LibraryManager);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
+ var dtoOptions = new DtoOptions();
if (request.UserId.HasValue)
{
var user = UserManager.GetUserById(request.UserId.Value);
- return DtoService.GetBaseItemDto(item, fields.ToList(), user);
+ return DtoService.GetBaseItemDto(item, dtoOptions, user);
}
- return DtoService.GetBaseItemDto(item, fields.ToList());
+ return DtoService.GetBaseItemDto(item, dtoOptions);
}
/// <summary>
diff --git a/MediaBrowser.Api/UserLibrary/MusicGenresService.cs b/MediaBrowser.Api/UserLibrary/MusicGenresService.cs
index 1088ada023..f8575aa7c7 100644
--- a/MediaBrowser.Api/UserLibrary/MusicGenresService.cs
+++ b/MediaBrowser.Api/UserLibrary/MusicGenresService.cs
@@ -69,17 +69,16 @@ namespace MediaBrowser.Api.UserLibrary
{
var item = GetMusicGenre(request.Name, LibraryManager);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
+ var dtoOptions = new DtoOptions();
if (request.UserId.HasValue)
{
var user = UserManager.GetUserById(request.UserId.Value);
- return DtoService.GetBaseItemDto(item, fields.ToList(), user);
+ return DtoService.GetBaseItemDto(item, dtoOptions, user);
}
- return DtoService.GetBaseItemDto(item, fields.ToList());
+ return DtoService.GetBaseItemDto(item, dtoOptions);
}
/// <summary>
diff --git a/MediaBrowser.Api/UserLibrary/PersonsService.cs b/MediaBrowser.Api/UserLibrary/PersonsService.cs
index dd80801eea..33ce6cd803 100644
--- a/MediaBrowser.Api/UserLibrary/PersonsService.cs
+++ b/MediaBrowser.Api/UserLibrary/PersonsService.cs
@@ -86,17 +86,16 @@ namespace MediaBrowser.Api.UserLibrary
{
var item = GetPerson(request.Name, LibraryManager);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
+ var dtoOptions = new DtoOptions();
if (request.UserId.HasValue)
{
var user = UserManager.GetUserById(request.UserId.Value);
- return DtoService.GetBaseItemDto(item, fields.ToList(), user);
+ return DtoService.GetBaseItemDto(item, dtoOptions, user);
}
- return DtoService.GetBaseItemDto(item, fields.ToList());
+ return DtoService.GetBaseItemDto(item, dtoOptions);
}
/// <summary>
diff --git a/MediaBrowser.Api/UserLibrary/StudiosService.cs b/MediaBrowser.Api/UserLibrary/StudiosService.cs
index 2024d779b7..272134b70f 100644
--- a/MediaBrowser.Api/UserLibrary/StudiosService.cs
+++ b/MediaBrowser.Api/UserLibrary/StudiosService.cs
@@ -73,17 +73,16 @@ namespace MediaBrowser.Api.UserLibrary
{
var item = GetStudio(request.Name, LibraryManager);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
+ var dtoOptions = new DtoOptions();
if (request.UserId.HasValue)
{
var user = UserManager.GetUserById(request.UserId.Value);
- return DtoService.GetBaseItemDto(item, fields.ToList(), user);
+ return DtoService.GetBaseItemDto(item, dtoOptions, user);
}
- return DtoService.GetBaseItemDto(item, fields.ToList());
+ return DtoService.GetBaseItemDto(item, dtoOptions);
}
/// <summary>
diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
index 040cad436e..45a330a501 100644
--- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
+++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
@@ -407,9 +407,6 @@ namespace MediaBrowser.Api.UserLibrary
{
var user = _userManager.GetUserById(request.UserId);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
-
var query = new UserViewQuery
{
UserId = request.UserId
@@ -423,7 +420,9 @@ namespace MediaBrowser.Api.UserLibrary
var folders = await _userViewManager.GetUserViews(query, CancellationToken.None).ConfigureAwait(false);
- var dtos = folders.Select(i => _dtoService.GetBaseItemDto(i, fields, user))
+ var dtoOptions = new DtoOptions();
+
+ var dtos = folders.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
.ToArray();
var result = new QueryResult<BaseItemDto>
@@ -443,14 +442,16 @@ namespace MediaBrowser.Api.UserLibrary
user.RootFolder :
_libraryManager.GetItemById(request.Id);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
-
var series = item as Series;
// Get them from the child tree
if (series != null)
{
+ var dtoOptions = new DtoOptions();
+
+ // Avoid implicitly captured closure
+ var currentUser = user;
+
var dtos = series
.GetRecursiveChildren()
.Where(i => i is Episode && i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == 0)
@@ -468,7 +469,7 @@ namespace MediaBrowser.Api.UserLibrary
return DateTime.MinValue;
})
.ThenBy(i => i.SortName)
- .Select(i => _dtoService.GetBaseItemDto(i, fields, user));
+ .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, currentUser));
return dtos.ToList();
}
@@ -478,10 +479,12 @@ namespace MediaBrowser.Api.UserLibrary
// Get them from the db
if (movie != null)
{
+ var dtoOptions = new DtoOptions();
+
var dtos = movie.SpecialFeatureIds
.Select(_libraryManager.GetItemById)
.OrderBy(i => i.SortName)
- .Select(i => _dtoService.GetBaseItemDto(i, fields, user, item));
+ .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
return dtos.ToList();
}
@@ -507,9 +510,6 @@ namespace MediaBrowser.Api.UserLibrary
var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : _libraryManager.GetItemById(request.Id);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
-
var trailerIds = new List<Guid>();
var hasTrailers = item as IHasTrailers;
@@ -518,10 +518,12 @@ namespace MediaBrowser.Api.UserLibrary
trailerIds = hasTrailers.GetTrailerIds();
}
+ var dtoOptions = new DtoOptions();
+
var dtos = trailerIds
.Select(_libraryManager.GetItemById)
.OrderBy(i => i.SortName)
- .Select(i => _dtoService.GetBaseItemDto(i, fields, user, item));
+ .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
return dtos.ToList();
}
@@ -537,10 +539,9 @@ namespace MediaBrowser.Api.UserLibrary
var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : _libraryManager.GetItemById(request.Id);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
+ var dtoOptions = new DtoOptions();
- var result = _dtoService.GetBaseItemDto(item, fields, user);
+ var result = _dtoService.GetBaseItemDto(item, dtoOptions, user);
return ToOptimizedSerializedResultUsingCache(result);
}
@@ -556,10 +557,9 @@ namespace MediaBrowser.Api.UserLibrary
var item = user.RootFolder;
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
+ var dtoOptions = new DtoOptions();
- var result = _dtoService.GetBaseItemDto(item, fields, user);
+ var result = _dtoService.GetBaseItemDto(item, dtoOptions, user);
return ToOptimizedSerializedResultUsingCache(result);
}
@@ -577,12 +577,9 @@ namespace MediaBrowser.Api.UserLibrary
var items = await _libraryManager.GetIntros(item, user).ConfigureAwait(false);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields))
- .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
- .ToList();
+ var dtoOptions = new DtoOptions();
- var dtos = items.Select(i => _dtoService.GetBaseItemDto(i, fields, user))
+ var dtos = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
.ToArray();
var result = new ItemsResult
diff --git a/MediaBrowser.Api/UserLibrary/YearsService.cs b/MediaBrowser.Api/UserLibrary/YearsService.cs
index 2b300f9003..b1b0aeb636 100644
--- a/MediaBrowser.Api/UserLibrary/YearsService.cs
+++ b/MediaBrowser.Api/UserLibrary/YearsService.cs
@@ -73,17 +73,16 @@ namespace MediaBrowser.Api.UserLibrary
{
var item = LibraryManager.GetYear(request.Year);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
+ var dtoOptions = new DtoOptions();
if (request.UserId.HasValue)
{
var user = UserManager.GetUserById(request.UserId.Value);
- return DtoService.GetBaseItemDto(item, fields.ToList(), user);
+ return DtoService.GetBaseItemDto(item, dtoOptions, user);
}
- return DtoService.GetBaseItemDto(item, fields.ToList());
+ return DtoService.GetBaseItemDto(item, dtoOptions);
}
/// <summary>
diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs
index 4b720c775c..51a7584b8d 100644
--- a/MediaBrowser.Api/UserService.cs
+++ b/MediaBrowser.Api/UserService.cs
@@ -1,10 +1,12 @@
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Connect;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Users;
@@ -51,7 +53,7 @@ namespace MediaBrowser.Api
/// </summary>
/// <value>The id.</value>
[ApiMember(Name = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public Guid Id { get; set; }
+ public string Id { get; set; }
}
/// <summary>
@@ -66,7 +68,7 @@ namespace MediaBrowser.Api
/// </summary>
/// <value>The id.</value>
[ApiMember(Name = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
- public Guid Id { get; set; }
+ public string Id { get; set; }
}
/// <summary>
@@ -80,7 +82,7 @@ namespace MediaBrowser.Api
/// </summary>
/// <value>The id.</value>
[ApiMember(Name = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public Guid Id { get; set; }
+ public string Id { get; set; }
/// <summary>
/// Gets or sets the password.
@@ -125,7 +127,7 @@ namespace MediaBrowser.Api
/// Gets or sets the id.
/// </summary>
/// <value>The id.</value>
- public Guid Id { get; set; }
+ public string Id { get; set; }
/// <summary>
/// Gets or sets the password.
@@ -156,6 +158,28 @@ namespace MediaBrowser.Api
}
/// <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 string 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 string Id { get; set; }
+ }
+
+ /// <summary>
/// Class CreateUser
/// </summary>
[Route("/Users/New", "POST", Summary = "Creates a user")]
@@ -193,22 +217,18 @@ namespace MediaBrowser.Api
private readonly ISessionManager _sessionMananger;
private readonly IServerConfigurationManager _config;
private readonly INetworkManager _networkManager;
+ private readonly IDeviceManager _deviceManager;
public IAuthorizationContext AuthorizationContext { get; set; }
- /// <summary>
- /// Initializes a new instance of the <see cref="UserService" /> class.
- /// </summary>
- /// <param name="userManager">The user manager.</param>
- /// <param name="dtoService">The dto service.</param>
- /// <param name="sessionMananger">The session mananger.</param>
- public UserService(IUserManager userManager, IDtoService dtoService, ISessionManager sessionMananger, IServerConfigurationManager config, INetworkManager networkManager)
+ public UserService(IUserManager userManager, IDtoService dtoService, ISessionManager sessionMananger, IServerConfigurationManager config, INetworkManager networkManager, IDeviceManager deviceManager)
{
_userManager = userManager;
_dtoService = dtoService;
_sessionMananger = sessionMananger;
_config = config;
_networkManager = networkManager;
+ _deviceManager = deviceManager;
}
public object Get(GetPublicUsers request)
@@ -222,18 +242,12 @@ namespace MediaBrowser.Api
});
}
- // TODO: Uncomment once clients can handle an empty user list (and below)
- //if (Request.IsLocal || IsInLocalNetwork(Request.RemoteIp))
+ return Get(new GetUsers
{
- return Get(new GetUsers
- {
- IsHidden = false,
- IsDisabled = false
- });
- }
+ IsHidden = false,
+ IsDisabled = false
- //// Return empty when external
- //return ToOptimizedResult(new List<UserDto>());
+ }, true);
}
/// <summary>
@@ -243,24 +257,38 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns>
public object Get(GetUsers request)
{
+ return Get(request, false);
+ }
+
+ private object Get(GetUsers request, bool filterByDevice)
+ {
var users = _userManager.Users;
if (request.IsDisabled.HasValue)
{
- users = users.Where(i => i.Configuration.IsDisabled == request.IsDisabled.Value);
+ users = users.Where(i => i.Policy.IsDisabled == request.IsDisabled.Value);
}
if (request.IsHidden.HasValue)
{
- users = users.Where(i => i.Configuration.IsHidden == request.IsHidden.Value);
+ users = users.Where(i => i.Policy.IsHidden == request.IsHidden.Value);
}
if (request.IsGuest.HasValue)
{
-
users = users.Where(i => (i.ConnectLinkType.HasValue && i.ConnectLinkType.Value == UserLinkType.Guest) == request.IsGuest.Value);
}
+ if (filterByDevice)
+ {
+ var deviceId = AuthorizationContext.GetAuthorizationInfo(Request).DeviceId;
+
+ if (!string.IsNullOrWhiteSpace(deviceId))
+ {
+ users = users.Where(i => _deviceManager.CanAccessDevice(i.Id.ToString("N"), deviceId));
+ }
+ }
+
var result = users
.OrderBy(u => u.Name)
.Select(i => _userManager.GetUserDto(i, Request.RemoteIp))
@@ -428,39 +456,13 @@ namespace MediaBrowser.Api
var user = _userManager.GetUserById(id);
- // If removing admin access
- if (!dtoUser.Configuration.IsAdministrator && user.Configuration.IsAdministrator)
- {
- if (_userManager.Users.Count(i => i.Configuration.IsAdministrator) == 1)
- {
- throw new ArgumentException("There must be at least one user in the system with administrative access.");
- }
- }
-
- // If disabling
- if (dtoUser.Configuration.IsDisabled && user.Configuration.IsAdministrator)
- {
- throw new ArgumentException("Administrators cannot be disabled.");
- }
-
- // If disabling
- if (dtoUser.Configuration.IsDisabled && !user.Configuration.IsDisabled)
- {
- if (_userManager.Users.Count(i => !i.Configuration.IsDisabled) == 1)
- {
- throw new ArgumentException("There must be at least one enabled user in the system.");
- }
-
- await _sessionMananger.RevokeUserTokens(user.Id.ToString("N")).ConfigureAwait(false);
- }
-
var task = user.Name.Equals(dtoUser.Name, StringComparison.Ordinal) ?
_userManager.UpdateUser(user) :
_userManager.RenameUser(user, dtoUser.Name);
await task.ConfigureAwait(false);
- user.UpdateConfiguration(dtoUser.Configuration);
+ await _userManager.UpdateConfiguration(dtoUser.Id, dtoUser.Configuration);
}
/// <summary>
@@ -495,5 +497,51 @@ namespace MediaBrowser.Api
{
return _userManager.RedeemPasswordResetPin(request.Pin);
}
+
+ public void Post(UpdateUserConfiguration request)
+ {
+ var task = _userManager.UpdateConfiguration(request.Id, request);
+
+ Task.WaitAll(task);
+ }
+
+ public void Post(UpdateUserPolicy request)
+ {
+ var task = UpdateUserPolicy(request);
+ Task.WaitAll(task);
+ }
+
+ private async Task UpdateUserPolicy(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.");
+ }
+
+ await _sessionMananger.RevokeUserTokens(user.Id.ToString("N")).ConfigureAwait(false);
+ }
+
+ await _userManager.UpdateUserPolicy(request.Id, request).ConfigureAwait(false);
+ }
}
}
diff --git a/MediaBrowser.Api/VideosService.cs b/MediaBrowser.Api/VideosService.cs
index fbf9cec2e7..28db46b986 100644
--- a/MediaBrowser.Api/VideosService.cs
+++ b/MediaBrowser.Api/VideosService.cs
@@ -5,6 +5,7 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying;
using ServiceStack;
using System;
@@ -79,15 +80,12 @@ namespace MediaBrowser.Api
: _libraryManager.RootFolder)
: _libraryManager.GetItemById(request.Id);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields))
- .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
- .ToList();
+ var dtoOptions = new DtoOptions();
var video = (Video)item;
var items = video.GetAdditionalParts()
- .Select(i => _dtoService.GetBaseItemDto(i, fields, user, video))
+ .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, video))
.ToArray();
var result = new ItemsResult
@@ -114,11 +112,11 @@ namespace MediaBrowser.Api
{
link.PrimaryVersionId = null;
- await link.UpdateToRepository(ItemUpdateType.MetadataDownload, CancellationToken.None).ConfigureAwait(false);
+ await link.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
}
video.LinkedAlternateVersions.Clear();
- await video.UpdateToRepository(ItemUpdateType.MetadataDownload, CancellationToken.None).ConfigureAwait(false);
+ await video.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
}
public void Post(MergeVersions request)
@@ -186,7 +184,7 @@ namespace MediaBrowser.Api
{
item.PrimaryVersionId = primaryVersion.Id;
- await item.UpdateToRepository(ItemUpdateType.MetadataDownload, CancellationToken.None).ConfigureAwait(false);
+ await item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
primaryVersion.LinkedAlternateVersions.Add(new LinkedChild
{
@@ -195,7 +193,7 @@ namespace MediaBrowser.Api
});
}
- await primaryVersion.UpdateToRepository(ItemUpdateType.MetadataDownload, CancellationToken.None).ConfigureAwait(false);
+ await primaryVersion.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
}
}
}