aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Api
diff options
context:
space:
mode:
authortikuf <admin@nyalindee.com>2014-03-29 21:34:16 +1100
committertikuf <admin@nyalindee.com>2014-03-29 21:34:16 +1100
commit241be6dd93f6e0ec96ef88f0182b8985eb275995 (patch)
treeac42c23908911099ebc2840bc6b9549de565bab6 /MediaBrowser.Api
parent520b77a098a5f3755c098636821a7ff3742a055f (diff)
parent5e5b1f180c2a13152c8f318f045547c6508c5b3e (diff)
Merge branch 'master' of https://github.com/MediaBrowser/MediaBrowser
Diffstat (limited to 'MediaBrowser.Api')
-rw-r--r--MediaBrowser.Api/AppThemeService.cs14
-rw-r--r--MediaBrowser.Api/BaseApiService.cs15
-rw-r--r--MediaBrowser.Api/ChannelService.cs6
-rw-r--r--MediaBrowser.Api/ConfigurationService.cs15
-rw-r--r--MediaBrowser.Api/DisplayPreferencesService.cs6
-rw-r--r--MediaBrowser.Api/DlnaService.cs90
-rw-r--r--MediaBrowser.Api/EnvironmentService.cs15
-rw-r--r--MediaBrowser.Api/GamesService.cs15
-rw-r--r--MediaBrowser.Api/Images/ImageService.cs10
-rw-r--r--MediaBrowser.Api/Library/LibraryService.cs12
-rw-r--r--MediaBrowser.Api/LiveTv/LiveTvService.cs72
-rw-r--r--MediaBrowser.Api/MediaBrowser.Api.csproj2
-rw-r--r--MediaBrowser.Api/Movies/MoviesService.cs6
-rw-r--r--MediaBrowser.Api/Movies/TrailersService.cs3
-rw-r--r--MediaBrowser.Api/Music/InstantMixService.cs12
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs275
-rw-r--r--MediaBrowser.Api/Playback/Hls/BaseHlsService.cs6
-rw-r--r--MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs4
-rw-r--r--MediaBrowser.Api/Playback/Hls/VideoHlsService.cs3
-rw-r--r--MediaBrowser.Api/Playback/Progressive/AudioService.cs37
-rw-r--r--MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs138
-rw-r--r--MediaBrowser.Api/Playback/Progressive/VideoService.cs8
-rw-r--r--MediaBrowser.Api/Playback/StreamRequest.cs3
-rw-r--r--MediaBrowser.Api/Playback/StreamState.cs14
-rw-r--r--MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs17
-rw-r--r--MediaBrowser.Api/UserLibrary/ItemsService.cs5
-rw-r--r--MediaBrowser.Api/UserLibrary/StudiosService.cs7
-rw-r--r--MediaBrowser.Api/UserLibrary/UserLibraryService.cs19
-rw-r--r--MediaBrowser.Api/WebSocket/SessionInfoWebSocketListener.cs2
29 files changed, 503 insertions, 328 deletions
diff --git a/MediaBrowser.Api/AppThemeService.cs b/MediaBrowser.Api/AppThemeService.cs
index 54141b3e22..4d8eed7ddb 100644
--- a/MediaBrowser.Api/AppThemeService.cs
+++ b/MediaBrowser.Api/AppThemeService.cs
@@ -9,16 +9,14 @@ using System.Linq;
namespace MediaBrowser.Api
{
- [Route("/Themes", "GET")]
- [Api(Description = "Gets a list of available themes for an app")]
+ [Route("/Themes", "GET", Summary = "Gets a list of available themes for an app")]
public class GetAppThemes : IReturn<List<AppThemeInfo>>
{
[ApiMember(Name = "App", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
public string App { get; set; }
}
- [Route("/Themes/Info", "GET")]
- [Api(Description = "Gets an app theme")]
+ [Route("/Themes/Info", "GET", Summary = "Gets an app theme")]
public class GetAppTheme : IReturn<AppTheme>
{
[ApiMember(Name = "App", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
@@ -28,8 +26,7 @@ namespace MediaBrowser.Api
public string Name { get; set; }
}
- [Route("/Themes/Images", "GET")]
- [Api(Description = "Gets an app theme")]
+ [Route("/Themes/Images", "GET", Summary = "Gets an app theme")]
public class GetAppThemeImage
{
[ApiMember(Name = "App", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
@@ -45,12 +42,11 @@ namespace MediaBrowser.Api
public string CacheTag { get; set; }
}
- [Route("/Themes", "POST")]
- [Api(Description = "Saves a theme")]
+ [Route("/Themes", "POST", Summary = "Saves a theme")]
public class SaveTheme : AppTheme, IReturnVoid
{
}
-
+
public class AppThemeService : BaseApiService
{
private readonly IAppThemeManager _themeManager;
diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs
index 08686b43a8..707cfb4572 100644
--- a/MediaBrowser.Api/BaseApiService.cs
+++ b/MediaBrowser.Api/BaseApiService.cs
@@ -2,6 +2,7 @@
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
+using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Logging;
using ServiceStack.Web;
using System;
@@ -79,6 +80,20 @@ namespace MediaBrowser.Api
}
/// <summary>
+ /// Gets the session.
+ /// </summary>
+ /// <param name="sessionManager">The session manager.</param>
+ /// <returns>SessionInfo.</returns>
+ protected SessionInfo GetSession(ISessionManager sessionManager)
+ {
+ var auth = AuthorizationRequestFilterAttribute.GetAuthorization(Request);
+
+ return sessionManager.Sessions.First(i => string.Equals(i.DeviceId, auth.DeviceId) &&
+ string.Equals(i.Client, auth.Client) &&
+ string.Equals(i.ApplicationVersion, auth.Version));
+ }
+
+ /// <summary>
/// To the cached result.
/// </summary>
/// <typeparam name="T"></typeparam>
diff --git a/MediaBrowser.Api/ChannelService.cs b/MediaBrowser.Api/ChannelService.cs
index c1724571ae..ed203a0f45 100644
--- a/MediaBrowser.Api/ChannelService.cs
+++ b/MediaBrowser.Api/ChannelService.cs
@@ -7,8 +7,7 @@ using System.Threading;
namespace MediaBrowser.Api
{
- [Route("/Channels", "GET")]
- [Api(("Gets available channels"))]
+ [Route("/Channels", "GET", Summary = "Gets available channels")]
public class GetChannels : IReturn<QueryResult<BaseItemDto>>
{
public string UserId { get; set; }
@@ -18,8 +17,7 @@ namespace MediaBrowser.Api
public int? Limit { get; set; }
}
- [Route("/Channels/{Id}/Items", "GET")]
- [Api(("Gets channel items"))]
+ [Route("/Channels/{Id}/Items", "GET", Summary = "Gets channel items")]
public class GetChannelItems : IReturn<QueryResult<BaseItemDto>>
{
public string Id { get; set; }
diff --git a/MediaBrowser.Api/ConfigurationService.cs b/MediaBrowser.Api/ConfigurationService.cs
index 6007043503..b3191cd4b9 100644
--- a/MediaBrowser.Api/ConfigurationService.cs
+++ b/MediaBrowser.Api/ConfigurationService.cs
@@ -17,8 +17,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class GetConfiguration
/// </summary>
- [Route("/System/Configuration", "GET")]
- [Api(("Gets application configuration"))]
+ [Route("/System/Configuration", "GET", Summary = "Gets application configuration")]
public class GetConfiguration : IReturn<ServerConfiguration>
{
@@ -27,28 +26,24 @@ namespace MediaBrowser.Api
/// <summary>
/// Class UpdateConfiguration
/// </summary>
- [Route("/System/Configuration", "POST")]
- [Api(("Updates application configuration"))]
+ [Route("/System/Configuration", "POST", Summary = "Updates application configuration")]
public class UpdateConfiguration : ServerConfiguration, IReturnVoid
{
}
- [Route("/System/Configuration/MetadataOptions/Default", "GET")]
- [Api(("Gets a default MetadataOptions object"))]
+ [Route("/System/Configuration/MetadataOptions/Default", "GET", Summary = "Gets a default MetadataOptions object")]
public class GetDefaultMetadataOptions : IReturn<MetadataOptions>
{
}
- [Route("/System/Configuration/MetadataPlugins", "GET")]
- [Api(("Gets all available metadata plugins"))]
+ [Route("/System/Configuration/MetadataPlugins", "GET", Summary = "Gets all available metadata plugins")]
public class GetMetadataPlugins : IReturn<List<MetadataPluginSummary>>
{
}
- [Route("/System/Configuration/VideoImageExtraction", "POST")]
- [Api(("Updates image extraction for all types"))]
+ [Route("/System/Configuration/VideoImageExtraction", "POST", Summary = "Updates image extraction for all types")]
public class UpdateVideoImageExtraction : IReturnVoid
{
public bool Enabled { get; set; }
diff --git a/MediaBrowser.Api/DisplayPreferencesService.cs b/MediaBrowser.Api/DisplayPreferencesService.cs
index f22dc9e39e..4060b42b49 100644
--- a/MediaBrowser.Api/DisplayPreferencesService.cs
+++ b/MediaBrowser.Api/DisplayPreferencesService.cs
@@ -12,8 +12,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class UpdateDisplayPreferences
/// </summary>
- [Route("/DisplayPreferences/{DisplayPreferencesId}", "POST")]
- [Api(("Updates a user's display preferences for an item"))]
+ [Route("/DisplayPreferences/{DisplayPreferencesId}", "POST", Summary = "Updates a user's display preferences for an item")]
public class UpdateDisplayPreferences : DisplayPreferences, IReturnVoid
{
/// <summary>
@@ -30,8 +29,7 @@ namespace MediaBrowser.Api
public string Client { get; set; }
}
- [Route("/DisplayPreferences/{Id}", "GET")]
- [Api(("Gets a user's display preferences for an item"))]
+ [Route("/DisplayPreferences/{Id}", "GET", Summary = "Gets a user's display preferences for an item")]
public class GetDisplayPreferences : IReturn<DisplayPreferences>
{
/// <summary>
diff --git a/MediaBrowser.Api/DlnaService.cs b/MediaBrowser.Api/DlnaService.cs
new file mode 100644
index 0000000000..792a7ff43f
--- /dev/null
+++ b/MediaBrowser.Api/DlnaService.cs
@@ -0,0 +1,90 @@
+using MediaBrowser.Controller.Dlna;
+using MediaBrowser.Model.Dlna;
+using ServiceStack;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace MediaBrowser.Api
+{
+ [Route("/Dlna/ProfileInfos", "GET", Summary = "Gets a list of profiles")]
+ public class GetProfileInfos : IReturn<List<DeviceProfileInfo>>
+ {
+ }
+
+ [Route("/Dlna/Profiles/{Id}", "DELETE", Summary = "Deletes a profile")]
+ public class DeleteProfile : IReturnVoid
+ {
+ [ApiMember(Name = "Id", Description = "Profile Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
+ public string Id { get; set; }
+ }
+
+ [Route("/Dlna/Profiles/Default", "GET", Summary = "Gets the default profile")]
+ public class GetDefaultProfile : IReturn<DeviceProfile>
+ {
+ }
+
+ [Route("/Dlna/Profiles/{Id}", "GET", Summary = "Gets a single profile")]
+ public class GetProfile : IReturn<DeviceProfile>
+ {
+ [ApiMember(Name = "Id", Description = "Profile Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string Id { get; set; }
+ }
+
+ [Route("/Dlna/Profiles/{ProfileId}", "POST", Summary = "Updates a profile")]
+ public class UpdateProfile : DeviceProfile, IReturnVoid
+ {
+ [ApiMember(Name = "ProfileId", Description = "Profile Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string ProfileId { get; set; }
+ }
+
+ [Route("/Dlna/Profiles", "POST", Summary = "Creates a profile")]
+ public class CreateProfile : DeviceProfile, IReturnVoid
+ {
+ }
+
+ public class DlnaService : BaseApiService
+ {
+ private readonly IDlnaManager _dlnaManager;
+
+ public DlnaService(IDlnaManager dlnaManager)
+ {
+ _dlnaManager = dlnaManager;
+ }
+
+ public object Get(GetProfileInfos request)
+ {
+ var result = _dlnaManager.GetProfileInfos().ToList();
+
+ return ToOptimizedResult(result);
+ }
+
+ public object Get(GetProfile request)
+ {
+ var result = _dlnaManager.GetProfile(request.Id);
+
+ return ToOptimizedResult(result);
+ }
+
+ public object Get(GetDefaultProfile request)
+ {
+ var result = _dlnaManager.GetDefaultProfile();
+
+ return ToOptimizedResult(result);
+ }
+
+ public void Delete(DeleteProfile request)
+ {
+ _dlnaManager.DeleteProfile(request.Id);
+ }
+
+ public void Post(UpdateProfile request)
+ {
+ _dlnaManager.UpdateProfile(request);
+ }
+
+ public void Post(CreateProfile request)
+ {
+ _dlnaManager.CreateProfile(request);
+ }
+ }
+}
diff --git a/MediaBrowser.Api/EnvironmentService.cs b/MediaBrowser.Api/EnvironmentService.cs
index cb104072bd..56f71fc00e 100644
--- a/MediaBrowser.Api/EnvironmentService.cs
+++ b/MediaBrowser.Api/EnvironmentService.cs
@@ -13,8 +13,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class GetDirectoryContents
/// </summary>
- [Route("/Environment/DirectoryContents", "GET")]
- [Api(Description = "Gets the contents of a given directory in the file system")]
+ [Route("/Environment/DirectoryContents", "GET", Summary = "Gets the contents of a given directory in the file system")]
public class GetDirectoryContents : IReturn<List<FileSystemEntryInfo>>
{
/// <summary>
@@ -46,8 +45,7 @@ namespace MediaBrowser.Api
public bool IncludeHidden { get; set; }
}
- [Route("/Environment/NetworkShares", "GET")]
- [Api(Description = "Gets shares from a network device")]
+ [Route("/Environment/NetworkShares", "GET", Summary = "Gets shares from a network device")]
public class GetNetworkShares : IReturn<List<FileSystemEntryInfo>>
{
/// <summary>
@@ -61,8 +59,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class GetDrives
/// </summary>
- [Route("/Environment/Drives", "GET")]
- [Api(Description = "Gets available drives from the server's file system")]
+ [Route("/Environment/Drives", "GET", Summary = "Gets available drives from the server's file system")]
public class GetDrives : IReturn<List<FileSystemEntryInfo>>
{
}
@@ -70,14 +67,12 @@ namespace MediaBrowser.Api
/// <summary>
/// Class GetNetworkComputers
/// </summary>
- [Route("/Environment/NetworkDevices", "GET")]
- [Api(Description = "Gets a list of devices on the network")]
+ [Route("/Environment/NetworkDevices", "GET", Summary = "Gets a list of devices on the network")]
public class GetNetworkDevices : IReturn<List<FileSystemEntryInfo>>
{
}
- [Route("/Environment/ParentPath", "GET")]
- [Api(Description = "Gets the parent path of a given path")]
+ [Route("/Environment/ParentPath", "GET", Summary = "Gets the parent path of a given path")]
public class GetParentPath : IReturn<string>
{
/// <summary>
diff --git a/MediaBrowser.Api/GamesService.cs b/MediaBrowser.Api/GamesService.cs
index e371791f81..ff2771ce1b 100644
--- a/MediaBrowser.Api/GamesService.cs
+++ b/MediaBrowser.Api/GamesService.cs
@@ -1,5 +1,4 @@
-using System.Globalization;
-using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
@@ -7,6 +6,7 @@ using MediaBrowser.Model.Dto;
using ServiceStack;
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
@@ -15,8 +15,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class GetSimilarGames
/// </summary>
- [Route("/Games/{Id}/Similar", "GET")]
- [Api(Description = "Finds games similar to a given game.")]
+ [Route("/Games/{Id}/Similar", "GET", Summary = "Finds games similar to a given game.")]
public class GetSimilarGames : BaseGetSimilarItemsFromItem
{
}
@@ -24,8 +23,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class GetGameSystemSummaries
/// </summary>
- [Route("/Games/SystemSummaries", "GET")]
- [Api(Description = "Finds games similar to a given game.")]
+ [Route("/Games/SystemSummaries", "GET", Summary = "Finds games similar to a given game.")]
public class GetGameSystemSummaries : IReturn<List<GameSystemSummary>>
{
/// <summary>
@@ -39,8 +37,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class GetGameSystemSummaries
/// </summary>
- [Route("/Games/PlayerIndex", "GET")]
- [Api(Description = "Gets an index of players (1-x) and the number of games listed under each")]
+ [Route("/Games/PlayerIndex", "GET", Summary = "Gets an index of players (1-x) and the number of games listed under each")]
public class GetPlayerIndex : IReturn<List<ItemIndex>>
{
/// <summary>
@@ -117,7 +114,7 @@ namespace MediaBrowser.Api
}
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
+
public object Get(GetPlayerIndex request)
{
var games = GetAllLibraryItems(request.UserId, _userManager, _libraryManager)
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index 2cdaef1ed8..562da40ee5 100644
--- a/MediaBrowser.Api/Images/ImageService.cs
+++ b/MediaBrowser.Api/Images/ImageService.cs
@@ -15,7 +15,6 @@ using ServiceStack.Text.Controller;
using ServiceStack.Web;
using System;
using System.Collections.Generic;
-using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading;
@@ -776,15 +775,6 @@ namespace MediaBrowser.Api.Images
var bytes = Convert.FromBase64String(text);
- // Validate first
- using (var validationStream = new MemoryStream(bytes))
- {
- // This will throw an exception if it's not a valid image
- using (Image.FromStream(validationStream))
- {
- }
- }
-
var memoryStream = new MemoryStream(bytes)
{
Position = 0
diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs
index dba256418e..533a92fba8 100644
--- a/MediaBrowser.Api/Library/LibraryService.cs
+++ b/MediaBrowser.Api/Library/LibraryService.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Channels;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
@@ -245,12 +246,13 @@ namespace MediaBrowser.Api.Library
private readonly IDtoService _dtoService;
private readonly IChannelManager _channelManager;
+ private readonly ISessionManager _sessionManager;
/// <summary>
/// Initializes a new instance of the <see cref="LibraryService" /> class.
/// </summary>
public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager,
- IDtoService dtoService, IUserDataManager userDataManager, IChannelManager channelManager)
+ IDtoService dtoService, IUserDataManager userDataManager, IChannelManager channelManager, ISessionManager sessionManager)
{
_itemRepo = itemRepo;
_libraryManager = libraryManager;
@@ -258,6 +260,7 @@ namespace MediaBrowser.Api.Library
_dtoService = dtoService;
_userDataManager = userDataManager;
_channelManager = channelManager;
+ _sessionManager = sessionManager;
}
public object Get(GetMediaFolders request)
@@ -504,6 +507,13 @@ namespace MediaBrowser.Api.Library
{
var item = _dtoService.GetItemByDtoId(request.Id);
+ var session = GetSession(_sessionManager);
+
+ if (!session.UserId.HasValue || !_userManager.GetUserById(session.UserId.Value).Configuration.EnableContentDeletion)
+ {
+ throw new UnauthorizedAccessException("This operation requires a logged in user with delete access.");
+ }
+
return _libraryManager.DeleteItem(item);
}
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index 569e4b52b9..96fe01ab32 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -12,14 +12,12 @@ using System.Threading.Tasks;
namespace MediaBrowser.Api.LiveTv
{
- [Route("/LiveTv/Info", "GET")]
- [Api(Description = "Gets available live tv services.")]
+ [Route("/LiveTv/Info", "GET", Summary = "Gets available live tv services.")]
public class GetLiveTvInfo : IReturn<LiveTvInfo>
{
}
- [Route("/LiveTv/Channels", "GET")]
- [Api(Description = "Gets available live tv channels.")]
+ [Route("/LiveTv/Channels", "GET", Summary = "Gets available live tv channels.")]
public class GetChannels : IReturn<QueryResult<ChannelInfoDto>>
{
[ApiMember(Name = "Type", Description = "Optional filter by channel type.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
@@ -43,8 +41,7 @@ namespace MediaBrowser.Api.LiveTv
public int? Limit { get; set; }
}
- [Route("/LiveTv/Channels/{Id}", "GET")]
- [Api(Description = "Gets a live tv channel")]
+ [Route("/LiveTv/Channels/{Id}", "GET", Summary = "Gets a live tv channel")]
public class GetChannel : IReturn<ChannelInfoDto>
{
/// <summary>
@@ -58,8 +55,7 @@ namespace MediaBrowser.Api.LiveTv
public string UserId { get; set; }
}
- [Route("/LiveTv/Recordings", "GET")]
- [Api(Description = "Gets live tv recordings")]
+ [Route("/LiveTv/Recordings", "GET", Summary = "Gets live tv recordings")]
public class GetRecordings : IReturn<QueryResult<RecordingInfoDto>>
{
[ApiMember(Name = "ChannelId", Description = "Optional filter by channel id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
@@ -87,16 +83,14 @@ namespace MediaBrowser.Api.LiveTv
public string SeriesTimerId { get; set; }
}
- [Route("/LiveTv/Recordings/Groups", "GET")]
- [Api(Description = "Gets live tv recording groups")]
+ [Route("/LiveTv/Recordings/Groups", "GET", Summary = "Gets live tv recording groups")]
public class GetRecordingGroups : IReturn<QueryResult<RecordingGroupDto>>
{
[ApiMember(Name = "UserId", Description = "Optional filter by user and attach user data.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string UserId { get; set; }
}
- [Route("/LiveTv/Recordings/{Id}", "GET")]
- [Api(Description = "Gets a live tv recording")]
+ [Route("/LiveTv/Recordings/{Id}", "GET", Summary = "Gets a live tv recording")]
public class GetRecording : IReturn<RecordingInfoDto>
{
[ApiMember(Name = "Id", Description = "Recording Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
@@ -106,32 +100,28 @@ namespace MediaBrowser.Api.LiveTv
public string UserId { get; set; }
}
- [Route("/LiveTv/Tuners/{Id}/Reset", "POST")]
- [Api(Description = "Resets a tv tuner")]
+ [Route("/LiveTv/Tuners/{Id}/Reset", "POST", Summary = "Resets a tv tuner")]
public class ResetTuner : IReturnVoid
{
[ApiMember(Name = "Id", Description = "Tuner Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Id { get; set; }
}
- [Route("/LiveTv/Timers/{Id}", "GET")]
- [Api(Description = "Gets a live tv timer")]
+ [Route("/LiveTv/Timers/{Id}", "GET", Summary = "Gets a live tv timer")]
public class GetTimer : IReturn<TimerInfoDto>
{
[ApiMember(Name = "Id", Description = "Timer Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Id { get; set; }
}
- [Route("/LiveTv/Timers/Defaults", "GET")]
- [Api(Description = "Gets default values for a new timer")]
+ [Route("/LiveTv/Timers/Defaults", "GET", Summary = "Gets default values for a new timer")]
public class GetDefaultTimer : IReturn<SeriesTimerInfoDto>
{
[ApiMember(Name = "ProgramId", Description = "Optional, to attach default values based on a program.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string ProgramId { get; set; }
}
- [Route("/LiveTv/Timers", "GET")]
- [Api(Description = "Gets live tv timers")]
+ [Route("/LiveTv/Timers", "GET", Summary = "Gets live tv timers")]
public class GetTimers : IReturn<QueryResult<TimerInfoDto>>
{
[ApiMember(Name = "ChannelId", Description = "Optional filter by channel id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
@@ -141,8 +131,7 @@ namespace MediaBrowser.Api.LiveTv
public string SeriesTimerId { get; set; }
}
- [Route("/LiveTv/Programs", "GET,POST")]
- [Api(Description = "Gets available live tv epgs..")]
+ [Route("/LiveTv/Programs", "GET,POST", Summary = "Gets available live tv epgs..")]
public class GetPrograms : IReturn<QueryResult<ProgramInfoDto>>
{
[ApiMember(Name = "ChannelIds", Description = "The channels to return guide information for.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
@@ -164,8 +153,7 @@ namespace MediaBrowser.Api.LiveTv
public string MaxEndDate { get; set; }
}
- [Route("/LiveTv/Programs/Recommended", "GET")]
- [Api(Description = "Gets available live tv epgs..")]
+ [Route("/LiveTv/Programs/Recommended", "GET", Summary = "Gets available live tv epgs..")]
public class GetRecommendedPrograms : IReturn<QueryResult<ProgramInfoDto>>
{
[ApiMember(Name = "UserId", Description = "Optional filter by user id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
@@ -181,8 +169,7 @@ namespace MediaBrowser.Api.LiveTv
public bool? HasAired { get; set; }
}
- [Route("/LiveTv/Programs/{Id}", "GET")]
- [Api(Description = "Gets a live tv program")]
+ [Route("/LiveTv/Programs/{Id}", "GET", Summary = "Gets a live tv program")]
public class GetProgram : IReturn<ProgramInfoDto>
{
[ApiMember(Name = "Id", Description = "Program Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
@@ -193,44 +180,38 @@ namespace MediaBrowser.Api.LiveTv
}
- [Route("/LiveTv/Recordings/{Id}", "DELETE")]
- [Api(Description = "Deletes a live tv recording")]
+ [Route("/LiveTv/Recordings/{Id}", "DELETE", Summary = "Deletes a live tv recording")]
public class DeleteRecording : IReturnVoid
{
[ApiMember(Name = "Id", Description = "Recording Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Id { get; set; }
}
- [Route("/LiveTv/Timers/{Id}", "DELETE")]
- [Api(Description = "Cancels a live tv timer")]
+ [Route("/LiveTv/Timers/{Id}", "DELETE", Summary = "Cancels a live tv timer")]
public class CancelTimer : IReturnVoid
{
[ApiMember(Name = "Id", Description = "Timer Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Id { get; set; }
}
- [Route("/LiveTv/Timers/{Id}", "POST")]
- [Api(Description = "Updates a live tv timer")]
+ [Route("/LiveTv/Timers/{Id}", "POST", Summary = "Updates a live tv timer")]
public class UpdateTimer : TimerInfoDto, IReturnVoid
{
}
- [Route("/LiveTv/Timers", "POST")]
- [Api(Description = "Creates a live tv timer")]
+ [Route("/LiveTv/Timers", "POST", Summary = "Creates a live tv timer")]
public class CreateTimer : TimerInfoDto, IReturnVoid
{
}
- [Route("/LiveTv/SeriesTimers/{Id}", "GET")]
- [Api(Description = "Gets a live tv series timer")]
+ [Route("/LiveTv/SeriesTimers/{Id}", "GET", Summary = "Gets a live tv series timer")]
public class GetSeriesTimer : IReturn<TimerInfoDto>
{
[ApiMember(Name = "Id", Description = "Timer Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Id { get; set; }
}
- [Route("/LiveTv/SeriesTimers", "GET")]
- [Api(Description = "Gets live tv series timers")]
+ [Route("/LiveTv/SeriesTimers", "GET", Summary = "Gets live tv series timers")]
public class GetSeriesTimers : IReturn<QueryResult<SeriesTimerInfoDto>>
{
[ApiMember(Name = "SortBy", Description = "Optional. Sort by SortName or Priority", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
@@ -240,36 +221,31 @@ namespace MediaBrowser.Api.LiveTv
public SortOrder SortOrder { get; set; }
}
- [Route("/LiveTv/SeriesTimers/{Id}", "DELETE")]
- [Api(Description = "Cancels a live tv series timer")]
+ [Route("/LiveTv/SeriesTimers/{Id}", "DELETE", Summary = "Cancels a live tv series timer")]
public class CancelSeriesTimer : IReturnVoid
{
[ApiMember(Name = "Id", Description = "Timer Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Id { get; set; }
}
- [Route("/LiveTv/SeriesTimers/{Id}", "POST")]
- [Api(Description = "Updates a live tv series timer")]
+ [Route("/LiveTv/SeriesTimers/{Id}", "POST", Summary = "Updates a live tv series timer")]
public class UpdateSeriesTimer : SeriesTimerInfoDto, IReturnVoid
{
}
- [Route("/LiveTv/SeriesTimers", "POST")]
- [Api(Description = "Creates a live tv series timer")]
+ [Route("/LiveTv/SeriesTimers", "POST", Summary = "Creates a live tv series timer")]
public class CreateSeriesTimer : SeriesTimerInfoDto, IReturnVoid
{
}
- [Route("/LiveTv/Recordings/Groups/{Id}", "GET")]
- [Api(Description = "Gets a recording group")]
+ [Route("/LiveTv/Recordings/Groups/{Id}", "GET", Summary = "Gets a recording group")]
public class GetRecordingGroup : IReturn<RecordingGroupDto>
{
[ApiMember(Name = "Id", Description = "Recording group Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Id { get; set; }
}
- [Route("/LiveTv/GuideInfo", "GET")]
- [Api(Description = "Gets guide info")]
+ [Route("/LiveTv/GuideInfo", "GET", Summary = "Gets guide info")]
public class GetGuideInfo : IReturn<GuideInfo>
{
}
diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index 38cf39b54f..18559a68df 100644
--- a/MediaBrowser.Api/MediaBrowser.Api.csproj
+++ b/MediaBrowser.Api/MediaBrowser.Api.csproj
@@ -53,7 +53,6 @@
<Reference Include="System.Core" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
- <Reference Include="System.Drawing" />
<Reference Include="System.Xml" />
<Reference Include="ServiceStack.Interfaces">
<HintPath>..\ThirdParty\ServiceStack\ServiceStack.Interfaces.dll</HintPath>
@@ -67,6 +66,7 @@
<Link>Properties\SharedVersion.cs</Link>
</Compile>
<Compile Include="ChannelService.cs" />
+ <Compile Include="DlnaService.cs" />
<Compile Include="Movies\CollectionService.cs" />
<Compile Include="Music\AlbumsService.cs" />
<Compile Include="AppThemeService.cs" />
diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs
index 204a7aab45..228dc378b5 100644
--- a/MediaBrowser.Api/Movies/MoviesService.cs
+++ b/MediaBrowser.Api/Movies/MoviesService.cs
@@ -17,8 +17,7 @@ namespace MediaBrowser.Api.Movies
/// <summary>
/// Class GetSimilarMovies
/// </summary>
- [Route("/Movies/{Id}/Similar", "GET")]
- [Api(Description = "Finds movies and trailers similar to a given movie.")]
+ [Route("/Movies/{Id}/Similar", "GET", Summary = "Finds movies and trailers similar to a given movie.")]
public class GetSimilarMovies : BaseGetSimilarItemsFromItem
{
[ApiMember(Name = "IncludeTrailers", Description = "Whether or not to include trailers within the results. Defaults to true.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
@@ -30,8 +29,7 @@ namespace MediaBrowser.Api.Movies
}
}
- [Route("/Movies/Recommendations", "GET")]
- [Api(Description = "Gets movie recommendations")]
+ [Route("/Movies/Recommendations", "GET", Summary = "Gets movie recommendations")]
public class GetMovieRecommendations : IReturn<RecommendationDto[]>, IHasItemFields
{
[ApiMember(Name = "CategoryLimit", Description = "The max number of categories to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
diff --git a/MediaBrowser.Api/Movies/TrailersService.cs b/MediaBrowser.Api/Movies/TrailersService.cs
index 0575066350..05e6a95774 100644
--- a/MediaBrowser.Api/Movies/TrailersService.cs
+++ b/MediaBrowser.Api/Movies/TrailersService.cs
@@ -10,8 +10,7 @@ namespace MediaBrowser.Api.Movies
/// <summary>
/// Class GetSimilarTrailers
/// </summary>
- [Route("/Trailers/{Id}/Similar", "GET")]
- [Api(Description = "Finds movies and trailers similar to a given trailer.")]
+ [Route("/Trailers/{Id}/Similar", "GET", Summary = "Finds movies and trailers similar to a given trailer.")]
public class GetSimilarTrailers : BaseGetSimilarItemsFromItem
{
}
diff --git a/MediaBrowser.Api/Music/InstantMixService.cs b/MediaBrowser.Api/Music/InstantMixService.cs
index a8446a7ef2..9b9df3a92c 100644
--- a/MediaBrowser.Api/Music/InstantMixService.cs
+++ b/MediaBrowser.Api/Music/InstantMixService.cs
@@ -9,28 +9,24 @@ using System.Linq;
namespace MediaBrowser.Api.Music
{
- [Route("/Songs/{Id}/InstantMix", "GET")]
- [Api(Description = "Creates an instant playlist based on a given song")]
+ [Route("/Songs/{Id}/InstantMix", "GET", Summary = "Creates an instant playlist based on a given song")]
public class GetInstantMixFromSong : BaseGetSimilarItemsFromItem
{
}
- [Route("/Albums/{Id}/InstantMix", "GET")]
- [Api(Description = "Creates an instant playlist based on a given album")]
+ [Route("/Albums/{Id}/InstantMix", "GET", Summary = "Creates an instant playlist based on a given album")]
public class GetInstantMixFromAlbum : BaseGetSimilarItemsFromItem
{
}
- [Route("/Artists/{Name}/InstantMix", "GET")]
- [Api(Description = "Creates an instant playlist based on a given artist")]
+ [Route("/Artists/{Name}/InstantMix", "GET", Summary = "Creates an instant playlist based on a given artist")]
public class GetInstantMixFromArtist : BaseGetSimilarItems
{
[ApiMember(Name = "Name", Description = "The artist name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Name { get; set; }
}
- [Route("/MusicGenres/{Name}/InstantMix", "GET")]
- [Api(Description = "Creates an instant playlist based on a music genre")]
+ [Route("/MusicGenres/{Name}/InstantMix", "GET", Summary = "Creates an instant playlist based on a music genre")]
public class GetInstantMixFromMusicGenre : BaseGetSimilarItems
{
[ApiMember(Name = "Name", Description = "The genre name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index 7dcb06f7b3..519ff7947a 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -1,6 +1,7 @@
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
@@ -65,6 +66,7 @@ namespace MediaBrowser.Api.Playback
protected IItemRepository ItemRepository { get; private set; }
protected ILiveTvManager LiveTvManager { get; private set; }
+ protected IDlnaManager DlnaManager { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
@@ -77,8 +79,9 @@ namespace MediaBrowser.Api.Playback
/// <param name="dtoService">The dto service.</param>
/// <param name="fileSystem">The file system.</param>
/// <param name="itemRepository">The item repository.</param>
- protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager)
+ protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager)
{
+ DlnaManager = dlnaManager;
EncodingManager = encodingManager;
LiveTvManager = liveTvManager;
ItemRepository = itemRepository;
@@ -313,6 +316,7 @@ namespace MediaBrowser.Api.Playback
/// </summary>
/// <param name="state">The state.</param>
/// <param name="videoCodec">The video codec.</param>
+ /// <param name="isHls">if set to <c>true</c> [is HLS].</param>
/// <returns>System.String.</returns>
protected string GetVideoQualityParam(StreamState state, string videoCodec, bool isHls)
{
@@ -337,20 +341,17 @@ namespace MediaBrowser.Api.Playback
break;
}
- if (!isHls)
+ switch (qualitySetting)
{
- switch (qualitySetting)
- {
- case EncodingQuality.HighSpeed:
- param += " -crf 23";
- break;
- case EncodingQuality.HighQuality:
- param += " -crf 20";
- break;
- case EncodingQuality.MaxQuality:
- param += " -crf 18";
- break;
- }
+ case EncodingQuality.HighSpeed:
+ param += " -crf 23";
+ break;
+ case EncodingQuality.HighQuality:
+ param += " -crf 20";
+ break;
+ case EncodingQuality.MaxQuality:
+ param += " -crf 18";
+ break;
}
}
@@ -502,14 +503,13 @@ namespace MediaBrowser.Api.Playback
return string.Format("{4} -vf \"{0}scale=trunc({1}/2)*2:trunc({2}/2)*2{3}\"", yadifParam, widthParam, heightParam, assSubtitleParam, copyTsParam);
}
- // If Max dimensions were supplied
- //this makes my brain hurt. For width selects lowest even number between input width and width req size and selects lowest even number from in width*display aspect and requested size
+ // If Max dimensions were supplied, for width selects lowest even number between input width and width req size and selects lowest even number from in width*display aspect and requested size
if (request.MaxWidth.HasValue && request.MaxHeight.HasValue)
{
- var MaxwidthParam = request.MaxWidth.Value.ToString(UsCulture);
- var MaxheightParam = request.MaxHeight.Value.ToString(UsCulture);
+ var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
+ var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
- return string.Format("{4} -vf \"{0}scale=trunc(min(iw\\,{1})/2)*2:trunc(min((iw/dar)\\,{2})/2)*2{3}\"", yadifParam, MaxwidthParam, MaxheightParam, assSubtitleParam, copyTsParam);
+ return string.Format("{4} -vf \"{0}scale=trunc(min(iw\\,{1})/2)*2:trunc(min((iw/dar)\\,{2})/2)*2{3}\"", yadifParam, maxWidthParam, maxHeightParam, assSubtitleParam, copyTsParam);
}
var isH264Output = outputVideoCodec.Equals("libx264", StringComparison.OrdinalIgnoreCase);
@@ -774,29 +774,24 @@ namespace MediaBrowser.Api.Playback
{
var codec = request.AudioCodec;
- if (!string.IsNullOrEmpty(codec))
+ if (string.Equals(codec, "aac", StringComparison.OrdinalIgnoreCase))
{
- if (string.Equals(codec, "aac", StringComparison.OrdinalIgnoreCase))
- {
- return "aac -strict experimental";
- }
- if (string.Equals(codec, "mp3", StringComparison.OrdinalIgnoreCase))
- {
- return "libmp3lame";
- }
- if (string.Equals(codec, "vorbis", StringComparison.OrdinalIgnoreCase))
- {
- return "libvorbis";
- }
- if (string.Equals(codec, "wma", StringComparison.OrdinalIgnoreCase))
- {
- return "wmav2";
- }
-
- return codec.ToLower();
+ return "aac -strict experimental";
+ }
+ if (string.Equals(codec, "mp3", StringComparison.OrdinalIgnoreCase))
+ {
+ return "libmp3lame";
+ }
+ if (string.Equals(codec, "vorbis", StringComparison.OrdinalIgnoreCase))
+ {
+ return "libvorbis";
+ }
+ if (string.Equals(codec, "wma", StringComparison.OrdinalIgnoreCase))
+ {
+ return "wmav2";
}
- return "copy";
+ return codec.ToLower();
}
/// <summary>
@@ -972,8 +967,6 @@ namespace MediaBrowser.Api.Playback
private async void StreamToStandardInput(Process process, StreamState state)
{
- state.StandardInputCancellationTokenSource = new CancellationTokenSource();
-
try
{
await StreamToStandardInputInternal(process, state).ConfigureAwait(false);
@@ -1034,11 +1027,6 @@ namespace MediaBrowser.Api.Playback
{
var hasFixedResolution = state.VideoRequest.HasFixedResolution;
- if (isHls)
- {
- return string.Format(" -b:v {0} -maxrate ({0}*.80) -bufsize {0}", bitrate.Value.ToString(UsCulture));
- }
-
if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase))
{
if (hasFixedResolution)
@@ -1049,7 +1037,6 @@ namespace MediaBrowser.Api.Playback
// With vpx when crf is used, b:v becomes a max rate
// https://trac.ffmpeg.org/wiki/vpxEncodingGuide
return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
- //return string.Format(" -minrate:v ({0}*.95) -maxrate:v ({0}*1.05) -bufsize:v {0} -b:v {0}", bitrate.Value.ToString(UsCulture));
}
if (string.Equals(videoCodec, "msmpeg4", StringComparison.OrdinalIgnoreCase))
@@ -1057,13 +1044,17 @@ namespace MediaBrowser.Api.Playback
return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
}
-
// H264
if (hasFixedResolution)
{
+ if (isHls)
+ {
+ return string.Format(" -b:v {0} -maxrate ({0}*.80) -bufsize {0}", bitrate.Value.ToString(UsCulture));
+ }
+
return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
}
-
+
return string.Format(" -maxrate {0} -bufsize {1}",
bitrate.Value.ToString(UsCulture),
(bitrate.Value * 2).ToString(UsCulture));
@@ -1212,7 +1203,7 @@ namespace MediaBrowser.Api.Playback
if (i == 0)
{
- // Device profile name
+ request.DeviceProfileId = val;
}
else if (i == 1)
{
@@ -1270,35 +1261,35 @@ namespace MediaBrowser.Api.Playback
{
if (videoRequest != null)
{
- videoRequest.MaxWidth = int.Parse(val, UsCulture);
+ videoRequest.MaxFramerate = double.Parse(val, UsCulture);
}
}
else if (i == 12)
{
if (videoRequest != null)
{
- videoRequest.MaxHeight = int.Parse(val, UsCulture);
+ videoRequest.MaxWidth = int.Parse(val, UsCulture);
}
}
else if (i == 13)
{
if (videoRequest != null)
{
- videoRequest.Framerate = int.Parse(val, UsCulture);
+ videoRequest.MaxHeight = int.Parse(val, UsCulture);
}
}
else if (i == 14)
{
if (videoRequest != null)
{
- request.StartTimeTicks = long.Parse(val, UsCulture);
+ videoRequest.Framerate = int.Parse(val, UsCulture);
}
}
else if (i == 15)
{
if (videoRequest != null)
{
- videoRequest.Profile = val;
+ request.StartTimeTicks = long.Parse(val, UsCulture);
}
}
else if (i == 16)
@@ -1487,9 +1478,181 @@ namespace MediaBrowser.Api.Playback
state.SegmentLength = state.ReadInputAtNativeFramerate ? 5 : 10;
state.HlsListSize = state.ReadInputAtNativeFramerate ? 100 : 1440;
+ ApplyDeviceProfileSettings(state);
+
return state;
}
+ private void ApplyDeviceProfileSettings(StreamState state)
+ {
+ var headers = new Dictionary<string, string>();
+
+ foreach (var key in Request.Headers.AllKeys)
+ {
+ headers[key] = Request.Headers[key];
+ }
+
+ var profile = string.IsNullOrWhiteSpace(state.Request.DeviceProfileId) ?
+ DlnaManager.GetProfile(headers) :
+ DlnaManager.GetProfile(state.Request.DeviceProfileId);
+
+ if (profile == null)
+ {
+ // Don't use settings from the default profile.
+ // Only use a specific profile if it was requested.
+ return;
+ }
+
+ var container = Path.GetExtension(state.RequestedUrl);
+
+ if (string.IsNullOrEmpty(container))
+ {
+ container = Path.GetExtension(GetOutputFilePath(state));
+ }
+
+ var audioCodec = state.Request.AudioCodec;
+
+ if (string.Equals(audioCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.AudioStream != null)
+ {
+ audioCodec = state.AudioStream.Codec;
+ }
+
+ var videoCodec = state.VideoRequest == null ? null : state.VideoRequest.VideoCodec;
+
+ if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.VideoStream != null)
+ {
+ videoCodec = state.VideoStream.Codec;
+ }
+
+ var mediaProfile = state.VideoRequest == null ?
+ profile.GetAudioMediaProfile(container, audioCodec, state.AudioStream) :
+ profile.GetVideoMediaProfile(container, audioCodec, videoCodec, state.AudioStream, state.VideoStream);
+
+ if (mediaProfile != null)
+ {
+ state.MimeType = mediaProfile.MimeType;
+ state.OrgPn = mediaProfile.OrgPn;
+ }
+
+ var transcodingProfile = state.VideoRequest == null ?
+ profile.GetAudioTranscodingProfile(container, audioCodec) :
+ profile.GetVideoTranscodingProfile(container, audioCodec, videoCodec);
+
+ if (transcodingProfile != null)
+ {
+ state.EstimateContentLength = transcodingProfile.EstimateContentLength;
+ state.EnableMpegtsM2TsMode = transcodingProfile.EnableMpegtsM2TsMode;
+ state.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo;
+
+ foreach (var setting in transcodingProfile.Settings)
+ {
+ switch (setting.Name)
+ {
+ case TranscodingSettingType.VideoProfile:
+ {
+ if (state.VideoRequest != null && string.IsNullOrWhiteSpace(state.VideoRequest.Profile))
+ {
+ state.VideoRequest.Profile = setting.Value;
+ }
+ break;
+ }
+ default:
+ throw new ArgumentException("Unrecognized TranscodingSettingType");
+ }
+ }
+ }
+ }
+
+
+ /// <summary>
+ /// Adds the dlna headers.
+ /// </summary>
+ /// <param name="state">The state.</param>
+ /// <param name="responseHeaders">The response headers.</param>
+ /// <param name="isStaticallyStreamed">if set to <c>true</c> [is statically streamed].</param>
+ /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
+ protected void AddDlnaHeaders(StreamState state, IDictionary<string, string> responseHeaders, bool isStaticallyStreamed)
+ {
+ var timeSeek = GetHeader("TimeSeekRange.dlna.org");
+
+ if (!string.IsNullOrEmpty(timeSeek))
+ {
+ ResultFactory.ThrowError(406, "Time seek not supported during encoding.", responseHeaders);
+ return;
+ }
+
+ var transferMode = GetHeader("transferMode.dlna.org");
+ responseHeaders["transferMode.dlna.org"] = string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode;
+ responseHeaders["realTimeInfo.dlna.org"] = "DLNA.ORG_TLAG=*";
+
+ var contentFeatures = string.Empty;
+ var extension = GetOutputFileExtension(state);
+
+ // first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none
+ var orgOp = isStaticallyStreamed || state.TranscodeSeekInfo == TranscodeSeekInfo.Bytes ? ";DLNA.ORG_OP=01" : ";DLNA.ORG_OP=00";
+
+ // 0 = native, 1 = transcoded
+ var orgCi = isStaticallyStreamed ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1";
+
+ const string dlnaflags = ";DLNA.ORG_FLAGS=01500000000000000000000000000000";
+
+ if (!string.IsNullOrWhiteSpace(state.OrgPn))
+ {
+ contentFeatures = "DLNA.ORG_PN=" + state.OrgPn;
+ }
+ else if (string.Equals(extension, ".mp3", StringComparison.OrdinalIgnoreCase))
+ {
+ contentFeatures = "DLNA.ORG_PN=MP3";
+ }
+ else if (string.Equals(extension, ".aac", StringComparison.OrdinalIgnoreCase))
+ {
+ contentFeatures = "DLNA.ORG_PN=AAC_ISO";
+ }
+ else if (string.Equals(extension, ".wma", StringComparison.OrdinalIgnoreCase))
+ {
+ contentFeatures = "DLNA.ORG_PN=WMABASE";
+ }
+ else if (string.Equals(extension, ".avi", StringComparison.OrdinalIgnoreCase))
+ {
+ contentFeatures = "DLNA.ORG_PN=AVI";
+ }
+ else if (string.Equals(extension, ".mkv", StringComparison.OrdinalIgnoreCase))
+ {
+ contentFeatures = "DLNA.ORG_PN=MATROSKA";
+ }
+ else if (string.Equals(extension, ".mp4", StringComparison.OrdinalIgnoreCase))
+ {
+ contentFeatures = "DLNA.ORG_PN=AVC_MP4_MP_HD_720p_AAC";
+ }
+ else if (string.Equals(extension, ".mpeg", StringComparison.OrdinalIgnoreCase))
+ {
+ contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL";
+ }
+ else if (string.Equals(extension, ".ts", StringComparison.OrdinalIgnoreCase))
+ {
+ contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL";
+ }
+ //else if (string.Equals(extension, ".wmv", StringComparison.OrdinalIgnoreCase))
+ //{
+ // contentFeatures = "DLNA.ORG_PN=WMVHIGH_BASE";
+ //}
+ //else if (string.Equals(extension, ".asf", StringComparison.OrdinalIgnoreCase))
+ //{
+ // // ??
+ // contentFeatures = "DLNA.ORG_PN=WMVHIGH_BASE";
+ //}
+
+ if (!string.IsNullOrEmpty(contentFeatures))
+ {
+ responseHeaders["contentFeatures.dlna.org"] = (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';');
+ }
+
+ foreach (var item in responseHeaders)
+ {
+ Request.Response.AddHeader(item.Key, item.Value);
+ }
+ }
+
/// <summary>
/// Enforces the resolution limit.
/// </summary>
@@ -1605,7 +1768,7 @@ namespace MediaBrowser.Api.Playback
return "vorbis";
}
- return null;
+ return "copy";
}
/// <summary>
diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
index eb8f415e0d..96b36ac7fc 100644
--- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
@@ -2,13 +2,13 @@
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Dto;
using MediaBrowser.Model.IO;
using System;
using System.Collections.Generic;
@@ -24,7 +24,7 @@ namespace MediaBrowser.Api.Playback.Hls
/// </summary>
public abstract class BaseHlsService : BaseStreamingService
{
- protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager)
+ protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager)
{
}
@@ -200,7 +200,7 @@ namespace MediaBrowser.Api.Playback.Hls
builder.AppendLine("#EXTM3U");
// Pad a little to satisfy the apple hls validator
- var paddedBitrate = Convert.ToInt32(bitrate * 1.05);
+ var paddedBitrate = Convert.ToInt32(bitrate * 1.15);
// Main stream
builder.AppendLine("#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=" + paddedBitrate.ToString(UsCulture));
diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
index 66e8b0d149..ab0cd8871f 100644
--- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
@@ -1,12 +1,12 @@
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Model.Dto;
using MediaBrowser.Model.IO;
using ServiceStack;
using System;
@@ -60,7 +60,7 @@ namespace MediaBrowser.Api.Playback.Hls
public class DynamicHlsService : BaseHlsService
{
- public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager)
+ public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager)
{
}
diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
index a2080995d0..1bca4cae9a 100644
--- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
@@ -52,7 +53,7 @@ namespace MediaBrowser.Api.Playback.Hls
/// </summary>
public class VideoHlsService : BaseHlsService
{
- public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager)
+ public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager)
{
}
diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
index 4d8d3a5816..55b311f867 100644
--- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
@@ -1,6 +1,7 @@
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library;
@@ -16,23 +17,22 @@ namespace MediaBrowser.Api.Playback.Progressive
/// <summary>
/// Class GetAudioStream
/// </summary>
- [Route("/Audio/{Id}/stream.mp3", "GET")]
- [Route("/Audio/{Id}/stream.wma", "GET")]
- [Route("/Audio/{Id}/stream.aac", "GET")]
- [Route("/Audio/{Id}/stream.flac", "GET")]
- [Route("/Audio/{Id}/stream.ogg", "GET")]
- [Route("/Audio/{Id}/stream.oga", "GET")]
- [Route("/Audio/{Id}/stream.webm", "GET")]
- [Route("/Audio/{Id}/stream", "GET")]
- [Route("/Audio/{Id}/stream.mp3", "HEAD")]
- [Route("/Audio/{Id}/stream.wma", "HEAD")]
- [Route("/Audio/{Id}/stream.aac", "HEAD")]
- [Route("/Audio/{Id}/stream.flac", "HEAD")]
- [Route("/Audio/{Id}/stream.ogg", "HEAD")]
- [Route("/Audio/{Id}/stream.oga", "HEAD")]
- [Route("/Audio/{Id}/stream.webm", "HEAD")]
- [Route("/Audio/{Id}/stream", "HEAD")]
- [Api(Description = "Gets an audio stream")]
+ [Route("/Audio/{Id}/stream.mp3", "GET", Summary = "Gets an audio stream")]
+ [Route("/Audio/{Id}/stream.wma", "GET", Summary = "Gets an audio stream")]
+ [Route("/Audio/{Id}/stream.aac", "GET", Summary = "Gets an audio stream")]
+ [Route("/Audio/{Id}/stream.flac", "GET", Summary = "Gets an audio stream")]
+ [Route("/Audio/{Id}/stream.ogg", "GET", Summary = "Gets an audio stream")]
+ [Route("/Audio/{Id}/stream.oga", "GET", Summary = "Gets an audio stream")]
+ [Route("/Audio/{Id}/stream.webm", "GET", Summary = "Gets an audio stream")]
+ [Route("/Audio/{Id}/stream", "GET", Summary = "Gets an audio stream")]
+ [Route("/Audio/{Id}/stream.mp3", "HEAD", Summary = "Gets an audio stream")]
+ [Route("/Audio/{Id}/stream.wma", "HEAD", Summary = "Gets an audio stream")]
+ [Route("/Audio/{Id}/stream.aac", "HEAD", Summary = "Gets an audio stream")]
+ [Route("/Audio/{Id}/stream.flac", "HEAD", Summary = "Gets an audio stream")]
+ [Route("/Audio/{Id}/stream.ogg", "HEAD", Summary = "Gets an audio stream")]
+ [Route("/Audio/{Id}/stream.oga", "HEAD", Summary = "Gets an audio stream")]
+ [Route("/Audio/{Id}/stream.webm", "HEAD", Summary = "Gets an audio stream")]
+ [Route("/Audio/{Id}/stream", "HEAD", Summary = "Gets an audio stream")]
public class GetAudioStream : StreamRequest
{
@@ -43,7 +43,8 @@ namespace MediaBrowser.Api.Playback.Progressive
/// </summary>
public class AudioService : BaseProgressiveStreamingService
{
- public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IHttpClient httpClient, IImageProcessor imageProcessor) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, httpClient, imageProcessor)
+ public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IHttpClient httpClient, IImageProcessor imageProcessor)
+ : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager, httpClient, imageProcessor)
{
}
diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
index 9cb989fc21..b4fe9a094f 100644
--- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
@@ -1,13 +1,13 @@
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Model.Dto;
using MediaBrowser.Model.IO;
using ServiceStack.Web;
using System;
@@ -26,8 +26,8 @@ namespace MediaBrowser.Api.Playback.Progressive
protected readonly IImageProcessor ImageProcessor;
protected readonly IHttpClient HttpClient;
- protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IHttpClient httpClient, IImageProcessor imageProcessor)
- : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager)
+ protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IHttpClient httpClient, IImageProcessor imageProcessor)
+ : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager)
{
HttpClient = httpClient;
ImageProcessor = imageProcessor;
@@ -101,92 +101,6 @@ namespace MediaBrowser.Api.Playback.Progressive
}
/// <summary>
- /// Adds the dlna headers.
- /// </summary>
- /// <param name="state">The state.</param>
- /// <param name="responseHeaders">The response headers.</param>
- /// <param name="isStaticallyStreamed">if set to <c>true</c> [is statically streamed].</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- private void AddDlnaHeaders(StreamState state, IDictionary<string, string> responseHeaders, bool isStaticallyStreamed)
- {
- var timeSeek = GetHeader("TimeSeekRange.dlna.org");
-
- if (!string.IsNullOrEmpty(timeSeek))
- {
- ResultFactory.ThrowError(406, "Time seek not supported during encoding.", responseHeaders);
- return;
- }
-
- var transferMode = GetHeader("transferMode.dlna.org");
- responseHeaders["transferMode.dlna.org"] = string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode;
- responseHeaders["realTimeInfo.dlna.org"] = "DLNA.ORG_TLAG=*";
-
- var contentFeatures = string.Empty;
- var extension = GetOutputFileExtension(state);
-
- // first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none
- var orgOp = isStaticallyStreamed ? ";DLNA.ORG_OP=01" : ";DLNA.ORG_OP=00";
-
- // 0 = native, 1 = transcoded
- var orgCi = isStaticallyStreamed ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1";
-
- const string dlnaflags = ";DLNA.ORG_FLAGS=01500000000000000000000000000000";
-
- if (string.Equals(extension, ".mp3", StringComparison.OrdinalIgnoreCase))
- {
- contentFeatures = "DLNA.ORG_PN=MP3";
- }
- else if (string.Equals(extension, ".aac", StringComparison.OrdinalIgnoreCase))
- {
- contentFeatures = "DLNA.ORG_PN=AAC_ISO";
- }
- else if (string.Equals(extension, ".wma", StringComparison.OrdinalIgnoreCase))
- {
- contentFeatures = "DLNA.ORG_PN=WMABASE";
- }
- else if (string.Equals(extension, ".avi", StringComparison.OrdinalIgnoreCase))
- {
- contentFeatures = "DLNA.ORG_PN=AVI";
- }
- else if (string.Equals(extension, ".mkv", StringComparison.OrdinalIgnoreCase))
- {
- contentFeatures = "DLNA.ORG_PN=MATROSKA";
- }
- else if (string.Equals(extension, ".mp4", StringComparison.OrdinalIgnoreCase))
- {
- contentFeatures = "DLNA.ORG_PN=AVC_MP4_MP_HD_720p_AAC";
- }
- else if (string.Equals(extension, ".mpeg", StringComparison.OrdinalIgnoreCase))
- {
- contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL";
- }
- else if (string.Equals(extension, ".ts", StringComparison.OrdinalIgnoreCase))
- {
- contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL";
- }
- //else if (string.Equals(extension, ".wmv", StringComparison.OrdinalIgnoreCase))
- //{
- // contentFeatures = "DLNA.ORG_PN=WMVHIGH_BASE";
- //}
- //else if (string.Equals(extension, ".asf", StringComparison.OrdinalIgnoreCase))
- //{
- // // ??
- // contentFeatures = "DLNA.ORG_PN=WMVHIGH_BASE";
- //}
-
-
- if (!string.IsNullOrEmpty(contentFeatures))
- {
- responseHeaders["contentFeatures.dlna.org"] = (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';');
- }
-
- foreach (var item in responseHeaders)
- {
- Request.Response.AddHeader(item.Key, item.Value);
- }
- }
-
- /// <summary>
/// Gets the type of the transcoding job.
/// </summary>
/// <value>The type of the transcoding job.</value>
@@ -303,18 +217,30 @@ namespace MediaBrowser.Api.Playback.Progressive
var contentType = state.GetMimeType(outputPath);
+ var contentLength = state.EstimateContentLength ? GetEstimatedContentLength(state) : null;
+
+ if (contentLength.HasValue)
+ {
+ responseHeaders["Content-Length"] = contentLength.Value.ToString(UsCulture);
+ }
+
// Headers only
if (isHeadRequest)
{
var streamResult = ResultFactory.GetResult(new byte[] { }, contentType, responseHeaders);
- var hasOptions = streamResult as IHasOptions;
- if (hasOptions != null)
+
+ if (!contentLength.HasValue)
{
- if (hasOptions.Options.ContainsKey("Content-Length"))
+ var hasOptions = streamResult as IHasOptions;
+ if (hasOptions != null)
{
- hasOptions.Options.Remove("Content-Length");
+ if (hasOptions.Options.ContainsKey("Content-Length"))
+ {
+ hasOptions.Options.Remove("Content-Length");
+ }
}
}
+
return streamResult;
}
@@ -339,5 +265,31 @@ namespace MediaBrowser.Api.Playback.Progressive
return result;
}
+
+ /// <summary>
+ /// Gets the length of the estimated content.
+ /// </summary>
+ /// <param name="state">The state.</param>
+ /// <returns>System.Nullable{System.Int64}.</returns>
+ private long? GetEstimatedContentLength(StreamState state)
+ {
+ var totalBitrate = 0;
+
+ if (state.Request.AudioBitRate.HasValue)
+ {
+ totalBitrate += state.Request.AudioBitRate.Value;
+ }
+ if (state.VideoRequest != null && state.VideoRequest.VideoBitRate.HasValue)
+ {
+ totalBitrate += state.VideoRequest.VideoBitRate.Value;
+ }
+
+ if (totalBitrate > 0 && state.RunTimeTicks.HasValue)
+ {
+ return Convert.ToInt64(totalBitrate * TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalSeconds);
+ }
+
+ return null;
+ }
}
}
diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
index 43dc6f0d49..855c036911 100644
--- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
@@ -1,6 +1,7 @@
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library;
@@ -58,7 +59,7 @@ namespace MediaBrowser.Api.Playback.Progressive
/// </summary>
public class VideoService : BaseProgressiveStreamingService
{
- public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IHttpClient httpClient, IImageProcessor imageProcessor) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, httpClient, imageProcessor)
+ public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IHttpClient httpClient, IImageProcessor imageProcessor) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager, httpClient, imageProcessor)
{
}
@@ -137,6 +138,11 @@ namespace MediaBrowser.Api.Playback.Progressive
return state.VideoStream != null && IsH264(state.VideoStream) ? args + " -bsf h264_mp4toannexb" : args;
}
+ if (state.EnableMpegtsM2TsMode)
+ {
+ args += " -mpegts_m2ts_mode 1";
+ }
+
const string keyFrameArg = " -force_key_frames expr:if(isnan(prev_forced_t),gte(t,.1),gte(t,prev_forced_t+5))";
args += keyFrameArg;
diff --git a/MediaBrowser.Api/Playback/StreamRequest.cs b/MediaBrowser.Api/Playback/StreamRequest.cs
index 8db5920f6b..0eb2984fb5 100644
--- a/MediaBrowser.Api/Playback/StreamRequest.cs
+++ b/MediaBrowser.Api/Playback/StreamRequest.cs
@@ -65,6 +65,9 @@ namespace MediaBrowser.Api.Playback
[ApiMember(Name = "Static", Description = "Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool Static { get; set; }
+ [ApiMember(Name = "DeviceProfileId", Description = "Optional. The dlna device profile id to utilize.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string DeviceProfileId { get; set; }
+
/// <summary>
/// For testing purposes
/// </summary>
diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs
index ecc5c93ef2..504d7d921b 100644
--- a/MediaBrowser.Api/Playback/StreamState.cs
+++ b/MediaBrowser.Api/Playback/StreamState.cs
@@ -1,4 +1,5 @@
using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Dlna;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using System.Collections.Generic;
@@ -77,8 +78,21 @@ namespace MediaBrowser.Api.Playback
public string InputAudioCodec { get; set; }
+ public string MimeType { get; set; }
+ public string OrgPn { get; set; }
+
+ // DLNA Settings
+ public bool EstimateContentLength { get; set; }
+ public bool EnableMpegtsM2TsMode { get; set; }
+ public TranscodeSeekInfo TranscodeSeekInfo { get; set; }
+
public string GetMimeType(string outputPath)
{
+ if (!string.IsNullOrEmpty(MimeType))
+ {
+ return MimeType;
+ }
+
return MimeTypes.GetMimeType(outputPath);
}
}
diff --git a/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs b/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs
index daa735fe53..80080fbb31 100644
--- a/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs
+++ b/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs
@@ -2,18 +2,17 @@
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Model.Tasks;
using ServiceStack;
+using ServiceStack.Text.Controller;
using System;
using System.Collections.Generic;
using System.Linq;
-using ServiceStack.Text.Controller;
namespace MediaBrowser.Api.ScheduledTasks
{
/// <summary>
/// Class GetScheduledTask
/// </summary>
- [Route("/ScheduledTasks/{Id}", "GET")]
- [Api(Description = "Gets a scheduled task, by Id")]
+ [Route("/ScheduledTasks/{Id}", "GET", Summary = "Gets a scheduled task, by Id")]
public class GetScheduledTask : IReturn<TaskInfo>
{
/// <summary>
@@ -27,8 +26,7 @@ namespace MediaBrowser.Api.ScheduledTasks
/// <summary>
/// Class GetScheduledTasks
/// </summary>
- [Route("/ScheduledTasks", "GET")]
- [Api(Description = "Gets scheduled tasks")]
+ [Route("/ScheduledTasks", "GET", Summary = "Gets scheduled tasks")]
public class GetScheduledTasks : IReturn<List<TaskInfo>>
{
[ApiMember(Name = "IsHidden", Description = "Optional filter tasks that are hidden, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
@@ -38,8 +36,7 @@ namespace MediaBrowser.Api.ScheduledTasks
/// <summary>
/// Class StartScheduledTask
/// </summary>
- [Route("/ScheduledTasks/Running/{Id}", "POST")]
- [Api(Description = "Starts a scheduled task")]
+ [Route("/ScheduledTasks/Running/{Id}", "POST", Summary = "Starts a scheduled task")]
public class StartScheduledTask : IReturnVoid
{
/// <summary>
@@ -53,8 +50,7 @@ namespace MediaBrowser.Api.ScheduledTasks
/// <summary>
/// Class StopScheduledTask
/// </summary>
- [Route("/ScheduledTasks/Running/{Id}", "DELETE")]
- [Api(Description = "Stops a scheduled task")]
+ [Route("/ScheduledTasks/Running/{Id}", "DELETE", Summary = "Stops a scheduled task")]
public class StopScheduledTask : IReturnVoid
{
/// <summary>
@@ -68,8 +64,7 @@ namespace MediaBrowser.Api.ScheduledTasks
/// <summary>
/// Class UpdateScheduledTaskTriggers
/// </summary>
- [Route("/ScheduledTasks/{Id}/Triggers", "POST")]
- [Api(Description = "Updates the triggers for a scheduled task")]
+ [Route("/ScheduledTasks/{Id}/Triggers", "POST", Summary = "Updates the triggers for a scheduled task")]
public class UpdateScheduledTaskTriggers : List<TaskTriggerInfo>, IReturnVoid
{
/// <summary>
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index a787684bbf..c5d0a621d4 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -20,9 +20,8 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Class GetItems
/// </summary>
- [Route("/Items", "GET")]
- [Route("/Users/{UserId}/Items", "GET")]
- [Api(Description = "Gets items based on a query.")]
+ [Route("/Items", "GET", Summary = "Gets items based on a query.")]
+ [Route("/Users/{UserId}/Items", "GET", Summary = "Gets items based on a query.")]
public class GetItems : BaseItemsRequest, IReturn<ItemsResult>
{
/// <summary>
diff --git a/MediaBrowser.Api/UserLibrary/StudiosService.cs b/MediaBrowser.Api/UserLibrary/StudiosService.cs
index fc7fdd1600..7eff5054be 100644
--- a/MediaBrowser.Api/UserLibrary/StudiosService.cs
+++ b/MediaBrowser.Api/UserLibrary/StudiosService.cs
@@ -8,15 +8,13 @@ using ServiceStack;
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Threading.Tasks;
namespace MediaBrowser.Api.UserLibrary
{
/// <summary>
/// Class GetStudios
/// </summary>
- [Route("/Studios", "GET")]
- [Api(Description = "Gets all studios from a given item, folder, or the entire library")]
+ [Route("/Studios", "GET", Summary = "Gets all studios from a given item, folder, or the entire library")]
public class GetStudios : GetItemsByName
{
}
@@ -24,8 +22,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Class GetStudio
/// </summary>
- [Route("/Studios/{Name}", "GET")]
- [Api(Description = "Gets a studio, by name")]
+ [Route("/Studios/{Name}", "GET", Summary = "Gets a studio, by name")]
public class GetStudio : IReturn<BaseItemDto>
{
/// <summary>
diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
index c6051c02cc..a49f957f60 100644
--- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
+++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
@@ -705,7 +705,7 @@ namespace MediaBrowser.Api.UserLibrary
datePlayed = DateTime.ParseExact(request.DatePlayed, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
}
- var session = GetSession();
+ var session = GetSession(_sessionManager);
var dto = await UpdatePlayedStatus(user, request.Id, true, datePlayed).ConfigureAwait(false);
@@ -719,15 +719,6 @@ namespace MediaBrowser.Api.UserLibrary
return dto;
}
- private SessionInfo GetSession()
- {
- var auth = AuthorizationRequestFilterAttribute.GetAuthorization(Request);
-
- return _sessionManager.Sessions.First(i => string.Equals(i.DeviceId, auth.DeviceId) &&
- string.Equals(i.Client, auth.Client) &&
- string.Equals(i.ApplicationVersion, auth.Version));
- }
-
/// <summary>
/// Posts the specified request.
/// </summary>
@@ -744,7 +735,7 @@ namespace MediaBrowser.Api.UserLibrary
{
CanSeek = request.CanSeek,
Item = item,
- SessionId = GetSession().Id,
+ SessionId = GetSession(_sessionManager).Id,
QueueableMediaTypes = queueableMediaTypes.Split(',').ToList(),
MediaSourceId = request.MediaSourceId
};
@@ -768,7 +759,7 @@ namespace MediaBrowser.Api.UserLibrary
PositionTicks = request.PositionTicks,
IsMuted = request.IsMuted,
IsPaused = request.IsPaused,
- SessionId = GetSession().Id,
+ SessionId = GetSession(_sessionManager).Id,
MediaSourceId = request.MediaSourceId
};
@@ -787,7 +778,7 @@ namespace MediaBrowser.Api.UserLibrary
var item = _dtoService.GetItemByDtoId(request.Id, user.Id);
- var session = GetSession();
+ var session = GetSession(_sessionManager);
var info = new PlaybackStopInfo
{
@@ -817,7 +808,7 @@ namespace MediaBrowser.Api.UserLibrary
{
var user = _userManager.GetUserById(request.UserId);
- var session = GetSession();
+ var session = GetSession(_sessionManager);
var dto = await UpdatePlayedStatus(user, request.Id, false, null).ConfigureAwait(false);
diff --git a/MediaBrowser.Api/WebSocket/SessionInfoWebSocketListener.cs b/MediaBrowser.Api/WebSocket/SessionInfoWebSocketListener.cs
index 38139645eb..25acd613ca 100644
--- a/MediaBrowser.Api/WebSocket/SessionInfoWebSocketListener.cs
+++ b/MediaBrowser.Api/WebSocket/SessionInfoWebSocketListener.cs
@@ -49,7 +49,7 @@ namespace MediaBrowser.Api.WebSocket
/// <returns>Task{SystemInfo}.</returns>
protected override Task<IEnumerable<SessionInfoDto>> GetDataToSend(object state)
{
- return Task.FromResult(_sessionManager.Sessions.Select(_dtoService.GetSessionInfoDto));
+ return Task.FromResult(_sessionManager.Sessions.Where(i => i.IsActive).Select(_dtoService.GetSessionInfoDto));
}
}
}