aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
-rw-r--r--MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj1
-rw-r--r--MediaBrowser.Controller/Dlna/CodecProfile.cs22
-rw-r--r--MediaBrowser.Controller/Dlna/ContainerProfile.cs4
-rw-r--r--MediaBrowser.Controller/Dlna/DeviceIdentification.cs11
-rw-r--r--MediaBrowser.Controller/Dlna/DeviceProfile.cs199
-rw-r--r--MediaBrowser.Controller/Dlna/DirectPlayProfile.cs7
-rw-r--r--MediaBrowser.Controller/Dlna/IDlnaManager.cs43
-rw-r--r--MediaBrowser.Controller/Dlna/MediaProfile.cs16
-rw-r--r--MediaBrowser.Controller/Dlna/TranscodingProfile.cs27
-rw-r--r--MediaBrowser.Controller/Entities/Trailer.cs19
-rw-r--r--MediaBrowser.Controller/Entities/User.cs5
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj2
-rw-r--r--MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs21
-rw-r--r--MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs20
-rw-r--r--MediaBrowser.Controller/MediaEncoding/InternalMediaInfoResult.cs16
-rw-r--r--MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs32
-rw-r--r--MediaBrowser.Controller/Providers/BaseItemXmlParser.cs88
-rw-r--r--MediaBrowser.Controller/Providers/ISeriesOrderManager.cs26
-rw-r--r--MediaBrowser.Controller/Session/ISessionController.cs8
-rw-r--r--MediaBrowser.Dlna/DlnaManager.cs290
-rw-r--r--MediaBrowser.Dlna/MediaBrowser.Dlna.csproj27
-rw-r--r--MediaBrowser.Dlna/PlayTo/CurrentIdEventArgs.cs14
-rw-r--r--MediaBrowser.Dlna/PlayTo/Device.cs26
-rw-r--r--MediaBrowser.Dlna/PlayTo/DeviceInfo.cs25
-rw-r--r--MediaBrowser.Dlna/PlayTo/DidlBuilder.cs85
-rw-r--r--MediaBrowser.Dlna/PlayTo/DlnaController.cs65
-rw-r--r--MediaBrowser.Dlna/PlayTo/DlnaControllerFactory.cs31
-rw-r--r--MediaBrowser.Dlna/PlayTo/PlayToManager.cs60
-rw-r--r--MediaBrowser.Dlna/PlayTo/PlaylistItem.cs4
-rw-r--r--MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs37
-rw-r--r--MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs40
-rw-r--r--MediaBrowser.Dlna/PlayTo/StreamHelper.cs11
-rw-r--r--MediaBrowser.Dlna/Profiles/DefaultProfile.cs24
-rw-r--r--MediaBrowser.Dlna/Profiles/DenonAvrProfile.cs4
-rw-r--r--MediaBrowser.Dlna/Profiles/Foobar2000Profile.cs31
-rw-r--r--MediaBrowser.Dlna/Profiles/LgTvProfile.cs10
-rw-r--r--MediaBrowser.Dlna/Profiles/LinksysDMA2100Profile.cs4
-rw-r--r--MediaBrowser.Dlna/Profiles/PanasonicVieraProfile.cs38
-rw-r--r--MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs23
-rw-r--r--MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs10
-rw-r--r--MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs12
-rw-r--r--MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs29
-rw-r--r--MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs29
-rw-r--r--MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs23
-rw-r--r--MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs21
-rw-r--r--MediaBrowser.Dlna/Profiles/SonyPs3Profile.cs14
-rw-r--r--MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs6
-rw-r--r--MediaBrowser.Dlna/Profiles/Xbox360Profile.cs28
-rw-r--r--MediaBrowser.Dlna/Profiles/XboxOneProfile.cs4
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Default.xml35
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml39
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml73
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml39
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml66
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml102
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml69
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml97
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml100
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml103
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml86
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml86
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml94
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml80
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml103
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml41
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml41
-rw-r--r--MediaBrowser.Dlna/Server/Headers.cs2
-rw-r--r--MediaBrowser.Dlna/Server/RawHeaders.cs16
-rw-r--r--MediaBrowser.Dlna/Server/SsdpHandler.cs6
-rw-r--r--MediaBrowser.Dlna/Ssdp/SsdpHelper.cs (renamed from MediaBrowser.Dlna/PlayTo/SsdpHelper.cs)44
-rw-r--r--MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs (renamed from MediaBrowser.Server.Implementations/BdInfo/BdInfoExaminer.cs)2
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/ImageEncoder.cs235
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs (renamed from MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs)239
-rw-r--r--MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj81
-rw-r--r--MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs36
-rw-r--r--MediaBrowser.MediaEncoding/packages.config4
-rw-r--r--MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj6
-rw-r--r--MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj6
-rw-r--r--MediaBrowser.Model/ApiClient/IApiClient.cs8
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs6
-rw-r--r--MediaBrowser.Model/Configuration/UserConfiguration.cs4
-rw-r--r--MediaBrowser.Model/Dlna/DeviceProfileInfo.cs30
-rw-r--r--MediaBrowser.Model/Drawing/ImageOutputFormat.cs3
-rw-r--r--MediaBrowser.Model/Entities/MediaStream.cs6
-rw-r--r--MediaBrowser.Model/MediaBrowser.Model.csproj2
-rw-r--r--MediaBrowser.Model/Session/GenericCommand.cs48
-rw-r--r--MediaBrowser.Model/Session/PlaystateCommand.cs10
-rw-r--r--MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs2
-rw-r--r--MediaBrowser.Providers/Manager/SeriesOrderManager.cs36
-rw-r--r--MediaBrowser.Providers/MediaBrowser.Providers.csproj1
-rw-r--r--MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs2
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs19
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs29
-rw-r--r--MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs2
-rw-r--r--MediaBrowser.Providers/Movies/MovieDbProvider.cs2
-rw-r--r--MediaBrowser.Providers/Music/LastfmArtistProvider.cs24
-rw-r--r--MediaBrowser.Providers/Savers/MovieXmlSaver.cs15
-rw-r--r--MediaBrowser.Providers/Savers/SeriesXmlSaver.cs10
-rw-r--r--MediaBrowser.Providers/Savers/XmlSaverHelpers.cs28
-rw-r--r--MediaBrowser.Providers/TV/FanArtSeasonProvider.cs12
-rw-r--r--MediaBrowser.Providers/TV/SeriesXmlParser.cs2
-rw-r--r--MediaBrowser.Providers/TV/TvdbEpisodeImageProvider.cs3
-rw-r--r--MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs9
-rw-r--r--MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs29
-rw-r--r--MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs4
-rw-r--r--MediaBrowser.Providers/TV/TvdbSeriesProvider.cs30
-rw-r--r--MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs32
-rw-r--r--MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs87
-rw-r--r--MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs58
-rw-r--r--MediaBrowser.Server.Implementations/Library/UserManager.cs58
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs7
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj10
-rw-r--r--MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Roku/RokuSessionController.cs11
-rw-r--r--MediaBrowser.Server.Implementations/ServerApplicationPaths.cs12
-rw-r--r--MediaBrowser.Server.Implementations/Session/WebSocketController.cs12
-rw-r--r--MediaBrowser.Server.Implementations/packages.config1
-rw-r--r--MediaBrowser.ServerApplication/ApplicationHost.cs38
-rw-r--r--MediaBrowser.ServerApplication/MainStartup.cs5
-rw-r--r--MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj5
-rw-r--r--MediaBrowser.ServerApplication/Updates/ApplicationUpdater.cs (renamed from MediaBrowser.Common.Implementations/Updates/ApplicationUpdater.cs)12
-rw-r--r--MediaBrowser.WebDashboard/Api/DashboardInfo.cs39
-rw-r--r--MediaBrowser.WebDashboard/Api/DashboardInfoWebSocketListener.cs62
-rw-r--r--MediaBrowser.WebDashboard/Api/DashboardService.cs72
-rw-r--r--MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj28
-rw-r--r--MediaBrowser.sln16
-rw-r--r--Nuget/MediaBrowser.Common.Internal.nuspec4
-rw-r--r--Nuget/MediaBrowser.Common.nuspec2
-rw-r--r--Nuget/MediaBrowser.Server.Core.nuspec4
159 files changed, 3847 insertions, 1462 deletions
diff --git a/MediaBrowser.Api/AppThemeService.cs b/MediaBrowser.Api/AppThemeService.cs
index 54141b3e2..4d8eed7dd 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 08686b43a..707cfb457 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 c1724571a..ed203a0f4 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 600704350..b3191cd4b 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 f22dc9e39..4060b42b4 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 000000000..792a7ff43
--- /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 cb104072b..56f71fc00 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 e371791f8..ff2771ce1 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 2cdaef1ed..562da40ee 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 dba256418..533a92fba 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 569e4b52b..96fe01ab3 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 38cf39b54..18559a68d 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 204a7aab4..228dc378b 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 057506635..05e6a9577 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 a8446a7ef..9b9df3a92 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 7dcb06f7b..519ff7947 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 eb8f415e0..96b36ac7f 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 66e8b0d14..ab0cd8871 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 a2080995d..1bca4cae9 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 4d8d3a581..55b311f86 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 9cb989fc2..b4fe9a094 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 43dc6f0d4..855c03691 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 8db5920f6..0eb2984fb 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 ecc5c93ef..504d7d921 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 daa735fe5..80080fbb3 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 a787684bb..c5d0a621d 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 fc7fdd160..7eff5054b 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 c6051c02c..a49f957f6 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 38139645e..25acd613c 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));
}
}
}
diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
index 04b8865c1..f6f800f4a 100644
--- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
+++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
@@ -102,7 +102,6 @@
<Compile Include="Security\PluginSecurityManager.cs" />
<Compile Include="Serialization\JsonSerializer.cs" />
<Compile Include="Serialization\XmlSerializer.cs" />
- <Compile Include="Updates\ApplicationUpdater.cs" />
<Compile Include="Updates\InstallationManager.cs" />
<Compile Include="Security\UsageReporter.cs" />
</ItemGroup>
diff --git a/MediaBrowser.Controller/Dlna/CodecProfile.cs b/MediaBrowser.Controller/Dlna/CodecProfile.cs
index 2b9a40ea0..e2eb60d9a 100644
--- a/MediaBrowser.Controller/Dlna/CodecProfile.cs
+++ b/MediaBrowser.Controller/Dlna/CodecProfile.cs
@@ -1,13 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Xml.Serialization;
namespace MediaBrowser.Controller.Dlna
{
public class CodecProfile
{
+ [XmlAttribute("type")]
public CodecType Type { get; set; }
+
public ProfileCondition[] Conditions { get; set; }
+
+ [XmlAttribute("codec")]
public string Codec { get; set; }
public CodecProfile()
@@ -30,16 +35,23 @@ namespace MediaBrowser.Controller.Dlna
public enum CodecType
{
- VideoCodec = 0,
- VideoAudioCodec = 1,
- AudioCodec = 2
+ Video = 0,
+ VideoAudio = 1,
+ Audio = 2
}
public class ProfileCondition
{
+ [XmlAttribute("condition")]
public ProfileConditionType Condition { get; set; }
+
+ [XmlAttribute("property")]
public ProfileConditionValue Property { get; set; }
+
+ [XmlAttribute("value")]
public string Value { get; set; }
+
+ [XmlAttribute("isRequired")]
public bool IsRequired { get; set; }
public ProfileCondition()
@@ -69,8 +81,6 @@ namespace MediaBrowser.Controller.Dlna
VideoBitrate,
VideoFramerate,
VideoLevel,
- VideoPacketLength,
- VideoProfile,
- VideoTimestamp
+ VideoProfile
}
}
diff --git a/MediaBrowser.Controller/Dlna/ContainerProfile.cs b/MediaBrowser.Controller/Dlna/ContainerProfile.cs
index 3bd3c9eaf..1029ba72c 100644
--- a/MediaBrowser.Controller/Dlna/ContainerProfile.cs
+++ b/MediaBrowser.Controller/Dlna/ContainerProfile.cs
@@ -1,12 +1,16 @@
using System.Collections.Generic;
using System.Linq;
+using System.Xml.Serialization;
namespace MediaBrowser.Controller.Dlna
{
public class ContainerProfile
{
+ [XmlAttribute("type")]
public DlnaProfileType Type { get; set; }
public ProfileCondition[] Conditions { get; set; }
+
+ [XmlAttribute("container")]
public string Container { get; set; }
public ContainerProfile()
diff --git a/MediaBrowser.Controller/Dlna/DeviceIdentification.cs b/MediaBrowser.Controller/Dlna/DeviceIdentification.cs
index 461c77537..c9cd4bc70 100644
--- a/MediaBrowser.Controller/Dlna/DeviceIdentification.cs
+++ b/MediaBrowser.Controller/Dlna/DeviceIdentification.cs
@@ -1,4 +1,6 @@

+using System.Xml.Serialization;
+
namespace MediaBrowser.Controller.Dlna
{
public class DeviceIdentification
@@ -41,9 +43,7 @@ namespace MediaBrowser.Controller.Dlna
/// <summary>
/// Gets or sets the manufacturer.
/// </summary>
- /// <value>
- /// The manufacturer.
- /// </value>
+ /// <value>The manufacturer.</value>
public string Manufacturer { get; set; }
/// <summary>
/// Gets or sets the manufacturer URL.
@@ -64,8 +64,13 @@ namespace MediaBrowser.Controller.Dlna
public class HttpHeaderInfo
{
+ [XmlAttribute("name")]
public string Name { get; set; }
+
+ [XmlAttribute("value")]
public string Value { get; set; }
+
+ [XmlAttribute("match")]
public HeaderMatchType Match { get; set; }
}
diff --git a/MediaBrowser.Controller/Dlna/DeviceProfile.cs b/MediaBrowser.Controller/Dlna/DeviceProfile.cs
index f3de1bc34..c1fc713e4 100644
--- a/MediaBrowser.Controller/Dlna/DeviceProfile.cs
+++ b/MediaBrowser.Controller/Dlna/DeviceProfile.cs
@@ -1,6 +1,13 @@
-
+using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Entities;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml.Serialization;
+
namespace MediaBrowser.Controller.Dlna
{
+ [XmlRoot("Profile")]
public class DeviceProfile
{
/// <summary>
@@ -9,25 +16,11 @@ namespace MediaBrowser.Controller.Dlna
/// <value>The name.</value>
public string Name { get; set; }
- /// <summary>
- /// Gets or sets the type of the client.
- /// </summary>
- /// <value>The type of the client.</value>
- public string ClientType { get; set; }
-
- /// <summary>
- /// Gets or sets the transcoding profiles.
- /// </summary>
- /// <value>The transcoding profiles.</value>
- public TranscodingProfile[] TranscodingProfiles { get; set; }
-
- /// <summary>
- /// Gets or sets the direct play profiles.
- /// </summary>
- /// <value>The direct play profiles.</value>
- public DirectPlayProfile[] DirectPlayProfiles { get; set; }
+ [XmlIgnore]
+ public string Id { get; set; }
- public ContainerProfile[] ContainerProfiles { get; set; }
+ [XmlIgnore]
+ public DeviceProfileType ProfileType { get; set; }
/// <summary>
/// Gets or sets the identification.
@@ -43,7 +36,9 @@ namespace MediaBrowser.Controller.Dlna
public string ModelNumber { get; set; }
public string ModelUrl { get; set; }
public bool IgnoreTranscodeByteRangeRequests { get; set; }
- public bool SupportsAlbumArtInDidl { get; set; }
+ public bool EnableAlbumArtInDidl { get; set; }
+
+ public string SupportedMediaTypes { get; set; }
/// <summary>
/// Controls the content of the X_DLNADOC element in the urn:schemas-dlna-org:device-1-0 namespace.
@@ -60,14 +55,27 @@ namespace MediaBrowser.Controller.Dlna
public string ProtocolInfo { get; set; }
- public MediaProfile[] MediaProfiles { get; set; }
- public CodecProfile[] CodecProfiles { get; set; }
-
public int TimelineOffsetSeconds { get; set; }
-
public bool RequiresPlainVideoItems { get; set; }
public bool RequiresPlainFolders { get; set; }
+ /// <summary>
+ /// Gets or sets the direct play profiles.
+ /// </summary>
+ /// <value>The direct play profiles.</value>
+ public DirectPlayProfile[] DirectPlayProfiles { get; set; }
+
+ /// <summary>
+ /// Gets or sets the transcoding profiles.
+ /// </summary>
+ /// <value>The transcoding profiles.</value>
+ public TranscodingProfile[] TranscodingProfiles { get; set; }
+
+ public ContainerProfile[] ContainerProfiles { get; set; }
+
+ public CodecProfile[] CodecProfiles { get; set; }
+ public MediaProfile[] MediaProfiles { get; set; }
+
public DeviceProfile()
{
DirectPlayProfiles = new DirectPlayProfile[] { };
@@ -75,6 +83,149 @@ namespace MediaBrowser.Controller.Dlna
MediaProfiles = new MediaProfile[] { };
CodecProfiles = new CodecProfile[] { };
ContainerProfiles = new ContainerProfile[] { };
+
+ SupportedMediaTypes = "Audio,Photo,Video";
+ }
+
+ public List<string> GetSupportedMediaTypes()
+ {
+ return (SupportedMediaTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
+ }
+
+ public TranscodingProfile GetAudioTranscodingProfile(string container, string audioCodec)
+ {
+ container = (container ?? string.Empty).TrimStart('.');
+
+ return TranscodingProfiles.FirstOrDefault(i =>
+ {
+ if (i.Type != DlnaProfileType.Audio)
+ {
+ return false;
+ }
+
+ if (!string.Equals(container, i.Container, StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+
+ if (!i.GetAudioCodecs().Contains(audioCodec ?? string.Empty))
+ {
+ return false;
+ }
+
+ return true;
+ });
+ }
+
+ public TranscodingProfile GetVideoTranscodingProfile(string container, string audioCodec, string videoCodec)
+ {
+ container = (container ?? string.Empty).TrimStart('.');
+
+ return TranscodingProfiles.FirstOrDefault(i =>
+ {
+ if (i.Type != DlnaProfileType.Video)
+ {
+ return false;
+ }
+
+ if (!string.Equals(container, i.Container, StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+
+ if (!i.GetAudioCodecs().Contains(audioCodec ?? string.Empty))
+ {
+ return false;
+ }
+
+ if (!string.Equals(videoCodec, i.VideoCodec, StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+
+ return true;
+ });
+ }
+
+ public MediaProfile GetAudioMediaProfile(string container, string audioCodec, MediaStream audioStream)
+ {
+ container = (container ?? string.Empty).TrimStart('.');
+
+ return MediaProfiles.FirstOrDefault(i =>
+ {
+ if (i.Type != DlnaProfileType.Audio)
+ {
+ return false;
+ }
+
+ var containers = i.GetContainers().ToList();
+ if (containers.Count > 0 && !containers.Contains(container))
+ {
+ return false;
+ }
+
+ var audioCodecs = i.GetAudioCodecs().ToList();
+ if (audioCodecs.Count > 0 && !audioCodecs.Contains(audioCodec ?? string.Empty))
+ {
+ return false;
+ }
+
+ return true;
+ });
+ }
+
+ public MediaProfile GetVideoMediaProfile(string container, string audioCodec, string videoCodec, MediaStream audioStream, MediaStream videoStream)
+ {
+ container = (container ?? string.Empty).TrimStart('.');
+
+ return MediaProfiles.FirstOrDefault(i =>
+ {
+ if (i.Type != DlnaProfileType.Video)
+ {
+ return false;
+ }
+
+ var containers = i.GetContainers().ToList();
+ if (containers.Count > 0 && !containers.Contains(container))
+ {
+ return false;
+ }
+
+ var audioCodecs = i.GetAudioCodecs().ToList();
+ if (audioCodecs.Count > 0 && !audioCodecs.Contains(audioCodec ?? string.Empty))
+ {
+ return false;
+ }
+
+ var videoCodecs = i.GetVideoCodecs().ToList();
+ if (videoCodecs.Count > 0 && !videoCodecs.Contains(videoCodec ?? string.Empty))
+ {
+ return false;
+ }
+
+ return true;
+ });
+ }
+
+ public MediaProfile GetPhotoMediaProfile(string container)
+ {
+ container = (container ?? string.Empty).TrimStart('.');
+
+ return MediaProfiles.FirstOrDefault(i =>
+ {
+ if (i.Type != DlnaProfileType.Photo)
+ {
+ return false;
+ }
+
+ var containers = i.GetContainers().ToList();
+ if (containers.Count > 0 && !containers.Contains(container))
+ {
+ return false;
+ }
+
+ return true;
+ });
}
}
}
diff --git a/MediaBrowser.Controller/Dlna/DirectPlayProfile.cs b/MediaBrowser.Controller/Dlna/DirectPlayProfile.cs
index 686b31287..ad70640da 100644
--- a/MediaBrowser.Controller/Dlna/DirectPlayProfile.cs
+++ b/MediaBrowser.Controller/Dlna/DirectPlayProfile.cs
@@ -1,14 +1,21 @@
using System.Collections.Generic;
using System.Linq;
+using System.Xml.Serialization;
namespace MediaBrowser.Controller.Dlna
{
public class DirectPlayProfile
{
+ [XmlAttribute("container")]
public string Container { get; set; }
+
+ [XmlAttribute("audioCodec")]
public string AudioCodec { get; set; }
+
+ [XmlAttribute("videoCodec")]
public string VideoCodec { get; set; }
+ [XmlAttribute("type")]
public DlnaProfileType Type { get; set; }
public List<string> GetContainers()
diff --git a/MediaBrowser.Controller/Dlna/IDlnaManager.cs b/MediaBrowser.Controller/Dlna/IDlnaManager.cs
index 6de17e551..521d17e01 100644
--- a/MediaBrowser.Controller/Dlna/IDlnaManager.cs
+++ b/MediaBrowser.Controller/Dlna/IDlnaManager.cs
@@ -1,22 +1,55 @@
-using System.Collections.Generic;
+using MediaBrowser.Model.Dlna;
+using System.Collections.Generic;
namespace MediaBrowser.Controller.Dlna
{
public interface IDlnaManager
{
/// <summary>
- /// Gets the dlna profiles.
+ /// Gets the profile infos.
/// </summary>
- /// <returns>IEnumerable{DlnaProfile}.</returns>
- IEnumerable<DeviceProfile> GetProfiles();
+ /// <returns>IEnumerable{DeviceProfileInfo}.</returns>
+ IEnumerable<DeviceProfileInfo> GetProfileInfos();
+
+ /// <summary>
+ /// Gets the profile.
+ /// </summary>
+ /// <param name="headers">The headers.</param>
+ /// <returns>DeviceProfile.</returns>
+ DeviceProfile GetProfile(IDictionary<string,string> headers);
/// <summary>
/// Gets the default profile.
/// </summary>
- /// <returns>DlnaProfile.</returns>
+ /// <returns>DeviceProfile.</returns>
DeviceProfile GetDefaultProfile();
/// <summary>
+ /// Creates the profile.
+ /// </summary>
+ /// <param name="profile">The profile.</param>
+ void CreateProfile(DeviceProfile profile);
+
+ /// <summary>
+ /// Updates the profile.
+ /// </summary>
+ /// <param name="profile">The profile.</param>
+ void UpdateProfile(DeviceProfile profile);
+
+ /// <summary>
+ /// Deletes the profile.
+ /// </summary>
+ /// <param name="id">The identifier.</param>
+ void DeleteProfile(string id);
+
+ /// <summary>
+ /// Gets the profile.
+ /// </summary>
+ /// <param name="id">The identifier.</param>
+ /// <returns>DeviceProfile.</returns>
+ DeviceProfile GetProfile(string id);
+
+ /// <summary>
/// Gets the profile.
/// </summary>
/// <param name="deviceInfo">The device information.</param>
diff --git a/MediaBrowser.Controller/Dlna/MediaProfile.cs b/MediaBrowser.Controller/Dlna/MediaProfile.cs
index 1d2613fac..bf3057294 100644
--- a/MediaBrowser.Controller/Dlna/MediaProfile.cs
+++ b/MediaBrowser.Controller/Dlna/MediaProfile.cs
@@ -1,16 +1,27 @@
using System.Collections.Generic;
using System.Linq;
+using System.Xml.Serialization;
namespace MediaBrowser.Controller.Dlna
{
public class MediaProfile
{
+ [XmlAttribute("container")]
public string Container { get; set; }
+
+ [XmlAttribute("audioCodec")]
public string AudioCodec { get; set; }
+
+ [XmlAttribute("videoCodec")]
public string VideoCodec { get; set; }
+ [XmlAttribute("type")]
public DlnaProfileType Type { get; set; }
+
+ [XmlAttribute("orgPn")]
public string OrgPn { get; set; }
+
+ [XmlAttribute("mimeType")]
public string MimeType { get; set; }
public ProfileCondition[] Conditions { get; set; }
@@ -19,6 +30,11 @@ namespace MediaBrowser.Controller.Dlna
{
Conditions = new ProfileCondition[] {};
}
+
+ public List<string> GetContainers()
+ {
+ return (Container ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
+ }
public List<string> GetAudioCodecs()
{
diff --git a/MediaBrowser.Controller/Dlna/TranscodingProfile.cs b/MediaBrowser.Controller/Dlna/TranscodingProfile.cs
index 007cb632e..707f0c573 100644
--- a/MediaBrowser.Controller/Dlna/TranscodingProfile.cs
+++ b/MediaBrowser.Controller/Dlna/TranscodingProfile.cs
@@ -1,17 +1,33 @@
-
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml.Serialization;
+
namespace MediaBrowser.Controller.Dlna
{
public class TranscodingProfile
{
+ [XmlAttribute("container")]
public string Container { get; set; }
+ [XmlAttribute("type")]
public DlnaProfileType Type { get; set; }
+ [XmlAttribute("videoCodec")]
public string VideoCodec { get; set; }
+
+ [XmlAttribute("audioCodec")]
public string AudioCodec { get; set; }
+ [XmlAttribute("protocol")]
+ public string Protocol { get; set; }
+
+ [XmlAttribute("estimateContentLength")]
public bool EstimateContentLength { get; set; }
+ [XmlAttribute("enableMpegtsM2TsMode")]
+ public bool EnableMpegtsM2TsMode { get; set; }
+
+ [XmlAttribute("transcodeSeekInfo")]
public TranscodeSeekInfo TranscodeSeekInfo { get; set; }
public TranscodingSetting[] Settings { get; set; }
@@ -21,12 +37,19 @@ namespace MediaBrowser.Controller.Dlna
Settings = new TranscodingSetting[] { };
}
- public bool EnableMpegtsM2TsMode { get; set; }
+
+ public List<string> GetAudioCodecs()
+ {
+ return (AudioCodec ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
+ }
}
public class TranscodingSetting
{
+ [XmlAttribute("name")]
public TranscodingSettingType Name { get; set; }
+
+ [XmlAttribute("value")]
public string Value { get; set; }
}
diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs
index b3d73dc34..53ec030a7 100644
--- a/MediaBrowser.Controller/Entities/Trailer.cs
+++ b/MediaBrowser.Controller/Entities/Trailer.cs
@@ -3,8 +3,9 @@ using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic;
-using System.Runtime.Serialization;
+using System.Globalization;
using System.Linq;
+using System.Runtime.Serialization;
namespace MediaBrowser.Controller.Entities
{
@@ -22,7 +23,7 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <value>The preferred metadata country code.</value>
public string PreferredMetadataCountryCode { get; set; }
-
+
public Trailer()
{
RemoteTrailers = new List<MediaUrl>();
@@ -33,19 +34,19 @@ namespace MediaBrowser.Controller.Entities
}
public float? Metascore { get; set; }
-
+
public List<Guid> LocalTrailerIds { get; set; }
-
+
public List<MediaUrl> RemoteTrailers { get; set; }
public List<string> Keywords { get; set; }
-
+
/// <summary>
/// Gets or sets the taglines.
/// </summary>
/// <value>The taglines.</value>
public List<string> Taglines { get; set; }
-
+
/// <summary>
/// Gets or sets the budget.
/// </summary>
@@ -92,6 +93,12 @@ namespace MediaBrowser.Controller.Entities
{
key = key + "-trailer";
+ // Make sure different trailers have their own data.
+ if (RunTimeTicks.HasValue)
+ {
+ key += "-" + RunTimeTicks.Value.ToString(CultureInfo.InvariantCulture);
+ }
+
return key;
}
diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs
index e6a62c181..0a34b8016 100644
--- a/MediaBrowser.Controller/Entities/User.cs
+++ b/MediaBrowser.Controller/Entities/User.cs
@@ -121,10 +121,7 @@ namespace MediaBrowser.Controller.Entities
{
_configuration = value;
- if (value == null)
- {
- _configurationInitialized = false;
- }
+ _configurationInitialized = value != null;
}
}
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 5e6297d06..9915ac044 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -157,6 +157,7 @@
<Compile Include="Localization\ILocalizationManager.cs" />
<Compile Include="MediaEncoding\ChapterImageRefreshOptions.cs" />
<Compile Include="MediaEncoding\IEncodingManager.cs" />
+ <Compile Include="MediaEncoding\ImageEncodingOptions.cs" />
<Compile Include="MediaEncoding\IMediaEncoder.cs" />
<Compile Include="MediaEncoding\InternalMediaInfoResult.cs" />
<Compile Include="Net\IHasResultFactory.cs" />
@@ -187,6 +188,7 @@
<Compile Include="Providers\MetadataRefreshOptions.cs" />
<Compile Include="Providers\NameParser.cs" />
<Compile Include="Providers\MetadataStatus.cs" />
+ <Compile Include="Providers\ISeriesOrderManager.cs" />
<Compile Include="Session\ISessionManager.cs" />
<Compile Include="Drawing\ImageExtensions.cs" />
<Compile Include="Entities\AggregateFolder.cs" />
diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
index 119688fa7..e9081fe8a 100644
--- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
+++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
@@ -24,16 +24,23 @@ namespace MediaBrowser.Controller.MediaEncoding
string Version { get; }
/// <summary>
- /// Extracts the image.
+ /// Extracts the audio image.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task{Stream}.</returns>
+ Task<Stream> ExtractAudioImage(string path, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Extracts the video image.
/// </summary>
/// <param name="inputFiles">The input files.</param>
/// <param name="type">The type.</param>
- /// <param name="isAudio">if set to <c>true</c> [is audio].</param>
/// <param name="threedFormat">The threed format.</param>
/// <param name="offset">The offset.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{Stream}.</returns>
- Task<Stream> ExtractImage(string[] inputFiles, InputType type, bool isAudio, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken);
+ Task<Stream> ExtractVideoImage(string[] inputFiles, InputType type, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken);
/// <summary>
/// Extracts the text subtitle.
@@ -81,6 +88,14 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <param name="type">The type.</param>
/// <returns>System.String.</returns>
string GetInputArgument(string[] inputFiles, InputType type);
+
+ /// <summary>
+ /// Encodes the image.
+ /// </summary>
+ /// <param name="options">The options.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task{Stream}.</returns>
+ Task<Stream> EncodeImage(ImageEncodingOptions options, CancellationToken cancellationToken);
}
/// <summary>
diff --git a/MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs b/MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs
new file mode 100644
index 000000000..a8d1e5a0f
--- /dev/null
+++ b/MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs
@@ -0,0 +1,20 @@
+
+namespace MediaBrowser.Controller.MediaEncoding
+{
+ public class ImageEncodingOptions
+ {
+ public string InputPath { get; set; }
+
+ public int? Width { get; set; }
+
+ public int? Height { get; set; }
+
+ public int? MaxWidth { get; set; }
+
+ public int? MaxHeight { get; set; }
+
+ public int? Quality { get; set; }
+
+ public string Format { get; set; }
+ }
+}
diff --git a/MediaBrowser.Controller/MediaEncoding/InternalMediaInfoResult.cs b/MediaBrowser.Controller/MediaEncoding/InternalMediaInfoResult.cs
index e113521ec..39d1c3220 100644
--- a/MediaBrowser.Controller/MediaEncoding/InternalMediaInfoResult.cs
+++ b/MediaBrowser.Controller/MediaEncoding/InternalMediaInfoResult.cs
@@ -1,5 +1,4 @@
-using MediaBrowser.Model.Entities;
-using System.Collections.Generic;
+using System.Collections.Generic;
namespace MediaBrowser.Controller.MediaEncoding
{
@@ -24,7 +23,18 @@ namespace MediaBrowser.Controller.MediaEncoding
/// Gets or sets the chapters.
/// </summary>
/// <value>The chapters.</value>
- public List<ChapterInfo> Chapters { get; set; }
+ public MediaChapter[] Chapters { get; set; }
+ }
+
+ public class MediaChapter
+ {
+ public int id { get; set; }
+ public string time_base { get; set; }
+ public long start { get; set; }
+ public string start_time { get; set; }
+ public long end { get; set; }
+ public string end_time { get; set; }
+ public Dictionary<string, string> tags { get; set; }
}
/// <summary>
diff --git a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
index 184033177..fd1f65101 100644
--- a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
+++ b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
@@ -154,7 +154,8 @@ namespace MediaBrowser.Controller.MediaEncoding
Codec = streamInfo.codec_name,
Profile = streamInfo.profile,
Level = streamInfo.level,
- Index = streamInfo.index
+ Index = streamInfo.index,
+ PixelFormat = streamInfo.pix_fmt
};
if (streamInfo.tags != null)
@@ -196,24 +197,21 @@ namespace MediaBrowser.Controller.MediaEncoding
}
// Get stream bitrate
- if (stream.Type != MediaStreamType.Subtitle)
- {
- var bitrate = 0;
+ var bitrate = 0;
- if (!string.IsNullOrEmpty(streamInfo.bit_rate))
- {
- bitrate = int.Parse(streamInfo.bit_rate, UsCulture);
- }
- else if (formatInfo != null && !string.IsNullOrEmpty(formatInfo.bit_rate))
- {
- // If the stream info doesn't have a bitrate get the value from the media format info
- bitrate = int.Parse(formatInfo.bit_rate, UsCulture);
- }
+ if (!string.IsNullOrEmpty(streamInfo.bit_rate))
+ {
+ bitrate = int.Parse(streamInfo.bit_rate, UsCulture);
+ }
+ else if (formatInfo != null && !string.IsNullOrEmpty(formatInfo.bit_rate) && stream.Type == MediaStreamType.Video)
+ {
+ // If the stream info doesn't have a bitrate get the value from the media format info
+ bitrate = int.Parse(formatInfo.bit_rate, UsCulture);
+ }
- if (bitrate > 0)
- {
- stream.BitRate = bitrate;
- }
+ if (bitrate > 0)
+ {
+ stream.BitRate = bitrate;
}
if (streamInfo.disposition != null)
diff --git a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs
index d71c7af32..70b49efec 100644
--- a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs
+++ b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs
@@ -1,5 +1,4 @@
using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
@@ -284,22 +283,6 @@ namespace MediaBrowser.Controller.Providers
break;
}
- case "TagLine":
- {
- var tagline = reader.ReadElementContentAsString();
-
- var hasTaglines = item as IHasTaglines;
- if (hasTaglines != null)
- {
- if (!string.IsNullOrWhiteSpace(tagline))
- {
- hasTaglines.AddTagline(tagline);
- }
- }
-
- break;
- }
-
case "Language":
{
var val = reader.ReadElementContentAsString();
@@ -380,9 +363,7 @@ namespace MediaBrowser.Controller.Providers
}
case "ContentRating":
- case "certification":
case "MPAARating":
- case "ESRBRating":
{
var rating = reader.ReadElementContentAsString();
@@ -415,7 +396,6 @@ namespace MediaBrowser.Controller.Providers
break;
}
- case "Runtime":
case "RunningTime":
{
var text = reader.ReadElementContentAsString();
@@ -431,19 +411,6 @@ namespace MediaBrowser.Controller.Providers
break;
}
- case "Genre":
- {
- foreach (var name in SplitNames(reader.ReadElementContentAsString()))
- {
- if (string.IsNullOrWhiteSpace(name))
- {
- continue;
- }
- item.AddGenre(name);
- }
- break;
- }
-
case "AspectRatio":
{
var val = reader.ReadElementContentAsString();
@@ -587,7 +554,6 @@ namespace MediaBrowser.Controller.Providers
break;
}
- case "ReleaseYear":
case "ProductionYear":
{
var val = reader.ReadElementContentAsString();
@@ -606,7 +572,6 @@ namespace MediaBrowser.Controller.Providers
case "Rating":
case "IMDBrating":
- case "TGDBRating":
{
var rating = reader.ReadElementContentAsString();
@@ -683,22 +648,6 @@ namespace MediaBrowser.Controller.Providers
}
break;
}
- case "MusicbrainzId":
- {
- var mbz = reader.ReadElementContentAsString();
- if (!string.IsNullOrWhiteSpace(mbz))
- {
- if (item is MusicAlbum)
- {
- item.SetProviderId(MetadataProviders.MusicBrainzAlbum, mbz);
- }
- else if (item is MusicArtist)
- {
- item.SetProviderId(MetadataProviders.MusicBrainzArtist, mbz);
- }
- }
- break;
- }
case "MusicBrainzAlbumId":
{
var mbz = reader.ReadElementContentAsString();
@@ -802,9 +751,7 @@ namespace MediaBrowser.Controller.Providers
}
break;
- case "IMDB_ID":
case "IMDB":
- case "IMDbId":
var imDbId = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(imDbId))
{
@@ -856,15 +803,6 @@ namespace MediaBrowser.Controller.Providers
break;
}
- case "ParentalRating":
- {
- using (var subtree = reader.ReadSubtree())
- {
- FetchFromParentalRatingNode(subtree, item);
- }
- break;
- }
-
case "Studios":
{
using (var subtree = reader.ReadSubtree())
@@ -1228,32 +1166,6 @@ namespace MediaBrowser.Controller.Providers
}
/// <summary>
- /// Fetches from parental rating node.
- /// </summary>
- /// <param name="reader">The reader.</param>
- /// <param name="item">The item.</param>
- private void FetchFromParentalRatingNode(XmlReader reader, T item)
- {
- reader.MoveToContent();
-
- while (reader.Read())
- {
- if (reader.NodeType == XmlNodeType.Element)
- {
- switch (reader.Name)
- {
- // Removed support for "Value" tag as it conflicted with MPAA rating but leaving this function for possible
- // future support of "Description" -ebr
-
- default:
- reader.Skip();
- break;
- }
- }
- }
- }
-
- /// <summary>
/// Gets the persons from XML node.
/// </summary>
/// <param name="reader">The reader.</param>
diff --git a/MediaBrowser.Controller/Providers/ISeriesOrderManager.cs b/MediaBrowser.Controller/Providers/ISeriesOrderManager.cs
new file mode 100644
index 000000000..a3adab1b9
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/ISeriesOrderManager.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using MediaBrowser.Common;
+
+namespace MediaBrowser.Controller.Providers
+{
+ public interface ISeriesOrderProvider
+ {
+ string OrderType { get; }
+ Task<int?> FindSeriesIndex(string seriesName);
+ }
+
+ public static class SeriesOrderTypes
+ {
+ public const string Anime = "Anime";
+ }
+
+ public interface ISeriesOrderManager
+ {
+ Task<int?> FindSeriesIndex(string orderType, string seriesName);
+ void AddParts(IEnumerable<ISeriesOrderProvider> orderProviders);
+ }
+}
diff --git a/MediaBrowser.Controller/Session/ISessionController.cs b/MediaBrowser.Controller/Session/ISessionController.cs
index 21206af75..02cc875bd 100644
--- a/MediaBrowser.Controller/Session/ISessionController.cs
+++ b/MediaBrowser.Controller/Session/ISessionController.cs
@@ -60,6 +60,14 @@ namespace MediaBrowser.Controller.Session
Task SendPlaystateCommand(PlaystateRequest command, CancellationToken cancellationToken);
/// <summary>
+ /// Sends the generic command.
+ /// </summary>
+ /// <param name="command">The command.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task SendGenericCommand(GenericCommand command, CancellationToken cancellationToken);
+
+ /// <summary>
/// Sends the library update info.
/// </summary>
/// <param name="info">The info.</param>
diff --git a/MediaBrowser.Dlna/DlnaManager.cs b/MediaBrowser.Dlna/DlnaManager.cs
index c6da865cd..ec9ecb9ef 100644
--- a/MediaBrowser.Dlna/DlnaManager.cs
+++ b/MediaBrowser.Dlna/DlnaManager.cs
@@ -1,9 +1,14 @@
using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Dlna.Profiles;
+using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
+using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
@@ -11,22 +16,37 @@ namespace MediaBrowser.Dlna
{
public class DlnaManager : IDlnaManager
{
- private IApplicationPaths _appPaths;
+ private readonly IApplicationPaths _appPaths;
private readonly IXmlSerializer _xmlSerializer;
private readonly IFileSystem _fileSystem;
- private readonly IJsonSerializer _jsonSerializer;
+ private readonly ILogger _logger;
- public DlnaManager(IXmlSerializer xmlSerializer, IFileSystem fileSystem, IJsonSerializer jsonSerializer)
+ public DlnaManager(IXmlSerializer xmlSerializer, IFileSystem fileSystem, IApplicationPaths appPaths, ILogger logger)
{
_xmlSerializer = xmlSerializer;
_fileSystem = fileSystem;
- _jsonSerializer = jsonSerializer;
+ _appPaths = appPaths;
+ _logger = logger;
- GetProfiles();
+ //DumpProfiles();
}
public IEnumerable<DeviceProfile> GetProfiles()
{
+ ExtractProfilesIfNeeded();
+
+ var list = GetProfiles(UserProfilesPath, DeviceProfileType.User)
+ .OrderBy(i => i.Name)
+ .ToList();
+
+ list.AddRange(GetProfiles(SystemProfilesPath, DeviceProfileType.System)
+ .OrderBy(i => i.Name));
+
+ return list;
+ }
+
+ private void DumpProfiles()
+ {
var list = new List<DeviceProfile>
{
new SamsungSmartTvProfile(),
@@ -43,27 +63,72 @@ namespace MediaBrowser.Dlna
new WdtvLiveProfile(),
new DenonAvrProfile(),
new LinksysDMA2100Profile(),
- new LgTvProfile()
+ new LgTvProfile(),
+ new Foobar2000Profile(),
+ new DefaultProfile()
};
foreach (var item in list)
{
- //_xmlSerializer.SerializeToFile(item, "d:\\" + _fileSystem.GetValidFilename(item.Name) + ".xml");
- //_jsonSerializer.SerializeToFile(item, "d:\\" + _fileSystem.GetValidFilename(item.Name) + ".json");
+ var path = Path.Combine(_appPaths.ProgramDataPath, _fileSystem.GetValidFilename(item.Name) + ".xml");
+
+ _xmlSerializer.SerializeToFile(item, path);
}
+ }
- return list;
+ private bool _extracted;
+ private readonly object _syncLock = new object();
+ private void ExtractProfilesIfNeeded()
+ {
+ if (!_extracted)
+ {
+ lock (_syncLock)
+ {
+ if (!_extracted)
+ {
+ try
+ {
+ ExtractSystemProfiles();
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error extracting DLNA profiles.", ex);
+ }
+
+ _extracted = true;
+ }
+
+ }
+ }
}
public DeviceProfile GetDefaultProfile()
{
+ ExtractProfilesIfNeeded();
+
return new DefaultProfile();
}
public DeviceProfile GetProfile(DeviceIdentification deviceInfo)
{
- return GetProfiles().FirstOrDefault(i => IsMatch(deviceInfo, i.Identification)) ??
- GetDefaultProfile();
+ if (deviceInfo == null)
+ {
+ throw new ArgumentNullException("deviceInfo");
+ }
+
+ var profile = GetProfiles()
+ .FirstOrDefault(i => i.Identification != null && IsMatch(deviceInfo, i.Identification));
+
+ if (profile != null)
+ {
+ _logger.Debug("Found matching device profile: {0}", profile.Name);
+ }
+ else
+ {
+ _logger.Debug("No matching device profile found. The default will need to be used.");
+ }
+
+ return profile;
}
private bool IsMatch(DeviceIdentification deviceInfo, DeviceIdentification profileInfo)
@@ -124,5 +189,208 @@ namespace MediaBrowser.Dlna
return true;
}
+
+ public DeviceProfile GetProfile(IDictionary<string, string> headers)
+ {
+ if (headers == null)
+ {
+ throw new ArgumentNullException("headers");
+ }
+
+ return GetProfiles().FirstOrDefault(i => i.Identification != null && IsMatch(headers, i.Identification));
+ }
+
+ private bool IsMatch(IDictionary<string, string> headers, DeviceIdentification profileInfo)
+ {
+ return profileInfo.Headers.Any(i => IsMatch(headers, i));
+ }
+
+ private bool IsMatch(IDictionary<string, string> headers, HttpHeaderInfo header)
+ {
+ string value;
+
+ if (headers.TryGetValue(header.Name, out value))
+ {
+ switch (header.Match)
+ {
+ case HeaderMatchType.Equals:
+ return string.Equals(value, header.Value, StringComparison.OrdinalIgnoreCase);
+ case HeaderMatchType.Substring:
+ return value.IndexOf(header.Value, StringComparison.OrdinalIgnoreCase) != -1;
+ case HeaderMatchType.Regex:
+ return Regex.IsMatch(value, header.Value, RegexOptions.IgnoreCase);
+ default:
+ throw new ArgumentException("Unrecognized HeaderMatchType");
+ }
+ }
+
+ return false;
+ }
+
+ private string UserProfilesPath
+ {
+ get
+ {
+ return Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "user");
+ }
+ }
+
+ private string SystemProfilesPath
+ {
+ get
+ {
+ return Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "system");
+ }
+ }
+
+ private IEnumerable<DeviceProfile> GetProfiles(string path, DeviceProfileType type)
+ {
+ try
+ {
+ return new DirectoryInfo(path)
+ .EnumerateFiles("*", SearchOption.TopDirectoryOnly)
+ .Where(i => string.Equals(i.Extension, ".xml", StringComparison.OrdinalIgnoreCase))
+ .Select(i => ParseProfileXmlFile(i.FullName, type))
+ .Where(i => i != null)
+ .ToList();
+ }
+ catch (DirectoryNotFoundException)
+ {
+ return new List<DeviceProfile>();
+ }
+ }
+
+ private DeviceProfile ParseProfileXmlFile(string path, DeviceProfileType type)
+ {
+ try
+ {
+ var profile = (DeviceProfile)_xmlSerializer.DeserializeFromFile(typeof(DeviceProfile), path);
+
+ profile.Id = path.ToLower().GetMD5().ToString("N");
+ profile.ProfileType = type;
+
+ return profile;
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error parsing profile xml: {0}", ex, path);
+
+ return null;
+ }
+ }
+
+ public DeviceProfile GetProfile(string id)
+ {
+ if (string.IsNullOrWhiteSpace(id))
+ {
+ throw new ArgumentNullException("id");
+ }
+
+ var info = GetProfileInfosInternal().First(i => string.Equals(i.Info.Id, id));
+
+ return ParseProfileXmlFile(info.Path, info.Info.Type);
+ }
+
+ private IEnumerable<InternalProfileInfo> GetProfileInfosInternal()
+ {
+ ExtractProfilesIfNeeded();
+
+ return GetProfileInfos(UserProfilesPath, DeviceProfileType.User)
+ .Concat(GetProfileInfos(SystemProfilesPath, DeviceProfileType.System))
+ .OrderBy(i => i.Info.Type == DeviceProfileType.User ? 0 : 1)
+ .ThenBy(i => i.Info.Name);
+ }
+
+ public IEnumerable<DeviceProfileInfo> GetProfileInfos()
+ {
+ return GetProfileInfosInternal().Select(i => i.Info);
+ }
+
+ private IEnumerable<InternalProfileInfo> GetProfileInfos(string path, DeviceProfileType type)
+ {
+ try
+ {
+ return new DirectoryInfo(path)
+ .EnumerateFiles("*", SearchOption.TopDirectoryOnly)
+ .Where(i => string.Equals(i.Extension, ".xml", StringComparison.OrdinalIgnoreCase))
+ .Select(i => new InternalProfileInfo
+ {
+ Path = i.FullName,
+
+ Info = new DeviceProfileInfo
+ {
+ Id = i.FullName.ToLower().GetMD5().ToString("N"),
+ Name = Path.GetFileNameWithoutExtension(i.FullName),
+ Type = type
+ }
+ })
+ .ToList();
+ }
+ catch (DirectoryNotFoundException)
+ {
+ return new List<InternalProfileInfo>();
+ }
+ }
+
+ private void ExtractSystemProfiles()
+ {
+ var assembly = GetType().Assembly;
+ var namespaceName = GetType().Namespace + ".Profiles.Xml.";
+
+ var systemProfilesPath = SystemProfilesPath;
+
+ foreach (var name in assembly.GetManifestResourceNames()
+ .Where(i => i.StartsWith(namespaceName))
+ .ToList())
+ {
+ var filename = Path.GetFileName(name).Substring(namespaceName.Length);
+
+ var path = Path.Combine(systemProfilesPath, filename);
+
+ using (var stream = assembly.GetManifestResourceStream(name))
+ {
+ var fileInfo = new FileInfo(path);
+
+ if (!fileInfo.Exists || fileInfo.Length != stream.Length)
+ {
+ Directory.CreateDirectory(systemProfilesPath);
+
+ using (var fileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
+ {
+ stream.CopyTo(fileStream);
+ }
+ }
+ }
+ }
+
+ // Not necessary, but just to make it easy to find
+ Directory.CreateDirectory(UserProfilesPath);
+ }
+
+ public void DeleteProfile(string id)
+ {
+ var info = GetProfileInfosInternal().First(i => string.Equals(id, i.Info.Id));
+
+ if (info.Info.Type == DeviceProfileType.System)
+ {
+ throw new ArgumentException("System profiles cannot be deleted.");
+ }
+
+ File.Delete(info.Path);
+ }
+
+ public void CreateProfile(DeviceProfile profile)
+ {
+ }
+
+ public void UpdateProfile(DeviceProfile profile)
+ {
+ }
+
+ class InternalProfileInfo
+ {
+ internal DeviceProfileInfo Info { get; set; }
+ internal string Path { get; set; }
+ }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj
index bea281b61..df1fed12f 100644
--- a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj
+++ b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj
@@ -61,7 +61,6 @@
<Compile Include="PlayTo\DeviceService.cs" />
<Compile Include="PlayTo\DidlBuilder.cs" />
<Compile Include="PlayTo\DlnaController.cs" />
- <Compile Include="PlayTo\DlnaControllerFactory.cs" />
<Compile Include="PlayTo\Extensions.cs" />
<Compile Include="PlayTo\PlaylistItem.cs">
<SubType>Code</SubType>
@@ -70,7 +69,8 @@
<Compile Include="PlayTo\PlayToManager.cs" />
<Compile Include="PlayTo\PlayToServerEntryPoint.cs" />
<Compile Include="PlayTo\ServiceAction.cs" />
- <Compile Include="PlayTo\SsdpHelper.cs" />
+ <Compile Include="Profiles\Foobar2000Profile.cs" />
+ <Compile Include="Ssdp\SsdpHelper.cs" />
<Compile Include="PlayTo\SsdpHttpClient.cs" />
<Compile Include="PlayTo\StateVariable.cs" />
<Compile Include="PlayTo\StreamHelper.cs" />
@@ -100,7 +100,6 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Server\DlnaServerEntryPoint.cs" />
<Compile Include="Server\Headers.cs" />
- <Compile Include="Server\RawHeaders.cs" />
<Compile Include="Server\SsdpHandler.cs" />
<Compile Include="Server\UpnpDevice.cs" />
</ItemGroup>
@@ -118,7 +117,27 @@
<Name>MediaBrowser.Model</Name>
</ProjectReference>
</ItemGroup>
- <ItemGroup />
+ <ItemGroup>
+ <EmbeddedResource Include="Profiles\Xml\Denon AVR.xml" />
+ <EmbeddedResource Include="Profiles\Xml\foobar2000.xml" />
+ <EmbeddedResource Include="Profiles\Xml\LG Smart TV.xml" />
+ <EmbeddedResource Include="Profiles\Xml\Linksys DMA2100.xml" />
+ <EmbeddedResource Include="Profiles\Xml\Panasonic Viera.xml" />
+ <EmbeddedResource Include="Profiles\Xml\Samsung Smart TV.xml" />
+ <EmbeddedResource Include="Profiles\Xml\Sony Blu-ray Player 2013.xml" />
+ <EmbeddedResource Include="Profiles\Xml\Sony Blu-ray Player.xml" />
+ <EmbeddedResource Include="Profiles\Xml\Sony Bravia %282010%29.xml" />
+ <EmbeddedResource Include="Profiles\Xml\Sony Bravia %282011%29.xml" />
+ <EmbeddedResource Include="Profiles\Xml\Sony Bravia %282012%29.xml" />
+ <EmbeddedResource Include="Profiles\Xml\Sony Bravia %282013%29.xml" />
+ <EmbeddedResource Include="Profiles\Xml\Sony PlayStation 3.xml" />
+ <EmbeddedResource Include="Profiles\Xml\WDTV Live.xml" />
+ <EmbeddedResource Include="Profiles\Xml\Xbox 360.xml" />
+ <EmbeddedResource Include="Profiles\Xml\Xbox One.xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Include="Profiles\Xml\Default.xml" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
diff --git a/MediaBrowser.Dlna/PlayTo/CurrentIdEventArgs.cs b/MediaBrowser.Dlna/PlayTo/CurrentIdEventArgs.cs
index 24158b890..c34293e52 100644
--- a/MediaBrowser.Dlna/PlayTo/CurrentIdEventArgs.cs
+++ b/MediaBrowser.Dlna/PlayTo/CurrentIdEventArgs.cs
@@ -4,18 +4,6 @@ namespace MediaBrowser.Dlna.PlayTo
{
public class CurrentIdEventArgs : EventArgs
{
- public Guid Id { get; set; }
-
- public CurrentIdEventArgs(string id)
- {
- if (string.IsNullOrWhiteSpace(id) || id == "0")
- {
- Id = Guid.Empty;
- }
- else
- {
- Id = new Guid(id);
- }
- }
+ public string Id { get; set; }
}
}
diff --git a/MediaBrowser.Dlna/PlayTo/Device.cs b/MediaBrowser.Dlna/PlayTo/Device.cs
index 2b43c019c..c0f88f285 100644
--- a/MediaBrowser.Dlna/PlayTo/Device.cs
+++ b/MediaBrowser.Dlna/PlayTo/Device.cs
@@ -42,6 +42,7 @@ namespace MediaBrowser.Dlna.PlayTo
if (_currentId == value)
return;
_currentId = value;
+
NotifyCurrentIdChanged(value);
}
}
@@ -250,7 +251,7 @@ namespace MediaBrowser.Dlna.PlayTo
StopTimer();
await SetStop().ConfigureAwait(false);
- CurrentId = "0";
+ CurrentId = null;
var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetAVTransportURI");
if (command == null)
@@ -514,7 +515,7 @@ namespace MediaBrowser.Dlna.PlayTo
if (String.IsNullOrEmpty(track))
{
- CurrentId = "0";
+ CurrentId = null;
return;
}
@@ -607,7 +608,7 @@ namespace MediaBrowser.Dlna.PlayTo
url = "/" + url;
var httpClient = new SsdpHttpClient(_httpClient, _config);
- var document = await httpClient.GetDataAsync(new Uri(Properties.BaseUrl + url));
+ var document = await httpClient.GetDataAsync(Properties.BaseUrl + url);
AvCommands = TransportCommands.Create(document);
}
@@ -625,12 +626,12 @@ namespace MediaBrowser.Dlna.PlayTo
url = "/" + url;
var httpClient = new SsdpHttpClient(_httpClient, _config);
- var document = await httpClient.GetDataAsync(new Uri(Properties.BaseUrl + url));
+ var document = await httpClient.GetDataAsync(Properties.BaseUrl + url);
RendererCommands = TransportCommands.Create(document);
}
- internal TransportCommands AvCommands
+ private TransportCommands AvCommands
{
get;
set;
@@ -646,7 +647,7 @@ namespace MediaBrowser.Dlna.PlayTo
{
var ssdpHttpClient = new SsdpHttpClient(httpClient, config);
- var document = await ssdpHttpClient.GetDataAsync(url).ConfigureAwait(false);
+ var document = await ssdpHttpClient.GetDataAsync(url.ToString()).ConfigureAwait(false);
var deviceProperties = new DeviceInfo();
@@ -681,10 +682,18 @@ namespace MediaBrowser.Dlna.PlayTo
var presentationUrl = document.Descendants(uPnpNamespaces.ud.GetName("presentationURL")).FirstOrDefault();
if (presentationUrl != null)
deviceProperties.PresentationUrl = presentationUrl.Value;
+
var modelUrl = document.Descendants(uPnpNamespaces.ud.GetName("modelURL")).FirstOrDefault();
if (modelUrl != null)
deviceProperties.ModelUrl = modelUrl.Value;
-
+
+ var serialNumber = document.Descendants(uPnpNamespaces.ud.GetName("serialNumber")).FirstOrDefault();
+ if (serialNumber != null)
+ deviceProperties.SerialNumber = serialNumber.Value;
+
+ var modelDescription = document.Descendants(uPnpNamespaces.ud.GetName("modelDescription")).FirstOrDefault();
+ if (modelDescription != null)
+ deviceProperties.ModelDescription = modelDescription.Value;
deviceProperties.BaseUrl = String.Format("http://{0}:{1}", url.Host, url.Port);
@@ -724,7 +733,6 @@ namespace MediaBrowser.Dlna.PlayTo
if (isRenderer)
{
-
var device = new Device(deviceProperties, httpClient, logger, config);
await device.GetRenderingProtocolAsync().ConfigureAwait(false);
@@ -768,7 +776,7 @@ namespace MediaBrowser.Dlna.PlayTo
private void NotifyCurrentIdChanged(string value)
{
if (CurrentIdChanged != null)
- CurrentIdChanged.Invoke(this, new CurrentIdEventArgs(value));
+ CurrentIdChanged.Invoke(this, new CurrentIdEventArgs { Id = value });
}
#endregion
diff --git a/MediaBrowser.Dlna/PlayTo/DeviceInfo.cs b/MediaBrowser.Dlna/PlayTo/DeviceInfo.cs
index c57e95c19..122549c7d 100644
--- a/MediaBrowser.Dlna/PlayTo/DeviceInfo.cs
+++ b/MediaBrowser.Dlna/PlayTo/DeviceInfo.cs
@@ -1,5 +1,5 @@
-using System.Collections.Generic;
-using MediaBrowser.Controller.Dlna;
+using MediaBrowser.Controller.Dlna;
+using System.Collections.Generic;
namespace MediaBrowser.Dlna.PlayTo
{
@@ -17,27 +17,18 @@ namespace MediaBrowser.Dlna.PlayTo
public string ClientType { get; set; }
- private string _displayName = string.Empty;
- public string DisplayName
- {
- get
- {
- return string.IsNullOrEmpty(_displayName) ? Name : _displayName;
- }
- set
- {
- _displayName = value;
- }
- }
-
public string ModelName { get; set; }
public string ModelNumber { get; set; }
+ public string ModelDescription { get; set; }
+
public string ModelUrl { get; set; }
public string Manufacturer { get; set; }
+ public string SerialNumber { get; set; }
+
public string ManufacturerUrl { get; set; }
public string PresentationUrl { get; set; }
@@ -75,7 +66,9 @@ namespace MediaBrowser.Dlna.PlayTo
ModelNumber = ModelNumber,
FriendlyName = Name,
ManufacturerUrl = ManufacturerUrl,
- ModelUrl = ModelUrl
+ ModelUrl = ModelUrl,
+ ModelDescription = ModelDescription,
+ SerialNumber = SerialNumber
};
}
}
diff --git a/MediaBrowser.Dlna/PlayTo/DidlBuilder.cs b/MediaBrowser.Dlna/PlayTo/DidlBuilder.cs
index 04f9a4644..80235740f 100644
--- a/MediaBrowser.Dlna/PlayTo/DidlBuilder.cs
+++ b/MediaBrowser.Dlna/PlayTo/DidlBuilder.cs
@@ -9,31 +9,27 @@ namespace MediaBrowser.Dlna.PlayTo
{
internal class DidlBuilder
{
- #region Constants
-
- internal const string CRLF = "\r\n";
- internal const string UNKNOWN = "Unknown";
-
- internal const string DIDL_START = @"<item id=""{0}"" parentID=""{1}"" restricted=""1"" xmlns=""urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"">" + CRLF;
- internal const string DIDL_TITLE = @" <dc:title xmlns:dc=""http://purl.org/dc/elements/1.1/"">{0}</dc:title>" + CRLF;
- internal const string DIDL_ARTIST = @"<upnp:artist xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:artist>" + CRLF;
- internal const string DIDL_ALBUM = @"<upnp:album xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:album>" + CRLF;
- internal const string DIDL_TRACKNUM = @"<upnp:originalTrackNumber xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">0</upnp:originalTrackNumber>" + CRLF;
- internal const string DIDL_VIDEOCLASS = @" <upnp:class xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">object.item.videoItem</upnp:class>" + CRLF;
- internal const string DIDL_AUDIOCLASS = @" <upnp:class xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">object.item.audioItem.musicTrack</upnp:class>" + CRLF;
- internal const string DIDL_IMAGE = @" <upnp:albumArtURI dlna:profileID=""JPEG_TN"" xmlns:dlna=""urn:schemas-dlna-org:metadata-1-0/"" xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:albumArtURI>" + CRLF +
- @" <upnp:icon xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:icon>" + CRLF;
- internal const string DIDL_RELEASEDATE = @" <dc:date xmlns:dc=""http://purl.org/dc/elements/1.1/"">{0}</dc:date>" + CRLF;
- internal const string DIDL_GENRE = @" <upnp:genre xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:genre>" + CRLF;
- internal const string DESCRIPTION = @" <dc:description xmlns:dc=""http://purl.org/dc/elements/1.1/"">{0}</dc:description>" + CRLF;
- internal const string DIDL_VIDEO_RES = @" <res bitrate=""{0}"" duration=""{1}"" protocolInfo=""http-get:*:video/x-msvideo:DLNA.ORG_PN=AVI;DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000"" resolution=""{2}x{3}"" size=""0"">{4}</res>" + CRLF;
- internal const string DIDL_AUDIO_RES = @" <res bitrate=""{0}"" duration=""{1}"" nrAudioChannels=""2"" protocolInfo=""http-get:*:audio/mp3:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000"" sampleFrequency=""{2}"" size=""0"">{3}</res>" + CRLF;
- internal const string DIDL_IMAGE_RES = @" <res protocolInfo=""http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_CI=1;DLNA.ORG_FLAGS=00D00000000000000000000000000000"" resolution=""212x320"">{0}</res>" + CRLF;
- internal const string DIDL_ALBUMIMAGE_RES = @" <res protocolInfo=""http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_CI=1;DLNA.ORG_FLAGS=00D00000000000000000000000000000"" resolution=""320x320"">{0}</res>" + CRLF;
- internal const string DIDL_RATING = @" <upnp:rating xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:rating>" + CRLF;
- internal const string DIDL_END = "</item>";
-
- #endregion
+ const string CRLF = "\r\n";
+ const string UNKNOWN = "Unknown";
+
+ const string DIDL_START = @"<item id=""{0}"" parentID=""{1}"" restricted=""1"" xmlns=""urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"">" + CRLF;
+ const string DIDL_TITLE = @" <dc:title xmlns:dc=""http://purl.org/dc/elements/1.1/"">{0}</dc:title>" + CRLF;
+ const string DIDL_ARTIST = @"<upnp:artist xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:artist>" + CRLF;
+ const string DIDL_ALBUM = @"<upnp:album xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:album>" + CRLF;
+ const string DIDL_TRACKNUM = @"<upnp:originalTrackNumber xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:originalTrackNumber>" + CRLF;
+ const string DIDL_VIDEOCLASS = @" <upnp:class xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">object.item.videoItem</upnp:class>" + CRLF;
+ const string DIDL_AUDIOCLASS = @" <upnp:class xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">object.item.audioItem.musicTrack</upnp:class>" + CRLF;
+ const string DIDL_IMAGE = @" <upnp:albumArtURI dlna:profileID=""JPEG_TN"" xmlns:dlna=""urn:schemas-dlna-org:metadata-1-0/"" xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:albumArtURI>" + CRLF +
+ @" <upnp:icon xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:icon>" + CRLF;
+ const string DIDL_RELEASEDATE = @" <dc:date xmlns:dc=""http://purl.org/dc/elements/1.1/"">{0}</dc:date>" + CRLF;
+ const string DIDL_GENRE = @" <upnp:genre xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:genre>" + CRLF;
+ const string DESCRIPTION = @" <dc:description xmlns:dc=""http://purl.org/dc/elements/1.1/"">{0}</dc:description>" + CRLF;
+ const string DIDL_VIDEO_RES = @" <res bitrate=""{0}"" duration=""{1}"" protocolInfo=""http-get:*:video/x-msvideo:DLNA.ORG_PN=AVI;DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000"" resolution=""{2}x{3}"" size=""0"">{4}</res>" + CRLF;
+ const string DIDL_AUDIO_RES = @" <res bitrate=""{0}"" duration=""{1}"" nrAudioChannels=""2"" protocolInfo=""http-get:*:audio/mp3:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000"" sampleFrequency=""{2}"" size=""0"">{3}</res>" + CRLF;
+ const string DIDL_IMAGE_RES = @" <res protocolInfo=""http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_CI=1;DLNA.ORG_FLAGS=00D00000000000000000000000000000"" resolution=""212x320"">{0}</res>" + CRLF;
+ const string DIDL_ALBUMIMAGE_RES = @" <res protocolInfo=""http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_CI=1;DLNA.ORG_FLAGS=00D00000000000000000000000000000"" resolution=""320x320"">{0}</res>" + CRLF;
+ const string DIDL_RATING = @" <upnp:rating xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:rating>" + CRLF;
+ const string DIDL_END = "</item>";
/// <summary>
/// Builds a Didl MetaData object for the specified dto.
@@ -44,7 +40,7 @@ namespace MediaBrowser.Dlna.PlayTo
/// <param name="streamUrl">The stream URL.</param>
/// <param name="streams">The streams.</param>
/// <returns>System.String.</returns>
- internal static string Build(BaseItem dto, string userId, string serverAddress, string streamUrl, IEnumerable<MediaStream> streams)
+ public static string Build(BaseItem dto, string userId, string serverAddress, string streamUrl, IEnumerable<MediaStream> streams, bool includeImageRes)
{
string response = string.Format(DIDL_START, dto.Id, userId);
response += string.Format(DIDL_TITLE, dto.Name.Replace("&", "and"));
@@ -53,7 +49,12 @@ namespace MediaBrowser.Dlna.PlayTo
else
response += DIDL_AUDIOCLASS;
- response += string.Format(DIDL_IMAGE, GetImageUrl(dto, serverAddress));
+ var imageUrl = GetImageUrl(dto, serverAddress);
+
+ if (!string.IsNullOrWhiteSpace(imageUrl))
+ {
+ response += string.Format(DIDL_IMAGE, imageUrl);
+ }
response += string.Format(DIDL_RELEASEDATE, GetDateString(dto.PremiereDate));
//TODO Add genres to didl;
@@ -63,7 +64,11 @@ namespace MediaBrowser.Dlna.PlayTo
{
response += string.Format(DESCRIPTION, UNKNOWN);
response += GetVideoDIDL(dto, streamUrl, streams);
- response += string.Format(DIDL_IMAGE_RES, GetImageUrl(dto, serverAddress));
+
+ if (includeImageRes && !string.IsNullOrWhiteSpace(imageUrl))
+ {
+ response += string.Format(DIDL_IMAGE_RES, imageUrl);
+ }
}
else
{
@@ -74,25 +79,25 @@ namespace MediaBrowser.Dlna.PlayTo
response += string.Format(DIDL_ARTIST, audio.Artists.FirstOrDefault() ?? UNKNOWN);
response += string.Format(DIDL_ALBUM, audio.Album);
- // TODO: Bad format string?
response += string.Format(DIDL_TRACKNUM, audio.IndexNumber ?? 0);
}
response += GetAudioDIDL(dto, streamUrl, streams);
- response += string.Format(DIDL_ALBUMIMAGE_RES, GetImageUrl(dto, serverAddress));
+
+ if (includeImageRes && !string.IsNullOrWhiteSpace(imageUrl))
+ {
+ response += string.Format(DIDL_ALBUMIMAGE_RES, imageUrl);
+ }
}
response += DIDL_END;
return response;
-
}
- #region Private methods
-
private static string GetVideoDIDL(BaseItem dto, string streamUrl, IEnumerable<MediaStream> streams)
{
- var videostream = streams.Where(stream => stream.Type == Model.Entities.MediaStreamType.Video).OrderBy(s => s.IsDefault).FirstOrDefault();
+ var videostream = streams.Where(stream => stream.Type == MediaStreamType.Video).OrderBy(s => s.IsDefault ? 0 : 1).FirstOrDefault();
if (videostream == null)
{
@@ -105,7 +110,7 @@ namespace MediaBrowser.Dlna.PlayTo
private static string GetAudioDIDL(BaseItem dto, string streamUrl, IEnumerable<MediaStream> streams)
{
- var audiostream = streams.Where(stream => stream.Type == MediaStreamType.Audio).OrderBy(s => s.IsDefault).FirstOrDefault();
+ var audiostream = streams.Where(stream => stream.Type == MediaStreamType.Audio).OrderBy(s => s.IsDefault ? 0 : 1).FirstOrDefault();
if (audiostream == null)
{
@@ -118,14 +123,14 @@ namespace MediaBrowser.Dlna.PlayTo
private static string GetImageUrl(BaseItem dto, string serverAddress)
{
- var imageType = ImageType.Primary;
+ const ImageType imageType = ImageType.Primary;
- if (!dto.HasImage(ImageType.Primary))
+ if (!dto.HasImage(imageType))
{
- dto = dto.Parents.FirstOrDefault(i => i.HasImage(ImageType.Primary));
+ dto = dto.Parents.FirstOrDefault(i => i.HasImage(imageType));
}
- return string.Format("{0}/Items/{1}/Images/{2}", serverAddress, dto.Id, imageType);
+ return dto == null ? null : string.Format("{0}/Items/{1}/Images/{2}", serverAddress, dto.Id, imageType);
}
private static string GetDurationString(BaseItem dto)
@@ -148,7 +153,5 @@ namespace MediaBrowser.Dlna.PlayTo
{
return string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
}
-
- #endregion
}
}
diff --git a/MediaBrowser.Dlna/PlayTo/DlnaController.cs b/MediaBrowser.Dlna/PlayTo/DlnaController.cs
index ecda07f0b..0c9f292ad 100644
--- a/MediaBrowser.Dlna/PlayTo/DlnaController.cs
+++ b/MediaBrowser.Dlna/PlayTo/DlnaController.cs
@@ -20,7 +20,7 @@ namespace MediaBrowser.Dlna.PlayTo
public class PlayToController : ISessionController, IDisposable
{
private Device _device;
- private BaseItem _currentItem = null;
+ private BaseItem _currentItem;
private readonly SessionInfo _session;
private readonly ISessionManager _sessionManager;
private readonly IItemRepository _itemRepository;
@@ -30,7 +30,7 @@ namespace MediaBrowser.Dlna.PlayTo
private readonly IDlnaManager _dlnaManager;
private readonly IUserManager _userManager;
private readonly IServerApplicationHost _appHost;
- private bool _playbackStarted = false;
+ private bool _playbackStarted;
private const int UpdateTimerIntervalMs = 1000;
@@ -103,22 +103,27 @@ namespace MediaBrowser.Dlna.PlayTo
async void Device_CurrentIdChanged(object sender, CurrentIdEventArgs e)
{
- if (e.Id != Guid.Empty)
+ if (!string.IsNullOrWhiteSpace(e.Id))
{
- if (_currentItem != null && _currentItem.Id == e.Id)
+ Guid guid;
+
+ if (Guid.TryParse(e.Id, out guid))
{
- return;
- }
+ if (_currentItem != null && _currentItem.Id == guid)
+ {
+ return;
+ }
- var item = _libraryManager.GetItemById(e.Id);
+ var item = _libraryManager.GetItemById(guid);
- if (item != null)
- {
- _logger.Debug("{0} - CurrentId {1}", _session.DeviceName, item.Id);
- _currentItem = item;
- _playbackStarted = false;
+ if (item != null)
+ {
+ _logger.Debug("{0} - CurrentId {1}", _session.DeviceName, item.Id);
+ _currentItem = item;
+ _playbackStarted = false;
- await ReportProgress().ConfigureAwait(false);
+ await ReportProgress().ConfigureAwait(false);
+ }
}
}
}
@@ -140,8 +145,15 @@ namespace MediaBrowser.Dlna.PlayTo
{
_updateTimer.Change(Timeout.Infinite, Timeout.Infinite);
- //Session is inactive, mark it for Disposal and don't start the elapsed timer.
- await _sessionManager.ReportSessionEnded(_session.Id);
+ try
+ {
+ // Session is inactive, mark it for Disposal and don't start the elapsed timer.
+ await _sessionManager.ReportSessionEnded(_session.Id);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error in ReportSessionEnded", ex);
+ }
}
}
@@ -156,7 +168,15 @@ namespace MediaBrowser.Dlna.PlayTo
if (!_playbackStarted)
{
- await _sessionManager.OnPlaybackStart(new PlaybackInfo { Item = _currentItem, SessionId = _session.Id, CanSeek = true, QueueableMediaTypes = new List<string> { "Audio", "Video" } }).ConfigureAwait(false);
+ await _sessionManager.OnPlaybackStart(new PlaybackInfo
+ {
+ Item = _currentItem,
+ SessionId = _session.Id,
+ CanSeek = true,
+ QueueableMediaTypes = new List<string> { _currentItem.MediaType }
+
+ }).ConfigureAwait(false);
+
_playbackStarted = true;
}
@@ -399,11 +419,12 @@ namespace MediaBrowser.Dlna.PlayTo
var deviceInfo = _device.Properties;
- var profile = _dlnaManager.GetProfile(deviceInfo.ToDeviceIdentification());
+ var profile = _dlnaManager.GetProfile(deviceInfo.ToDeviceIdentification()) ??
+ _dlnaManager.GetDefaultProfile();
var playlistItem = GetPlaylistItem(item, streams, profile);
playlistItem.StartPositionTicks = startPostionTicks;
- playlistItem.DeviceProfileName = profile.Name;
+ playlistItem.DeviceProfileId = profile.Id;
if (playlistItem.MediaType == DlnaProfileType.Audio)
{
@@ -414,8 +435,7 @@ namespace MediaBrowser.Dlna.PlayTo
playlistItem.StreamUrl = StreamHelper.GetVideoUrl(_device.Properties, playlistItem, streams, serverAddress);
}
- var didl = DidlBuilder.Build(item, _session.UserId.ToString(), serverAddress, playlistItem.StreamUrl, streams);
- playlistItem.Didl = didl;
+ playlistItem.Didl = DidlBuilder.Build(item, _session.UserId.ToString(), serverAddress, playlistItem.StreamUrl, streams, profile.EnableAlbumArtInDidl);
return playlistItem;
}
@@ -599,5 +619,10 @@ namespace MediaBrowser.Dlna.PlayTo
_logger.Log(LogSeverity.Debug, "Controller disposed");
}
}
+
+ public Task SendGenericCommand(GenericCommand command, CancellationToken cancellationToken)
+ {
+ throw new NotImplementedException();
+ }
}
}
diff --git a/MediaBrowser.Dlna/PlayTo/DlnaControllerFactory.cs b/MediaBrowser.Dlna/PlayTo/DlnaControllerFactory.cs
deleted file mode 100644
index 720dc200b..000000000
--- a/MediaBrowser.Dlna/PlayTo/DlnaControllerFactory.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Logging;
-
-namespace MediaBrowser.Dlna.PlayTo
-{
- public class PlayToControllerFactory : ISessionControllerFactory
- {
- private readonly ISessionManager _sessionManager;
- private readonly IItemRepository _itemRepository;
- private readonly ILibraryManager _libraryManager;
- private readonly ILogger _logger;
- private readonly INetworkManager _networkManager;
-
- public PlayToControllerFactory(ISessionManager sessionManager, IItemRepository itemRepository, ILibraryManager libraryManager, ILogManager logManager, INetworkManager networkManager)
- {
- _itemRepository = itemRepository;
- _sessionManager = sessionManager;
- _libraryManager = libraryManager;
- _networkManager = networkManager;
- _logger = logManager.GetLogger("PlayTo");
- }
-
- public ISessionController GetSessionController(SessionInfo session)
- {
- return null;
- }
- }
-}
diff --git a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
index ca76116fe..9e73450cb 100644
--- a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
+++ b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
@@ -5,16 +5,17 @@ using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Session;
+using MediaBrowser.Dlna.Ssdp;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Session;
using System;
using System.Collections.Concurrent;
+using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -126,10 +127,9 @@ namespace MediaBrowser.Dlna.PlayTo
if (receivedBytes > 0)
{
- var rawData = Encoding.UTF8.GetString(receiveBuffer, 0, receivedBytes);
- var uri = SsdpHelper.ParseSsdpResponse(rawData);
+ var headers = SsdpHelper.ParseSsdpResponse(receiveBuffer);
- TryCreateController(uri);
+ TryCreateController(headers);
}
}
@@ -146,13 +146,20 @@ namespace MediaBrowser.Dlna.PlayTo
}, _tokenSource.Token, TaskCreationOptions.LongRunning);
}
- private void TryCreateController(Uri uri)
+ private void TryCreateController(IDictionary<string,string> headers)
{
+ string location;
+
+ if (!headers.TryGetValue("Location", out location))
+ {
+ return;
+ }
+
Task.Run(async () =>
{
try
{
- await CreateController(uri).ConfigureAwait(false);
+ await CreateController(new Uri(location)).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
@@ -221,46 +228,29 @@ namespace MediaBrowser.Dlna.PlayTo
if (device != null && device.RendererCommands != null && !_sessionManager.Sessions.Any(s => string.Equals(s.DeviceId, device.Properties.UUID) && s.IsActive))
{
- GetProfileSettings(device.Properties);
-
- var sessionInfo = await _sessionManager.LogSessionActivity(device.Properties.ClientType, device.Properties.Name, device.Properties.UUID, device.Properties.DisplayName, uri.OriginalString, null)
+ var sessionInfo = await _sessionManager.LogSessionActivity(device.Properties.ClientType, _appHost.ApplicationVersion.ToString(), device.Properties.UUID, device.Properties.Name, uri.OriginalString, null)
.ConfigureAwait(false);
- _sessionManager.ReportCapabilities(sessionInfo.Id, new SessionCapabilities
- {
- PlayableMediaTypes = new[] { MediaType.Audio, MediaType.Video, MediaType.Photo },
- SupportsFullscreenToggle = false
- });
-
var controller = sessionInfo.SessionController as PlayToController;
if (controller == null)
{
sessionInfo.SessionController = controller = new PlayToController(sessionInfo, _sessionManager, _itemRepository, _libraryManager, _logger, _networkManager, _dlnaManager, _userManager, _appHost);
- }
- controller.Init(device);
+ controller.Init(device);
- _logger.Info("DLNA Session created for {0} - {1}", device.Properties.Name, device.Properties.ModelName);
- }
- }
+ var profile = _dlnaManager.GetProfile(device.Properties.ToDeviceIdentification()) ??
+ _dlnaManager.GetDefaultProfile();
- /// <summary>
- /// Gets the profile settings.
- /// </summary>
- /// <param name="deviceProperties">The device properties.</param>
- /// <returns>The TranscodeSettings for the device</returns>
- private void GetProfileSettings(DeviceInfo deviceProperties)
- {
- var profile = _dlnaManager.GetProfile(deviceProperties.ToDeviceIdentification());
+ _sessionManager.ReportCapabilities(sessionInfo.Id, new SessionCapabilities
+ {
+ PlayableMediaTypes = profile.GetSupportedMediaTypes().ToArray(),
- if (!string.IsNullOrWhiteSpace(profile.Name))
- {
- deviceProperties.DisplayName = profile.Name;
- }
- if (!string.IsNullOrWhiteSpace(profile.ClientType))
- {
- deviceProperties.ClientType = profile.ClientType;
+ SupportsFullscreenToggle = false
+ });
+
+ _logger.Info("DLNA Session created for {0} - {1}", device.Properties.Name, device.Properties.ModelName);
+ }
}
}
diff --git a/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs b/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs
index 20f31cf9d..50605c61f 100644
--- a/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs
+++ b/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs
@@ -33,8 +33,6 @@ namespace MediaBrowser.Dlna.PlayTo
public int? SubtitleStreamIndex { get; set; }
- public string DeviceProfileName { get; set; }
-
public int? MaxAudioChannels { get; set; }
public int? AudioBitrate { get; set; }
@@ -48,6 +46,8 @@ namespace MediaBrowser.Dlna.PlayTo
public int? MaxFramerate { get; set; }
+ public string DeviceProfileId { get; set; }
+
public PlaylistItem()
{
TranscodingSettings = new List<TranscodingSetting>();
diff --git a/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs b/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs
index 1b2d79113..c14a851ca 100644
--- a/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs
+++ b/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs
@@ -32,7 +32,7 @@ namespace MediaBrowser.Dlna.PlayTo
var audioCodec = audioStream == null ? null : audioStream.Codec;
// Make sure audio codec profiles are satisfied
- if (!string.IsNullOrEmpty(audioCodec) && profile.CodecProfiles.Where(i => i.Type == CodecType.AudioCodec && i.ContainsCodec(audioCodec))
+ if (!string.IsNullOrEmpty(audioCodec) && profile.CodecProfiles.Where(i => i.Type == CodecType.Audio && i.ContainsCodec(audioCodec))
.All(i => AreConditionsSatisfied(i.Conditions, item.Path, null, audioStream)))
{
playlistItem.Transcode = false;
@@ -53,7 +53,7 @@ namespace MediaBrowser.Dlna.PlayTo
playlistItem.AudioCodec = transcodingProfile.AudioCodec;
var audioTranscodingConditions = profile.CodecProfiles
- .Where(i => i.Type == CodecType.AudioCodec && i.ContainsCodec(transcodingProfile.AudioCodec))
+ .Where(i => i.Type == CodecType.Audio && i.ContainsCodec(transcodingProfile.AudioCodec))
.Take(1)
.SelectMany(i => i.Conditions);
@@ -114,13 +114,13 @@ namespace MediaBrowser.Dlna.PlayTo
var videoCodec = videoStream == null ? null : videoStream.Codec;
// Make sure video codec profiles are satisfied
- if (!string.IsNullOrEmpty(videoCodec) && profile.CodecProfiles.Where(i => i.Type == CodecType.VideoCodec && i.ContainsCodec(videoCodec))
+ if (!string.IsNullOrEmpty(videoCodec) && profile.CodecProfiles.Where(i => i.Type == CodecType.Video && i.ContainsCodec(videoCodec))
.All(i => AreConditionsSatisfied(i.Conditions, item.Path, videoStream, audioStream)))
{
var audioCodec = audioStream == null ? null : audioStream.Codec;
// Make sure audio codec profiles are satisfied
- if (string.IsNullOrEmpty(audioCodec) || profile.CodecProfiles.Where(i => i.Type == CodecType.VideoAudioCodec && i.ContainsCodec(audioCodec))
+ if (string.IsNullOrEmpty(audioCodec) || profile.CodecProfiles.Where(i => i.Type == CodecType.VideoAudio && i.ContainsCodec(audioCodec))
.All(i => AreConditionsSatisfied(i.Conditions, item.Path, videoStream, audioStream)))
{
playlistItem.Transcode = false;
@@ -143,14 +143,14 @@ namespace MediaBrowser.Dlna.PlayTo
playlistItem.VideoCodec = transcodingProfile.VideoCodec;
var videoTranscodingConditions = profile.CodecProfiles
- .Where(i => i.Type == CodecType.VideoCodec && i.ContainsCodec(transcodingProfile.VideoCodec))
+ .Where(i => i.Type == CodecType.Video && i.ContainsCodec(transcodingProfile.VideoCodec))
.Take(1)
.SelectMany(i => i.Conditions);
ApplyTranscodingConditions(playlistItem, videoTranscodingConditions);
var audioTranscodingConditions = profile.CodecProfiles
- .Where(i => i.Type == CodecType.VideoAudioCodec && i.ContainsCodec(transcodingProfile.AudioCodec))
+ .Where(i => i.Type == CodecType.VideoAudio && i.ContainsCodec(transcodingProfile.AudioCodec))
.Take(1)
.SelectMany(i => i.Conditions);
@@ -162,7 +162,8 @@ namespace MediaBrowser.Dlna.PlayTo
private void ApplyTranscodingConditions(PlaylistItem item, IEnumerable<ProfileCondition> conditions)
{
- foreach (var condition in conditions.Where(i => !string.IsNullOrEmpty(i.Value)))
+ foreach (var condition in conditions
+ .Where(i => !string.IsNullOrEmpty(i.Value)))
{
var value = condition.Value;
@@ -170,7 +171,7 @@ namespace MediaBrowser.Dlna.PlayTo
{
case ProfileConditionValue.AudioBitrate:
{
- var num = 0;
+ int num;
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
{
item.AudioBitrate = num;
@@ -179,7 +180,7 @@ namespace MediaBrowser.Dlna.PlayTo
}
case ProfileConditionValue.AudioChannels:
{
- var num = 0;
+ int num;
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
{
item.MaxAudioChannels = num;
@@ -190,16 +191,14 @@ namespace MediaBrowser.Dlna.PlayTo
case ProfileConditionValue.AudioProfile:
case ProfileConditionValue.Has64BitOffsets:
case ProfileConditionValue.VideoBitDepth:
- case ProfileConditionValue.VideoPacketLength:
case ProfileConditionValue.VideoProfile:
- case ProfileConditionValue.VideoTimestamp:
{
// Not supported yet
break;
}
case ProfileConditionValue.Height:
{
- var num = 0;
+ int num;
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
{
item.MaxHeight = num;
@@ -208,7 +207,7 @@ namespace MediaBrowser.Dlna.PlayTo
}
case ProfileConditionValue.VideoBitrate:
{
- var num = 0;
+ int num;
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
{
item.VideoBitrate = num;
@@ -217,7 +216,7 @@ namespace MediaBrowser.Dlna.PlayTo
}
case ProfileConditionValue.VideoFramerate:
{
- var num = 0;
+ int num;
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
{
item.MaxFramerate = num;
@@ -226,7 +225,7 @@ namespace MediaBrowser.Dlna.PlayTo
}
case ProfileConditionValue.VideoLevel:
{
- var num = 0;
+ int num;
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
{
item.VideoLevel = num;
@@ -235,7 +234,7 @@ namespace MediaBrowser.Dlna.PlayTo
}
case ProfileConditionValue.Width:
{
- var num = 0;
+ int num;
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
{
item.MaxWidth = num;
@@ -460,12 +459,6 @@ namespace MediaBrowser.Dlna.PlayTo
return videoStream == null ? null : videoStream.Width;
case ProfileConditionValue.VideoLevel:
return videoStream == null ? null : ConvertToLong(videoStream.Level);
- case ProfileConditionValue.VideoPacketLength:
- // TODO: Determine how to get this
- return null;
- case ProfileConditionValue.VideoTimestamp:
- // TODO: Determine how to get this
- return null;
default:
throw new InvalidOperationException("Unexpected Property");
}
diff --git a/MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs b/MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs
index f540a8004..42c788d38 100644
--- a/MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs
+++ b/MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs
@@ -2,7 +2,6 @@
using MediaBrowser.Controller.Configuration;
using System;
using System.IO;
-using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
@@ -14,8 +13,6 @@ namespace MediaBrowser.Dlna.PlayTo
private const string USERAGENT = "Microsoft-Windows/6.2 UPnP/1.0 Microsoft-DLNA DLNADOC/1.50";
private const string FriendlyName = "MediaBrowser";
- private static readonly CookieContainer Container = new CookieContainer();
-
private readonly IHttpClient _httpClient;
private readonly IServerConfigurationManager _config;
@@ -25,13 +22,17 @@ namespace MediaBrowser.Dlna.PlayTo
_config = config;
}
- public async Task<XDocument> SendCommandAsync(string baseUrl, DeviceService service, string command, string postData, string header = null)
+ public async Task<XDocument> SendCommandAsync(string baseUrl,
+ DeviceService service,
+ string command,
+ string postData,
+ string header = null)
{
var serviceUrl = service.ControlUrl;
if (!serviceUrl.StartsWith("/"))
serviceUrl = "/" + serviceUrl;
- var response = await PostSoapDataAsync(new Uri(baseUrl + serviceUrl), "\"" + service.ServiceType + "#" + command + "\"", postData, header)
+ var response = await PostSoapDataAsync(baseUrl + serviceUrl, "\"" + service.ServiceType + "#" + command + "\"", postData, header)
.ConfigureAwait(false);
using (var stream = response.Content)
@@ -43,11 +44,16 @@ namespace MediaBrowser.Dlna.PlayTo
}
}
- public async Task SubscribeAsync(Uri url, string ip, int port, string localIp, int eventport, int timeOut = 3600)
+ public async Task SubscribeAsync(string url,
+ string ip,
+ int port,
+ string localIp,
+ int eventport,
+ int timeOut = 3600)
{
var options = new HttpRequestOptions
{
- Url = url.ToString(),
+ Url = url,
UserAgent = USERAGENT,
LogRequest = _config.Configuration.DlnaOptions.EnableDebugLogging
};
@@ -56,14 +62,17 @@ namespace MediaBrowser.Dlna.PlayTo
options.RequestHeaders["CALLBACK"] = "<" + localIp + ":" + eventport + ">";
options.RequestHeaders["NT"] = "upnp:event";
options.RequestHeaders["TIMEOUT"] = "Second - " + timeOut;
- //request.CookieContainer = Container;
using (await _httpClient.Get(options).ConfigureAwait(false))
{
}
}
- public async Task RespondAsync(Uri url, string ip, int port, string localIp, int eventport, int timeOut = 20000)
+ public async Task RespondAsync(Uri url,
+ string ip,
+ int port,
+ string localIp,
+ int eventport)
{
var options = new HttpRequestOptions
{
@@ -75,24 +84,22 @@ namespace MediaBrowser.Dlna.PlayTo
options.RequestHeaders["CALLBACK"] = "<" + localIp + ":" + eventport + ">";
options.RequestHeaders["NT"] = "upnp:event";
options.RequestHeaders["TIMEOUT"] = "Second - 3600";
- //request.CookieContainer = Container;
using (await _httpClient.Get(options).ConfigureAwait(false))
{
}
}
- public async Task<XDocument> GetDataAsync(Uri url)
+ public async Task<XDocument> GetDataAsync(string url)
{
var options = new HttpRequestOptions
{
- Url = url.ToString(),
+ Url = url,
UserAgent = USERAGENT,
LogRequest = _config.Configuration.DlnaOptions.EnableDebugLogging
};
options.RequestHeaders["FriendlyName.DLNA.ORG"] = FriendlyName;
- //request.CookieContainer = Container;
using (var stream = await _httpClient.Get(options).ConfigureAwait(false))
{
@@ -103,14 +110,17 @@ namespace MediaBrowser.Dlna.PlayTo
}
}
- private Task<HttpResponseInfo> PostSoapDataAsync(Uri url, string soapAction, string postData, string header = null, int timeOut = 20000)
+ private Task<HttpResponseInfo> PostSoapDataAsync(string url,
+ string soapAction,
+ string postData,
+ string header = null)
{
if (!soapAction.StartsWith("\""))
soapAction = "\"" + soapAction + "\"";
var options = new HttpRequestOptions
{
- Url = url.ToString(),
+ Url = url,
UserAgent = USERAGENT,
LogRequest = _config.Configuration.DlnaOptions.EnableDebugLogging
};
diff --git a/MediaBrowser.Dlna/PlayTo/StreamHelper.cs b/MediaBrowser.Dlna/PlayTo/StreamHelper.cs
index 61c3bdd73..b65e94fd1 100644
--- a/MediaBrowser.Dlna/PlayTo/StreamHelper.cs
+++ b/MediaBrowser.Dlna/PlayTo/StreamHelper.cs
@@ -1,8 +1,6 @@
-using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Entities;
using System.Collections.Generic;
using System.Globalization;
-using System.Linq;
namespace MediaBrowser.Dlna.PlayTo
{
@@ -43,15 +41,11 @@ namespace MediaBrowser.Dlna.PlayTo
/// </summary>
private static string BuildDlnaUrl(DeviceInfo deviceProperties, PlaylistItem item)
{
- var profile = item.TranscodingSettings.Where(i => i.Name == TranscodingSettingType.VideoProfile)
- .Select(i => i.Value)
- .FirstOrDefault();
-
var usCulture = new CultureInfo("en-US");
var list = new List<string>
{
- item.DeviceProfileName ?? string.Empty,
+ item.DeviceProfileId ?? string.Empty,
deviceProperties.UUID ?? string.Empty,
item.MediaSourceId ?? string.Empty,
(!item.Transcode).ToString().ToLower(),
@@ -66,7 +60,6 @@ namespace MediaBrowser.Dlna.PlayTo
item.MaxWidth.HasValue ? item.MaxWidth.Value.ToString(usCulture) : string.Empty,
item.MaxHeight.HasValue ? item.MaxHeight.Value.ToString(usCulture) : string.Empty,
item.StartPositionTicks.ToString(usCulture),
- profile ?? string.Empty,
item.VideoLevel.HasValue ? item.VideoLevel.Value.ToString(usCulture) : string.Empty
};
diff --git a/MediaBrowser.Dlna/Profiles/DefaultProfile.cs b/MediaBrowser.Dlna/Profiles/DefaultProfile.cs
index 710f02df2..6b5513e28 100644
--- a/MediaBrowser.Dlna/Profiles/DefaultProfile.cs
+++ b/MediaBrowser.Dlna/Profiles/DefaultProfile.cs
@@ -1,14 +1,18 @@
using MediaBrowser.Controller.Dlna;
+using System.Xml.Serialization;
namespace MediaBrowser.Dlna.Profiles
{
+ [XmlRoot("Profile")]
public class DefaultProfile : DeviceProfile
{
public DefaultProfile()
{
+ Name = "Generic Device";
+
ProtocolInfo = "DLNA";
- ClientType = "DLNA";
+ FriendlyName = "Media Browser";
Manufacturer = "Media Browser";
ModelDescription = "Media Browser";
ModelName = "Media Browser";
@@ -53,24 +57,6 @@ namespace MediaBrowser.Dlna.Profiles
Type = DlnaProfileType.Video
}
};
-
- CodecProfiles = new[]
- {
- new CodecProfile
- {
- Type = CodecType.VideoCodec,
- Conditions = new []
- {
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.VideoLevel,
- Value = "3",
- IsRequired = false
- }
- }
- }
- };
}
}
}
diff --git a/MediaBrowser.Dlna/Profiles/DenonAvrProfile.cs b/MediaBrowser.Dlna/Profiles/DenonAvrProfile.cs
index cca6ab6bb..3c5064ad6 100644
--- a/MediaBrowser.Dlna/Profiles/DenonAvrProfile.cs
+++ b/MediaBrowser.Dlna/Profiles/DenonAvrProfile.cs
@@ -1,7 +1,9 @@
-using MediaBrowser.Controller.Dlna;
+using System.Xml.Serialization;
+using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
+ [XmlRoot("Profile")]
public class DenonAvrProfile : DefaultProfile
{
public DenonAvrProfile()
diff --git a/MediaBrowser.Dlna/Profiles/Foobar2000Profile.cs b/MediaBrowser.Dlna/Profiles/Foobar2000Profile.cs
new file mode 100644
index 000000000..198b0a73a
--- /dev/null
+++ b/MediaBrowser.Dlna/Profiles/Foobar2000Profile.cs
@@ -0,0 +1,31 @@
+using MediaBrowser.Controller.Dlna;
+using System.Xml.Serialization;
+
+namespace MediaBrowser.Dlna.Profiles
+{
+ [XmlRoot("Profile")]
+ public class Foobar2000Profile : DefaultProfile
+ {
+ public Foobar2000Profile()
+ {
+ Name = "foobar2000";
+
+ SupportedMediaTypes = "Audio";
+
+ Identification = new DeviceIdentification
+ {
+ FriendlyName = @"foobar",
+
+ Headers = new[]
+ {
+ new HttpHeaderInfo
+ {
+ Name = "User-Agent",
+ Value = "foobar",
+ Match = HeaderMatchType.Substring
+ }
+ }
+ };
+ }
+ }
+}
diff --git a/MediaBrowser.Dlna/Profiles/LgTvProfile.cs b/MediaBrowser.Dlna/Profiles/LgTvProfile.cs
index ec20c9df8..ccf36e844 100644
--- a/MediaBrowser.Dlna/Profiles/LgTvProfile.cs
+++ b/MediaBrowser.Dlna/Profiles/LgTvProfile.cs
@@ -1,7 +1,9 @@
-using MediaBrowser.Controller.Dlna;
+using System.Xml.Serialization;
+using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
+ [XmlRoot("Profile")]
public class LgTvProfile : DefaultProfile
{
public LgTvProfile()
@@ -111,7 +113,7 @@ namespace MediaBrowser.Dlna.Profiles
{
new CodecProfile
{
- Type = CodecType.VideoCodec,
+ Type = CodecType.Video,
Codec = "mpeg4",
Conditions = new[]
@@ -139,7 +141,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoCodec,
+ Type = CodecType.Video,
Codec = "h264",
Conditions = new[]
@@ -173,7 +175,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoAudioCodec,
+ Type = CodecType.VideoAudio,
Codec = "ac3,aac,mp3",
Conditions = new[]
diff --git a/MediaBrowser.Dlna/Profiles/LinksysDMA2100Profile.cs b/MediaBrowser.Dlna/Profiles/LinksysDMA2100Profile.cs
index e7086c205..a64cd24f3 100644
--- a/MediaBrowser.Dlna/Profiles/LinksysDMA2100Profile.cs
+++ b/MediaBrowser.Dlna/Profiles/LinksysDMA2100Profile.cs
@@ -1,7 +1,9 @@
-using MediaBrowser.Controller.Dlna;
+using System.Xml.Serialization;
+using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
+ [XmlRoot("Profile")]
public class LinksysDMA2100Profile : DefaultProfile
{
public LinksysDMA2100Profile()
diff --git a/MediaBrowser.Dlna/Profiles/PanasonicVieraProfile.cs b/MediaBrowser.Dlna/Profiles/PanasonicVieraProfile.cs
index 6755c0680..ced9a7c61 100644
--- a/MediaBrowser.Dlna/Profiles/PanasonicVieraProfile.cs
+++ b/MediaBrowser.Dlna/Profiles/PanasonicVieraProfile.cs
@@ -1,19 +1,21 @@
-using MediaBrowser.Controller.Dlna;
+using System.Xml.Serialization;
+using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
- public class PanasonicVieraProfile : DefaultProfile
+ [XmlRoot("Profile")]
+ public class PanasonicVieraProfile : DefaultProfile
{
- public PanasonicVieraProfile()
- {
- Name = "Panasonic Viera";
+ public PanasonicVieraProfile()
+ {
+ Name = "Panasonic Viera";
- Identification = new DeviceIdentification
- {
- FriendlyName = @"VIERA",
- Manufacturer = "Panasonic",
+ Identification = new DeviceIdentification
+ {
+ FriendlyName = @"VIERA",
+ Manufacturer = "Panasonic",
- Headers = new[]
+ Headers = new[]
{
new HttpHeaderInfo
{
@@ -22,11 +24,11 @@ namespace MediaBrowser.Dlna.Profiles
Match = HeaderMatchType.Substring
}
}
- };
+ };
- TimelineOffsetSeconds = 10;
+ TimelineOffsetSeconds = 10;
- TranscodingProfiles = new[]
+ TranscodingProfiles = new[]
{
new TranscodingProfile
{
@@ -48,7 +50,7 @@ namespace MediaBrowser.Dlna.Profiles
}
};
- DirectPlayProfiles = new[]
+ DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
@@ -127,7 +129,7 @@ namespace MediaBrowser.Dlna.Profiles
}
};
- ContainerProfiles = new[]
+ ContainerProfiles = new[]
{
new ContainerProfile
{
@@ -151,11 +153,11 @@ namespace MediaBrowser.Dlna.Profiles
}
};
- CodecProfiles = new[]
+ CodecProfiles = new[]
{
new CodecProfile
{
- Type = CodecType.VideoCodec,
+ Type = CodecType.Video,
Conditions = new[]
{
@@ -181,6 +183,6 @@ namespace MediaBrowser.Dlna.Profiles
}
}
};
- }
+ }
}
}
diff --git a/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs b/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs
index fa6b1201a..122bde875 100644
--- a/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs
+++ b/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs
@@ -1,14 +1,16 @@
-using MediaBrowser.Controller.Dlna;
+using System.Xml.Serialization;
+using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
+ [XmlRoot("Profile")]
public class SamsungSmartTvProfile : DefaultProfile
{
public SamsungSmartTvProfile()
{
Name = "Samsung Smart TV";
- SupportsAlbumArtInDidl = true;
+ EnableAlbumArtInDidl = true;
Identification = new DeviceIdentification
{
@@ -143,7 +145,7 @@ namespace MediaBrowser.Dlna.Profiles
{
new CodecProfile
{
- Type = CodecType.VideoCodec,
+ Type = CodecType.Video,
Codec = "mpeg2video",
Conditions = new[]
@@ -177,7 +179,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoCodec,
+ Type = CodecType.Video,
Codec = "mpeg4",
Conditions = new[]
@@ -211,7 +213,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoCodec,
+ Type = CodecType.Video,
Codec = "h264",
Conditions = new[]
@@ -251,7 +253,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoCodec,
+ Type = CodecType.Video,
Codec = "wmv2,wmv3,vc1",
Conditions = new[]
@@ -285,7 +287,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoAudioCodec,
+ Type = CodecType.VideoAudio,
Codec = "ac3,wmav2,dca,aac,mp3",
Conditions = new[]
@@ -304,6 +306,13 @@ namespace MediaBrowser.Dlna.Profiles
{
new MediaProfile
{
+ Container = "avi",
+ MimeType = "video/x-msvideo",
+ Type = DlnaProfileType.Video
+ },
+
+ new MediaProfile
+ {
Container = "mkv",
MimeType = "video/x-mkv",
Type = DlnaProfileType.Video
diff --git a/MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs
index 49aa47027..b64d4f6ca 100644
--- a/MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs
+++ b/MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs
@@ -1,11 +1,15 @@
-using MediaBrowser.Controller.Dlna;
+using System.Xml.Serialization;
+using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
+ [XmlRoot("Profile")]
public class SonyBlurayPlayer2013Profile : DefaultProfile
{
public SonyBlurayPlayer2013Profile()
{
+ Name = "Sony Blu-ray Player 2013";
+
Identification = new DeviceIdentification
{
FriendlyName = @"Blu-ray Disc Player",
@@ -109,7 +113,7 @@ namespace MediaBrowser.Dlna.Profiles
{
new CodecProfile
{
- Type = CodecType.VideoCodec,
+ Type = CodecType.Video,
Codec = "h264",
Conditions = new []
{
@@ -137,7 +141,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoAudioCodec,
+ Type = CodecType.VideoAudio,
Codec = "ac3",
Conditions = new []
{
diff --git a/MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs b/MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs
index 512172670..c5025edbb 100644
--- a/MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs
+++ b/MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs
@@ -1,11 +1,15 @@
-using MediaBrowser.Controller.Dlna;
+using System.Xml.Serialization;
+using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
+ [XmlRoot("Profile")]
public class SonyBlurayPlayerProfile : DefaultProfile
{
public SonyBlurayPlayerProfile()
{
+ Name = "Sony Blu-ray Player";
+
Identification = new DeviceIdentification
{
FriendlyName = @"Blu-ray Disc Player",
@@ -105,7 +109,7 @@ namespace MediaBrowser.Dlna.Profiles
{
new CodecProfile
{
- Type = CodecType.VideoCodec,
+ Type = CodecType.Video,
Codec = "h264",
Conditions = new []
{
@@ -147,7 +151,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoAudioCodec,
+ Type = CodecType.VideoAudio,
Codec = "ac3",
Conditions = new []
{
@@ -163,7 +167,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoAudioCodec,
+ Type = CodecType.VideoAudio,
Codec = "aac",
Conditions = new []
{
diff --git a/MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs
index 042cc0a96..8f29ad76e 100644
--- a/MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs
+++ b/MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs
@@ -1,7 +1,9 @@
-using MediaBrowser.Controller.Dlna;
+using System.Xml.Serialization;
+using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
+ [XmlRoot("Profile")]
public class SonyBravia2010Profile : DefaultProfile
{
public SonyBravia2010Profile()
@@ -96,13 +98,7 @@ namespace MediaBrowser.Dlna.Profiles
AudioCodec="ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
- Type = DlnaProfileType.Video,
-
- Conditions = new []
- {
- new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoPacketLength, Value="192"},
- new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoTimestamp, Value="1"}
- }
+ Type = DlnaProfileType.Video
},
new MediaProfile
@@ -112,12 +108,7 @@ namespace MediaBrowser.Dlna.Profiles
AudioCodec="ac3,aac,mp3",
MimeType = "video/mpeg",
OrgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
- Type = DlnaProfileType.Video,
-
- Conditions = new []
- {
- new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoPacketLength, Value="188"}
- }
+ Type = DlnaProfileType.Video
},
new MediaProfile
@@ -177,7 +168,7 @@ namespace MediaBrowser.Dlna.Profiles
{
new CodecProfile
{
- Type = CodecType.VideoCodec,
+ Type = CodecType.Video,
Conditions = new []
{
new ProfileCondition
@@ -197,7 +188,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoCodec,
+ Type = CodecType.Video,
Codec = "h264",
Conditions = new []
{
@@ -224,7 +215,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoCodec,
+ Type = CodecType.Video,
Codec = "mpeg2video",
Conditions = new []
{
@@ -245,7 +236,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoAudioCodec,
+ Type = CodecType.VideoAudio,
Codec = "ac3",
Conditions = new []
@@ -261,7 +252,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoAudioCodec,
+ Type = CodecType.VideoAudio,
Codec = "aac",
Conditions = new []
diff --git a/MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs
index 401c40c36..eaf6979a6 100644
--- a/MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs
+++ b/MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs
@@ -1,7 +1,9 @@
-using MediaBrowser.Controller.Dlna;
+using System.Xml.Serialization;
+using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
+ [XmlRoot("Profile")]
public class SonyBravia2011Profile : DefaultProfile
{
public SonyBravia2011Profile()
@@ -138,13 +140,7 @@ namespace MediaBrowser.Dlna.Profiles
AudioCodec="ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
- Type = DlnaProfileType.Video,
-
- Conditions = new []
- {
- new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoPacketLength, Value="192"},
- new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoTimestamp, Value="1"}
- }
+ Type = DlnaProfileType.Video
},
new MediaProfile
@@ -154,12 +150,7 @@ namespace MediaBrowser.Dlna.Profiles
AudioCodec="ac3,aac,mp3",
MimeType = "video/mpeg",
OrgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
- Type = DlnaProfileType.Video,
-
- Conditions = new []
- {
- new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoPacketLength, Value="188"}
- }
+ Type = DlnaProfileType.Video
},
new MediaProfile
@@ -195,7 +186,7 @@ namespace MediaBrowser.Dlna.Profiles
{
new CodecProfile
{
- Type = CodecType.VideoCodec,
+ Type = CodecType.Video,
Conditions = new []
{
new ProfileCondition
@@ -215,7 +206,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoCodec,
+ Type = CodecType.Video,
Codec = "h264",
Conditions = new []
{
@@ -242,7 +233,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoCodec,
+ Type = CodecType.Video,
Codec = "mpeg2video",
Conditions = new []
{
@@ -263,7 +254,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoAudioCodec,
+ Type = CodecType.VideoAudio,
Codec = "ac3",
Conditions = new []
@@ -279,7 +270,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoAudioCodec,
+ Type = CodecType.VideoAudio,
Codec = "aac",
Conditions = new[]
diff --git a/MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs
index 2d24c406e..41d057ef8 100644
--- a/MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs
+++ b/MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs
@@ -1,7 +1,9 @@
-using MediaBrowser.Controller.Dlna;
+using System.Xml.Serialization;
+using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
+ [XmlRoot("Profile")]
public class SonyBravia2012Profile : DefaultProfile
{
public SonyBravia2012Profile()
@@ -126,13 +128,7 @@ namespace MediaBrowser.Dlna.Profiles
AudioCodec="ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
- Type = DlnaProfileType.Video,
-
- Conditions = new []
- {
- new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoPacketLength, Value="192"},
- new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoTimestamp, Value="1"}
- }
+ Type = DlnaProfileType.Video
},
new MediaProfile
@@ -142,12 +138,7 @@ namespace MediaBrowser.Dlna.Profiles
AudioCodec="ac3,aac,mp3",
MimeType = "video/mpeg",
OrgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
- Type = DlnaProfileType.Video,
-
- Conditions = new []
- {
- new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoPacketLength, Value="188"}
- }
+ Type = DlnaProfileType.Video
},
new MediaProfile
@@ -207,7 +198,7 @@ namespace MediaBrowser.Dlna.Profiles
{
new CodecProfile
{
- Type = CodecType.VideoCodec,
+ Type = CodecType.Video,
Conditions = new[]
{
new ProfileCondition
@@ -227,7 +218,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoAudioCodec,
+ Type = CodecType.VideoAudio,
Codec = "ac3",
Conditions = new[]
diff --git a/MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs
index 10f712958..386a36ae0 100644
--- a/MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs
+++ b/MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs
@@ -1,7 +1,9 @@
-using MediaBrowser.Controller.Dlna;
+using System.Xml.Serialization;
+using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
+ [XmlRoot("Profile")]
public class SonyBravia2013Profile : DefaultProfile
{
public SonyBravia2013Profile()
@@ -182,13 +184,7 @@ namespace MediaBrowser.Dlna.Profiles
AudioCodec="ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
- Type = DlnaProfileType.Video,
-
- Conditions = new []
- {
- new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoPacketLength, Value="192"},
- new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoTimestamp, Value="1"}
- }
+ Type = DlnaProfileType.Video
},
new MediaProfile
@@ -198,12 +194,7 @@ namespace MediaBrowser.Dlna.Profiles
AudioCodec="ac3,aac,mp3",
MimeType = "video/mpeg",
OrgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
- Type = DlnaProfileType.Video,
-
- Conditions = new []
- {
- new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoPacketLength, Value="188"}
- }
+ Type = DlnaProfileType.Video
},
new MediaProfile
@@ -240,7 +231,7 @@ namespace MediaBrowser.Dlna.Profiles
{
new CodecProfile
{
- Type = CodecType.VideoCodec,
+ Type = CodecType.Video,
Conditions = new []
{
diff --git a/MediaBrowser.Dlna/Profiles/SonyPs3Profile.cs b/MediaBrowser.Dlna/Profiles/SonyPs3Profile.cs
index 39490f806..351a13f00 100644
--- a/MediaBrowser.Dlna/Profiles/SonyPs3Profile.cs
+++ b/MediaBrowser.Dlna/Profiles/SonyPs3Profile.cs
@@ -1,7 +1,9 @@
-using MediaBrowser.Controller.Dlna;
+using System.Xml.Serialization;
+using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
+ [XmlRoot("Profile")]
public class SonyPs3Profile : DefaultProfile
{
public SonyPs3Profile()
@@ -83,7 +85,7 @@ namespace MediaBrowser.Dlna.Profiles
{
new CodecProfile
{
- Type = CodecType.VideoCodec,
+ Type = CodecType.Video,
Codec = "h264",
Conditions = new []
@@ -126,7 +128,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoAudioCodec,
+ Type = CodecType.VideoAudio,
Codec = "ac3",
Conditions = new []
@@ -151,7 +153,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoAudioCodec,
+ Type = CodecType.VideoAudio,
Codec = "wmapro",
Conditions = new []
@@ -167,7 +169,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoAudioCodec,
+ Type = CodecType.VideoAudio,
Codec = "aac",
Conditions = new []
@@ -184,7 +186,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoAudioCodec,
+ Type = CodecType.VideoAudio,
Codec = "aac",
Conditions = new []
diff --git a/MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs b/MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs
index 47c7b21cc..f0b95d4e8 100644
--- a/MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs
+++ b/MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs
@@ -1,7 +1,9 @@
using MediaBrowser.Controller.Dlna;
+using System.Xml.Serialization;
namespace MediaBrowser.Dlna.Profiles
{
+ [XmlRoot("Profile")]
public class WdtvLiveProfile : DefaultProfile
{
public WdtvLiveProfile()
@@ -193,7 +195,7 @@ namespace MediaBrowser.Dlna.Profiles
{
new CodecProfile
{
- Type = CodecType.VideoCodec,
+ Type = CodecType.Video,
Codec = "h264",
Conditions = new []
@@ -221,7 +223,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoAudioCodec,
+ Type = CodecType.VideoAudio,
Codec = "aac",
Conditions = new []
diff --git a/MediaBrowser.Dlna/Profiles/Xbox360Profile.cs b/MediaBrowser.Dlna/Profiles/Xbox360Profile.cs
index 660d821d3..38d08adef 100644
--- a/MediaBrowser.Dlna/Profiles/Xbox360Profile.cs
+++ b/MediaBrowser.Dlna/Profiles/Xbox360Profile.cs
@@ -1,7 +1,9 @@
-using MediaBrowser.Controller.Dlna;
+using System.Xml.Serialization;
+using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
+ [XmlRoot("Profile")]
public class Xbox360Profile : DefaultProfile
{
public Xbox360Profile()
@@ -163,7 +165,7 @@ namespace MediaBrowser.Dlna.Profiles
{
new CodecProfile
{
- Type = CodecType.VideoCodec,
+ Type = CodecType.Video,
Codec = "mpeg4",
Conditions = new []
{
@@ -198,7 +200,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoCodec,
+ Type = CodecType.Video,
Codec = "h264",
Conditions = new []
{
@@ -227,20 +229,13 @@ namespace MediaBrowser.Dlna.Profiles
Property = ProfileConditionValue.VideoBitrate,
Value = "10240000",
IsRequired = false
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.VideoLevel,
- Value = "3",
- IsRequired = false
}
}
},
new CodecProfile
{
- Type = CodecType.VideoCodec,
+ Type = CodecType.Video,
Codec = "wmv2,wmv3,vc1",
Conditions = new []
{
@@ -269,20 +264,13 @@ namespace MediaBrowser.Dlna.Profiles
Property = ProfileConditionValue.VideoBitrate,
Value = "15360000",
IsRequired = false
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.VideoLevel,
- Value = "3",
- IsRequired = false
}
}
},
new CodecProfile
{
- Type = CodecType.VideoAudioCodec,
+ Type = CodecType.VideoAudio,
Codec = "ac3,wmav2,wmapro",
Conditions = new []
{
@@ -298,7 +286,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
- Type = CodecType.VideoAudioCodec,
+ Type = CodecType.VideoAudio,
Codec = "aac",
Conditions = new []
{
diff --git a/MediaBrowser.Dlna/Profiles/XboxOneProfile.cs b/MediaBrowser.Dlna/Profiles/XboxOneProfile.cs
index 0daa5d7a2..058c69e1f 100644
--- a/MediaBrowser.Dlna/Profiles/XboxOneProfile.cs
+++ b/MediaBrowser.Dlna/Profiles/XboxOneProfile.cs
@@ -1,7 +1,9 @@
-using MediaBrowser.Controller.Dlna;
+using System.Xml.Serialization;
+using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
+ [XmlRoot("Profile")]
public class XboxOneProfile : DefaultProfile
{
public XboxOneProfile()
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Default.xml b/MediaBrowser.Dlna/Profiles/Xml/Default.xml
new file mode 100644
index 000000000..895cb99d3
--- /dev/null
+++ b/MediaBrowser.Dlna/Profiles/Xml/Default.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <Name>Generic Device</Name>
+ <FriendlyName>Media Browser</FriendlyName>
+ <Manufacturer>Media Browser</Manufacturer>
+ <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl>
+ <ModelName>Media Browser</ModelName>
+ <ModelDescription>Media Browser</ModelDescription>
+ <ModelNumber>Media Browser</ModelNumber>
+ <ModelUrl>http://mediabrowser3.com/</ModelUrl>
+ <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
+ <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+ <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
+ <ProtocolInfo>DLNA</ProtocolInfo>
+ <TimelineOffsetSeconds>0</TimelineOffsetSeconds>
+ <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
+ <RequiresPlainFolders>false</RequiresPlainFolders>
+ <DirectPlayProfiles>
+ <DirectPlayProfile container="mp3,wma" type="Audio" />
+ <DirectPlayProfile container="avi,mp4" type="Video" />
+ </DirectPlayProfiles>
+ <TranscodingProfiles>
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings>
+ <TranscodingSetting name="VideoProfile" value="baseline" />
+ </Settings>
+ </TranscodingProfile>
+ </TranscodingProfiles>
+ <ContainerProfiles />
+ <CodecProfiles />
+ <MediaProfiles />
+</Profile> \ No newline at end of file
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml b/MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml
new file mode 100644
index 000000000..58c5cefbc
--- /dev/null
+++ b/MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <Name>Denon AVR</Name>
+ <Identification>
+ <FriendlyName>Denon:\[AVR:.*</FriendlyName>
+ <Manufacturer>Denon</Manufacturer>
+ <Headers />
+ </Identification>
+ <FriendlyName>Media Browser</FriendlyName>
+ <Manufacturer>Media Browser</Manufacturer>
+ <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl>
+ <ModelName>Media Browser</ModelName>
+ <ModelDescription>Media Browser</ModelDescription>
+ <ModelNumber>Media Browser</ModelNumber>
+ <ModelUrl>http://mediabrowser3.com/</ModelUrl>
+ <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
+ <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+ <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
+ <ProtocolInfo>DLNA</ProtocolInfo>
+ <TimelineOffsetSeconds>0</TimelineOffsetSeconds>
+ <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
+ <RequiresPlainFolders>false</RequiresPlainFolders>
+ <DirectPlayProfiles>
+ <DirectPlayProfile container="mp3,flac,m4a,wma" type="Audio" />
+ </DirectPlayProfiles>
+ <TranscodingProfiles>
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings>
+ <TranscodingSetting name="VideoProfile" value="baseline" />
+ </Settings>
+ </TranscodingProfile>
+ </TranscodingProfiles>
+ <ContainerProfiles />
+ <CodecProfiles />
+ <MediaProfiles />
+</Profile> \ No newline at end of file
diff --git a/MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml b/MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml
new file mode 100644
index 000000000..53781ad32
--- /dev/null
+++ b/MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0"?>
+<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <Name>LG Smart TV</Name>
+ <Identification>
+ <FriendlyName>LG.*</FriendlyName>
+ <Headers>
+ <HttpHeaderInfo name="User-Agent" value="LG" match="Substring" />
+ </Headers>
+ </Identification>
+ <FriendlyName>Media Browser</FriendlyName>
+ <Manufacturer>Media Browser</Manufacturer>
+ <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl>
+ <ModelName>Media Browser</ModelName>
+ <ModelDescription>Media Browser</ModelDescription>
+ <ModelNumber>Media Browser</ModelNumber>
+ <ModelUrl>http://mediabrowser3.com/</ModelUrl>
+ <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
+ <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+ <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
+ <ProtocolInfo>DLNA</ProtocolInfo>
+ <TimelineOffsetSeconds>10</TimelineOffsetSeconds>
+ <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
+ <RequiresPlainFolders>false</RequiresPlainFolders>
+ <DirectPlayProfiles>
+ <DirectPlayProfile container="ts" audioCodec="aac,ac3,mp3" videoCodec="h264" type="Video" />
+ <DirectPlayProfile container="mkv" audioCodec="aac,ac3,mp3" videoCodec="h264" type="Video" />
+ <DirectPlayProfile container="mp4" audioCodec="aac,ac3,mp3" videoCodec="h264,mpeg4" type="Video" />
+ <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" />
+ <DirectPlayProfile container="jpeg" type="Photo" />
+ </DirectPlayProfiles>
+ <TranscodingProfiles>
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ </TranscodingProfiles>
+ <ContainerProfiles>
+ <ContainerProfile type="Photo">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ </Conditions>
+ </ContainerProfile>
+ </ContainerProfiles>
+ <CodecProfiles>
+ <CodecProfile type="Video" codec="mpeg4">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="Video" codec="h264">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="41" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="VideoAudio" codec="ac3,aac,mp3">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ </CodecProfiles>
+ <MediaProfiles />
+</Profile> \ No newline at end of file
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml b/MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml
new file mode 100644
index 000000000..fc833b918
--- /dev/null
+++ b/MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <Name>Linksys DMA2100</Name>
+ <Identification>
+ <ModelName>DMA2100us</ModelName>
+ <Headers />
+ </Identification>
+ <FriendlyName>Media Browser</FriendlyName>
+ <Manufacturer>Media Browser</Manufacturer>
+ <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl>
+ <ModelName>Media Browser</ModelName>
+ <ModelDescription>Media Browser</ModelDescription>
+ <ModelNumber>Media Browser</ModelNumber>
+ <ModelUrl>http://mediabrowser3.com/</ModelUrl>
+ <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
+ <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+ <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
+ <ProtocolInfo>DLNA</ProtocolInfo>
+ <TimelineOffsetSeconds>0</TimelineOffsetSeconds>
+ <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
+ <RequiresPlainFolders>false</RequiresPlainFolders>
+ <DirectPlayProfiles>
+ <DirectPlayProfile container="mp3,flac,m4a,wma" type="Audio" />
+ <DirectPlayProfile container="avi,mp4,mkv,ts" type="Video" />
+ </DirectPlayProfiles>
+ <TranscodingProfiles>
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings>
+ <TranscodingSetting name="VideoProfile" value="baseline" />
+ </Settings>
+ </TranscodingProfile>
+ </TranscodingProfiles>
+ <ContainerProfiles />
+ <CodecProfiles />
+ <MediaProfiles />
+</Profile> \ No newline at end of file
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml b/MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml
new file mode 100644
index 000000000..49fd05b1e
--- /dev/null
+++ b/MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0"?>
+<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <Name>Panasonic Viera</Name>
+ <Identification>
+ <FriendlyName>VIERA</FriendlyName>
+ <Manufacturer>Panasonic</Manufacturer>
+ <Headers>
+ <HttpHeaderInfo name="User-Agent" value="Panasonic MIL DLNA" match="Substring" />
+ </Headers>
+ </Identification>
+ <FriendlyName>Media Browser</FriendlyName>
+ <Manufacturer>Media Browser</Manufacturer>
+ <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl>
+ <ModelName>Media Browser</ModelName>
+ <ModelDescription>Media Browser</ModelDescription>
+ <ModelNumber>Media Browser</ModelNumber>
+ <ModelUrl>http://mediabrowser3.com/</ModelUrl>
+ <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
+ <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+ <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
+ <ProtocolInfo>DLNA</ProtocolInfo>
+ <TimelineOffsetSeconds>10</TimelineOffsetSeconds>
+ <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
+ <RequiresPlainFolders>false</RequiresPlainFolders>
+ <DirectPlayProfiles>
+ <DirectPlayProfile container="mpeg" audioCodec="ac3,mp3" videoCodec="mpeg2video,mpeg4" type="Video" />
+ <DirectPlayProfile container="mkv" audioCodec="aac,ac3,mp3,pcm" videoCodec="h264" type="Video" />
+ <DirectPlayProfile container="ts" audioCodec="aac,mp3" videoCodec="h264" type="Video" />
+ <DirectPlayProfile container="mp4" audioCodec="aac,ac3,mp3,pcm" videoCodec="h264" type="Video" />
+ <DirectPlayProfile container="mov" audioCodec="aac,pcm" videoCodec="h264" type="Video" />
+ <DirectPlayProfile container="avi" audioCodec="pcm" videoCodec="mpeg4" type="Video" />
+ <DirectPlayProfile container="flv" audioCodec="aac" videoCodec="h264" type="Video" />
+ <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" />
+ <DirectPlayProfile container="mp4" audioCodec="aac" type="Audio" />
+ <DirectPlayProfile container="jpeg" type="Photo" />
+ </DirectPlayProfiles>
+ <TranscodingProfiles>
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ </TranscodingProfiles>
+ <ContainerProfiles>
+ <ContainerProfile type="Photo">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ </Conditions>
+ </ContainerProfile>
+ </ContainerProfiles>
+ <CodecProfiles>
+ <CodecProfile type="Video">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoBitDepth" value="8" isRequired="false" />
+ </Conditions>
+ </CodecProfile>
+ </CodecProfiles>
+ <MediaProfiles />
+</Profile> \ No newline at end of file
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml b/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml
new file mode 100644
index 000000000..75c50aae3
--- /dev/null
+++ b/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0"?>
+<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <Name>Samsung Smart TV</Name>
+ <Identification>
+ <ModelUrl>samsung.com</ModelUrl>
+ <Headers />
+ </Identification>
+ <FriendlyName>Media Browser</FriendlyName>
+ <Manufacturer>Media Browser</Manufacturer>
+ <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl>
+ <ModelName>Media Browser</ModelName>
+ <ModelDescription>Media Browser</ModelDescription>
+ <ModelNumber>Media Browser</ModelNumber>
+ <ModelUrl>http://mediabrowser3.com/</ModelUrl>
+ <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
+ <EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
+ <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
+ <ProtocolInfo>DLNA</ProtocolInfo>
+ <TimelineOffsetSeconds>0</TimelineOffsetSeconds>
+ <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
+ <RequiresPlainFolders>false</RequiresPlainFolders>
+ <DirectPlayProfiles>
+ <DirectPlayProfile container="asf" audioCodec="mp3,ac3,wmav2,wmapro,wmavoice" videoCodec="h264,mpeg4,mjpeg" type="Video" />
+ <DirectPlayProfile container="avi" audioCodec="mp3,ac3,dca" videoCodec="h264,mpeg4,mjpeg" type="Video" />
+ <DirectPlayProfile container="mkv" audioCodec="mp3,ac3,dca,aac" videoCodec="h264,mpeg4,mjpeg4" type="Video" />
+ <DirectPlayProfile container="mp4" audioCodec="mp3,aac" videoCodec="h264,mpeg4" type="Video" />
+ <DirectPlayProfile container="3gpp" audioCodec="aac,he-aac" videoCodec="h264,mpeg4" type="Video" />
+ <DirectPlayProfile container="mpg,mpeg" audioCodec="ac3,mp2,mp3,aac" videoCodec="mpeg1video,mpeg2video,h264" type="Video" />
+ <DirectPlayProfile container="vro,vob" audioCodec="ac3,mp2,mp3" videoCodec="mpeg1video,mpeg2video" type="Video" />
+ <DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3,eac3" videoCodec="mpeg2video,h264,vc1" type="Video" />
+ <DirectPlayProfile container="asf" audioCodec="wmav2,wmavoice" videoCodec="wmv2,wmv3" type="Video" />
+ <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" />
+ <DirectPlayProfile container="jpeg" type="Photo" />
+ </DirectPlayProfiles>
+ <TranscodingProfiles>
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ </TranscodingProfiles>
+ <ContainerProfiles>
+ <ContainerProfile type="Photo">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ </Conditions>
+ </ContainerProfile>
+ </ContainerProfiles>
+ <CodecProfiles>
+ <CodecProfile type="Video" codec="mpeg2video">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="30720000" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="Video" codec="mpeg4">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="8192000" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="Video" codec="h264">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="37500000" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="41" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="Video" codec="wmv2,wmv3,vc1">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="25600000" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="VideoAudio" codec="ac3,wmav2,dca,aac,mp3">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ </CodecProfiles>
+ <MediaProfiles>
+ <MediaProfile container="avi" type="Video" mimeType="video/x-msvideo">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="mkv" type="Video" mimeType="video/x-mkv">
+ <Conditions />
+ </MediaProfile>
+ </MediaProfiles>
+</Profile> \ No newline at end of file
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml
new file mode 100644
index 000000000..5bd27c771
--- /dev/null
+++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0"?>
+<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <Name>Sony Blu-ray Player 2013</Name>
+ <Identification>
+ <FriendlyName>Blu-ray Disc Player</FriendlyName>
+ <ModelNumber>BDP-2013</ModelNumber>
+ <Manufacturer>Sony</Manufacturer>
+ <Headers />
+ </Identification>
+ <FriendlyName>Media Browser</FriendlyName>
+ <Manufacturer>Microsoft Corporation</Manufacturer>
+ <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl>
+ <ModelName>Windows Media Player Sharing</ModelName>
+ <ModelDescription>Media Browser</ModelDescription>
+ <ModelNumber>3.0</ModelNumber>
+ <ModelUrl>http://mediabrowser3.com/</ModelUrl>
+ <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
+ <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+ <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
+ <ProtocolInfo>http-get:*:video/divx:DLNA.ORG_PN=MATROSKA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_NTSC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMABASE;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMAFULL;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_SD_AAC_MULT5;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mp4:DLNA.ORG_PN=AAC_ISO;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mp4:DLNA.ORG_PN=AAC_ISO_320;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/vnd.dlna.adts:DLNA.ORG_PN=AAC_ADTS;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/vnd.dlna.adts:DLNA.ORG_PN=AAC_ADTS_320;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/flac:DLNA.ORG_PN=FLAC;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/ogg:DLNA.ORG_PN=OGG;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_MED;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/png:DLNA.ORG_PN=PNG_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/png:DLNA.ORG_PN=PNG_TN;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/gif:DLNA.ORG_PN=GIF_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG1;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_EU_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_NA_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_KO_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_JP_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-msvideo:DLNA.ORG_PN=AVI;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-flv:DLNA.ORG_PN=FLV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-dvr:DLNA.ORG_PN=DVR_MS;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/wtv:DLNA.ORG_PN=WTV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/ogg:DLNA.ORG_PN=OGV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.rn-realvideo:DLNA.ORG_PN=REAL_VIDEO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_BASE;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L1_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L2_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L3_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_P2_3GPP_SP_L0B_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_P2_3GPP_SP_L0B_AMR;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_H263_3GPP_P0_L10_AMR;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_H263_MP4_P0_L10_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000</ProtocolInfo>
+ <TimelineOffsetSeconds>0</TimelineOffsetSeconds>
+ <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
+ <RequiresPlainFolders>false</RequiresPlainFolders>
+ <DirectPlayProfiles>
+ <DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3,pcm" videoCodec="mpeg1video,mpeg2video,h264" type="Video" />
+ <DirectPlayProfile container="mpeg" audioCodec="ac3,mp3,mp2,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" />
+ <DirectPlayProfile container="mp4" audioCodec="ac3,aac,pcm,mp3" videoCodec="mpeg4,h264" type="Video" />
+ <DirectPlayProfile container="avi" audioCodec="ac3,aac,mp3,pcm" videoCodec="mpeg4,h264" type="Video" />
+ <DirectPlayProfile container="mkv" audioCodec="ac3,dca,aac,mp3,pcm" videoCodec="mpeg4,h264" type="Video" />
+ <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" />
+ <DirectPlayProfile container="mp4" audioCodec="aac" type="Audio" />
+ <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" type="Audio" />
+ <DirectPlayProfile container="jpeg" type="Photo" />
+ </DirectPlayProfiles>
+ <TranscodingProfiles>
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ </TranscodingProfiles>
+ <ContainerProfiles>
+ <ContainerProfile type="Photo">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ </Conditions>
+ </ContainerProfile>
+ </ContainerProfiles>
+ <CodecProfiles>
+ <CodecProfile type="Video" codec="h264">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="false" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="VideoAudio" codec="ac3">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="false" />
+ </Conditions>
+ </CodecProfile>
+ </CodecProfiles>
+ <MediaProfiles />
+</Profile> \ No newline at end of file
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml
new file mode 100644
index 000000000..f5502ca14
--- /dev/null
+++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0"?>
+<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <Name>Sony Blu-ray Player</Name>
+ <Identification>
+ <FriendlyName>Blu-ray Disc Player</FriendlyName>
+ <Manufacturer>Sony</Manufacturer>
+ <Headers>
+ <HttpHeaderInfo name="X-AV-Client-Info" value="(Blu-ray Disc Player|Home Theater System|Home Theatre System|Media Player)" match="Regex" />
+ <HttpHeaderInfo name="X-AV-Physical-Unit-Info" value="(Blu-ray Disc Player|Home Theater System|Home Theatre System|Media Player)" match="Regex" />
+ </Headers>
+ </Identification>
+ <FriendlyName>Media Browser</FriendlyName>
+ <Manufacturer>Microsoft Corporation</Manufacturer>
+ <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl>
+ <ModelName>Windows Media Player Sharing</ModelName>
+ <ModelDescription>Media Browser</ModelDescription>
+ <ModelNumber>3.0</ModelNumber>
+ <ModelUrl>http://mediabrowser3.com/</ModelUrl>
+ <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
+ <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+ <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
+ <ProtocolInfo>http-get:*:video/divx:DLNA.ORG_PN=MATROSKA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_NTSC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMABASE;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMAFULL;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_SD_AAC_MULT5;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mp4:DLNA.ORG_PN=AAC_ISO;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mp4:DLNA.ORG_PN=AAC_ISO_320;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/vnd.dlna.adts:DLNA.ORG_PN=AAC_ADTS;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/vnd.dlna.adts:DLNA.ORG_PN=AAC_ADTS_320;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/flac:DLNA.ORG_PN=FLAC;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/ogg:DLNA.ORG_PN=OGG;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_MED;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/png:DLNA.ORG_PN=PNG_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/png:DLNA.ORG_PN=PNG_TN;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/gif:DLNA.ORG_PN=GIF_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG1;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_EU_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_NA_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_KO_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_JP_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-msvideo:DLNA.ORG_PN=AVI;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-flv:DLNA.ORG_PN=FLV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-dvr:DLNA.ORG_PN=DVR_MS;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/wtv:DLNA.ORG_PN=WTV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/ogg:DLNA.ORG_PN=OGV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.rn-realvideo:DLNA.ORG_PN=REAL_VIDEO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_BASE;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L1_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L2_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L3_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_P2_3GPP_SP_L0B_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_P2_3GPP_SP_L0B_AMR;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_H263_3GPP_P0_L10_AMR;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_H263_MP4_P0_L10_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000</ProtocolInfo>
+ <TimelineOffsetSeconds>0</TimelineOffsetSeconds>
+ <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
+ <RequiresPlainFolders>false</RequiresPlainFolders>
+ <DirectPlayProfiles>
+ <DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3,pcm" videoCodec="mpeg1video,mpeg2video,h264" type="Video" />
+ <DirectPlayProfile container="mpeg" audioCodec="ac3,mp3,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" />
+ <DirectPlayProfile container="avi,mp4" audioCodec="ac3,aac,mp3,pcm" videoCodec="mpeg4,h264" type="Video" />
+ <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" />
+ <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" type="Audio" />
+ <DirectPlayProfile container="jpeg" type="Photo" />
+ </DirectPlayProfiles>
+ <TranscodingProfiles>
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="ts" type="Video" videoCodec="mpeg2video" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ </TranscodingProfiles>
+ <ContainerProfiles>
+ <ContainerProfile type="Photo">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ </Conditions>
+ </ContainerProfile>
+ </ContainerProfiles>
+ <CodecProfiles>
+ <CodecProfile type="Video" codec="h264">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="false" />
+ <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="41" isRequired="false" />
+ <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="15360000" isRequired="false" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="VideoAudio" codec="ac3">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="false" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="VideoAudio" codec="aac">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="2" isRequired="false" />
+ </Conditions>
+ </CodecProfile>
+ </CodecProfiles>
+ <MediaProfiles>
+ <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264,mpeg4,vc1" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="avi" type="Video" mimeType="video/mpeg">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="mkv" type="Video" mimeType="video/vnd.dlna.mpeg-tts">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="ts" type="Video" mimeType="video/vnd.dlna.mpeg-tts">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="mp4" type="Video" mimeType="video/mpeg">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="mpeg" type="Video" mimeType="video/mpeg">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="mp3" type="Audio" mimeType="audio/mpeg">
+ <Conditions />
+ </MediaProfile>
+ </MediaProfiles>
+</Profile> \ No newline at end of file
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml
new file mode 100644
index 000000000..1337b5936
--- /dev/null
+++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml
@@ -0,0 +1,100 @@
+<?xml version="1.0"?>
+<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <Name>Sony Bravia (2010)</Name>
+ <Identification>
+ <FriendlyName>KDL-\d{2}[EHLNPB]X\d[01]\d.*</FriendlyName>
+ <Manufacturer>Sony</Manufacturer>
+ <Headers>
+ <HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-\d{2}[EHLNPB]X\d[01]\d.*" match="Regex" />
+ </Headers>
+ </Identification>
+ <FriendlyName>Media Browser</FriendlyName>
+ <Manufacturer>Microsoft Corporation</Manufacturer>
+ <ManufacturerUrl>http://www.microsoft.com/</ManufacturerUrl>
+ <ModelName>Windows Media Player Sharing</ModelName>
+ <ModelDescription>Media Browser</ModelDescription>
+ <ModelNumber>3.0</ModelNumber>
+ <ModelUrl>http://www.microsoft.com/</ModelUrl>
+ <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
+ <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+ <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
+ <SonyAggregationFlags>10</SonyAggregationFlags>
+ <ProtocolInfo>http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000</ProtocolInfo>
+ <TimelineOffsetSeconds>0</TimelineOffsetSeconds>
+ <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
+ <RequiresPlainFolders>false</RequiresPlainFolders>
+ <DirectPlayProfiles>
+ <DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" />
+ <DirectPlayProfile container="ts" audioCodec="mp3,mp2" videoCodec="mpeg1video,mpeg2video" type="Video" />
+ <DirectPlayProfile container="mpeg" audioCodec="mp3,mp2" videoCodec="mpeg2video,mpeg1video" type="Video" />
+ <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" />
+ </DirectPlayProfiles>
+ <TranscodingProfiles>
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3,aac" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ </TranscodingProfiles>
+ <ContainerProfiles>
+ <ContainerProfile type="Photo">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ </Conditions>
+ </ContainerProfile>
+ </ContainerProfiles>
+ <CodecProfiles>
+ <CodecProfile type="Video">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="Video" codec="h264">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="20000000" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="41" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="Video" codec="mpeg2video">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="20000000" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="VideoAudio" codec="ac3">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="VideoAudio" codec="aac">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="2" isRequired="true" />
+ <ProfileCondition condition="NotEquals" property="AudioProfile" value="he-aac" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ </CodecProfiles>
+ <MediaProfiles>
+ <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="ts" videoCodec="mpeg2video" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="mpeg" videoCodec="mpeg1video,mpeg2video" type="Video" orgPn="MPEG_PS_NTSC,MPEG_PS_PAL" mimeType="video/mpeg">
+ <Conditions />
+ </MediaProfile>
+ </MediaProfiles>
+</Profile> \ No newline at end of file
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml
new file mode 100644
index 000000000..b022c10a5
--- /dev/null
+++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml
@@ -0,0 +1,103 @@
+<?xml version="1.0"?>
+<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <Name>Sony Bravia (2011)</Name>
+ <Identification>
+ <FriendlyName>KDL-\d{2}([A-Z]X\d2\d|CX400).*</FriendlyName>
+ <Manufacturer>Sony</Manufacturer>
+ <Headers>
+ <HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-\d{2}([A-Z]X\d2\d|CX400).*" match="Regex" />
+ </Headers>
+ </Identification>
+ <FriendlyName>Media Browser</FriendlyName>
+ <Manufacturer>Microsoft Corporation</Manufacturer>
+ <ManufacturerUrl>http://www.microsoft.com/</ManufacturerUrl>
+ <ModelName>Windows Media Player Sharing</ModelName>
+ <ModelDescription>Media Browser</ModelDescription>
+ <ModelNumber>3.0</ModelNumber>
+ <ModelUrl>http://www.microsoft.com/</ModelUrl>
+ <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
+ <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+ <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
+ <SonyAggregationFlags>10</SonyAggregationFlags>
+ <ProtocolInfo>DLNA</ProtocolInfo>
+ <TimelineOffsetSeconds>0</TimelineOffsetSeconds>
+ <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
+ <RequiresPlainFolders>false</RequiresPlainFolders>
+ <DirectPlayProfiles>
+ <DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" />
+ <DirectPlayProfile container="ts" audioCodec="mp3,mp2" videoCodec="mpeg2video" type="Video" />
+ <DirectPlayProfile container="mp4" audioCodec="ac3,aac,mp3,mp2" videoCodec="h264,mpeg4" type="Video" />
+ <DirectPlayProfile container="mpeg" audioCodec="mp3,mp2" videoCodec="mpeg2video,mpeg1video" type="Video" />
+ <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" videoCodec="wmv2,wmv3,vc1" type="Video" />
+ <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" />
+ <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" type="Audio" />
+ </DirectPlayProfiles>
+ <TranscodingProfiles>
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3,aac" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ </TranscodingProfiles>
+ <ContainerProfiles>
+ <ContainerProfile type="Photo">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ </Conditions>
+ </ContainerProfile>
+ </ContainerProfiles>
+ <CodecProfiles>
+ <CodecProfile type="Video">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="Video" codec="h264">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="20000000" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="41" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="Video" codec="mpeg2video">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="20000000" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="VideoAudio" codec="ac3">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="VideoAudio" codec="aac">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="2" isRequired="true" />
+ <ProfileCondition condition="NotEquals" property="AudioProfile" value="he-aac" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ </CodecProfiles>
+ <MediaProfiles>
+ <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="ts" videoCodec="mpeg2video" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="mpeg" videoCodec="mpeg1video,mpeg2video" type="Video" orgPn="MPEG_PS_NTSC,MPEG_PS_PAL" mimeType="video/mpeg">
+ <Conditions />
+ </MediaProfile>
+ </MediaProfiles>
+</Profile> \ No newline at end of file
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml
new file mode 100644
index 000000000..cbef70b37
--- /dev/null
+++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml
@@ -0,0 +1,86 @@
+<?xml version="1.0"?>
+<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <Name>Sony Bravia (2012)</Name>
+ <Identification>
+ <FriendlyName>KDL-\d{2}[A-Z]X\d5(\d|G).*</FriendlyName>
+ <Manufacturer>Sony</Manufacturer>
+ <Headers>
+ <HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-\d{2}[A-Z]X\d5(\d|G).*" match="Regex" />
+ </Headers>
+ </Identification>
+ <FriendlyName>Media Browser</FriendlyName>
+ <Manufacturer>Microsoft Corporation</Manufacturer>
+ <ManufacturerUrl>http://www.microsoft.com/</ManufacturerUrl>
+ <ModelName>Windows Media Player Sharing</ModelName>
+ <ModelDescription>Media Browser</ModelDescription>
+ <ModelNumber>3.0</ModelNumber>
+ <ModelUrl>http://www.microsoft.com/</ModelUrl>
+ <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
+ <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+ <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
+ <SonyAggregationFlags>10</SonyAggregationFlags>
+ <ProtocolInfo>DLNA</ProtocolInfo>
+ <TimelineOffsetSeconds>0</TimelineOffsetSeconds>
+ <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
+ <RequiresPlainFolders>false</RequiresPlainFolders>
+ <DirectPlayProfiles>
+ <DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" />
+ <DirectPlayProfile container="ts" audioCodec="mp3,mp2" videoCodec="mpeg2video" type="Video" />
+ <DirectPlayProfile container="mp4" audioCodec="ac3,aac,mp3,mp2" videoCodec="h264,mpeg4" type="Video" />
+ <DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" />
+ <DirectPlayProfile container="mpeg" audioCodec="mp3,mp2" videoCodec="mpeg2video,mpeg1video" type="Video" />
+ <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" videoCodec="wmv2,wmv3,vc1" type="Video" />
+ <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" />
+ <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" type="Audio" />
+ <DirectPlayProfile container="jpeg" type="Photo" />
+ </DirectPlayProfiles>
+ <TranscodingProfiles>
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3,aac" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ </TranscodingProfiles>
+ <ContainerProfiles>
+ <ContainerProfile type="Photo">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ </Conditions>
+ </ContainerProfile>
+ </ContainerProfiles>
+ <CodecProfiles>
+ <CodecProfile type="Video">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="VideoAudio" codec="ac3">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ </CodecProfiles>
+ <MediaProfiles>
+ <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="ts" videoCodec="mpeg2video" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="mpeg" videoCodec="mpeg1video,mpeg2video" type="Video" orgPn="MPEG_PS_NTSC,MPEG_PS_PAL" mimeType="video/mpeg">
+ <Conditions />
+ </MediaProfile>
+ </MediaProfiles>
+</Profile> \ No newline at end of file
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml
new file mode 100644
index 000000000..47db46ce1
--- /dev/null
+++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml
@@ -0,0 +1,86 @@
+<?xml version="1.0"?>
+<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <Name>Sony Bravia (2013)</Name>
+ <Identification>
+ <FriendlyName>KDL-\d{2}[WR][5689]\d{2}A.*</FriendlyName>
+ <Manufacturer>Sony</Manufacturer>
+ <Headers>
+ <HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-\d{2}[WR][5689]\d{2}A.*" match="Regex" />
+ </Headers>
+ </Identification>
+ <FriendlyName>Media Browser</FriendlyName>
+ <Manufacturer>Microsoft Corporation</Manufacturer>
+ <ManufacturerUrl>http://www.microsoft.com/</ManufacturerUrl>
+ <ModelName>Windows Media Player Sharing</ModelName>
+ <ModelDescription>Media Browser</ModelDescription>
+ <ModelNumber>3.0</ModelNumber>
+ <ModelUrl>http://www.microsoft.com/</ModelUrl>
+ <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
+ <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+ <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
+ <SonyAggregationFlags>10</SonyAggregationFlags>
+ <ProtocolInfo>DLNA</ProtocolInfo>
+ <TimelineOffsetSeconds>0</TimelineOffsetSeconds>
+ <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
+ <RequiresPlainFolders>false</RequiresPlainFolders>
+ <DirectPlayProfiles>
+ <DirectPlayProfile container="ts" audioCodec="ac3,eac3,aac,mp3" videoCodec="h264" type="Video" />
+ <DirectPlayProfile container="ts" audioCodec="mp3,mp2" videoCodec="mpeg2video" type="Video" />
+ <DirectPlayProfile container="mp4" audioCodec="ac3,eac3,aac,mp3,mp2" videoCodec="h264,mpeg4" type="Video" />
+ <DirectPlayProfile container="mov" audioCodec="ac3,eac3,aac,mp3,mp2" videoCodec="h264,mpeg4,mjpeg" type="Video" />
+ <DirectPlayProfile container="mkv" audioCodec="ac3,eac3,aac,mp3,mp2,pcm,vorbis" videoCodec="h264,mpeg4,vp8" type="Video" />
+ <DirectPlayProfile container="avi" audioCodec="ac3,eac3,mp3" videoCodec="mpeg4" type="Video" />
+ <DirectPlayProfile container="avi" audioCodec="pcm" videoCodec="mjpeg" type="Video" />
+ <DirectPlayProfile container="mpeg" audioCodec="mp3,mp2" videoCodec="mpeg2video,mpeg1video" type="Video" />
+ <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" videoCodec="wmv2,wmv3,vc1" type="Video" />
+ <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" />
+ <DirectPlayProfile container="mp4" audioCodec="aac" type="Audio" />
+ <DirectPlayProfile container="wav" audioCodec="pcm" type="Audio" />
+ <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" type="Audio" />
+ <DirectPlayProfile container="jpeg" type="Photo" />
+ </DirectPlayProfiles>
+ <TranscodingProfiles>
+ <TranscodingProfile container="mp3" type="Audio" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3,aac" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ </TranscodingProfiles>
+ <ContainerProfiles>
+ <ContainerProfile type="Photo">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ </Conditions>
+ </ContainerProfile>
+ </ContainerProfiles>
+ <CodecProfiles>
+ <CodecProfile type="Video">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ </CodecProfiles>
+ <MediaProfiles>
+ <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="ts" videoCodec="mpeg2video" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="mpeg" videoCodec="mpeg1video,mpeg2video" type="Video" orgPn="MPEG_PS_NTSC,MPEG_PS_PAL" mimeType="video/mpeg">
+ <Conditions />
+ </MediaProfile>
+ </MediaProfiles>
+</Profile> \ No newline at end of file
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml b/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml
new file mode 100644
index 000000000..d9aa441bb
--- /dev/null
+++ b/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0"?>
+<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <Name>Sony PlayStation 3</Name>
+ <Identification>
+ <FriendlyName>PLAYSTATION 3</FriendlyName>
+ <Headers>
+ <HttpHeaderInfo name="User-Agent" value="PLAYSTATION 3" match="Substring" />
+ <HttpHeaderInfo name="X-AV-Client-Info" value="PLAYSTATION 3" match="Substring" />
+ </Headers>
+ </Identification>
+ <FriendlyName>Media Browser</FriendlyName>
+ <Manufacturer>Media Browser</Manufacturer>
+ <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl>
+ <ModelName>Media Browser</ModelName>
+ <ModelDescription>Media Browser</ModelDescription>
+ <ModelNumber>Media Browser</ModelNumber>
+ <ModelUrl>http://mediabrowser3.com/</ModelUrl>
+ <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
+ <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+ <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
+ <XDlnaDoc>DMS-1.50</XDlnaDoc>
+ <SonyAggregationFlags>10</SonyAggregationFlags>
+ <ProtocolInfo>DLNA</ProtocolInfo>
+ <TimelineOffsetSeconds>0</TimelineOffsetSeconds>
+ <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
+ <RequiresPlainFolders>false</RequiresPlainFolders>
+ <DirectPlayProfiles>
+ <DirectPlayProfile container="mp3,wma" type="Audio" />
+ <DirectPlayProfile container="avi,mp4" type="Video" />
+ </DirectPlayProfiles>
+ <TranscodingProfiles>
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ </TranscodingProfiles>
+ <ContainerProfiles>
+ <ContainerProfile type="Photo">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ </Conditions>
+ </ContainerProfile>
+ </ContainerProfiles>
+ <CodecProfiles>
+ <CodecProfile type="Video" codec="h264">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="false" />
+ <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="15360000" isRequired="false" />
+ <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="41" isRequired="false" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="VideoAudio" codec="ac3">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="false" />
+ <ProfileCondition condition="LessThanEqual" property="AudioBitrate" value="640000" isRequired="false" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="VideoAudio" codec="wmapro">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="2" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="VideoAudio" codec="aac">
+ <Conditions>
+ <ProfileCondition condition="NotEquals" property="AudioProfile" value="he-aac" isRequired="false" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="VideoAudio" codec="aac">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="2" isRequired="true" />
+ <ProfileCondition condition="NotEquals" property="AudioProfile" value="he-aac" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ </CodecProfiles>
+ <MediaProfiles>
+ <MediaProfile container="mp4,mov" audioCodec="aac" type="Video" mimeType="video/mp4">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="avi" type="Video" orgPn="AVI" mimeType="video/divx">
+ <Conditions />
+ </MediaProfile>
+ <MediaProfile container="wav" type="Audio" mimeType="audio/wav">
+ <Conditions />
+ </MediaProfile>
+ </MediaProfiles>
+</Profile> \ No newline at end of file
diff --git a/MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml b/MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml
new file mode 100644
index 000000000..0f4ad54a7
--- /dev/null
+++ b/MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0"?>
+<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <Name>WDTV Live</Name>
+ <Identification>
+ <ModelName>WD TV HD Live</ModelName>
+ <Headers>
+ <HttpHeaderInfo name="User-Agent" value="alphanetworks" match="Substring" />
+ <HttpHeaderInfo name="User-Agent" value="ALPHA Networks" match="Substring" />
+ </Headers>
+ </Identification>
+ <FriendlyName>Media Browser</FriendlyName>
+ <Manufacturer>Media Browser</Manufacturer>
+ <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl>
+ <ModelName>Media Browser</ModelName>
+ <ModelDescription>Media Browser</ModelDescription>
+ <ModelNumber>Media Browser</ModelNumber>
+ <ModelUrl>http://mediabrowser3.com/</ModelUrl>
+ <IgnoreTranscodeByteRangeRequests>true</IgnoreTranscodeByteRangeRequests>
+ <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+ <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
+ <ProtocolInfo>DLNA</ProtocolInfo>
+ <TimelineOffsetSeconds>5</TimelineOffsetSeconds>
+ <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
+ <RequiresPlainFolders>false</RequiresPlainFolders>
+ <DirectPlayProfiles>
+ <DirectPlayProfile container="avi" audioCodec="ac3,dca,mp2,mp3,pcm" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
+ <DirectPlayProfile container="mpeg" audioCodec="ac3,dca,mp2,mp3,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" />
+ <DirectPlayProfile container="mkv" audioCodec="ac3,dca,aac,mp2,mp3,pcm" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
+ <DirectPlayProfile container="ts" audioCodec="ac3,dca,mp2,mp3" videoCodec="mpeg1video,mpeg2video,h264,vc1" type="Video" />
+ <DirectPlayProfile container="mp4,mov" audioCodec="ac3,aac,mp2,mp3" videoCodec="h264,mpeg4" type="Video" />
+ <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro" videoCodec="vc1" type="Video" />
+ <DirectPlayProfile container="asf" audioCodec="mp2,ac3" videoCodec="mpeg2video" type="Video" />
+ <DirectPlayProfile container="mp3" audioCodec="mp2,mp3" type="Audio" />
+ <DirectPlayProfile container="mp4" audioCodec="mp4" type="Audio" />
+ <DirectPlayProfile container="flac" audioCodec="flac" type="Audio" />
+ <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" type="Audio" />
+ <DirectPlayProfile container="ogg" audioCodec="vorbis" type="Audio" />
+ <DirectPlayProfile container="jpeg,png,gif,bmp,tiff" type="Photo" />
+ </DirectPlayProfiles>
+ <TranscodingProfiles>
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings>
+ <TranscodingSetting name="VideoProfile" value="baseline" />
+ </Settings>
+ </TranscodingProfile>
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ </TranscodingProfiles>
+ <ContainerProfiles>
+ <ContainerProfile type="Photo">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ </Conditions>
+ </ContainerProfile>
+ </ContainerProfiles>
+ <CodecProfiles>
+ <CodecProfile type="Video" codec="h264">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="41" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="VideoAudio" codec="aac">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="2" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
+ </CodecProfiles>
+ <MediaProfiles>
+ <MediaProfile container="ts" type="Video" orgPn="MPEG_TS_SD_NA">
+ <Conditions />
+ </MediaProfile>
+ </MediaProfiles>
+</Profile> \ No newline at end of file
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml b/MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml
new file mode 100644
index 000000000..1e8d8164c
--- /dev/null
+++ b/MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0"?>
+<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <Name>Xbox 360</Name>
+ <Identification>
+ <ModelName>Xbox 360</ModelName>
+ <Headers>
+ <HttpHeaderInfo name="User-Agent" value="Xbox" match="Substring" />
+ <HttpHeaderInfo name="User-Agent" value="Xenon" match="Substring" />
+ </Headers>
+ </Identification>
+ <FriendlyName>Media Browser</FriendlyName>
+ <Manufacturer>Microsoft Corporation</Manufacturer>
+ <ManufacturerUrl>http://www.microsoft.com/</ManufacturerUrl>
+ <ModelName>Windows Media Player Sharing</ModelName>
+ <ModelDescription>Media Browser</ModelDescription>
+ <ModelNumber>12.0</ModelNumber>
+ <ModelUrl>http://www.microsoft.com/</ModelUrl>
+ <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
+ <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+ <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
+ <XDlnaDoc>DMS-1.50</XDlnaDoc>
+ <ProtocolInfo>DLNA</ProtocolInfo>
+ <TimelineOffsetSeconds>40</TimelineOffsetSeconds>
+ <RequiresPlainVideoItems>true</RequiresPlainVideoItems>
+ <RequiresPlainFolders>true</RequiresPlainFolders>
+ <DirectPlayProfiles>
+ <DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" />
+ <DirectPlayProfile container="avi" audioCodec="aac" videoCodec="h264" type="Video" />
+ <DirectPlayProfile container="mp4,mov" audioCodec="aac,ac3" videoCodec="h264,mpeg4" type="Video" />
+ <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro" videoCodec="wmv2,wmv3,vc1" type="Video" />
+ <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" type="Audio" />
+ <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" />
+ <DirectPlayProfile container="jpeg" type="Photo" />
+ </DirectPlayProfiles>
+ <TranscodingProfiles>
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="asf" type="Video" videoCodec="wmv2" audioCodec="wmav2" estimateContentLength="true" enableMpegtsM2TsMode="false" transcodeSeekInfo="Bytes">
+ <Settings>
+ <TranscodingSetting name="VideoProfile" value="baseline" />
+ </Settings>
+ </TranscodingProfile>
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ </TranscodingProfiles>
+ <ContainerProfiles>
+ <ContainerProfile type="Video" container="mp4,mov">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Has64BitOffsets" value="false" isRequired="false" />
+ </Conditions>
+ </ContainerProfile>
+ <ContainerProfile type="Photo">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ </Conditions>
+ </ContainerProfile>
+ </ContainerProfiles>
+ <CodecProfiles>
+ <CodecProfile type="Video" codec="mpeg4">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1280" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="720" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="false" />
+ <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="5120000" isRequired="false" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="Video" codec="h264">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="41" isRequired="false" />
+ <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="10240000" isRequired="false" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="Video" codec="wmv2,wmv3,vc1">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="false" />
+ <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="15360000" isRequired="false" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="VideoAudio" codec="ac3,wmav2,wmapro">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="false" />
+ </Conditions>
+ </CodecProfile>
+ <CodecProfile type="VideoAudio" codec="aac">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="2" isRequired="false" />
+ <ProfileCondition condition="Equals" property="AudioProfile" value="lc" isRequired="false" />
+ </Conditions>
+ </CodecProfile>
+ </CodecProfiles>
+ <MediaProfiles>
+ <MediaProfile container="avi" type="Video" mimeType="video/avi">
+ <Conditions />
+ </MediaProfile>
+ </MediaProfiles>
+</Profile> \ No newline at end of file
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml b/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml
new file mode 100644
index 000000000..f6c338b2f
--- /dev/null
+++ b/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <Name>Xbox One</Name>
+ <Identification>
+ <FriendlyName>Xbox-SystemOS</FriendlyName>
+ <ModelName>Xbox One</ModelName>
+ <Headers />
+ </Identification>
+ <FriendlyName>Media Browser</FriendlyName>
+ <Manufacturer>Media Browser</Manufacturer>
+ <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl>
+ <ModelName>Media Browser</ModelName>
+ <ModelDescription>Media Browser</ModelDescription>
+ <ModelNumber>Media Browser</ModelNumber>
+ <ModelUrl>http://mediabrowser3.com/</ModelUrl>
+ <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
+ <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+ <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
+ <ProtocolInfo>DLNA</ProtocolInfo>
+ <TimelineOffsetSeconds>0</TimelineOffsetSeconds>
+ <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
+ <RequiresPlainFolders>false</RequiresPlainFolders>
+ <DirectPlayProfiles>
+ <DirectPlayProfile container="mp3,wma" type="Audio" />
+ </DirectPlayProfiles>
+ <TranscodingProfiles>
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ </TranscodingProfiles>
+ <ContainerProfiles />
+ <CodecProfiles />
+ <MediaProfiles>
+ <MediaProfile container="avi" type="Video" mimeType="video/x-msvideo">
+ <Conditions />
+ </MediaProfile>
+ </MediaProfiles>
+</Profile> \ No newline at end of file
diff --git a/MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml b/MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml
new file mode 100644
index 000000000..f682e4c42
--- /dev/null
+++ b/MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <Name>foobar2000</Name>
+ <Identification>
+ <FriendlyName>foobar</FriendlyName>
+ <Headers>
+ <HttpHeaderInfo name="User-Agent" value="foobar" match="Substring" />
+ </Headers>
+ </Identification>
+ <FriendlyName>Media Browser</FriendlyName>
+ <Manufacturer>Media Browser</Manufacturer>
+ <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl>
+ <ModelName>Media Browser</ModelName>
+ <ModelDescription>Media Browser</ModelDescription>
+ <ModelNumber>Media Browser</ModelNumber>
+ <ModelUrl>http://mediabrowser3.com/</ModelUrl>
+ <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
+ <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+ <SupportedMediaTypes>Audio</SupportedMediaTypes>
+ <ProtocolInfo>DLNA</ProtocolInfo>
+ <TimelineOffsetSeconds>0</TimelineOffsetSeconds>
+ <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
+ <RequiresPlainFolders>false</RequiresPlainFolders>
+ <DirectPlayProfiles>
+ <DirectPlayProfile container="mp3,wma" type="Audio" />
+ <DirectPlayProfile container="avi,mp4" type="Video" />
+ </DirectPlayProfiles>
+ <TranscodingProfiles>
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings />
+ </TranscodingProfile>
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto">
+ <Settings>
+ <TranscodingSetting name="VideoProfile" value="baseline" />
+ </Settings>
+ </TranscodingProfile>
+ </TranscodingProfiles>
+ <ContainerProfiles />
+ <CodecProfiles />
+ <MediaProfiles />
+</Profile> \ No newline at end of file
diff --git a/MediaBrowser.Dlna/Server/Headers.cs b/MediaBrowser.Dlna/Server/Headers.cs
index 859ae7fbf..2bd1a72f7 100644
--- a/MediaBrowser.Dlna/Server/Headers.cs
+++ b/MediaBrowser.Dlna/Server/Headers.cs
@@ -13,7 +13,7 @@ namespace MediaBrowser.Dlna.Server
private readonly Dictionary<string, string> _dict = new Dictionary<string, string>();
private readonly static Regex Validator = new Regex(@"^[a-z\d][a-z\d_.-]+$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
- protected Headers(bool asIs)
+ public Headers(bool asIs)
{
_asIs = asIs;
}
diff --git a/MediaBrowser.Dlna/Server/RawHeaders.cs b/MediaBrowser.Dlna/Server/RawHeaders.cs
deleted file mode 100644
index f57e6b9f3..000000000
--- a/MediaBrowser.Dlna/Server/RawHeaders.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Dlna.Server
-{
- public class RawHeaders : Headers
- {
- public RawHeaders()
- : base(true)
- {
- }
- }
-}
diff --git a/MediaBrowser.Dlna/Server/SsdpHandler.cs b/MediaBrowser.Dlna/Server/SsdpHandler.cs
index 63c2abbec..64c111819 100644
--- a/MediaBrowser.Dlna/Server/SsdpHandler.cs
+++ b/MediaBrowser.Dlna/Server/SsdpHandler.cs
@@ -96,7 +96,7 @@ namespace MediaBrowser.Dlna.Server
{
break;
}
- var parts = line.Split(new char[] { ':' }, 2);
+ var parts = line.Split(new[] { ':' }, 2);
headers[parts[0]] = parts[1].Trim();
}
@@ -148,7 +148,7 @@ namespace MediaBrowser.Dlna.Server
private void SendSearchResponse(IPEndPoint endpoint, UpnpDevice dev)
{
- var headers = new RawHeaders();
+ var headers = new Headers(true);
headers.Add("CACHE-CONTROL", "max-age = 600");
headers.Add("DATE", DateTime.Now.ToString("R"));
headers.Add("EXT", "");
@@ -188,7 +188,7 @@ namespace MediaBrowser.Dlna.Server
private void NotifyDevice(UpnpDevice dev, string type, bool sticky)
{
_logger.Debug("NotifyDevice");
- var headers = new RawHeaders();
+ var headers = new Headers(true);
headers.Add("HOST", "239.255.255.250:1900");
headers.Add("CACHE-CONTROL", "max-age = 600");
headers.Add("LOCATION", dev.Descriptor.ToString());
diff --git a/MediaBrowser.Dlna/PlayTo/SsdpHelper.cs b/MediaBrowser.Dlna/Ssdp/SsdpHelper.cs
index d07a7679f..b22db781a 100644
--- a/MediaBrowser.Dlna/PlayTo/SsdpHelper.cs
+++ b/MediaBrowser.Dlna/Ssdp/SsdpHelper.cs
@@ -1,8 +1,9 @@
using System;
-using System.Linq;
+using System.Collections.Generic;
+using System.IO;
using System.Text;
-namespace MediaBrowser.Dlna.PlayTo
+namespace MediaBrowser.Dlna.Ssdp
{
public class SsdpHelper
{
@@ -29,28 +30,29 @@ namespace MediaBrowser.Dlna.PlayTo
/// </summary>
/// <param name="data">The data.</param>
/// <returns></returns>
- public static Uri ParseSsdpResponse(string data)
+ public static Dictionary<string,string> ParseSsdpResponse(byte[] data)
{
- var res = (from line in data.Split(new[] { '\r', '\n' })
- where line.ToLowerInvariant().StartsWith("location:")
- select line).FirstOrDefault();
+ var headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- return !string.IsNullOrEmpty(res) ? new Uri(res.Substring(9).Trim()) : null;
- }
-
- /// <summary>
- /// Parses data into SSDP event.
- /// </summary>
- /// <param name="data">The data.</param>
- /// <returns></returns>
- [Obsolete("Not yet used", true)]
- public static string ParseSsdpEvent(string data)
- {
- var sid = (from line in data.Split(new[] { '\r', '\n' })
- where line.ToLowerInvariant().StartsWith("sid:")
- select line).FirstOrDefault();
+ using (var reader = new StreamReader(new MemoryStream(data), Encoding.ASCII))
+ {
+ for (var line = reader.ReadLine(); line != null; line = reader.ReadLine())
+ {
+ line = line.Trim();
+ if (string.IsNullOrEmpty(line))
+ {
+ break;
+ }
+ var parts = line.Split(new[] { ':' }, 2);
- return data;
+ if (parts.Length == 2)
+ {
+ headers[parts[0]] = parts[1].Trim();
+ }
+ }
+ }
+
+ return headers;
}
}
}
diff --git a/MediaBrowser.Server.Implementations/BdInfo/BdInfoExaminer.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs
index 18f1b92fe..b15b8d15d 100644
--- a/MediaBrowser.Server.Implementations/BdInfo/BdInfoExaminer.cs
+++ b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs
@@ -5,7 +5,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
-namespace MediaBrowser.Server.Implementations.BdInfo
+namespace MediaBrowser.MediaEncoding.BdInfo
{
/// <summary>
/// Class BdInfoExaminer
diff --git a/MediaBrowser.MediaEncoding/Encoder/ImageEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/ImageEncoder.cs
new file mode 100644
index 000000000..e0ca86c41
--- /dev/null
+++ b/MediaBrowser.MediaEncoding/Encoder/ImageEncoder.cs
@@ -0,0 +1,235 @@
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.MediaEncoding;
+using MediaBrowser.Model.Logging;
+using System;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.MediaEncoding.Encoder
+{
+ public class ImageEncoder
+ {
+ private readonly string _ffmpegPath;
+ private readonly ILogger _logger;
+ private readonly IFileSystem _fileSystem;
+ private readonly IApplicationPaths _appPaths;
+
+ private readonly CultureInfo _usCulture = new CultureInfo("en-US");
+
+ private static readonly SemaphoreSlim ResourcePool = new SemaphoreSlim(10, 10);
+
+ public ImageEncoder(string ffmpegPath, ILogger logger, IFileSystem fileSystem, IApplicationPaths appPaths)
+ {
+ _ffmpegPath = ffmpegPath;
+ _logger = logger;
+ _fileSystem = fileSystem;
+ _appPaths = appPaths;
+ }
+
+ public async Task<Stream> EncodeImage(ImageEncodingOptions options, CancellationToken cancellationToken)
+ {
+ ValidateInput(options);
+
+ await ResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
+
+ try
+ {
+ return await EncodeImageInternal(options, cancellationToken).ConfigureAwait(false);
+ }
+ finally
+ {
+ ResourcePool.Release();
+ }
+ }
+
+ private async Task<Stream> EncodeImageInternal(ImageEncodingOptions options, CancellationToken cancellationToken)
+ {
+ ValidateInput(options);
+
+ var inputPath = options.InputPath;
+ var filename = Path.GetFileName(inputPath);
+
+ if (HasDiacritics(filename))
+ {
+ inputPath = GetTempFile(inputPath);
+ filename = Path.GetFileName(inputPath);
+ }
+
+ var process = new Process
+ {
+ StartInfo = new ProcessStartInfo
+ {
+ CreateNoWindow = true,
+ UseShellExecute = false,
+ FileName = _ffmpegPath,
+ Arguments = GetArguments(options, filename),
+ WindowStyle = ProcessWindowStyle.Hidden,
+ ErrorDialog = false,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ WorkingDirectory = Path.GetDirectoryName(inputPath)
+ }
+ };
+
+ _logger.Debug("ffmpeg " + process.StartInfo.Arguments);
+
+ process.Start();
+
+ var memoryStream = new MemoryStream();
+
+#pragma warning disable 4014
+ // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
+ process.StandardOutput.BaseStream.CopyToAsync(memoryStream);
+#pragma warning restore 4014
+
+ // MUST read both stdout and stderr asynchronously or a deadlock may occurr
+ process.BeginErrorReadLine();
+
+ var ranToCompletion = process.WaitForExit(5000);
+
+ if (!ranToCompletion)
+ {
+ try
+ {
+ _logger.Info("Killing ffmpeg process");
+
+ process.Kill();
+
+ process.WaitForExit(1000);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error killing process", ex);
+ }
+ }
+
+ var exitCode = ranToCompletion ? process.ExitCode : -1;
+
+ process.Dispose();
+
+ if (exitCode == -1 || memoryStream.Length == 0)
+ {
+ memoryStream.Dispose();
+
+ var msg = string.Format("ffmpeg image encoding failed for {0}", options.InputPath);
+
+ _logger.Error(msg);
+
+ throw new ApplicationException(msg);
+ }
+
+ memoryStream.Position = 0;
+ return memoryStream;
+ }
+
+ private string GetTempFile(string path)
+ {
+ var extension = Path.GetExtension(path) ?? string.Empty;
+
+ var tempPath = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString("N") + extension);
+
+ File.Copy(path, tempPath);
+
+ return tempPath;
+ }
+
+ private string GetArguments(ImageEncodingOptions options, string inputFilename)
+ {
+ var vfScale = GetFilterGraph(options);
+ var outputFormat = GetOutputFormat(options.Format);
+
+ var quality = (options.Quality ?? 100) * .3;
+ quality = 31 - quality;
+ var qualityValue = Convert.ToInt32(Math.Max(quality, 1));
+
+ return string.Format("-f image2 -i file:\"{3}\" -q:v {0} {1} -f image2pipe -vcodec {2} -",
+ qualityValue.ToString(_usCulture),
+ vfScale,
+ outputFormat,
+ inputFilename);
+ }
+
+ private string GetFilterGraph(ImageEncodingOptions options)
+ {
+ if (!options.Width.HasValue &&
+ !options.Height.HasValue &&
+ !options.MaxHeight.HasValue &&
+ !options.MaxWidth.HasValue)
+ {
+ return string.Empty;
+ }
+
+ var widthScale = "-1";
+ var heightScale = "-1";
+
+ if (options.MaxWidth.HasValue)
+ {
+ widthScale = "min(iw\\," + options.MaxWidth.Value.ToString(_usCulture) + ")";
+ }
+ else if (options.Width.HasValue)
+ {
+ widthScale = options.Width.Value.ToString(_usCulture);
+ }
+
+ if (options.MaxHeight.HasValue)
+ {
+ heightScale = "min(ih\\," + options.MaxHeight.Value.ToString(_usCulture) + ")";
+ }
+ else if (options.Height.HasValue)
+ {
+ heightScale = options.Height.Value.ToString(_usCulture);
+ }
+
+ var scaleMethod = "lanczos";
+
+ return string.Format("-vf scale=\"{0}:{1}\"",
+ widthScale,
+ heightScale);
+ }
+
+ private string GetOutputFormat(string format)
+ {
+ if (string.Equals(format, "jpeg", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(format, "jpg", StringComparison.OrdinalIgnoreCase))
+ {
+ return "mjpeg";
+ }
+ return format;
+ }
+
+ private void ValidateInput(ImageEncodingOptions options)
+ {
+
+ }
+
+ /// <summary>
+ /// Determines whether the specified text has diacritics.
+ /// </summary>
+ /// <param name="text">The text.</param>
+ /// <returns><c>true</c> if the specified text has diacritics; otherwise, <c>false</c>.</returns>
+ private bool HasDiacritics(string text)
+ {
+ return !String.Equals(text, RemoveDiacritics(text), StringComparison.Ordinal);
+ }
+
+ /// <summary>
+ /// Removes the diacritics.
+ /// </summary>
+ /// <param name="text">The text.</param>
+ /// <returns>System.String.</returns>
+ private string RemoveDiacritics(string text)
+ {
+ return String.Concat(
+ text.Normalize(NormalizationForm.FormD)
+ .Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) !=
+ UnicodeCategory.NonSpacingMark)
+ ).Normalize(NormalizationForm.FormC);
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index 02c629906..fac54ecff 100644
--- a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -6,17 +6,15 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using System;
using System.Collections.Concurrent;
-using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
-using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
-namespace MediaBrowser.Server.Implementations.MediaEncoder
+namespace MediaBrowser.MediaEncoding.Encoder
{
/// <summary>
/// Class MediaEncoder
@@ -53,6 +51,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
/// The FF probe resource pool
/// </summary>
private readonly SemaphoreSlim _ffProbeResourcePool = new SemaphoreSlim(2, 2);
+
private readonly IFileSystem _fileSystem;
public string FFMpegPath { get; private set; }
@@ -62,7 +61,8 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
public string Version { get; private set; }
public MediaEncoder(ILogger logger, IApplicationPaths appPaths,
- IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, string version, IFileSystem fileSystem)
+ IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, string version,
+ IFileSystem fileSystem)
{
_logger = logger;
_appPaths = appPaths;
@@ -85,7 +85,8 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
/// <summary>
/// The _semaphoreLocks
/// </summary>
- private readonly ConcurrentDictionary<string, SemaphoreSlim> _semaphoreLocks = new ConcurrentDictionary<string, SemaphoreSlim>();
+ private readonly ConcurrentDictionary<string, SemaphoreSlim> _semaphoreLocks =
+ new ConcurrentDictionary<string, SemaphoreSlim>();
/// <summary>
/// Gets the lock.
@@ -106,10 +107,10 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public Task<InternalMediaInfoResult> GetMediaInfo(string[] inputFiles, InputType type, bool isAudio,
- CancellationToken cancellationToken)
+ CancellationToken cancellationToken)
{
return GetMediaInfoInternal(GetInputArgument(inputFiles, type), !isAudio,
- GetProbeSizeArgument(type), cancellationToken);
+ GetProbeSizeArgument(type), cancellationToken);
}
/// <summary>
@@ -172,9 +173,13 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
/// <returns>Task{MediaInfoResult}.</returns>
/// <exception cref="System.ApplicationException"></exception>
private async Task<InternalMediaInfoResult> GetMediaInfoInternal(string inputPath, bool extractChapters,
- string probeSizeArgument,
- CancellationToken cancellationToken)
+ string probeSizeArgument,
+ CancellationToken cancellationToken)
{
+ var args = extractChapters
+ ? "{0} -i {1} -threads 0 -v info -print_format json -show_streams -show_chapters -show_format"
+ : "{0} -i {1} -threads 0 -v info -print_format json -show_streams -show_format";
+
var process = new Process
{
StartInfo = new ProcessStartInfo
@@ -186,9 +191,8 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
RedirectStandardOutput = true,
RedirectStandardError = true,
FileName = FFProbePath,
- Arguments = string.Format(
- "{0} -i {1} -threads 0 -v info -print_format json -show_streams -show_format",
- probeSizeArgument, inputPath).Trim(),
+ Arguments = string.Format(args,
+ probeSizeArgument, inputPath).Trim(),
WindowStyle = ProcessWindowStyle.Hidden,
ErrorDialog = false
@@ -204,7 +208,6 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
await _ffProbeResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
InternalMediaInfoResult result;
- string standardError = null;
try
{
@@ -221,24 +224,10 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
try
{
- Task<string> standardErrorReadTask = null;
-
- // MUST read both stdout and stderr asynchronously or a deadlock may occurr
- if (extractChapters)
- {
- standardErrorReadTask = process.StandardError.ReadToEndAsync();
- }
- else
- {
- process.BeginErrorReadLine();
- }
-
- result = _jsonSerializer.DeserializeFromStream<InternalMediaInfoResult>(process.StandardOutput.BaseStream);
+ process.BeginErrorReadLine();
- if (extractChapters)
- {
- standardError = await standardErrorReadTask.ConfigureAwait(false);
- }
+ result =
+ _jsonSerializer.DeserializeFromStream<InternalMediaInfoResult>(process.StandardOutput.BaseStream);
}
catch
{
@@ -282,11 +271,6 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
}
}
- if (extractChapters && !string.IsNullOrEmpty(standardError))
- {
- AddChapters(result, standardError);
- }
-
return result;
}
@@ -296,66 +280,6 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
/// <summary>
- /// Adds the chapters.
- /// </summary>
- /// <param name="result">The result.</param>
- /// <param name="standardError">The standard error.</param>
- private void AddChapters(InternalMediaInfoResult result, string standardError)
- {
- var lines = standardError.Split('\n').Select(l => l.TrimStart());
-
- var chapters = new List<ChapterInfo>();
-
- ChapterInfo lastChapter = null;
-
- foreach (var line in lines)
- {
- if (line.StartsWith("Chapter", StringComparison.OrdinalIgnoreCase))
- {
- // Example:
- // Chapter #0.2: start 400.534, end 4565.435
- const string srch = "start ";
- var start = line.IndexOf(srch, StringComparison.OrdinalIgnoreCase);
-
- if (start == -1)
- {
- continue;
- }
-
- var subString = line.Substring(start + srch.Length);
- subString = subString.Substring(0, subString.IndexOf(','));
-
- double seconds;
-
- if (double.TryParse(subString, NumberStyles.Any, UsCulture, out seconds))
- {
- lastChapter = new ChapterInfo
- {
- StartPositionTicks = TimeSpan.FromSeconds(seconds).Ticks
- };
-
- chapters.Add(lastChapter);
- }
- }
-
- else if (line.StartsWith("title", StringComparison.OrdinalIgnoreCase))
- {
- if (lastChapter != null && string.IsNullOrEmpty(lastChapter.Name))
- {
- var index = line.IndexOf(':');
-
- if (index != -1)
- {
- lastChapter.Name = line.Substring(index + 1).Trim().TrimEnd('\r');
- }
- }
- }
- }
-
- result.Chapters = chapters;
- }
-
- /// <summary>
/// Processes the exited.
/// </summary>
/// <param name="sender">The sender.</param>
@@ -373,7 +297,8 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
/// <param name="language">The language.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- public async Task ConvertTextSubtitleToAss(string inputPath, string outputPath, string language, CancellationToken cancellationToken)
+ public async Task ConvertTextSubtitleToAss(string inputPath, string outputPath, string language,
+ CancellationToken cancellationToken)
{
var semaphore = GetLock(outputPath);
@@ -418,33 +343,35 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
}
- var encodingParam = string.IsNullOrEmpty(language) ? string.Empty :
- GetSubtitleLanguageEncodingParam(language) + " ";
+ var encodingParam = string.IsNullOrEmpty(language)
+ ? string.Empty
+ : GetSubtitleLanguageEncodingParam(language) + " ";
var process = new Process
+ {
+ StartInfo = new ProcessStartInfo
{
- StartInfo = new ProcessStartInfo
- {
- RedirectStandardOutput = false,
- RedirectStandardError = true,
-
- CreateNoWindow = true,
- UseShellExecute = false,
- FileName = FFMpegPath,
- Arguments =
- string.Format("{0} -i \"{1}\" -c:s ass \"{2}\"", encodingParam, inputPath, outputPath),
-
- WindowStyle = ProcessWindowStyle.Hidden,
- ErrorDialog = false
- }
- };
+ RedirectStandardOutput = false,
+ RedirectStandardError = true,
+
+ CreateNoWindow = true,
+ UseShellExecute = false,
+ FileName = FFMpegPath,
+ Arguments =
+ string.Format("{0} -i \"{1}\" -c:s ass \"{2}\"", encodingParam, inputPath, outputPath),
+
+ WindowStyle = ProcessWindowStyle.Hidden,
+ ErrorDialog = false
+ }
+ };
_logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "ffmpeg-sub-convert-" + Guid.NewGuid() + ".txt");
Directory.CreateDirectory(Path.GetDirectoryName(logFilePath));
- var logFileStream = _fileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true);
+ var logFileStream = _fileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read,
+ true);
try
{
@@ -603,7 +530,8 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
/// <exception cref="System.ArgumentException">Must use inputPath list overload</exception>
- public async Task ExtractTextSubtitle(string[] inputFiles, InputType type, int subtitleStreamIndex, bool copySubtitleStream, string outputPath, CancellationToken cancellationToken)
+ public async Task ExtractTextSubtitle(string[] inputFiles, InputType type, int subtitleStreamIndex,
+ bool copySubtitleStream, string outputPath, CancellationToken cancellationToken)
{
var semaphore = GetLock(outputPath);
@@ -613,7 +541,9 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
{
if (!File.Exists(outputPath))
{
- await ExtractTextSubtitleInternal(GetInputArgument(inputFiles, type), subtitleStreamIndex, copySubtitleStream, outputPath, cancellationToken).ConfigureAwait(false);
+ await
+ ExtractTextSubtitleInternal(GetInputArgument(inputFiles, type), subtitleStreamIndex,
+ copySubtitleStream, outputPath, cancellationToken).ConfigureAwait(false);
}
}
finally
@@ -637,7 +567,8 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
/// or
/// cancellationToken</exception>
/// <exception cref="System.ApplicationException"></exception>
- private async Task ExtractTextSubtitleInternal(string inputPath, int subtitleStreamIndex, bool copySubtitleStream, string outputPath, CancellationToken cancellationToken)
+ private async Task ExtractTextSubtitleInternal(string inputPath, int subtitleStreamIndex,
+ bool copySubtitleStream, string outputPath, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(inputPath))
{
@@ -649,11 +580,13 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
throw new ArgumentNullException("outputPath");
}
- string processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s ass \"{2}\"", inputPath, subtitleStreamIndex, outputPath);
+ string processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s ass \"{2}\"", inputPath,
+ subtitleStreamIndex, outputPath);
if (copySubtitleStream)
{
- processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s copy \"{2}\"", inputPath, subtitleStreamIndex, outputPath);
+ processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s copy \"{2}\"", inputPath,
+ subtitleStreamIndex, outputPath);
}
var process = new Process
@@ -678,7 +611,8 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "ffmpeg-sub-extract-" + Guid.NewGuid() + ".txt");
Directory.CreateDirectory(Path.GetDirectoryName(logFilePath));
- var logFileStream = _fileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true);
+ var logFileStream = _fileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read,
+ true);
try
{
@@ -793,7 +727,18 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
}
}
- public async Task<Stream> ExtractImage(string[] inputFiles, InputType type, bool isAudio,
+ public Task<Stream> ExtractAudioImage(string path, CancellationToken cancellationToken)
+ {
+ return ExtractImage(new[] { path }, InputType.File, true, null, null, cancellationToken);
+ }
+
+ public Task<Stream> ExtractVideoImage(string[] inputFiles, InputType type, Video3DFormat? threedFormat,
+ TimeSpan? offset, CancellationToken cancellationToken)
+ {
+ return ExtractImage(inputFiles, type, false, threedFormat, offset, cancellationToken);
+ }
+
+ private async Task<Stream> ExtractImage(string[] inputFiles, InputType type, bool isAudio,
Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken)
{
var resourcePool = isAudio ? _audioImageResourcePool : _videoImageResourcePool;
@@ -851,7 +796,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
}
// Use ffmpeg to sample 100 (we can drop this if required using thumbnail=50 for 50 frames) frames and pick the best thumbnail. Have a fall back just in case.
- var args = useIFrame ? string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"{2},thumbnail=20\" -f image2 \"{1}\"", inputPath, "-", vf) :
+ var args = useIFrame ? string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"{2},thumbnail=80\" -f image2 \"{1}\"", inputPath, "-", vf) :
string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, "-", vf);
var probeSize = GetProbeSizeArgument(type);
@@ -912,7 +857,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
_logger.ErrorException("Error killing process", ex);
}
}
-
+
resourcePool.Release();
var exitCode = ranToCompletion ? process.ExitCode : -1;
@@ -935,45 +880,6 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
}
/// <summary>
- /// Starts the and wait for process.
- /// </summary>
- /// <param name="process">The process.</param>
- /// <param name="timeout">The timeout.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- private bool StartAndWaitForProcess(Process process, int timeout = 10000)
- {
- process.Start();
-
- var ranToCompletion = process.WaitForExit(timeout);
-
- if (!ranToCompletion)
- {
- try
- {
- _logger.Info("Killing ffmpeg process");
-
- process.Kill();
-
- process.WaitForExit(1000);
- }
- catch (Win32Exception ex)
- {
- _logger.ErrorException("Error killing process", ex);
- }
- catch (InvalidOperationException ex)
- {
- _logger.ErrorException("Error killing process", ex);
- }
- catch (NotSupportedException ex)
- {
- _logger.ErrorException("Error killing process", ex);
- }
- }
-
- return ranToCompletion;
- }
-
- /// <summary>
/// Gets the file input argument.
/// </summary>
/// <param name="path">The path.</param>
@@ -1003,14 +909,9 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
return GetFileInputArgument(playableStreamFiles[0]);
}
- /// <summary>
- /// Gets the bluray input argument.
- /// </summary>
- /// <param name="blurayRoot">The bluray root.</param>
- /// <returns>System.String.</returns>
- private string GetBlurayInputArgument(string blurayRoot)
+ public Task<Stream> EncodeImage(ImageEncodingOptions options, CancellationToken cancellationToken)
{
- return string.Format("bluray:\"{0}\"", blurayRoot);
+ return new ImageEncoder(FFMpegPath, _logger, _fileSystem, _appPaths).EncodeImage(options, cancellationToken);
}
/// <summary>
diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
new file mode 100644
index 000000000..fb1041f89
--- /dev/null
+++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{0BD82FA6-EB8A-4452-8AF5-74F9C3849451}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>MediaBrowser.MediaEncoding</RootNamespace>
+ <AssemblyName>MediaBrowser.MediaEncoding</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
+ <RestorePackages>true</RestorePackages>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="BDInfo">
+ <HintPath>..\packages\MediaBrowser.BdInfo.1.0.0.10\lib\net35\BDInfo.dll</HintPath>
+ </Reference>
+ <Reference Include="DvdLib">
+ <HintPath>..\packages\MediaBrowser.BdInfo.1.0.0.10\lib\net35\DvdLib.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="BdInfo\BdInfoExaminer.cs" />
+ <Compile Include="Encoder\ImageEncoder.cs" />
+ <Compile Include="Encoder\MediaEncoder.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
+ <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
+ <Name>MediaBrowser.Common</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
+ <Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
+ <Name>MediaBrowser.Controller</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
+ <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
+ <Name>MediaBrowser.Model</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="packages.config" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs b/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..6616e46ac
--- /dev/null
+++ b/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("MediaBrowser.MediaEncoding")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("MediaBrowser.MediaEncoding")]
+[assembly: AssemblyCopyright("Copyright © 2014")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("05f49ab9-2a90-4332-9d41-7817a9cccd90")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/MediaBrowser.MediaEncoding/packages.config b/MediaBrowser.MediaEncoding/packages.config
new file mode 100644
index 000000000..6e52b72b8
--- /dev/null
+++ b/MediaBrowser.MediaEncoding/packages.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="MediaBrowser.BdInfo" version="1.0.0.10" targetFramework="net45" />
+</packages> \ No newline at end of file
diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
index 960b0f635..6c4d9d9e2 100644
--- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
+++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
@@ -101,6 +101,9 @@
<Compile Include="..\MediaBrowser.Model\Configuration\UserConfiguration.cs">
<Link>Configuration\UserConfiguration.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Dlna\DeviceProfileInfo.cs">
+ <Link>Dlna\DeviceProfileInfo.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Drawing\DrawingUtils.cs">
<Link>Drawing\DrawingUtils.cs</Link>
</Compile>
@@ -425,6 +428,9 @@
<Compile Include="..\MediaBrowser.Model\Session\BrowseRequest.cs">
<Link>Session\BrowseRequest.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Session\GenericCommand.cs">
+ <Link>Session\GenericCommand.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Session\MessageCommand.cs">
<Link>Session\MessageCommand.cs</Link>
</Compile>
diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
index b010ad9c9..b39cecc61 100644
--- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
+++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
@@ -88,6 +88,9 @@
<Compile Include="..\MediaBrowser.Model\Configuration\UserConfiguration.cs">
<Link>Configuration\UserConfiguration.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Dlna\DeviceProfileInfo.cs">
+ <Link>Dlna\DeviceProfileInfo.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Drawing\DrawingUtils.cs">
<Link>Drawing\DrawingUtils.cs</Link>
</Compile>
@@ -412,6 +415,9 @@
<Compile Include="..\MediaBrowser.Model\Session\BrowseRequest.cs">
<Link>Session\BrowseRequest.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Session\GenericCommand.cs">
+ <Link>Session\GenericCommand.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Session\MessageCommand.cs">
<Link>Session\MessageCommand.cs</Link>
</Compile>
diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs
index 8de54f34a..28c5822e9 100644
--- a/MediaBrowser.Model/ApiClient/IApiClient.cs
+++ b/MediaBrowser.Model/ApiClient/IApiClient.cs
@@ -590,6 +590,14 @@ namespace MediaBrowser.Model.ApiClient
Task SendPlayCommandAsync(string sessionId, PlayRequest request);
/// <summary>
+ /// Sends the command asynchronous.
+ /// </summary>
+ /// <param name="sessionId">The session identifier.</param>
+ /// <param name="request">The request.</param>
+ /// <returns>Task.</returns>
+ Task SendCommandAsync(string sessionId, GenericCommand request);
+
+ /// <summary>
/// Sends a system command to the client
/// </summary>
/// <param name="sessionId">The session id.</param>
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index 1f304112f..d0caa3ad2 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -58,6 +58,12 @@ namespace MediaBrowser.Model.Configuration
public string ItemsByNamePath { get; set; }
/// <summary>
+ /// Gets or sets the metadata path.
+ /// </summary>
+ /// <value>The metadata path.</value>
+ public string MetadataPath { get; set; }
+
+ /// <summary>
/// Gets or sets the display name of the season zero.
/// </summary>
/// <value>The display name of the season zero.</value>
diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs
index 2145860c7..10f984f88 100644
--- a/MediaBrowser.Model/Configuration/UserConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs
@@ -52,6 +52,7 @@ namespace MediaBrowser.Model.Configuration
public bool EnableLiveTvAccess { get; set; }
public bool EnableMediaPlayback { get; set; }
+ public bool EnableContentDeletion { get; set; }
public string[] BlockedMediaFolders { get; set; }
@@ -63,8 +64,9 @@ namespace MediaBrowser.Model.Configuration
public UserConfiguration()
{
IsAdministrator = true;
- EnableRemoteControlOfOtherUsers = true;
+ EnableRemoteControlOfOtherUsers = true;
+ EnableContentDeletion = true;
EnableLiveTvManagement = true;
EnableMediaPlayback = true;
EnableLiveTvAccess = true;
diff --git a/MediaBrowser.Model/Dlna/DeviceProfileInfo.cs b/MediaBrowser.Model/Dlna/DeviceProfileInfo.cs
new file mode 100644
index 000000000..ceb27386c
--- /dev/null
+++ b/MediaBrowser.Model/Dlna/DeviceProfileInfo.cs
@@ -0,0 +1,30 @@
+
+namespace MediaBrowser.Model.Dlna
+{
+ public class DeviceProfileInfo
+ {
+ /// <summary>
+ /// Gets or sets the identifier.
+ /// </summary>
+ /// <value>The identifier.</value>
+ public string Id { get; set; }
+
+ /// <summary>
+ /// Gets or sets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ public string Name { get; set; }
+
+ /// <summary>
+ /// Gets or sets the type.
+ /// </summary>
+ /// <value>The type.</value>
+ public DeviceProfileType Type { get; set; }
+ }
+
+ public enum DeviceProfileType
+ {
+ System = 0,
+ User = 1
+ }
+}
diff --git a/MediaBrowser.Model/Drawing/ImageOutputFormat.cs b/MediaBrowser.Model/Drawing/ImageOutputFormat.cs
index 6cbe75a7a..824970073 100644
--- a/MediaBrowser.Model/Drawing/ImageOutputFormat.cs
+++ b/MediaBrowser.Model/Drawing/ImageOutputFormat.cs
@@ -25,6 +25,7 @@ namespace MediaBrowser.Model.Drawing
/// <summary>
/// The PNG
/// </summary>
- Png
+ Png,
+ Webp
}
}
diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs
index a8f751c10..b644661f4 100644
--- a/MediaBrowser.Model/Entities/MediaStream.cs
+++ b/MediaBrowser.Model/Entities/MediaStream.cs
@@ -124,6 +124,12 @@ namespace MediaBrowser.Model.Entities
public string Path { get; set; }
/// <summary>
+ /// Gets or sets the pixel format.
+ /// </summary>
+ /// <value>The pixel format.</value>
+ public string PixelFormat { get; set; }
+
+ /// <summary>
/// Gets or sets the level.
/// </summary>
/// <value>The level.</value>
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index 5e9b97939..207543fe8 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -66,6 +66,7 @@
<Compile Include="Configuration\MetadataPlugin.cs" />
<Compile Include="Configuration\MetadataOptions.cs" />
<Compile Include="Configuration\ServerConfiguration.cs" />
+ <Compile Include="Dlna\DeviceProfileInfo.cs" />
<Compile Include="Drawing\ImageOutputFormat.cs" />
<Compile Include="Dto\BaseItemPerson.cs" />
<Compile Include="Dto\ChapterInfoDto.cs" />
@@ -131,6 +132,7 @@
<Compile Include="Querying\UserQuery.cs" />
<Compile Include="Search\SearchQuery.cs" />
<Compile Include="Session\BrowseRequest.cs" />
+ <Compile Include="Session\GenericCommand.cs" />
<Compile Include="Session\MessageCommand.cs" />
<Compile Include="Session\PlaybackReports.cs" />
<Compile Include="Session\PlayRequest.cs" />
diff --git a/MediaBrowser.Model/Session/GenericCommand.cs b/MediaBrowser.Model/Session/GenericCommand.cs
new file mode 100644
index 000000000..f7ea0a84a
--- /dev/null
+++ b/MediaBrowser.Model/Session/GenericCommand.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Model.Session
+{
+ public class GenericCommand
+ {
+ public string Name { get; set; }
+
+ public string ControllingUserId { get; set; }
+
+ public Dictionary<string, string> Arguments { get; set; }
+
+ public GenericCommand()
+ {
+ Arguments = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ }
+ }
+
+ /// <summary>
+ /// This exists simply to identify a set of known commands.
+ /// </summary>
+ public enum CoreGenericCommand
+ {
+ MoveUp = 0,
+ MoveDown = 1,
+ MoveLeft = 2,
+ MoveRight = 3,
+ PageUp = 4,
+ PageDown = 5,
+ PreviousLetter = 6,
+ NextLetter = 7,
+ ToggleOsd = 8,
+ ToggleContextMenu = 9,
+ Select = 10,
+ Back = 11,
+ TakeScreenshot = 12,
+ SendKey = 13,
+ SendString = 14,
+ GoHome = 15,
+ GoToSettings = 16,
+ VolumeUp = 17,
+ VolumeDown = 18,
+ Mute = 19,
+ Unmute = 20,
+ ToggleMute = 21
+ }
+}
diff --git a/MediaBrowser.Model/Session/PlaystateCommand.cs b/MediaBrowser.Model/Session/PlaystateCommand.cs
index d83c6dae5..91572ba62 100644
--- a/MediaBrowser.Model/Session/PlaystateCommand.cs
+++ b/MediaBrowser.Model/Session/PlaystateCommand.cs
@@ -33,7 +33,15 @@ namespace MediaBrowser.Model.Session
/// <summary>
/// The fullscreen
/// </summary>
- Fullscreen
+ Fullscreen,
+ /// <summary>
+ /// The rewind
+ /// </summary>
+ Rewind,
+ /// <summary>
+ /// The fast forward
+ /// </summary>
+ FastForward
}
public class PlaystateRequest
diff --git a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs
index 29032ca29..cf7904e5c 100644
--- a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs
+++ b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs
@@ -172,7 +172,7 @@ namespace MediaBrowser.Providers.BoxSets
if (!string.IsNullOrEmpty(language))
{
// If preferred language isn't english, get those images too
- if (imageLanguages.Contains(language, StringComparer.OrdinalIgnoreCase))
+ if (!imageLanguages.Contains(language, StringComparer.OrdinalIgnoreCase))
{
imageLanguages.Add(language);
}
diff --git a/MediaBrowser.Providers/Manager/SeriesOrderManager.cs b/MediaBrowser.Providers/Manager/SeriesOrderManager.cs
new file mode 100644
index 000000000..39175d1f9
--- /dev/null
+++ b/MediaBrowser.Providers/Manager/SeriesOrderManager.cs
@@ -0,0 +1,36 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using MediaBrowser.Common;
+using MediaBrowser.Controller.Providers;
+
+namespace MediaBrowser.Providers.Manager
+{
+ public class SeriesOrderManager : ISeriesOrderManager
+ {
+ private Dictionary<string, ISeriesOrderProvider[]> _providers;
+
+ public void AddParts(IEnumerable<ISeriesOrderProvider> orderProviders)
+ {
+ _providers = orderProviders
+ .GroupBy(p => p.OrderType)
+ .ToDictionary(g => g.Key, g => g.ToArray());
+ }
+
+ public async Task<int?> FindSeriesIndex(string orderType, string seriesName)
+ {
+ ISeriesOrderProvider[] providers;
+ if (!_providers.TryGetValue(orderType, out providers))
+ return null;
+
+ foreach (ISeriesOrderProvider provider in providers)
+ {
+ int? index = await provider.FindSeriesIndex(seriesName);
+ if (index != null)
+ return index;
+ }
+
+ return null;
+ }
+ }
+} \ No newline at end of file
diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
index f347e7229..ff39ec70d 100644
--- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj
+++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
@@ -103,6 +103,7 @@
<Compile Include="Games\GameXmlParser.cs" />
<Compile Include="Games\GameXmlProvider.cs" />
<Compile Include="Games\GameSystemXmlProvider.cs" />
+ <Compile Include="Manager\SeriesOrderManager.cs" />
<Compile Include="MediaInfo\FFProbeAudioInfo.cs" />
<Compile Include="MediaInfo\FFProbeHelpers.cs" />
<Compile Include="MediaInfo\FFProbeProvider.cs" />
diff --git a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
index b3c3f278e..b2ca97f55 100644
--- a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
@@ -94,7 +94,7 @@ namespace MediaBrowser.Providers.MediaInfo
{
Directory.CreateDirectory(Path.GetDirectoryName(path));
- using (var stream = await _mediaEncoder.ExtractImage(new[] { item.Path }, InputType.File, true, null, null, cancellationToken).ConfigureAwait(false))
+ using (var stream = await _mediaEncoder.ExtractAudioImage(item.Path, cancellationToken).ConfigureAwait(false))
{
using (var fileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true))
{
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
index 044973064..75a9d9c36 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
@@ -50,12 +50,16 @@ namespace MediaBrowser.Providers.MediaInfo
return ItemUpdateType.MetadataImport;
}
+ private const string SchemaVersion = "1";
+
private async Task<InternalMediaInfoResult> GetMediaInfo(BaseItem item, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var idString = item.Id.ToString("N");
- var cachePath = Path.Combine(_appPaths.CachePath, "ffprobe-audio", idString.Substring(0, 2), idString, "v" + _mediaEncoder.Version + item.DateModified.Ticks.ToString(_usCulture) + ".json");
+ var cachePath = Path.Combine(_appPaths.CachePath,
+ "ffprobe-audio",
+ idString.Substring(0, 2), idString, "v" + SchemaVersion + _mediaEncoder.Version + item.DateModified.Ticks.ToString(_usCulture) + ".json");
try
{
@@ -148,7 +152,7 @@ namespace MediaBrowser.Providers.MediaInfo
if (!string.IsNullOrWhiteSpace(composer))
{
- foreach (var person in Split(composer))
+ foreach (var person in Split(composer, false))
{
audio.AddPerson(new PersonInfo { Name = person, Type = PersonType.Composer });
}
@@ -221,12 +225,15 @@ namespace MediaBrowser.Providers.MediaInfo
/// Splits the specified val.
/// </summary>
/// <param name="val">The val.</param>
+ /// <param name="allowCommaDelimiter">if set to <c>true</c> [allow comma delimiter].</param>
/// <returns>System.String[][].</returns>
- private IEnumerable<string> Split(string val)
+ private IEnumerable<string> Split(string val, bool allowCommaDelimiter)
{
// Only use the comma as a delimeter if there are no slashes or pipes.
// We want to be careful not to split names that have commas in them
- var delimeter = _nameDelimiters.Any(i => val.IndexOf(i) != -1) ? _nameDelimiters : new[] { ',' };
+ var delimeter = !allowCommaDelimiter || _nameDelimiters.Any(i => val.IndexOf(i) != -1) ?
+ _nameDelimiters :
+ new[] { ',' };
return val.Split(delimeter, StringSplitOptions.RemoveEmptyEntries)
.Where(i => !string.IsNullOrWhiteSpace(i))
@@ -312,7 +319,7 @@ namespace MediaBrowser.Providers.MediaInfo
if (!string.IsNullOrEmpty(val))
{
// Sometimes the artist name is listed here, account for that
- var studios = Split(val).Where(i => !audio.HasArtist(i));
+ var studios = Split(val, true).Where(i => !audio.HasArtist(i));
foreach (var studio in studios)
{
@@ -334,7 +341,7 @@ namespace MediaBrowser.Providers.MediaInfo
{
audio.Genres.Clear();
- foreach (var genre in Split(val))
+ foreach (var genre in Split(val, true))
{
audio.AddGenre(genre);
}
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
index d516a8221..cb326c5ad 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
@@ -107,14 +107,16 @@ namespace MediaBrowser.Providers.MediaInfo
return ItemUpdateType.MetadataImport;
}
+ private const string SchemaVersion = "1";
+
private async Task<InternalMediaInfoResult> GetMediaInfo(BaseItem item, IIsoMount isoMount, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
- cancellationToken.ThrowIfCancellationRequested();
-
var idString = item.Id.ToString("N");
- var cachePath = Path.Combine(_appPaths.CachePath, "ffprobe-video", idString.Substring(0, 2), idString, "v" + _mediaEncoder.Version + item.DateModified.Ticks.ToString(_usCulture) + ".json");
+ var cachePath = Path.Combine(_appPaths.CachePath,
+ "ffprobe-video",
+ idString.Substring(0, 2), idString, "v" + SchemaVersion + _mediaEncoder.Version + item.DateModified.Ticks.ToString(_usCulture) + ".json");
try
{
@@ -161,7 +163,8 @@ namespace MediaBrowser.Providers.MediaInfo
var mediaStreams = MediaEncoderHelpers.GetMediaInfo(data).MediaStreams;
- var chapters = data.Chapters ?? new List<ChapterInfo>();
+ var mediaChapters = (data.Chapters ?? new MediaChapter[] { }).ToList();
+ var chapters = mediaChapters.Select(GetChapterInfo).ToList();
if (video.VideoType == VideoType.BluRay || (video.IsoType.HasValue && video.IsoType.Value == IsoType.BluRay))
{
@@ -200,6 +203,24 @@ namespace MediaBrowser.Providers.MediaInfo
await _itemRepo.SaveChapters(video.Id, chapters, cancellationToken).ConfigureAwait(false);
}
+ private ChapterInfo GetChapterInfo(MediaChapter chapter)
+ {
+ var info = new ChapterInfo();
+
+ if (chapter.tags != null)
+ {
+ string name;
+ if (chapter.tags.TryGetValue("title", out name))
+ {
+ info.Name = name;
+ }
+ }
+
+ info.StartPositionTicks = chapter.start/100;
+
+ return info;
+ }
+
private void FetchBdInfo(BaseItem item, List<ChapterInfo> chapters, List<MediaStream> mediaStreams, BlurayDiscInfo blurayInfo)
{
var video = (Video)item;
diff --git a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
index 354758497..70daa3f51 100644
--- a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
@@ -93,7 +93,7 @@ namespace MediaBrowser.Providers.MediaInfo
var inputPath = MediaEncoderHelpers.GetInputArgument(item.Path, item.LocationType == LocationType.Remote, item.VideoType, item.IsoType, isoMount, item.PlayableStreamFileNames, out type);
- var stream = await _mediaEncoder.ExtractImage(inputPath, type, false, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false);
+ var stream = await _mediaEncoder.ExtractVideoImage(inputPath, type, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false);
return new DynamicImageResponse
{
diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs
index 05f2d485e..7a63713f1 100644
--- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs
+++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs
@@ -295,7 +295,7 @@ namespace MediaBrowser.Providers.Movies
if (!string.IsNullOrEmpty(language))
{
// If preferred language isn't english, get those images too
- if (imageLanguages.Contains(language, StringComparer.OrdinalIgnoreCase))
+ if (!imageLanguages.Contains(language, StringComparer.OrdinalIgnoreCase))
{
imageLanguages.Add(language);
}
diff --git a/MediaBrowser.Providers/Music/LastfmArtistProvider.cs b/MediaBrowser.Providers/Music/LastfmArtistProvider.cs
index a50e5f9d5..95169aef0 100644
--- a/MediaBrowser.Providers/Music/LastfmArtistProvider.cs
+++ b/MediaBrowser.Providers/Music/LastfmArtistProvider.cs
@@ -131,30 +131,6 @@ namespace MediaBrowser.Providers.Music
}
/// <summary>
- /// Determines whether the specified text has diacritics.
- /// </summary>
- /// <param name="text">The text.</param>
- /// <returns><c>true</c> if the specified text has diacritics; otherwise, <c>false</c>.</returns>
- private bool HasDiacritics(string text)
- {
- return !String.Equals(text, RemoveDiacritics(text), StringComparison.Ordinal);
- }
-
- /// <summary>
- /// Removes the diacritics.
- /// </summary>
- /// <param name="text">The text.</param>
- /// <returns>System.String.</returns>
- private string RemoveDiacritics(string text)
- {
- return String.Concat(
- text.Normalize(NormalizationForm.FormD)
- .Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) !=
- UnicodeCategory.NonSpacingMark)
- ).Normalize(NormalizationForm.FormC);
- }
-
- /// <summary>
/// Encodes an URL.
/// </summary>
/// <param name="name">The name.</param>
diff --git a/MediaBrowser.Providers/Savers/MovieXmlSaver.cs b/MediaBrowser.Providers/Savers/MovieXmlSaver.cs
index 595793854..9a31fd091 100644
--- a/MediaBrowser.Providers/Savers/MovieXmlSaver.cs
+++ b/MediaBrowser.Providers/Savers/MovieXmlSaver.cs
@@ -3,7 +3,6 @@ using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Model.Entities;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
@@ -75,16 +74,6 @@ namespace MediaBrowser.Providers.Savers
XmlSaverHelpers.AddCommonNodes(video, builder);
- if (video.CommunityRating.HasValue)
- {
- builder.Append("<IMDBrating>" + SecurityElement.Escape(video.CommunityRating.Value.ToString(UsCulture)) + "</IMDBrating>");
- }
-
- if (!string.IsNullOrEmpty(video.Overview))
- {
- builder.Append("<Description><![CDATA[" + video.Overview + "]]></Description>");
- }
-
var musicVideo = item as MusicVideo;
if (musicVideo != null)
@@ -117,8 +106,12 @@ namespace MediaBrowser.Providers.Savers
XmlSaverHelpers.Save(builder, xmlFilePath, new List<string>
{
+ // Deprecated. No longer saving in this field.
"IMDBrating",
+
+ // Deprecated. No longer saving in this field.
"Description",
+
"Artist",
"Album",
"TmdbCollectionName"
diff --git a/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs b/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs
index e69f2e085..a7ed55e5d 100644
--- a/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs
+++ b/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs
@@ -60,11 +60,6 @@ namespace MediaBrowser.Providers.Savers
builder.Append("<id>" + SecurityElement.Escape(tvdb) + "</id>");
}
- if (!string.IsNullOrEmpty(item.Name))
- {
- builder.Append("<SeriesName>" + SecurityElement.Escape(item.Name) + "</SeriesName>");
- }
-
if (series.Status.HasValue)
{
builder.Append("<Status>" + SecurityElement.Escape(series.Status.Value.ToString()) + "</Status>");
@@ -111,7 +106,6 @@ namespace MediaBrowser.Providers.Savers
XmlSaverHelpers.Save(builder, xmlFilePath, new List<string>
{
"id",
- "SeriesName",
"Status",
"Network",
"Airs_Time",
@@ -120,6 +114,10 @@ namespace MediaBrowser.Providers.Savers
// Don't preserve old series node
"Series",
+
+ "SeriesName",
+
+ // Deprecated. No longer saving in this field.
"AnimeSeriesIndex"
});
}
diff --git a/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs b/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs
index 391ab7cfd..6d681197e 100644
--- a/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs
+++ b/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs
@@ -28,7 +28,10 @@ namespace MediaBrowser.Providers.Savers
"AwardSummary",
"BirthDate",
"Budget",
+
+ // Deprecated. No longer saving in this field.
"certification",
+
"Chapters",
"ContentRating",
"CustomRating",
@@ -40,22 +43,31 @@ namespace MediaBrowser.Providers.Savers
"Genres",
"Genre",
"GamesDbId",
+
+ // Deprecated. No longer saving in this field.
"IMDB_ID",
+
"IMDB",
+
+ // Deprecated. No longer saving in this field.
"IMDbId",
+
"Language",
"LocalTitle",
"LockData",
"LockedFields",
"Format3D",
"Metascore",
+
+ // Deprecated. No longer saving in this field.
"MPAARating",
+
"MusicBrainzArtistId",
"MusicBrainzAlbumArtistId",
"MusicBrainzAlbumId",
"MusicBrainzReleaseGroupId",
- // Old - not used anymore
+ // Deprecated. No longer saving in this field.
"MusicbrainzId",
"Overview",
@@ -67,15 +79,24 @@ namespace MediaBrowser.Providers.Savers
"Revenue",
"RottenTomatoesId",
"RunningTime",
+
+ // Deprecated. No longer saving in this field.
"Runtime",
+
"SortTitle",
"Studios",
"Tags",
+
+ // Deprecated. No longer saving in this field.
"TagLine",
+
"Taglines",
"TMDbCollectionId",
"TMDbId",
+
+ // Deprecated. No longer saving in this field.
"Trailer",
+
"Trailers",
"TVcomId",
"TvDbId",
@@ -207,8 +228,6 @@ namespace MediaBrowser.Providers.Savers
if (!string.IsNullOrEmpty(item.OfficialRating))
{
builder.Append("<ContentRating>" + SecurityElement.Escape(item.OfficialRating) + "</ContentRating>");
- builder.Append("<MPAARating>" + SecurityElement.Escape(item.OfficialRating) + "</MPAARating>");
- builder.Append("<certification>" + SecurityElement.Escape(item.OfficialRating) + "</certification>");
}
builder.Append("<Added>" + SecurityElement.Escape(item.DateCreated.ToLocalTime().ToString("G")) + "</Added>");
@@ -376,16 +395,13 @@ namespace MediaBrowser.Providers.Savers
var timespan = TimeSpan.FromTicks(runTimeTicks.Value);
builder.Append("<RunningTime>" + Convert.ToInt32(timespan.TotalMinutes).ToString(UsCulture) + "</RunningTime>");
- builder.Append("<Runtime>" + Convert.ToInt32(timespan.TotalMinutes).ToString(UsCulture) + "</Runtime>");
}
var imdb = item.GetProviderId(MetadataProviders.Imdb);
if (!string.IsNullOrEmpty(imdb))
{
- builder.Append("<IMDB_ID>" + SecurityElement.Escape(imdb) + "</IMDB_ID>");
builder.Append("<IMDB>" + SecurityElement.Escape(imdb) + "</IMDB>");
- builder.Append("<IMDbId>" + SecurityElement.Escape(imdb) + "</IMDbId>");
}
var tmdb = item.GetProviderId(MetadataProviders.Tmdb);
diff --git a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs
index 470bd7b3a..5bc58af91 100644
--- a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs
+++ b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs
@@ -77,7 +77,8 @@ namespace MediaBrowser.Providers.TV
try
{
- AddImages(list, season.IndexNumber.Value, xmlPath, cancellationToken);
+ int seasonNumber = AdjustForSeriesOffset(series, season.IndexNumber.Value);
+ AddImages(list, seasonNumber, xmlPath, cancellationToken);
}
catch (FileNotFoundException)
{
@@ -115,6 +116,15 @@ namespace MediaBrowser.Providers.TV
.ThenByDescending(i => i.VoteCount ?? 0);
}
+ private int AdjustForSeriesOffset(Series series, int seasonNumber)
+ {
+ var offset = TvdbSeriesProvider.GetSeriesOffset(series.ProviderIds);
+ if (offset != null)
+ return (int)(seasonNumber + offset);
+
+ return seasonNumber;
+ }
+
private void AddImages(List<RemoteImageInfo> list, int seasonNumber, string xmlPath, CancellationToken cancellationToken)
{
using (var streamReader = new StreamReader(xmlPath, Encoding.UTF8))
diff --git a/MediaBrowser.Providers/TV/SeriesXmlParser.cs b/MediaBrowser.Providers/TV/SeriesXmlParser.cs
index 0c220031c..9f68ad7a4 100644
--- a/MediaBrowser.Providers/TV/SeriesXmlParser.cs
+++ b/MediaBrowser.Providers/TV/SeriesXmlParser.cs
@@ -90,6 +90,8 @@ namespace MediaBrowser.Providers.TV
break;
}
case "SeriesName":
+ // TODO: Deprecate in mid-2014
+ // No longer saving this tag but will still read it for a while
item.Name = reader.ReadElementContentAsString();
break;
diff --git a/MediaBrowser.Providers/TV/TvdbEpisodeImageProvider.cs b/MediaBrowser.Providers/TV/TvdbEpisodeImageProvider.cs
index 36e349f60..ef3778450 100644
--- a/MediaBrowser.Providers/TV/TvdbEpisodeImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TvdbEpisodeImageProvider.cs
@@ -62,8 +62,9 @@ namespace MediaBrowser.Providers.TV
{
// Process images
var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesId);
+ var indexOffset = TvdbSeriesProvider.GetSeriesOffset(series.ProviderIds) ?? 0;
- var files = TvdbEpisodeProvider.Current.GetEpisodeXmlFiles(episode.ParentIndexNumber, episode.IndexNumber, episode.IndexNumberEnd, seriesDataPath);
+ var files = TvdbEpisodeProvider.Current.GetEpisodeXmlFiles(episode.ParentIndexNumber + indexOffset, episode.IndexNumber, episode.IndexNumberEnd, seriesDataPath);
var result = files.Select(i => GetImageInfo(i, cancellationToken))
.Where(i => i != null);
diff --git a/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs
index 5f6bdfa04..922c29fe9 100644
--- a/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs
@@ -52,7 +52,7 @@ namespace MediaBrowser.Providers.TV
try
{
- var item = FetchEpisodeData(searchInfo, seriesDataPath, cancellationToken);
+ var item = FetchEpisodeData(searchInfo, seriesDataPath, searchInfo.SeriesProviderIds, cancellationToken);
if (item != null)
{
@@ -96,7 +96,7 @@ namespace MediaBrowser.Providers.TV
try
{
- result.Item = FetchEpisodeData(searchInfo, seriesDataPath, cancellationToken);
+ result.Item = FetchEpisodeData(searchInfo, seriesDataPath, searchInfo.SeriesProviderIds, cancellationToken);
result.HasMetadata = result.Item != null;
}
catch (FileNotFoundException)
@@ -213,7 +213,7 @@ namespace MediaBrowser.Providers.TV
/// <param name="seriesDataPath">The series data path.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{System.Boolean}.</returns>
- private Episode FetchEpisodeData(EpisodeInfo id, string seriesDataPath, CancellationToken cancellationToken)
+ private Episode FetchEpisodeData(EpisodeInfo id, string seriesDataPath, Dictionary<string, string> seriesProviderIds, CancellationToken cancellationToken)
{
if (id.IndexNumber == null)
{
@@ -221,7 +221,8 @@ namespace MediaBrowser.Providers.TV
}
var episodeNumber = id.IndexNumber.Value;
- var seasonNumber = id.ParentIndexNumber;
+ var seasonOffset = TvdbSeriesProvider.GetSeriesOffset(seriesProviderIds) ?? 0;
+ var seasonNumber = id.ParentIndexNumber + seasonOffset;
if (seasonNumber == null)
{
diff --git a/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs b/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs
index c0c103b7f..5a9981c6e 100644
--- a/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs
@@ -22,8 +22,9 @@ namespace MediaBrowser.Providers.TV
{
public class TvdbSeasonImageProvider : IRemoteImageProvider, IHasOrder, IHasChangeMonitor
{
+ private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
+
private readonly IServerConfigurationManager _config;
- private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private readonly IHttpClient _httpClient;
private readonly IFileSystem _fileSystem;
@@ -77,7 +78,8 @@ namespace MediaBrowser.Providers.TV
try
{
- return GetImages(path, item.GetPreferredMetadataLanguage(), season.IndexNumber.Value, cancellationToken);
+ int seasonNumber = AdjustForSeriesOffset(series, season.IndexNumber.Value);
+ return GetImages(path, item.GetPreferredMetadataLanguage(), seasonNumber, cancellationToken);
}
catch (FileNotFoundException)
{
@@ -88,7 +90,16 @@ namespace MediaBrowser.Providers.TV
return new RemoteImageInfo[] { };
}
- private IEnumerable<RemoteImageInfo> GetImages(string xmlPath, string preferredLanguage, int seasonNumber, CancellationToken cancellationToken)
+ private int AdjustForSeriesOffset(Series series, int seasonNumber)
+ {
+ var offset = TvdbSeriesProvider.GetSeriesOffset(series.ProviderIds);
+ if (offset != null)
+ return (int) (seasonNumber + offset);
+
+ return seasonNumber;
+ }
+
+ internal static IEnumerable<RemoteImageInfo> GetImages(string xmlPath, string preferredLanguage, int seasonNumber, CancellationToken cancellationToken)
{
var settings = new XmlReaderSettings
{
@@ -159,7 +170,7 @@ namespace MediaBrowser.Providers.TV
.ToList();
}
- private void AddImage(XmlReader reader, List<RemoteImageInfo> images, int seasonNumber)
+ private static void AddImage(XmlReader reader, List<RemoteImageInfo> images, int seasonNumber)
{
reader.MoveToContent();
@@ -186,7 +197,7 @@ namespace MediaBrowser.Providers.TV
double rval;
- if (double.TryParse(val, NumberStyles.Any, _usCulture, out rval))
+ if (double.TryParse(val, NumberStyles.Any, UsCulture, out rval))
{
rating = rval;
}
@@ -200,7 +211,7 @@ namespace MediaBrowser.Providers.TV
int rval;
- if (int.TryParse(val, NumberStyles.Integer, _usCulture, out rval))
+ if (int.TryParse(val, NumberStyles.Integer, UsCulture, out rval))
{
voteCount = rval;
}
@@ -237,12 +248,12 @@ namespace MediaBrowser.Providers.TV
{
int rval;
- if (int.TryParse(resolutionParts[0], NumberStyles.Integer, _usCulture, out rval))
+ if (int.TryParse(resolutionParts[0], NumberStyles.Integer, UsCulture, out rval))
{
width = rval;
}
- if (int.TryParse(resolutionParts[1], NumberStyles.Integer, _usCulture, out rval))
+ if (int.TryParse(resolutionParts[1], NumberStyles.Integer, UsCulture, out rval))
{
height = rval;
}
@@ -285,7 +296,7 @@ namespace MediaBrowser.Providers.TV
CommunityRating = rating,
VoteCount = voteCount,
Url = TVUtils.BannerUrl + url,
- ProviderName = Name,
+ ProviderName = ProviderName,
Language = language,
Width = width,
Height = height
diff --git a/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs b/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs
index 761c77443..d1171f34b 100644
--- a/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs
@@ -77,6 +77,10 @@ namespace MediaBrowser.Providers.TV
try
{
+ var seriesOffset = TvdbSeriesProvider.GetSeriesOffset(series.ProviderIds);
+ if (seriesOffset != null)
+ return TvdbSeasonImageProvider.GetImages(path, language, seriesOffset.Value + 1, cancellationToken);
+
return GetImages(path, language, cancellationToken);
}
catch (FileNotFoundException)
diff --git a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs
index 4b78c1a96..a76e10111 100644
--- a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs
@@ -25,6 +25,8 @@ namespace MediaBrowser.Providers.TV
{
public class TvdbSeriesProvider : IRemoteMetadataProvider<Series, SeriesInfo>, IHasOrder
{
+ internal const string TvdbSeriesOffset = "TvdbSeriesOffset";
+
internal readonly SemaphoreSlim TvDbResourcePool = new SemaphoreSlim(2, 2);
internal static TvdbSeriesProvider Current { get; private set; }
private readonly IZipClient _zipClient;
@@ -33,14 +35,16 @@ namespace MediaBrowser.Providers.TV
private readonly IServerConfigurationManager _config;
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private readonly ILogger _logger;
+ private readonly ISeriesOrderManager _seriesOrder;
- public TvdbSeriesProvider(IZipClient zipClient, IHttpClient httpClient, IFileSystem fileSystem, IServerConfigurationManager config, ILogger logger)
+ public TvdbSeriesProvider(IZipClient zipClient, IHttpClient httpClient, IFileSystem fileSystem, IServerConfigurationManager config, ILogger logger, ISeriesOrderManager seriesOrder)
{
_zipClient = zipClient;
_httpClient = httpClient;
_fileSystem = fileSystem;
_config = config;
_logger = logger;
+ _seriesOrder = seriesOrder;
Current = this;
}
@@ -92,11 +96,35 @@ namespace MediaBrowser.Providers.TV
result.HasMetadata = true;
FetchSeriesData(result.Item, seriesId, cancellationToken);
+ await FindAnimeSeriesIndex(result.Item, itemId).ConfigureAwait(false);
}
return result;
}
+ private async Task FindAnimeSeriesIndex(Series series, SeriesInfo info)
+ {
+ var index = await _seriesOrder.FindSeriesIndex(SeriesOrderTypes.Anime, series.Name);
+ if (index == null)
+ return;
+
+ var offset = info.AnimeSeriesIndex - index;
+ series.SetProviderId(TvdbSeriesOffset, offset.ToString());
+ }
+
+ internal static int? GetSeriesOffset(Dictionary<string, string> seriesProviderIds)
+ {
+ string offsetString;
+ if (!seriesProviderIds.TryGetValue(TvdbSeriesOffset, out offsetString))
+ return null;
+
+ int offset;
+ if (int.TryParse(offsetString, out offset))
+ return offset;
+
+ return null;
+ }
+
/// <summary>
/// Fetches the series data.
/// </summary>
diff --git a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
index 415205cb1..cb3621fd1 100644
--- a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
+++ b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
@@ -26,6 +26,7 @@ namespace MediaBrowser.Server.Implementations.Configuration
{
UpdateItemsByNamePath();
UpdateTranscodingTempPath();
+ UpdateMetadataPath();
}
/// <summary>
@@ -77,6 +78,16 @@ namespace MediaBrowser.Server.Implementations.Configuration
}
/// <summary>
+ /// Updates the metadata path.
+ /// </summary>
+ private void UpdateMetadataPath()
+ {
+ ((ServerApplicationPaths)ApplicationPaths).InternalMetadataPath = string.IsNullOrEmpty(Configuration.MetadataPath) ?
+ null :
+ Configuration.MetadataPath;
+ }
+
+ /// <summary>
/// Updates the transcoding temporary path.
/// </summary>
private void UpdateTranscodingTempPath()
@@ -98,6 +109,7 @@ namespace MediaBrowser.Server.Implementations.Configuration
ValidateItemByNamePath(newConfig);
ValidateTranscodingTempPath(newConfig);
ValidatePathSubstitutions(newConfig);
+ ValidateMetadataPath(newConfig);
base.ReplaceConfiguration(newConfiguration);
}
@@ -166,5 +178,25 @@ namespace MediaBrowser.Server.Implementations.Configuration
}
}
}
+
+ /// <summary>
+ /// Validates the metadata path.
+ /// </summary>
+ /// <param name="newConfig">The new configuration.</param>
+ /// <exception cref="System.IO.DirectoryNotFoundException"></exception>
+ private void ValidateMetadataPath(ServerConfiguration newConfig)
+ {
+ var newPath = newConfig.MetadataPath;
+
+ if (!string.IsNullOrWhiteSpace(newPath)
+ && !string.Equals(Configuration.MetadataPath ?? string.Empty, newPath))
+ {
+ // Validate
+ if (!Directory.Exists(newPath))
+ {
+ throw new DirectoryNotFoundException(string.Format("{0} does not exist.", newPath));
+ }
+ }
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
index 12d3eadfd..c6c1ec050 100644
--- a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
+++ b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
@@ -3,6 +3,7 @@ using MediaBrowser.Common.IO;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Entities;
@@ -52,12 +53,14 @@ namespace MediaBrowser.Server.Implementations.Drawing
private readonly IFileSystem _fileSystem;
private readonly IJsonSerializer _jsonSerializer;
private readonly IServerApplicationPaths _appPaths;
+ private readonly IMediaEncoder _mediaEncoder;
- public ImageProcessor(ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem, IJsonSerializer jsonSerializer)
+ public ImageProcessor(ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder)
{
_logger = logger;
_fileSystem = fileSystem;
_jsonSerializer = jsonSerializer;
+ _mediaEncoder = mediaEncoder;
_appPaths = appPaths;
_saveImageSizeTimer = new Timer(SaveImageSizeCallback, null, Timeout.Infinite, Timeout.Infinite);
@@ -66,7 +69,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
try
{
- sizeDictionary = jsonSerializer.DeserializeFromFile<Dictionary<Guid, ImageSize>>(ImageSizeFile) ??
+ sizeDictionary = jsonSerializer.DeserializeFromFile<Dictionary<Guid, ImageSize>>(ImageSizeFile) ??
new Dictionary<Guid, ImageSize>();
}
catch (FileNotFoundException)
@@ -213,6 +216,39 @@ namespace MediaBrowser.Server.Implementations.Drawing
try
{
+ var hasPostProcessing = !string.IsNullOrEmpty(options.BackgroundColor) || options.UnplayedCount.HasValue || options.AddPlayedIndicator || options.PercentPlayed.HasValue;
+
+ //if (!hasPostProcessing)
+ //{
+ // using (var outputStream = await _mediaEncoder.EncodeImage(new ImageEncodingOptions
+ // {
+ // InputPath = originalImagePath,
+ // MaxHeight = options.MaxHeight,
+ // MaxWidth = options.MaxWidth,
+ // Height = options.Height,
+ // Width = options.Width,
+ // Quality = options.Quality,
+ // Format = options.OutputFormat == ImageOutputFormat.Original ? Path.GetExtension(originalImagePath).TrimStart('.') : options.OutputFormat.ToString().ToLower()
+
+ // }, CancellationToken.None).ConfigureAwait(false))
+ // {
+ // using (var outputMemoryStream = new MemoryStream())
+ // {
+ // // Save to the memory stream
+ // await outputStream.CopyToAsync(outputMemoryStream).ConfigureAwait(false);
+
+ // var bytes = outputMemoryStream.ToArray();
+
+ // await toStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
+
+ // // kick off a task to cache the result
+ // await CacheResizedImage(cacheFilePath, bytes).ConfigureAwait(false);
+ // }
+
+ // return;
+ // }
+ //}
+
using (var fileStream = _fileSystem.GetFileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, true))
{
// Copy to memory stream to avoid Image locking file
@@ -241,8 +277,8 @@ namespace MediaBrowser.Server.Implementations.Drawing
thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality;
thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
thumbnailGraph.PixelOffsetMode = PixelOffsetMode.HighQuality;
- thumbnailGraph.CompositingMode = string.IsNullOrEmpty(options.BackgroundColor) && !options.UnplayedCount.HasValue && !options.AddPlayedIndicator && !options.PercentPlayed.HasValue ?
- CompositingMode.SourceCopy :
+ thumbnailGraph.CompositingMode = !hasPostProcessing ?
+ CompositingMode.SourceCopy :
CompositingMode.SourceOver;
SetBackgroundColor(thumbnailGraph, options);
@@ -263,7 +299,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
await toStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
// kick off a task to cache the result
- CacheResizedImage(cacheFilePath, bytes, semaphore);
+ await CacheResizedImage(cacheFilePath, bytes).ConfigureAwait(false);
}
}
}
@@ -272,11 +308,9 @@ namespace MediaBrowser.Server.Implementations.Drawing
}
}
}
- catch
+ finally
{
semaphore.Release();
-
- throw;
}
}
@@ -285,33 +319,26 @@ namespace MediaBrowser.Server.Implementations.Drawing
/// </summary>
/// <param name="cacheFilePath">The cache file path.</param>
/// <param name="bytes">The bytes.</param>
- /// <param name="semaphore">The semaphore.</param>
- private void CacheResizedImage(string cacheFilePath, byte[] bytes, SemaphoreSlim semaphore)
+ /// <returns>Task.</returns>
+ private async Task CacheResizedImage(string cacheFilePath, byte[] bytes)
{
- Task.Run(async () =>
+ try
{
- try
- {
- var parentPath = Path.GetDirectoryName(cacheFilePath);
+ var parentPath = Path.GetDirectoryName(cacheFilePath);
- Directory.CreateDirectory(parentPath);
+ Directory.CreateDirectory(parentPath);
- // Save to the cache location
- using (var cacheFileStream = _fileSystem.GetFileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true))
- {
- // Save to the filestream
- await cacheFileStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
- }
- }
- catch (Exception ex)
+ // Save to the cache location
+ using (var cacheFileStream = _fileSystem.GetFileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true))
{
- _logger.ErrorException("Error writing to image cache file {0}", ex, cacheFilePath);
- }
- finally
- {
- semaphore.Release();
+ // Save to the filestream
+ await cacheFileStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
}
- });
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error writing to image cache file {0}", ex, cacheFilePath);
+ }
}
/// <summary>
@@ -519,7 +546,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
{
filename += "iv=" + IndicatorVersion;
}
-
+
if (!string.IsNullOrEmpty(backgroundColor))
{
filename += "b=" + backgroundColor;
diff --git a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
index 0a0b3f4bc..9279fd8d7 100644
--- a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
+++ b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
@@ -249,17 +249,24 @@ namespace MediaBrowser.Server.Implementations.IO
// Creating a FileSystemWatcher over the LAN can take hundreds of milliseconds, so wrap it in a Task to do them all in parallel
Task.Run(() =>
{
- var newWatcher = new FileSystemWatcher(path, "*") { IncludeSubdirectories = true, InternalBufferSize = 32767 };
+ try
+ {
+ var newWatcher = new FileSystemWatcher(path, "*")
+ {
+ IncludeSubdirectories = true,
+ InternalBufferSize = 32767
+ };
- newWatcher.Created += watcher_Changed;
- newWatcher.Deleted += watcher_Changed;
- newWatcher.Renamed += watcher_Changed;
- newWatcher.Changed += watcher_Changed;
+ newWatcher.NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.DirectoryName |
+ NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.Size;
- newWatcher.Error += watcher_Error;
+ newWatcher.Created += watcher_Changed;
+ newWatcher.Deleted += watcher_Changed;
+ newWatcher.Renamed += watcher_Changed;
+ newWatcher.Changed += watcher_Changed;
+
+ newWatcher.Error += watcher_Error;
- try
- {
if (_fileSystemWatchers.TryAdd(path, newWatcher))
{
newWatcher.EnableRaisingEvents = true;
@@ -272,11 +279,7 @@ namespace MediaBrowser.Server.Implementations.IO
}
}
- catch (IOException ex)
- {
- Logger.ErrorException("Error watching path: {0}", ex, path);
- }
- catch (PlatformNotSupportedException ex)
+ catch (Exception ex)
{
Logger.ErrorException("Error watching path: {0}", ex, path);
}
@@ -346,7 +349,9 @@ namespace MediaBrowser.Server.Implementations.IO
{
try
{
- OnWatcherChanged(e);
+ Logger.Debug("Watcher sees change of type " + e.ChangeType + " to " + e.FullPath);
+
+ ReportFileSystemChanged(e.FullPath);
}
catch (Exception ex)
{
@@ -354,13 +359,6 @@ namespace MediaBrowser.Server.Implementations.IO
}
}
- private void OnWatcherChanged(FileSystemEventArgs e)
- {
- Logger.Debug("Watcher sees change of type " + e.ChangeType + " to " + e.FullPath);
-
- ReportFileSystemChanged(e.FullPath);
- }
-
public void ReportFileSystemChanged(string path)
{
if (string.IsNullOrEmpty(path))
@@ -370,12 +368,9 @@ namespace MediaBrowser.Server.Implementations.IO
var filename = Path.GetFileName(path);
- // Ignore certain files
- if (!string.IsNullOrEmpty(filename) && _alwaysIgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase))
- {
- return;
- }
+ var monitorPath = !(!string.IsNullOrEmpty(filename) && _alwaysIgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase));
+ // Ignore certain files
var tempIgnorePaths = _tempIgnoredPaths.Keys.ToList();
// If the parent of an ignored path has a change event, ignore that too
@@ -416,12 +411,15 @@ namespace MediaBrowser.Server.Implementations.IO
}))
{
- return;
+ monitorPath = false;
}
- // Avoid implicitly captured closure
- var affectedPath = path;
- _affectedPaths.AddOrUpdate(path, path, (key, oldValue) => affectedPath);
+ if (monitorPath)
+ {
+ // Avoid implicitly captured closure
+ var affectedPath = path;
+ _affectedPaths.AddOrUpdate(path, path, (key, oldValue) => affectedPath);
+ }
lock (_timerLock)
{
diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs
index 06028d37e..2ee843f09 100644
--- a/MediaBrowser.Server.Implementations/Library/UserManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs
@@ -260,6 +260,8 @@ namespace MediaBrowser.Server.Implementations.Library
public event EventHandler<GenericEventArgs<User>> UserCreated;
+ private readonly SemaphoreSlim _userListLock = new SemaphoreSlim(1, 1);
+
/// <summary>
/// Creates the user.
/// </summary>
@@ -279,19 +281,28 @@ namespace MediaBrowser.Server.Implementations.Library
throw new ArgumentException(string.Format("A user with the name '{0}' already exists.", name));
}
- var user = InstantiateNewUser(name);
+ await _userListLock.WaitAsync(CancellationToken.None).ConfigureAwait(false);
- var list = Users.ToList();
- list.Add(user);
- Users = list;
+ try
+ {
+ var user = InstantiateNewUser(name);
- user.DateLastSaved = DateTime.UtcNow;
+ var list = Users.ToList();
+ list.Add(user);
+ Users = list;
- await UserRepository.SaveUser(user, CancellationToken.None).ConfigureAwait(false);
+ user.DateLastSaved = DateTime.UtcNow;
- EventHelper.QueueEventIfNotNull(UserCreated, this, new GenericEventArgs<User> { Argument = user }, _logger);
+ await UserRepository.SaveUser(user, CancellationToken.None).ConfigureAwait(false);
- return user;
+ EventHelper.QueueEventIfNotNull(UserCreated, this, new GenericEventArgs<User> { Argument = user }, _logger);
+
+ return user;
+ }
+ finally
+ {
+ _userListLock.Release();
+ }
}
/// <summary>
@@ -325,23 +336,32 @@ namespace MediaBrowser.Server.Implementations.Library
throw new ArgumentException(string.Format("The user '{0}' cannot be deleted because there must be at least one admin user in the system.", user.Name));
}
- await UserRepository.DeleteUser(user, CancellationToken.None).ConfigureAwait(false);
-
- var path = user.ConfigurationFilePath;
+ await _userListLock.WaitAsync(CancellationToken.None).ConfigureAwait(false);
try
{
- File.Delete(path);
+ await UserRepository.DeleteUser(user, CancellationToken.None).ConfigureAwait(false);
+
+ var path = user.ConfigurationFilePath;
+
+ try
+ {
+ File.Delete(path);
+ }
+ catch (IOException ex)
+ {
+ _logger.ErrorException("Error deleting file {0}", ex, path);
+ }
+
+ // Force this to be lazy loaded again
+ Users = await LoadUsers().ConfigureAwait(false);
+
+ OnUserDeleted(user);
}
- catch (IOException ex)
+ finally
{
- _logger.ErrorException("Error deleting file {0}", ex, path);
+ _userListLock.Release();
}
-
- // Force this to be lazy loaded again
- Users = await LoadUsers().ConfigureAwait(false);
-
- OnUserDeleted(user);
}
/// <summary>
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
index 6a4c3930a..db8786d62 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -1498,8 +1498,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
var programs = _programs.ToList();
- var startDate = programs.Select(i => i.Value.StartDate).Min();
- var endDate = programs.Select(i => i.Value.StartDate).Max();
+ var startDate = _programs.Count == 0 ? DateTime.MinValue :
+ programs.Select(i => i.Value.StartDate).Min();
+
+ var endDate = programs.Count == 0 ? DateTime.MinValue :
+ programs.Select(i => i.Value.StartDate).Max();
return new GuideInfo
{
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index 73a12caf2..ea7ef2ed6 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -48,14 +48,6 @@
<Reference Include="Alchemy">
<HintPath>..\packages\Alchemy.2.2.1\lib\net40\Alchemy.dll</HintPath>
</Reference>
- <Reference Include="BDInfo, Version=1.0.5167.21152, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\MediaBrowser.BdInfo.1.0.0.10\lib\net35\BDInfo.dll</HintPath>
- </Reference>
- <Reference Include="DvdLib, Version=1.0.5167.21152, Culture=neutral, PublicKeyToken=7a2f3f5ec8d93575, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\MediaBrowser.BdInfo.1.0.0.10\lib\net35\DvdLib.dll</HintPath>
- </Reference>
<Reference Include="Mono.Nat, Version=1.2.3.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Mono.Nat.1.2.3\lib\Net40\Mono.Nat.dll</HintPath>
@@ -105,7 +97,6 @@
<Compile Include="..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
- <Compile Include="BdInfo\BdInfoExaminer.cs" />
<Compile Include="Channels\ChannelImageProvider.cs" />
<Compile Include="Channels\ChannelItemImageProvider.cs" />
<Compile Include="Channels\ChannelManager.cs" />
@@ -191,7 +182,6 @@
<Compile Include="LiveTv\RefreshChannelsScheduledTask.cs" />
<Compile Include="Localization\LocalizationManager.cs" />
<Compile Include="MediaEncoder\EncodingManager.cs" />
- <Compile Include="MediaEncoder\MediaEncoder.cs" />
<Compile Include="News\NewsEntryPoint.cs" />
<Compile Include="News\NewsService.cs" />
<Compile Include="Persistence\SqliteChapterRepository.cs" />
diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs b/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs
index f74865d2c..7237ffee5 100644
--- a/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs
+++ b/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs
@@ -178,7 +178,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
{
Directory.CreateDirectory(Path.GetDirectoryName(path));
- using (var stream = await _encoder.ExtractImage(inputPath, type, false, video.Video3DFormat, time, cancellationToken).ConfigureAwait(false))
+ using (var stream = await _encoder.ExtractVideoImage(inputPath, type, video.Video3DFormat, time, cancellationToken).ConfigureAwait(false))
{
using (var fileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true))
{
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs
index f4e7fd0a6..fde1e7f21 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs
@@ -37,6 +37,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
var createTableCommand
= "create table if not exists mediastreams ";
+ // Add PixelFormat column
+
createTableCommand += "(ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PRIMARY KEY (ItemId, StreamIndex))";
string[] queries = {
diff --git a/MediaBrowser.Server.Implementations/Roku/RokuSessionController.cs b/MediaBrowser.Server.Implementations/Roku/RokuSessionController.cs
index 0e2f9e1b5..d806db1e0 100644
--- a/MediaBrowser.Server.Implementations/Roku/RokuSessionController.cs
+++ b/MediaBrowser.Server.Implementations/Roku/RokuSessionController.cs
@@ -146,5 +146,16 @@ namespace MediaBrowser.Server.Implementations.Roku
RequestContentType = "application/json"
});
}
+
+
+ public Task SendGenericCommand(GenericCommand command, CancellationToken cancellationToken)
+ {
+ return SendCommand(new WebSocketMessage<GenericCommand>
+ {
+ MessageType = "Command",
+ Data = command
+
+ }, cancellationToken);
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/ServerApplicationPaths.cs b/MediaBrowser.Server.Implementations/ServerApplicationPaths.cs
index c36c49df0..df2a5f83c 100644
--- a/MediaBrowser.Server.Implementations/ServerApplicationPaths.cs
+++ b/MediaBrowser.Server.Implementations/ServerApplicationPaths.cs
@@ -1,6 +1,6 @@
-using System;
-using MediaBrowser.Common.Implementations;
+using MediaBrowser.Common.Implementations;
using MediaBrowser.Controller;
+using System;
using System.IO;
namespace MediaBrowser.Server.Implementations
@@ -239,14 +239,20 @@ namespace MediaBrowser.Server.Implementations
}
}
+ private string _internalMetadataPath;
public string InternalMetadataPath
{
get
{
- return Path.Combine(DataPath, "metadata");
+ return _internalMetadataPath ?? (_internalMetadataPath = Path.Combine(DataPath, "metadata"));
+ }
+ set
+ {
+ _internalMetadataPath = value;
}
}
+
public string GetInternalMetadataPath(Guid id)
{
var idString = id.ToString("N");
diff --git a/MediaBrowser.Server.Implementations/Session/WebSocketController.cs b/MediaBrowser.Server.Implementations/Session/WebSocketController.cs
index 70d7ac071..ddf4ec2ca 100644
--- a/MediaBrowser.Server.Implementations/Session/WebSocketController.cs
+++ b/MediaBrowser.Server.Implementations/Session/WebSocketController.cs
@@ -198,5 +198,17 @@ namespace MediaBrowser.Server.Implementations.Session
}, cancellationToken);
}
+
+ public Task SendGenericCommand(GenericCommand command, CancellationToken cancellationToken)
+ {
+ var socket = GetActiveSocket();
+
+ return socket.SendAsync(new WebSocketMessage<GenericCommand>
+ {
+ MessageType = "Command",
+ Data = command
+
+ }, cancellationToken);
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/packages.config b/MediaBrowser.Server.Implementations/packages.config
index f04536190..d82e880c9 100644
--- a/MediaBrowser.Server.Implementations/packages.config
+++ b/MediaBrowser.Server.Implementations/packages.config
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Alchemy" version="2.2.1" targetFramework="net45" />
- <package id="MediaBrowser.BdInfo" version="1.0.0.10" targetFramework="net45" />
<package id="Mono.Nat" version="1.2.3" targetFramework="net45" />
<package id="morelinq" version="1.0.16006" targetFramework="net45" />
<package id="System.Data.SQLite.Core" version="1.0.91.3" targetFramework="net45" />
diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs
index e49244edf..b7e9017d6 100644
--- a/MediaBrowser.ServerApplication/ApplicationHost.cs
+++ b/MediaBrowser.ServerApplication/ApplicationHost.cs
@@ -33,13 +33,14 @@ using MediaBrowser.Controller.Sorting;
using MediaBrowser.Controller.Themes;
using MediaBrowser.Dlna;
using MediaBrowser.Dlna.PlayTo;
+using MediaBrowser.MediaEncoding.BdInfo;
+using MediaBrowser.MediaEncoding.Encoder;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Updates;
using MediaBrowser.Providers.Manager;
using MediaBrowser.Server.Implementations;
-using MediaBrowser.Server.Implementations.BdInfo;
using MediaBrowser.Server.Implementations.Channels;
using MediaBrowser.Server.Implementations.Collections;
using MediaBrowser.Server.Implementations.Configuration;
@@ -157,6 +158,7 @@ namespace MediaBrowser.ServerApplication
private IHttpServer HttpServer { get; set; }
private IDtoService DtoService { get; set; }
private IImageProcessor ImageProcessor { get; set; }
+ private ISeriesOrderManager SeriesOrderManager { get; set; }
/// <summary>
/// Gets or sets the media encoder.
@@ -441,7 +443,7 @@ namespace MediaBrowser.ServerApplication
FileOrganizationRepository = await GetFileOrganizationRepository().ConfigureAwait(false);
RegisterSingleInstance(FileOrganizationRepository);
- UserManager = new UserManager(Logger, ServerConfigurationManager, UserRepository);
+ UserManager = new UserManager(LogManager.GetLogger("UserManager"), ServerConfigurationManager, UserRepository);
RegisterSingleInstance(UserManager);
LibraryManager = new LibraryManager(Logger, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager);
@@ -453,6 +455,9 @@ namespace MediaBrowser.ServerApplication
ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, LibraryMonitor, LogManager, FileSystemManager);
RegisterSingleInstance(ProviderManager);
+ SeriesOrderManager = new SeriesOrderManager();
+ RegisterSingleInstance(SeriesOrderManager);
+
RegisterSingleInstance<ISearchEngine>(() => new SearchEngine(LogManager, LibraryManager, UserManager));
SessionManager = new SessionManager(UserDataManager, ServerConfigurationManager, Logger, UserRepository, LibraryManager, UserManager);
@@ -462,13 +467,19 @@ namespace MediaBrowser.ServerApplication
RegisterSingleInstance(HttpServer, false);
progress.Report(10);
- ServerManager = new ServerManager(this, JsonSerializer, Logger, ServerConfigurationManager);
+ ServerManager = new ServerManager(this, JsonSerializer, LogManager.GetLogger("ServerManager"), ServerConfigurationManager);
RegisterSingleInstance(ServerManager);
LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager);
RegisterSingleInstance(LocalizationManager);
- ImageProcessor = new ImageProcessor(Logger, ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer);
+ var innerProgress = new ActionableProgress<double>();
+ innerProgress.RegisterAction(p => progress.Report((.75 * p) + 15));
+
+ await RegisterMediaEncoder(innerProgress).ConfigureAwait(false);
+ progress.Report(90);
+
+ ImageProcessor = new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, MediaEncoder);
RegisterSingleInstance(ImageProcessor);
DtoService = new DtoService(Logger, LibraryManager, UserManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager);
@@ -477,17 +488,11 @@ namespace MediaBrowser.ServerApplication
var newsService = new Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer);
RegisterSingleInstance<INewsService>(newsService);
- var fileOrganizationService = new FileOrganizationService(TaskManager, FileOrganizationRepository, Logger, LibraryMonitor, LibraryManager, ServerConfigurationManager, FileSystemManager, ProviderManager);
+ var fileOrganizationService = new FileOrganizationService(TaskManager, FileOrganizationRepository, LogManager.GetLogger("FileOrganizationService"), LibraryMonitor, LibraryManager, ServerConfigurationManager, FileSystemManager, ProviderManager);
RegisterSingleInstance<IFileOrganizationService>(fileOrganizationService);
progress.Report(15);
- var innerProgress = new ActionableProgress<double>();
- innerProgress.RegisterAction(p => progress.Report((.75 * p) + 15));
-
- await RegisterMediaEncoder(innerProgress).ConfigureAwait(false);
- progress.Report(90);
-
EncodingManager = new EncodingManager(ServerConfigurationManager, FileSystemManager, Logger, ItemRepository,
MediaEncoder);
RegisterSingleInstance(EncodingManager);
@@ -498,7 +503,7 @@ namespace MediaBrowser.ServerApplication
var appThemeManager = new AppThemeManager(ApplicationPaths, FileSystemManager, JsonSerializer, Logger);
RegisterSingleInstance<IAppThemeManager>(appThemeManager);
- var dlnaManager = new DlnaManager(XmlSerializer, FileSystemManager, JsonSerializer);
+ var dlnaManager = new DlnaManager(XmlSerializer, FileSystemManager, ApplicationPaths, LogManager.GetLogger("DLNA"));
RegisterSingleInstance<IDlnaManager>(dlnaManager);
var collectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor);
@@ -680,6 +685,8 @@ namespace MediaBrowser.ServerApplication
GetExports<IImageSaver>(),
GetExports<IExternalId>());
+ SeriesOrderManager.AddParts(GetExports<ISeriesOrderProvider>());
+
ImageProcessor.AddParts(GetExports<IImageEnhancer>());
LiveTvManager.AddParts(GetExports<ILiveTvService>());
@@ -795,7 +802,7 @@ namespace MediaBrowser.ServerApplication
list.Add(typeof(ApiEntryPoint).Assembly);
// Include composable parts in the Dashboard assembly
- list.Add(typeof(DashboardInfo).Assembly);
+ list.Add(typeof(DashboardService).Assembly);
// Include composable parts in the Model assembly
list.Add(typeof(SystemInfo).Assembly);
@@ -815,7 +822,10 @@ namespace MediaBrowser.ServerApplication
// Server implementations
list.Add(typeof(ServerApplicationPaths).Assembly);
- // Dlna implementations
+ // MediaEncoding
+ list.Add(typeof(MediaEncoder).Assembly);
+
+ // Dlna
list.Add(typeof(PlayToServerEntryPoint).Assembly);
list.AddRange(Assemblies.GetAssembliesWithParts());
diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs
index 6afe9367e..3d490a1f8 100644
--- a/MediaBrowser.ServerApplication/MainStartup.cs
+++ b/MediaBrowser.ServerApplication/MainStartup.cs
@@ -1,12 +1,11 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Constants;
using MediaBrowser.Common.Implementations.Logging;
-using MediaBrowser.Common.Implementations.Updates;
-using MediaBrowser.Controller;
using MediaBrowser.Model.Logging;
using MediaBrowser.Server.Implementations;
using MediaBrowser.ServerApplication.Native;
using MediaBrowser.ServerApplication.Splash;
+using MediaBrowser.ServerApplication.Updates;
using Microsoft.Win32;
using System;
using System.Configuration.Install;
@@ -490,7 +489,7 @@ namespace MediaBrowser.ServerApplication
try
{
var serviceName = _isRunningAsService ? BackgroundService.Name : string.Empty;
- new ApplicationUpdater().UpdateApplication(MBApplication.MBServer, appPaths, updateArchive, logger, serviceName);
+ new ApplicationUpdater().UpdateApplication(appPaths, updateArchive, logger, serviceName);
// And just let the app exit so it can update
return true;
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
index 227d0dd1d..b49e100ab 100644
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
+++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
@@ -145,6 +145,7 @@
<Compile Include="Splash\SplashForm.Designer.cs">
<DependentUpon>SplashForm.cs</DependentUpon>
</Compile>
+ <Compile Include="Updates\ApplicationUpdater.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
@@ -195,6 +196,10 @@
<Project>{734098eb-6dc1-4dd0-a1ca-3140dcd2737c}</Project>
<Name>MediaBrowser.Dlna</Name>
</ProjectReference>
+ <ProjectReference Include="..\MediaBrowser.MediaEncoding\MediaBrowser.MediaEncoding.csproj">
+ <Project>{0bd82fa6-eb8a-4452-8af5-74f9c3849451}</Project>
+ <Name>MediaBrowser.MediaEncoding</Name>
+ </ProjectReference>
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
<Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
<Name>MediaBrowser.Model</Name>
diff --git a/MediaBrowser.Common.Implementations/Updates/ApplicationUpdater.cs b/MediaBrowser.ServerApplication/Updates/ApplicationUpdater.cs
index e24ff3064..9f3e44cb0 100644
--- a/MediaBrowser.Common.Implementations/Updates/ApplicationUpdater.cs
+++ b/MediaBrowser.ServerApplication/Updates/ApplicationUpdater.cs
@@ -3,14 +3,8 @@ using MediaBrowser.Model.Logging;
using System.Diagnostics;
using System.IO;
-namespace MediaBrowser.Common.Implementations.Updates
+namespace MediaBrowser.ServerApplication.Updates
{
- public enum MBApplication
- {
- MBServer,
- MBTheater
- }
-
/// <summary>
/// Update the specified application using the specified archive
/// </summary>
@@ -18,7 +12,7 @@ namespace MediaBrowser.Common.Implementations.Updates
{
private const string UpdaterExe = "Mediabrowser.Updater.exe";
private const string UpdaterDll = "Mediabrowser.InstallUtil.dll";
- public void UpdateApplication(MBApplication app, IApplicationPaths appPaths, string archive, ILogger logger, string restartServiceName)
+ public void UpdateApplication(IApplicationPaths appPaths, string archive, ILogger logger, string restartServiceName)
{
// First see if there is a version file and read that in
var version = "Unknown";
@@ -39,7 +33,7 @@ namespace MediaBrowser.Common.Implementations.Updates
logger.Info("Copying updater dependencies to temporary location");
File.Copy(source, tempUpdaterDll, true);
- var product = app == MBApplication.MBTheater ? "mbt" : "server";
+ const string product = "server";
// Our updater needs SS and ionic
source = Path.Combine(appPaths.ProgramSystemPath, "ServiceStack.Text.dll");
File.Copy(source, Path.Combine(Path.GetTempPath(), "ServiceStack.Text.dll"), true);
diff --git a/MediaBrowser.WebDashboard/Api/DashboardInfo.cs b/MediaBrowser.WebDashboard/Api/DashboardInfo.cs
deleted file mode 100644
index 78cc5a758..000000000
--- a/MediaBrowser.WebDashboard/Api/DashboardInfo.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using MediaBrowser.Model.Session;
-using MediaBrowser.Model.System;
-using MediaBrowser.Model.Tasks;
-using System;
-using System.Collections.Generic;
-
-namespace MediaBrowser.WebDashboard.Api
-{
- /// <summary>
- /// Class DashboardInfo
- /// </summary>
- public class DashboardInfo
- {
- /// <summary>
- /// Gets or sets the system info.
- /// </summary>
- /// <value>The system info.</value>
- public SystemInfo SystemInfo { get; set; }
-
- /// <summary>
- /// Gets or sets the running tasks.
- /// </summary>
- /// <value>The running tasks.</value>
- public List<TaskInfo> RunningTasks { get; set; }
-
- /// <summary>
- /// Gets or sets the application update task id.
- /// </summary>
- /// <value>The application update task id.</value>
- public Guid ApplicationUpdateTaskId { get; set; }
-
- /// <summary>
- /// Gets or sets the active connections.
- /// </summary>
- /// <value>The active connections.</value>
- public List<SessionInfoDto> ActiveConnections { get; set; }
- }
-
-}
diff --git a/MediaBrowser.WebDashboard/Api/DashboardInfoWebSocketListener.cs b/MediaBrowser.WebDashboard/Api/DashboardInfoWebSocketListener.cs
deleted file mode 100644
index af0f9e3a0..000000000
--- a/MediaBrowser.WebDashboard/Api/DashboardInfoWebSocketListener.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Common.ScheduledTasks;
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.Dto;
-using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Logging;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.WebDashboard.Api
-{
- /// <summary>
- /// Class DashboardInfoWebSocketListener
- /// </summary>
- class DashboardInfoWebSocketListener : BasePeriodicWebSocketListener<DashboardInfo, object>
- {
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- protected override string Name
- {
- get { return "DashboardInfo"; }
- }
-
- private readonly IServerApplicationHost _appHost;
-
- /// <summary>
- /// Gets or sets the task manager.
- /// </summary>
- /// <value>The task manager.</value>
- private readonly ITaskManager _taskManager;
-
- private readonly ISessionManager _sessionManager;
- private readonly IDtoService _dtoService;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="DashboardInfoWebSocketListener" /> class.
- /// </summary>
- /// <param name="appHost">The app host.</param>
- /// <param name="logger">The logger.</param>
- /// <param name="taskManager">The task manager.</param>
- /// <param name="sessionManager">The session manager.</param>
- public DashboardInfoWebSocketListener(IServerApplicationHost appHost, ILogger logger, ITaskManager taskManager, ISessionManager sessionManager, IDtoService dtoService)
- : base(logger)
- {
- _appHost = appHost;
- _taskManager = taskManager;
- _sessionManager = sessionManager;
- _dtoService = dtoService;
- }
-
- /// <summary>
- /// Gets the data to send.
- /// </summary>
- /// <param name="state">The state.</param>
- /// <returns>Task{IEnumerable{TaskInfo}}.</returns>
- protected override Task<DashboardInfo> GetDataToSend(object state)
- {
- return Task.FromResult(DashboardService.GetDashboardInfo(_appHost, _taskManager, _sessionManager, _dtoService));
- }
- }
-}
diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs
index 88f86632b..99afbbdd7 100644
--- a/MediaBrowser.WebDashboard/Api/DashboardService.cs
+++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs
@@ -1,16 +1,13 @@
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
-using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Plugins;
-using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Tasks;
using ServiceStack;
+using ServiceStack.Web;
using System;
using System.Collections.Generic;
using System.IO;
@@ -18,7 +15,6 @@ using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
-using ServiceStack.Web;
namespace MediaBrowser.WebDashboard.Api
{
@@ -67,14 +63,6 @@ namespace MediaBrowser.WebDashboard.Api
}
/// <summary>
- /// Class GetDashboardInfo
- /// </summary>
- [Route("/dashboard/dashboardInfo", "GET")]
- public class GetDashboardInfo : IReturn<DashboardInfo>
- {
- }
-
- /// <summary>
/// Class DashboardService
/// </summary>
public class DashboardService : IRestfulService, IHasResultFactory
@@ -98,12 +86,6 @@ namespace MediaBrowser.WebDashboard.Api
public IRequest Request { get; set; }
/// <summary>
- /// Gets or sets the task manager.
- /// </summary>
- /// <value>The task manager.</value>
- private readonly ITaskManager _taskManager;
-
- /// <summary>
/// The _app host
/// </summary>
private readonly IServerApplicationHost _appHost;
@@ -113,24 +95,18 @@ namespace MediaBrowser.WebDashboard.Api
/// </summary>
private readonly IServerConfigurationManager _serverConfigurationManager;
- private readonly ISessionManager _sessionManager;
- private readonly IDtoService _dtoService;
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="DashboardService" /> class.
/// </summary>
- /// <param name="taskManager">The task manager.</param>
/// <param name="appHost">The app host.</param>
/// <param name="serverConfigurationManager">The server configuration manager.</param>
- /// <param name="sessionManager">The session manager.</param>
- public DashboardService(ITaskManager taskManager, IServerApplicationHost appHost, IServerConfigurationManager serverConfigurationManager, ISessionManager sessionManager, IDtoService dtoService, IFileSystem fileSystem)
+ /// <param name="fileSystem">The file system.</param>
+ public DashboardService(IServerApplicationHost appHost, IServerConfigurationManager serverConfigurationManager, IFileSystem fileSystem)
{
- _taskManager = taskManager;
_appHost = appHost;
_serverConfigurationManager = serverConfigurationManager;
- _sessionManager = sessionManager;
- _dtoService = dtoService;
_fileSystem = fileSystem;
}
@@ -168,45 +144,6 @@ namespace MediaBrowser.WebDashboard.Api
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public object Get(GetDashboardInfo request)
- {
- var result = GetDashboardInfo(_appHost, _taskManager, _sessionManager, _dtoService);
-
- return ResultFactory.GetOptimizedResult(Request, result);
- }
-
- /// <summary>
- /// Gets the dashboard info.
- /// </summary>
- /// <param name="appHost">The app host.</param>
- /// <param name="taskManager">The task manager.</param>
- /// <param name="connectionManager">The connection manager.</param>
- /// <returns>DashboardInfo.</returns>
- public static DashboardInfo GetDashboardInfo(IServerApplicationHost appHost,
- ITaskManager taskManager,
- ISessionManager connectionManager, IDtoService dtoService)
- {
- var connections = connectionManager.Sessions.Where(i => i.IsActive).ToList();
-
- return new DashboardInfo
- {
- SystemInfo = appHost.GetSystemInfo(),
-
- RunningTasks = taskManager.ScheduledTasks.Where(i => i.State == TaskState.Running || i.State == TaskState.Cancelling)
- .Select(ScheduledTaskHelpers.GetTaskInfo)
- .ToList(),
-
- ApplicationUpdateTaskId = taskManager.ScheduledTasks.First(t => t.ScheduledTask.GetType().Name.Equals("SystemUpdateTask", StringComparison.OrdinalIgnoreCase)).Id,
-
- ActiveConnections = connections.Select(dtoService.GetSessionInfoDto).ToList()
- };
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
public object Get(GetDashboardConfigurationPage request)
{
var page = ServerEntryPoint.Instance.PluginConfigurationPages.First(p => p.Name.Equals(request.Name, StringComparison.OrdinalIgnoreCase));
@@ -473,6 +410,7 @@ namespace MediaBrowser.WebDashboard.Api
"alphapicker.js",
"addpluginpage.js",
"advancedconfigurationpage.js",
+ "advancedpaths.js",
"advancedserversettings.js",
"metadataadvanced.js",
"appsplayback.js",
@@ -484,6 +422,8 @@ namespace MediaBrowser.WebDashboard.Api
"dashboardinfo.js",
"dashboardpage.js",
"directorybrowser.js",
+ "dlnaprofile.js",
+ "dlnaprofiles.js",
"dlnasettings.js",
"editcollectionitems.js",
"edititemmetadata.js",
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index a0dbae3d4..6a8cc49b1 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -63,9 +63,7 @@
<Link>Properties\SharedVersion.cs</Link>
</Compile>
<Compile Include="Api\ConfigurationPageInfo.cs" />
- <Compile Include="Api\DashboardInfo.cs" />
<Compile Include="Api\DashboardService.cs" />
- <Compile Include="Api\DashboardInfoWebSocketListener.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ServerEntryPoint.cs" />
</ItemGroup>
@@ -85,6 +83,9 @@
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="ApiClient.js" />
+ <Content Include="dashboard-ui\advancedpaths.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\advancedserversettings.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -202,8 +203,12 @@
<Content Include="dashboard-ui\css\images\items\list\remotesearch.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\css\images\media\pause.png" />
- <Content Include="dashboard-ui\css\images\media\play.png" />
+ <Content Include="dashboard-ui\css\images\media\pause.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\css\images\media\play.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\css\images\media\tvflyout.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -219,6 +224,12 @@
<Content Include="dashboard-ui\dashboardinfopage.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\dlnaprofile.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\dlnaprofiles.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\dlnasettings.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -483,6 +494,9 @@
<Content Include="dashboard-ui\livetvrecordings.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\scripts\advancedpaths.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\scripts\advancedserversettings.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -504,6 +518,12 @@
<Content Include="dashboard-ui\scripts\dashboardinfo.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\scripts\dlnaprofile.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\scripts\dlnaprofiles.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\scripts\dlnasettings.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
diff --git a/MediaBrowser.sln b/MediaBrowser.sln
index 7ac158065..7dc06fb0c 100644
--- a/MediaBrowser.sln
+++ b/MediaBrowser.sln
@@ -41,6 +41,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.ServerApplicat
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Dlna", "MediaBrowser.Dlna\MediaBrowser.Dlna.csproj", "{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.MediaEncoding", "MediaBrowser.MediaEncoding\MediaBrowser.MediaEncoding.csproj", "{0BD82FA6-EB8A-4452-8AF5-74F9C3849451}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -247,6 +249,20 @@ Global
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|Win32.ActiveCfg = Release|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|x64.ActiveCfg = Release|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|x86.ActiveCfg = Release|Any CPU
+ {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|Win32.ActiveCfg = Release|Any CPU
+ {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|x64.ActiveCfg = Release|Any CPU
+ {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec
index c550b350c..a3b4533dd 100644
--- a/Nuget/MediaBrowser.Common.Internal.nuspec
+++ b/Nuget/MediaBrowser.Common.Internal.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common.Internal</id>
- <version>3.0.345</version>
+ <version>3.0.346</version>
<title>MediaBrowser.Common.Internal</title>
<authors>Luke</authors>
<owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
<description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
<copyright>Copyright © Media Browser 2013</copyright>
<dependencies>
- <dependency id="MediaBrowser.Common" version="3.0.345" />
+ <dependency id="MediaBrowser.Common" version="3.0.346" />
<dependency id="NLog" version="2.1.0" />
<dependency id="SimpleInjector" version="2.4.1" />
<dependency id="sharpcompress" version="0.10.2" />
diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec
index a6fa5c152..b80f673e3 100644
--- a/Nuget/MediaBrowser.Common.nuspec
+++ b/Nuget/MediaBrowser.Common.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common</id>
- <version>3.0.345</version>
+ <version>3.0.346</version>
<title>MediaBrowser.Common</title>
<authors>Media Browser Team</authors>
<owners>ebr,Luke,scottisafool</owners>
diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec
index cc87b0030..eccfcccd2 100644
--- a/Nuget/MediaBrowser.Server.Core.nuspec
+++ b/Nuget/MediaBrowser.Server.Core.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>MediaBrowser.Server.Core</id>
- <version>3.0.345</version>
+ <version>3.0.346</version>
<title>Media Browser.Server.Core</title>
<authors>Media Browser Team</authors>
<owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
<description>Contains core components required to build plugins for Media Browser Server.</description>
<copyright>Copyright © Media Browser 2013</copyright>
<dependencies>
- <dependency id="MediaBrowser.Common" version="3.0.345" />
+ <dependency id="MediaBrowser.Common" version="3.0.346" />
</dependencies>
</metadata>
<files>